1*4fcb4290SMatthew Sakai /* SPDX-License-Identifier: GPL-2.0-only */ 2*4fcb4290SMatthew Sakai /* 3*4fcb4290SMatthew Sakai * Copyright 2023 Red Hat 4*4fcb4290SMatthew Sakai */ 5*4fcb4290SMatthew Sakai 6*4fcb4290SMatthew Sakai #ifndef VDO_WAIT_QUEUE_H 7*4fcb4290SMatthew Sakai #define VDO_WAIT_QUEUE_H 8*4fcb4290SMatthew Sakai 9*4fcb4290SMatthew Sakai #include <linux/compiler.h> 10*4fcb4290SMatthew Sakai #include <linux/types.h> 11*4fcb4290SMatthew Sakai 12*4fcb4290SMatthew Sakai /** 13*4fcb4290SMatthew Sakai * DOC: Wait queues. 14*4fcb4290SMatthew Sakai * 15*4fcb4290SMatthew Sakai * A wait queue is a circular list of entries waiting to be notified of a change in a condition. 16*4fcb4290SMatthew Sakai * Keeping a circular list allows the queue structure to simply be a pointer to the tail (newest) 17*4fcb4290SMatthew Sakai * entry in the queue, supporting constant-time enqueue and dequeue operations. A null pointer is 18*4fcb4290SMatthew Sakai * an empty queue. 19*4fcb4290SMatthew Sakai * 20*4fcb4290SMatthew Sakai * An empty queue: 21*4fcb4290SMatthew Sakai * queue0.last_waiter -> NULL 22*4fcb4290SMatthew Sakai * 23*4fcb4290SMatthew Sakai * A singleton queue: 24*4fcb4290SMatthew Sakai * queue1.last_waiter -> entry1 -> entry1 -> [...] 25*4fcb4290SMatthew Sakai * 26*4fcb4290SMatthew Sakai * A three-element queue: 27*4fcb4290SMatthew Sakai * queue2.last_waiter -> entry3 -> entry1 -> entry2 -> entry3 -> [...] 28*4fcb4290SMatthew Sakai */ 29*4fcb4290SMatthew Sakai 30*4fcb4290SMatthew Sakai struct waiter; 31*4fcb4290SMatthew Sakai 32*4fcb4290SMatthew Sakai struct wait_queue { 33*4fcb4290SMatthew Sakai /* The tail of the queue, the last (most recently added) entry */ 34*4fcb4290SMatthew Sakai struct waiter *last_waiter; 35*4fcb4290SMatthew Sakai /* The number of waiters currently in the queue */ 36*4fcb4290SMatthew Sakai size_t queue_length; 37*4fcb4290SMatthew Sakai }; 38*4fcb4290SMatthew Sakai 39*4fcb4290SMatthew Sakai /** 40*4fcb4290SMatthew Sakai * typedef waiter_callback_fn - Callback type for functions which will be called to resume 41*4fcb4290SMatthew Sakai * processing of a waiter after it has been removed from its wait 42*4fcb4290SMatthew Sakai * queue. 43*4fcb4290SMatthew Sakai */ 44*4fcb4290SMatthew Sakai typedef void (*waiter_callback_fn)(struct waiter *waiter, void *context); 45*4fcb4290SMatthew Sakai 46*4fcb4290SMatthew Sakai /** 47*4fcb4290SMatthew Sakai * typedef waiter_match_fn - Method type for waiter matching methods. 48*4fcb4290SMatthew Sakai * 49*4fcb4290SMatthew Sakai * A waiter_match_fn method returns false if the waiter does not match. 50*4fcb4290SMatthew Sakai */ 51*4fcb4290SMatthew Sakai typedef bool (*waiter_match_fn)(struct waiter *waiter, void *context); 52*4fcb4290SMatthew Sakai 53*4fcb4290SMatthew Sakai /* The queue entry structure for entries in a wait_queue. */ 54*4fcb4290SMatthew Sakai struct waiter { 55*4fcb4290SMatthew Sakai /* 56*4fcb4290SMatthew Sakai * The next waiter in the queue. If this entry is the last waiter, then this is actually a 57*4fcb4290SMatthew Sakai * pointer back to the head of the queue. 58*4fcb4290SMatthew Sakai */ 59*4fcb4290SMatthew Sakai struct waiter *next_waiter; 60*4fcb4290SMatthew Sakai 61*4fcb4290SMatthew Sakai /* Optional waiter-specific callback to invoke when waking this waiter. */ 62*4fcb4290SMatthew Sakai waiter_callback_fn callback; 63*4fcb4290SMatthew Sakai }; 64*4fcb4290SMatthew Sakai 65*4fcb4290SMatthew Sakai /** 66*4fcb4290SMatthew Sakai * is_waiting() - Check whether a waiter is waiting. 67*4fcb4290SMatthew Sakai * @waiter: The waiter to check. 68*4fcb4290SMatthew Sakai * 69*4fcb4290SMatthew Sakai * Return: true if the waiter is on some wait_queue. 70*4fcb4290SMatthew Sakai */ 71*4fcb4290SMatthew Sakai static inline bool vdo_is_waiting(struct waiter *waiter) 72*4fcb4290SMatthew Sakai { 73*4fcb4290SMatthew Sakai return (waiter->next_waiter != NULL); 74*4fcb4290SMatthew Sakai } 75*4fcb4290SMatthew Sakai 76*4fcb4290SMatthew Sakai /** 77*4fcb4290SMatthew Sakai * initialize_wait_queue() - Initialize a wait queue. 78*4fcb4290SMatthew Sakai * @queue: The queue to initialize. 79*4fcb4290SMatthew Sakai */ 80*4fcb4290SMatthew Sakai static inline void vdo_initialize_wait_queue(struct wait_queue *queue) 81*4fcb4290SMatthew Sakai { 82*4fcb4290SMatthew Sakai *queue = (struct wait_queue) { 83*4fcb4290SMatthew Sakai .last_waiter = NULL, 84*4fcb4290SMatthew Sakai .queue_length = 0, 85*4fcb4290SMatthew Sakai }; 86*4fcb4290SMatthew Sakai } 87*4fcb4290SMatthew Sakai 88*4fcb4290SMatthew Sakai /** 89*4fcb4290SMatthew Sakai * has_waiters() - Check whether a wait queue has any entries waiting in it. 90*4fcb4290SMatthew Sakai * @queue: The queue to query. 91*4fcb4290SMatthew Sakai * 92*4fcb4290SMatthew Sakai * Return: true if there are any waiters in the queue. 93*4fcb4290SMatthew Sakai */ 94*4fcb4290SMatthew Sakai static inline bool __must_check vdo_has_waiters(const struct wait_queue *queue) 95*4fcb4290SMatthew Sakai { 96*4fcb4290SMatthew Sakai return (queue->last_waiter != NULL); 97*4fcb4290SMatthew Sakai } 98*4fcb4290SMatthew Sakai 99*4fcb4290SMatthew Sakai void vdo_enqueue_waiter(struct wait_queue *queue, struct waiter *waiter); 100*4fcb4290SMatthew Sakai 101*4fcb4290SMatthew Sakai void vdo_notify_all_waiters(struct wait_queue *queue, waiter_callback_fn callback, 102*4fcb4290SMatthew Sakai void *context); 103*4fcb4290SMatthew Sakai 104*4fcb4290SMatthew Sakai bool vdo_notify_next_waiter(struct wait_queue *queue, waiter_callback_fn callback, 105*4fcb4290SMatthew Sakai void *context); 106*4fcb4290SMatthew Sakai 107*4fcb4290SMatthew Sakai void vdo_transfer_all_waiters(struct wait_queue *from_queue, 108*4fcb4290SMatthew Sakai struct wait_queue *to_queue); 109*4fcb4290SMatthew Sakai 110*4fcb4290SMatthew Sakai struct waiter *vdo_get_first_waiter(const struct wait_queue *queue); 111*4fcb4290SMatthew Sakai 112*4fcb4290SMatthew Sakai void vdo_dequeue_matching_waiters(struct wait_queue *queue, waiter_match_fn match_method, 113*4fcb4290SMatthew Sakai void *match_context, struct wait_queue *matched_queue); 114*4fcb4290SMatthew Sakai 115*4fcb4290SMatthew Sakai struct waiter *vdo_dequeue_next_waiter(struct wait_queue *queue); 116*4fcb4290SMatthew Sakai 117*4fcb4290SMatthew Sakai /** 118*4fcb4290SMatthew Sakai * count_waiters() - Count the number of waiters in a wait queue. 119*4fcb4290SMatthew Sakai * @queue: The wait queue to query. 120*4fcb4290SMatthew Sakai * 121*4fcb4290SMatthew Sakai * Return: The number of waiters in the queue. 122*4fcb4290SMatthew Sakai */ 123*4fcb4290SMatthew Sakai static inline size_t __must_check vdo_count_waiters(const struct wait_queue *queue) 124*4fcb4290SMatthew Sakai { 125*4fcb4290SMatthew Sakai return queue->queue_length; 126*4fcb4290SMatthew Sakai } 127*4fcb4290SMatthew Sakai 128*4fcb4290SMatthew Sakai const struct waiter * __must_check vdo_get_next_waiter(const struct wait_queue *queue, 129*4fcb4290SMatthew Sakai const struct waiter *waiter); 130*4fcb4290SMatthew Sakai 131*4fcb4290SMatthew Sakai #endif /* VDO_WAIT_QUEUE_H */ 132