Blame source/vdo/base/waitQueue.h

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