|
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 */
|