Blame source/uds/util/eventCount.h

Packit Service 310c69
/*
Packit Service 310c69
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 310c69
 *
Packit Service 310c69
 * This program is free software; you can redistribute it and/or
Packit Service 310c69
 * modify it under the terms of the GNU General Public License
Packit Service 310c69
 * as published by the Free Software Foundation; either version 2
Packit Service 310c69
 * of the License, or (at your option) any later version.
Packit Service 310c69
 * 
Packit Service 310c69
 * This program is distributed in the hope that it will be useful,
Packit Service 310c69
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 310c69
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 310c69
 * GNU General Public License for more details.
Packit Service 310c69
 * 
Packit Service 310c69
 * You should have received a copy of the GNU General Public License
Packit Service 310c69
 * along with this program; if not, write to the Free Software
Packit Service 310c69
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 310c69
 * 02110-1301, USA. 
Packit Service 310c69
 *
Packit Service 310c69
 * $Id: //eng/uds-releases/jasper/src/uds/util/eventCount.h#1 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#ifndef EVENT_COUNT_H
Packit Service 310c69
#define EVENT_COUNT_H
Packit Service 310c69
Packit Service 310c69
#include "timeUtils.h"
Packit Service 310c69
#include "typeDefs.h"
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * An EventCount is a lock-free equivalent of a condition variable.
Packit Service 310c69
 *
Packit Service 310c69
 * Using an EventCount, a lock-free producer/consumer can wait for a state
Packit Service 310c69
 * change (adding an item to an empty queue, for example) without spinning or
Packit Service 310c69
 * falling back on the use of mutex-based locks. Signalling is cheap when
Packit Service 310c69
 * there are no waiters (a memory fence), and preparing to wait is
Packit Service 310c69
 * also inexpensive (an atomic add instruction).
Packit Service 310c69
 *
Packit Service 310c69
 * A lock-free producer should call eventCountBroadcast() after any mutation
Packit Service 310c69
 * to the lock-free data structure that a consumer might be waiting on. The
Packit Service 310c69
 * consumers should poll for work like this:
Packit Service 310c69
 *
Packit Service 310c69
 *   for (;;) {
Packit Service 310c69
 *     // Fast path--no additional cost to consumer.
Packit Service 310c69
 *     if (lockFreeDequeue(&item)) {
Packit Service 310c69
 *       return item;
Packit Service 310c69
 *     }
Packit Service 310c69
 *     // Two-step wait: get current token and poll state, either cancelling
Packit Service 310c69
 *     // the wait or waiting for the token to be signalled.
Packit Service 310c69
 *     EventToken token = eventCountPrepare(ec);
Packit Service 310c69
 *     if (lockFreeDequeue(&item)) {
Packit Service 310c69
 *       eventCountCancel(ec, token);
Packit Service 310c69
 *       return item;
Packit Service 310c69
 *     }
Packit Service 310c69
 *     eventCountWait(ec, token, NULL);
Packit Service 310c69
 *     // State has changed, but must check condition again, so loop.
Packit Service 310c69
 *   }
Packit Service 310c69
 *
Packit Service 310c69
 * Once eventCountPrepare() is called, the caller should neither dally, sleep,
Packit Service 310c69
 * nor perform long-running or blocking actions before passing the token to
Packit Service 310c69
 * eventCountCancel() or eventCountWait(). The implementation is optimized for
Packit Service 310c69
 * a short polling window, and will not perform well if there are outstanding
Packit Service 310c69
 * tokens that have been signalled but not waited upon.
Packit Service 310c69
 **/
Packit Service 310c69
Packit Service 310c69
typedef struct eventCount EventCount;
Packit Service 310c69
Packit Service 310c69
typedef unsigned int EventToken;
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Allocate and initialize an EventCount.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ecPtr  a pointer to hold the new EventCount
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
int makeEventCount(EventCount **ecPtr);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Free an EventCount. It must no longer be in use.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ec  the EventCount to free
Packit Service 310c69
 **/
Packit Service 310c69
void freeEventCount(EventCount *ec);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Wake all threads that are waiting for the next event.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ec  the EventCount to signal
Packit Service 310c69
 **/
Packit Service 310c69
void eventCountBroadcast(EventCount *ec);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Prepare to wait for the EventCount to change by capturing a token of its
Packit Service 310c69
 * current state. The caller MUST eventually either call eventCountWait() or
Packit Service 310c69
 * eventCountCancel() exactly once for each token obtained.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ec  the EventCount on which to prepare to wait
Packit Service 310c69
 *
Packit Service 310c69
 * @return an EventToken to be passed to the next eventCountWait() call
Packit Service 310c69
 **/
Packit Service 310c69
EventToken eventCountPrepare(EventCount *ec)
Packit Service 310c69
  __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Cancel a wait token that has been prepared but not waited upon. This must
Packit Service 310c69
 * be called after eventCountPrepare() when eventCountWait() is not going to
Packit Service 310c69
 * be invoked on the token.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ec     the EventCount from which a wait token was obtained
Packit Service 310c69
 * @param token  the wait token that will never be passed to eventCountWait()
Packit Service 310c69
 **/
Packit Service 310c69
void eventCountCancel(EventCount *ec, EventToken token);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Check if the current event count state corresponds to the provided token,
Packit Service 310c69
 * and if it is, wait for a signal that the state has changed. If an optional
Packit Service 310c69
 * timeout is provided, the wait will terminate after the timeout has elapsed.
Packit Service 310c69
 * Timing out automatically cancels the wait token, so callers must not
Packit Service 310c69
 * attempt to cancel the token on timeout.
Packit Service 310c69
 *
Packit Service 310c69
 * @param ec       the EventCount on which to wait
Packit Service 310c69
 * @param token    the EventToken returned by eventCountPrepare()
Packit Service 310c69
 * @param timeout  either NULL or a relative timeout for the wait operation
Packit Service 310c69
 *
Packit Service 310c69
 * @return true if the state has already changed or if signalled, otherwise
Packit Service 310c69
 *         false if a timeout was provided and the wait timed out
Packit Service 310c69
 **/
Packit Service 310c69
bool eventCountWait(EventCount *ec, EventToken token, const RelTime *timeout);
Packit Service 310c69
Packit Service 310c69
#endif /* EVENT_COUNT_H */