|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
d40955 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
d40955 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
d40955 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d40955 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d40955 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d40955 |
* GNU General Public License for more details.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d40955 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d40955 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
d40955 |
* 02110-1301, USA.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/waitQueue.h#1 $
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#ifndef WAIT_QUEUE_H
|
|
Packit Service |
d40955 |
#define WAIT_QUEUE_H
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "common.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* A wait queue is a circular list of entries waiting to be notified of a
|
|
Packit Service |
d40955 |
* change in a condition. Keeping a circular list allows the queue structure
|
|
Packit Service |
d40955 |
* to simply be a pointer to the tail (newest) entry in the queue, supporting
|
|
Packit Service |
d40955 |
* constant-time enqueue and dequeue operations. A null pointer is an empty
|
|
Packit Service |
d40955 |
* queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* An empty queue:
|
|
Packit Service |
d40955 |
* queue0.lastWaiter -> NULL
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* A singleton queue:
|
|
Packit Service |
d40955 |
* queue1.lastWaiter -> entry1 -> entry1 -> [...]
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* A three-element queue:
|
|
Packit Service |
d40955 |
* queue2.lastWaiter -> entry3 -> entry1 -> entry2 -> entry3 -> [...]
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
typedef struct waiter Waiter;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
/** The tail of the queue, the last (most recently added) entry */
|
|
Packit Service |
d40955 |
Waiter *lastWaiter;
|
|
Packit Service |
d40955 |
/** The number of waiters currently in the queue */
|
|
Packit Service |
d40955 |
size_t queueLength;
|
|
Packit Service |
d40955 |
} WaitQueue;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Callback type for functions which will be called to resume processing of a
|
|
Packit Service |
d40955 |
* waiter after it has been removed from its wait queue.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
typedef void WaiterCallback(Waiter *waiter, void *context);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Method type for Waiter matching methods.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* A WaiterMatch method returns false if the waiter does not match.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
typedef bool WaiterMatch(Waiter *waiter, void *context);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* The queue entry structure for entries in a WaitQueue.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
struct waiter {
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* The next waiter in the queue. If this entry is the last waiter, then this
|
|
Packit Service |
d40955 |
* is actually a pointer back to the head of the queue.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
struct waiter *nextWaiter;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/** Optional waiter-specific callback to invoke when waking this waiter. */
|
|
Packit Service |
d40955 |
WaiterCallback *callback;
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Check whether a Waiter is waiting.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param waiter The waiter to check
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return true if the waiter is on some WaitQueue
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static inline bool isWaiting(Waiter *waiter)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return (waiter->nextWaiter != NULL);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Initialize a wait queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The queue to initialize
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static inline void initializeWaitQueue(WaitQueue *queue)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
*queue = (WaitQueue) {
|
|
Packit Service |
d40955 |
.lastWaiter = NULL,
|
|
Packit Service |
d40955 |
.queueLength = 0,
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Check whether a wait queue has any entries waiting in it.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The queue to query
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return true if there are any waiters in the queue
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static inline bool hasWaiters(const WaitQueue *queue)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return (queue->lastWaiter != NULL);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Add a waiter to the tail end of a wait queue. The waiter must not already
|
|
Packit Service |
d40955 |
* be waiting in a queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The queue to which to add the waiter
|
|
Packit Service |
d40955 |
* @param waiter The waiter to add to the queue
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
int enqueueWaiter(WaitQueue *queue, Waiter *waiter)
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result));
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Notify all the entries waiting in a queue to continue execution by invoking
|
|
Packit Service |
d40955 |
* a callback function on each of them in turn. The queue is copied and
|
|
Packit Service |
d40955 |
* emptied before invoking any callbacks, and only the waiters that were in
|
|
Packit Service |
d40955 |
* the queue at the start of the call will be notified.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue containing the waiters to notify
|
|
Packit Service |
d40955 |
* @param callback The function to call to notify each waiter, or NULL
|
|
Packit Service |
d40955 |
* to invoke the callback field registered in each waiter
|
|
Packit Service |
d40955 |
* @param context The context to pass to the callback function
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
void notifyAllWaiters(WaitQueue *queue,
|
|
Packit Service |
d40955 |
WaiterCallback *callback,
|
|
Packit Service |
d40955 |
void *context);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Notify the next entry waiting in a queue to continue execution by invoking
|
|
Packit Service |
d40955 |
* a callback function on it after removing it from the queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue containing the waiter to notify
|
|
Packit Service |
d40955 |
* @param callback The function to call to notify the waiter, or NULL
|
|
Packit Service |
d40955 |
* to invoke the callback field registered in the waiter
|
|
Packit Service |
d40955 |
* @param context The context to pass to the callback function
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return true if there was a waiter in the queue
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
bool notifyNextWaiter(WaitQueue *queue,
|
|
Packit Service |
d40955 |
WaiterCallback *callback,
|
|
Packit Service |
d40955 |
void *context);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Transfer all waiters from one wait queue to a second queue, emptying the
|
|
Packit Service |
d40955 |
* first queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param fromQueue The queue containing the waiters to move
|
|
Packit Service |
d40955 |
* @param toQueue The queue that will receive the waiters from the
|
|
Packit Service |
d40955 |
* the first queue
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
void transferAllWaiters(WaitQueue *fromQueue, WaitQueue *toQueue);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Return the waiter that is at the head end of a wait queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The queue from which to get the first waiter
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return The first (oldest) waiter in the queue, or NULL if
|
|
Packit Service |
d40955 |
* the queue is empty
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
Waiter *getFirstWaiter(const WaitQueue *queue);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Remove all waiters that match based on the specified matching method and
|
|
Packit Service |
d40955 |
* append them to a WaitQueue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue to process
|
|
Packit Service |
d40955 |
* @param matchMethod The method to determine matching
|
|
Packit Service |
d40955 |
* @param matchContext Contextual info for the match method
|
|
Packit Service |
d40955 |
* @param matchedQueue A WaitQueue to store matches
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
int dequeueMatchingWaiters(WaitQueue *queue,
|
|
Packit Service |
d40955 |
WaiterMatch *matchMethod,
|
|
Packit Service |
d40955 |
void *matchContext,
|
|
Packit Service |
d40955 |
WaitQueue *matchedQueue);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Remove the first waiter from the head end of a wait queue. The caller will
|
|
Packit Service |
d40955 |
* be responsible for waking the waiter by invoking the correct callback
|
|
Packit Service |
d40955 |
* function to resume its execution.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue from which to remove the first entry
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return The first (oldest) waiter in the queue, or NULL if
|
|
Packit Service |
d40955 |
* the queue is empty
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
Waiter *dequeueNextWaiter(WaitQueue *queue);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Count the number of waiters in a wait queue.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue to query
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return the number of waiters in the queue
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static inline size_t countWaiters(const WaitQueue *queue)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return queue->queueLength;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Get the waiter after this one, for debug iteration.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param queue The wait queue
|
|
Packit Service |
d40955 |
* @param waiter A waiter
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return the next waiter, or NULL
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
const Waiter *getNextWaiter(const WaitQueue *queue, const Waiter *waiter)
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result));
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#endif // WAIT_QUEUE_H
|