xref: /linux/drivers/md/dm-vdo/wait-queue.h (revision 4fcb4290dfe303de048fe01968513da6f4512147)
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