14fcb4290SMatthew Sakai /* SPDX-License-Identifier: GPL-2.0-only */ 24fcb4290SMatthew Sakai /* 34fcb4290SMatthew Sakai * Copyright 2023 Red Hat 44fcb4290SMatthew Sakai */ 54fcb4290SMatthew Sakai 64fcb4290SMatthew Sakai #ifndef VDO_WAIT_QUEUE_H 74fcb4290SMatthew Sakai #define VDO_WAIT_QUEUE_H 84fcb4290SMatthew Sakai 94fcb4290SMatthew Sakai #include <linux/compiler.h> 104fcb4290SMatthew Sakai #include <linux/types.h> 114fcb4290SMatthew Sakai 124fcb4290SMatthew Sakai /** 13*d6e260ccSMike Snitzer * A vdo_wait_queue is a circular singly linked list of entries waiting to be notified 14*d6e260ccSMike Snitzer * of a change in a condition. Keeping a circular list allows the vdo_wait_queue 15*d6e260ccSMike Snitzer * structure to simply be a pointer to the tail (newest) entry, supporting 16*d6e260ccSMike Snitzer * constant-time enqueue and dequeue operations. A null pointer is an empty waitq. 174fcb4290SMatthew Sakai * 18*d6e260ccSMike Snitzer * An empty waitq: 19*d6e260ccSMike Snitzer * waitq0.last_waiter -> NULL 204fcb4290SMatthew Sakai * 21*d6e260ccSMike Snitzer * A singleton waitq: 22*d6e260ccSMike Snitzer * waitq1.last_waiter -> entry1 -> entry1 -> [...] 234fcb4290SMatthew Sakai * 24*d6e260ccSMike Snitzer * A three-element waitq: 25*d6e260ccSMike Snitzer * waitq2.last_waiter -> entry3 -> entry1 -> entry2 -> entry3 -> [...] 264fcb4290SMatthew Sakai * 27*d6e260ccSMike Snitzer * linux/wait.h's wait_queue_head is _not_ used because vdo_wait_queue's 28*d6e260ccSMike Snitzer * interface is much less complex (doesn't need locking, priorities or timers). 29*d6e260ccSMike Snitzer * Made possible by vdo's thread-based resource allocation and locking; and 30*d6e260ccSMike Snitzer * the polling nature of vdo_wait_queue consumers. 31*d6e260ccSMike Snitzer * 32*d6e260ccSMike Snitzer * FIXME: could be made to use a linux/list.h's list_head but its extra barriers 33*d6e260ccSMike Snitzer * really aren't needed. Nor is a doubly linked list, but vdo_wait_queue could 34*d6e260ccSMike Snitzer * make use of __list_del_clearprev() -- but that would compromise the ability 35*d6e260ccSMike Snitzer * to make full use of linux's list interface. 364fcb4290SMatthew Sakai */ 374fcb4290SMatthew Sakai 38*d6e260ccSMike Snitzer struct vdo_waiter; 394fcb4290SMatthew Sakai 40*d6e260ccSMike Snitzer struct vdo_wait_queue { 414fcb4290SMatthew Sakai /* The tail of the queue, the last (most recently added) entry */ 42*d6e260ccSMike Snitzer struct vdo_waiter *last_waiter; 434fcb4290SMatthew Sakai /* The number of waiters currently in the queue */ 44*d6e260ccSMike Snitzer size_t length; 454fcb4290SMatthew Sakai }; 464fcb4290SMatthew Sakai 474fcb4290SMatthew Sakai /** 48*d6e260ccSMike Snitzer * vdo_waiter_callback_fn - Callback type that will be called to resume processing 49*d6e260ccSMike Snitzer * of a waiter after it has been removed from its wait queue. 504fcb4290SMatthew Sakai */ 51*d6e260ccSMike Snitzer typedef void (*vdo_waiter_callback_fn)(struct vdo_waiter *waiter, void *context); 524fcb4290SMatthew Sakai 534fcb4290SMatthew Sakai /** 54*d6e260ccSMike Snitzer * vdo_waiter_match_fn - Method type for waiter matching methods. 554fcb4290SMatthew Sakai * 56*d6e260ccSMike Snitzer * Returns false if the waiter does not match. 574fcb4290SMatthew Sakai */ 58*d6e260ccSMike Snitzer typedef bool (*vdo_waiter_match_fn)(struct vdo_waiter *waiter, void *context); 594fcb4290SMatthew Sakai 60*d6e260ccSMike Snitzer /* The structure for entries in a vdo_wait_queue. */ 61*d6e260ccSMike Snitzer struct vdo_waiter { 624fcb4290SMatthew Sakai /* 63*d6e260ccSMike Snitzer * The next waiter in the waitq. If this entry is the last waiter, then this 64*d6e260ccSMike Snitzer * is actually a pointer back to the head of the waitq. 654fcb4290SMatthew Sakai */ 66*d6e260ccSMike Snitzer struct vdo_waiter *next_waiter; 674fcb4290SMatthew Sakai 68*d6e260ccSMike Snitzer /* Optional waiter-specific callback to invoke when dequeuing this waiter. */ 69*d6e260ccSMike Snitzer vdo_waiter_callback_fn callback; 704fcb4290SMatthew Sakai }; 714fcb4290SMatthew Sakai 724fcb4290SMatthew Sakai /** 73*d6e260ccSMike Snitzer * vdo_waiter_is_waiting() - Check whether a waiter is waiting. 744fcb4290SMatthew Sakai * @waiter: The waiter to check. 754fcb4290SMatthew Sakai * 76*d6e260ccSMike Snitzer * Return: true if the waiter is on some vdo_wait_queue. 774fcb4290SMatthew Sakai */ 78*d6e260ccSMike Snitzer static inline bool vdo_waiter_is_waiting(struct vdo_waiter *waiter) 794fcb4290SMatthew Sakai { 804fcb4290SMatthew Sakai return (waiter->next_waiter != NULL); 814fcb4290SMatthew Sakai } 824fcb4290SMatthew Sakai 834fcb4290SMatthew Sakai /** 84*d6e260ccSMike Snitzer * vdo_waitq_init() - Initialize a vdo_wait_queue. 85*d6e260ccSMike Snitzer * @waitq: The vdo_wait_queue to initialize. 864fcb4290SMatthew Sakai */ 87*d6e260ccSMike Snitzer static inline void vdo_waitq_init(struct vdo_wait_queue *waitq) 884fcb4290SMatthew Sakai { 89*d6e260ccSMike Snitzer *waitq = (struct vdo_wait_queue) { 904fcb4290SMatthew Sakai .last_waiter = NULL, 91*d6e260ccSMike Snitzer .length = 0, 924fcb4290SMatthew Sakai }; 934fcb4290SMatthew Sakai } 944fcb4290SMatthew Sakai 954fcb4290SMatthew Sakai /** 96*d6e260ccSMike Snitzer * vdo_waitq_has_waiters() - Check whether a vdo_wait_queue has any entries waiting. 97*d6e260ccSMike Snitzer * @waitq: The vdo_wait_queue to query. 984fcb4290SMatthew Sakai * 99*d6e260ccSMike Snitzer * Return: true if there are any waiters in the waitq. 1004fcb4290SMatthew Sakai */ 101*d6e260ccSMike Snitzer static inline bool __must_check vdo_waitq_has_waiters(const struct vdo_wait_queue *waitq) 1024fcb4290SMatthew Sakai { 103*d6e260ccSMike Snitzer return (waitq->last_waiter != NULL); 1044fcb4290SMatthew Sakai } 1054fcb4290SMatthew Sakai 106*d6e260ccSMike Snitzer void vdo_waitq_enqueue_waiter(struct vdo_wait_queue *waitq, 107*d6e260ccSMike Snitzer struct vdo_waiter *waiter); 1084fcb4290SMatthew Sakai 109*d6e260ccSMike Snitzer void vdo_waitq_notify_all_waiters(struct vdo_wait_queue *waitq, 110*d6e260ccSMike Snitzer vdo_waiter_callback_fn callback, void *context); 1114fcb4290SMatthew Sakai 112*d6e260ccSMike Snitzer bool vdo_waitq_notify_next_waiter(struct vdo_wait_queue *waitq, 113*d6e260ccSMike Snitzer vdo_waiter_callback_fn callback, void *context); 1144fcb4290SMatthew Sakai 115*d6e260ccSMike Snitzer void vdo_waitq_transfer_all_waiters(struct vdo_wait_queue *from_waitq, 116*d6e260ccSMike Snitzer struct vdo_wait_queue *to_waitq); 1174fcb4290SMatthew Sakai 118*d6e260ccSMike Snitzer struct vdo_waiter *vdo_waitq_get_first_waiter(const struct vdo_wait_queue *waitq); 1194fcb4290SMatthew Sakai 120*d6e260ccSMike Snitzer void vdo_waitq_dequeue_matching_waiters(struct vdo_wait_queue *waitq, 121*d6e260ccSMike Snitzer vdo_waiter_match_fn waiter_match, 122*d6e260ccSMike Snitzer void *match_context, 123*d6e260ccSMike Snitzer struct vdo_wait_queue *matched_waitq); 1244fcb4290SMatthew Sakai 125*d6e260ccSMike Snitzer struct vdo_waiter *vdo_waitq_dequeue_next_waiter(struct vdo_wait_queue *waitq); 1264fcb4290SMatthew Sakai 1274fcb4290SMatthew Sakai /** 128*d6e260ccSMike Snitzer * vdo_waitq_num_waiters() - Return the number of waiters in a vdo_wait_queue. 129*d6e260ccSMike Snitzer * @waitq: The vdo_wait_queue to query. 1304fcb4290SMatthew Sakai * 131*d6e260ccSMike Snitzer * Return: The number of waiters in the waitq. 1324fcb4290SMatthew Sakai */ 133*d6e260ccSMike Snitzer static inline size_t __must_check vdo_waitq_num_waiters(const struct vdo_wait_queue *waitq) 1344fcb4290SMatthew Sakai { 135*d6e260ccSMike Snitzer return waitq->length; 1364fcb4290SMatthew Sakai } 1374fcb4290SMatthew Sakai 138*d6e260ccSMike Snitzer const struct vdo_waiter * __must_check 139*d6e260ccSMike Snitzer vdo_waitq_get_next_waiter(const struct vdo_wait_queue *waitq, const struct vdo_waiter *waiter); 1404fcb4290SMatthew Sakai 1414fcb4290SMatthew Sakai #endif /* VDO_WAIT_QUEUE_H */ 142