2023-11-16 19:46:10 -05:00
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2023 Red Hat
*/
# ifndef VDO_WAIT_QUEUE_H
# define VDO_WAIT_QUEUE_H
# include <linux/compiler.h>
# include <linux/types.h>
/**
2023-11-20 17:29:16 -05:00
* A vdo_wait_queue is a circular singly linked list of entries waiting to be notified
* of a change in a condition . Keeping a circular list allows the vdo_wait_queue
* structure to simply be a pointer to the tail ( newest ) entry , supporting
* constant - time enqueue and dequeue operations . A null pointer is an empty waitq .
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* An empty waitq :
* waitq0 . last_waiter - > NULL
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* A singleton waitq :
* waitq1 . last_waiter - > entry1 - > entry1 - > [ . . . ]
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* A three - element waitq :
* waitq2 . last_waiter - > entry3 - > entry1 - > entry2 - > entry3 - > [ . . . ]
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* linux / wait . h ' s wait_queue_head is _not_ used because vdo_wait_queue ' s
* interface is much less complex ( doesn ' t need locking , priorities or timers ) .
* Made possible by vdo ' s thread - based resource allocation and locking ; and
* the polling nature of vdo_wait_queue consumers .
*
* FIXME : could be made to use a linux / list . h ' s list_head but its extra barriers
* really aren ' t needed . Nor is a doubly linked list , but vdo_wait_queue could
* make use of __list_del_clearprev ( ) - - but that would compromise the ability
* to make full use of linux ' s list interface .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
struct vdo_waiter ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
struct vdo_wait_queue {
2023-11-16 19:46:10 -05:00
/* The tail of the queue, the last (most recently added) entry */
2023-11-20 17:29:16 -05:00
struct vdo_waiter * last_waiter ;
2023-11-16 19:46:10 -05:00
/* The number of waiters currently in the queue */
2023-11-20 17:29:16 -05:00
size_t length ;
2023-11-16 19:46:10 -05:00
} ;
/**
2023-11-20 17:29:16 -05:00
* vdo_waiter_callback_fn - Callback type that will be called to resume processing
* of a waiter after it has been removed from its wait queue .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
typedef void ( * vdo_waiter_callback_fn ) ( struct vdo_waiter * waiter , void * context ) ;
2023-11-16 19:46:10 -05:00
/**
2023-11-20 17:29:16 -05:00
* vdo_waiter_match_fn - Method type for waiter matching methods .
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* Returns false if the waiter does not match .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
typedef bool ( * vdo_waiter_match_fn ) ( struct vdo_waiter * waiter , void * context ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
/* The structure for entries in a vdo_wait_queue. */
struct vdo_waiter {
2023-11-16 19:46:10 -05:00
/*
2023-11-20 17:29:16 -05:00
* The next waiter in the waitq . If this entry is the last waiter , then this
* is actually a pointer back to the head of the waitq .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
struct vdo_waiter * next_waiter ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
/* Optional waiter-specific callback to invoke when dequeuing this waiter. */
vdo_waiter_callback_fn callback ;
2023-11-16 19:46:10 -05:00
} ;
/**
2023-11-20 17:29:16 -05:00
* vdo_waiter_is_waiting ( ) - Check whether a waiter is waiting .
2023-11-16 19:46:10 -05:00
* @ waiter : The waiter to check .
*
2023-11-20 17:29:16 -05:00
* Return : true if the waiter is on some vdo_wait_queue .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
static inline bool vdo_waiter_is_waiting ( struct vdo_waiter * waiter )
2023-11-16 19:46:10 -05:00
{
return ( waiter - > next_waiter ! = NULL ) ;
}
/**
2023-11-20 17:29:16 -05:00
* vdo_waitq_init ( ) - Initialize a vdo_wait_queue .
* @ waitq : The vdo_wait_queue to initialize .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
static inline void vdo_waitq_init ( struct vdo_wait_queue * waitq )
2023-11-16 19:46:10 -05:00
{
2023-11-20 17:29:16 -05:00
* waitq = ( struct vdo_wait_queue ) {
2023-11-16 19:46:10 -05:00
. last_waiter = NULL ,
2023-11-20 17:29:16 -05:00
. length = 0 ,
2023-11-16 19:46:10 -05:00
} ;
}
/**
2023-11-20 17:29:16 -05:00
* vdo_waitq_has_waiters ( ) - Check whether a vdo_wait_queue has any entries waiting .
* @ waitq : The vdo_wait_queue to query .
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* Return : true if there are any waiters in the waitq .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
static inline bool __must_check vdo_waitq_has_waiters ( const struct vdo_wait_queue * waitq )
2023-11-16 19:46:10 -05:00
{
2023-11-20 17:29:16 -05:00
return ( waitq - > last_waiter ! = NULL ) ;
2023-11-16 19:46:10 -05:00
}
2023-11-20 17:29:16 -05:00
void vdo_waitq_enqueue_waiter ( struct vdo_wait_queue * waitq ,
struct vdo_waiter * waiter ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:20 -05:00
struct vdo_waiter * vdo_waitq_dequeue_waiter ( struct vdo_wait_queue * waitq ) ;
2023-11-20 17:29:16 -05:00
void vdo_waitq_notify_all_waiters ( struct vdo_wait_queue * waitq ,
vdo_waiter_callback_fn callback , void * context ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
bool vdo_waitq_notify_next_waiter ( struct vdo_wait_queue * waitq ,
vdo_waiter_callback_fn callback , void * context ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
void vdo_waitq_transfer_all_waiters ( struct vdo_wait_queue * from_waitq ,
struct vdo_wait_queue * to_waitq ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
struct vdo_waiter * vdo_waitq_get_first_waiter ( const struct vdo_wait_queue * waitq ) ;
2023-11-16 19:46:10 -05:00
2023-11-20 17:29:16 -05:00
void vdo_waitq_dequeue_matching_waiters ( struct vdo_wait_queue * waitq ,
vdo_waiter_match_fn waiter_match ,
void * match_context ,
struct vdo_wait_queue * matched_waitq ) ;
2023-11-16 19:46:10 -05:00
/**
2023-11-20 17:29:16 -05:00
* vdo_waitq_num_waiters ( ) - Return the number of waiters in a vdo_wait_queue .
* @ waitq : The vdo_wait_queue to query .
2023-11-16 19:46:10 -05:00
*
2023-11-20 17:29:16 -05:00
* Return : The number of waiters in the waitq .
2023-11-16 19:46:10 -05:00
*/
2023-11-20 17:29:16 -05:00
static inline size_t __must_check vdo_waitq_num_waiters ( const struct vdo_wait_queue * waitq )
2023-11-16 19:46:10 -05:00
{
2023-11-20 17:29:16 -05:00
return waitq - > length ;
2023-11-16 19:46:10 -05:00
}
# endif /* VDO_WAIT_QUEUE_H */