wait-queue.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2023 Red Hat
  4. */
  5. #include "wait-queue.h"
  6. #include <linux/device-mapper.h>
  7. #include "permassert.h"
  8. #include "status-codes.h"
  9. /**
  10. * vdo_waitq_enqueue_waiter() - Add a waiter to the tail end of a waitq.
  11. * @waitq: The vdo_wait_queue to which to add the waiter.
  12. * @waiter: The waiter to add to the waitq.
  13. *
  14. * The waiter must not already be waiting in a waitq.
  15. */
  16. void vdo_waitq_enqueue_waiter(struct vdo_wait_queue *waitq, struct vdo_waiter *waiter)
  17. {
  18. BUG_ON(waiter->next_waiter != NULL);
  19. if (waitq->last_waiter == NULL) {
  20. /*
  21. * The waitq is empty, so form the initial circular list by self-linking the
  22. * initial waiter.
  23. */
  24. waiter->next_waiter = waiter;
  25. } else {
  26. /* Splice the new waiter in at the end of the waitq. */
  27. waiter->next_waiter = waitq->last_waiter->next_waiter;
  28. waitq->last_waiter->next_waiter = waiter;
  29. }
  30. /* In both cases, the waiter we added to the ring becomes the last waiter. */
  31. waitq->last_waiter = waiter;
  32. waitq->length += 1;
  33. }
  34. /**
  35. * vdo_waitq_transfer_all_waiters() - Transfer all waiters from one waitq to
  36. * a second waitq, emptying the first waitq.
  37. * @from_waitq: The waitq containing the waiters to move.
  38. * @to_waitq: The waitq that will receive the waiters from the first waitq.
  39. */
  40. void vdo_waitq_transfer_all_waiters(struct vdo_wait_queue *from_waitq,
  41. struct vdo_wait_queue *to_waitq)
  42. {
  43. /* If the source waitq is empty, there's nothing to do. */
  44. if (!vdo_waitq_has_waiters(from_waitq))
  45. return;
  46. if (vdo_waitq_has_waiters(to_waitq)) {
  47. /*
  48. * Both are non-empty. Splice the two circular lists together
  49. * by swapping the next (head) pointers in the list tails.
  50. */
  51. struct vdo_waiter *from_head = from_waitq->last_waiter->next_waiter;
  52. struct vdo_waiter *to_head = to_waitq->last_waiter->next_waiter;
  53. to_waitq->last_waiter->next_waiter = from_head;
  54. from_waitq->last_waiter->next_waiter = to_head;
  55. }
  56. to_waitq->last_waiter = from_waitq->last_waiter;
  57. to_waitq->length += from_waitq->length;
  58. vdo_waitq_init(from_waitq);
  59. }
  60. /**
  61. * vdo_waitq_notify_all_waiters() - Notify all the entries waiting in a waitq.
  62. * @waitq: The vdo_wait_queue containing the waiters to notify.
  63. * @callback: The function to call to notify each waiter, or NULL to invoke the callback field
  64. * registered in each waiter.
  65. * @context: The context to pass to the callback function.
  66. *
  67. * Notifies all the entries waiting in a waitq to continue execution by invoking a callback
  68. * function on each of them in turn. The waitq is copied and emptied before invoking any callbacks,
  69. * and only the waiters that were in the waitq at the start of the call will be notified.
  70. */
  71. void vdo_waitq_notify_all_waiters(struct vdo_wait_queue *waitq,
  72. vdo_waiter_callback_fn callback, void *context)
  73. {
  74. /*
  75. * Copy and empty the waitq first, avoiding the possibility of an infinite
  76. * loop if entries are returned to the waitq by the callback function.
  77. */
  78. struct vdo_wait_queue waiters;
  79. vdo_waitq_init(&waiters);
  80. vdo_waitq_transfer_all_waiters(waitq, &waiters);
  81. /* Drain the copied waitq, invoking the callback on every entry. */
  82. while (vdo_waitq_has_waiters(&waiters))
  83. vdo_waitq_notify_next_waiter(&waiters, callback, context);
  84. }
  85. /**
  86. * vdo_waitq_get_first_waiter() - Return the waiter that is at the head end of a waitq.
  87. * @waitq: The vdo_wait_queue from which to get the first waiter.
  88. *
  89. * Return: The first (oldest) waiter in the waitq, or NULL if the waitq is empty.
  90. */
  91. struct vdo_waiter *vdo_waitq_get_first_waiter(const struct vdo_wait_queue *waitq)
  92. {
  93. struct vdo_waiter *last_waiter = waitq->last_waiter;
  94. if (last_waiter == NULL) {
  95. /* There are no waiters, so we're done. */
  96. return NULL;
  97. }
  98. /* The waitq is circular, so the last entry links to the head of the waitq. */
  99. return last_waiter->next_waiter;
  100. }
  101. /**
  102. * vdo_waitq_dequeue_matching_waiters() - Remove all waiters that match based on the specified
  103. * matching method and append them to a vdo_wait_queue.
  104. * @waitq: The vdo_wait_queue to process.
  105. * @waiter_match: The method to determine matching.
  106. * @match_context: Contextual info for the match method.
  107. * @matched_waitq: A wait_waitq to store matches.
  108. */
  109. void vdo_waitq_dequeue_matching_waiters(struct vdo_wait_queue *waitq,
  110. vdo_waiter_match_fn waiter_match,
  111. void *match_context,
  112. struct vdo_wait_queue *matched_waitq)
  113. {
  114. struct vdo_wait_queue iteration_waitq;
  115. vdo_waitq_init(&iteration_waitq);
  116. vdo_waitq_transfer_all_waiters(waitq, &iteration_waitq);
  117. while (vdo_waitq_has_waiters(&iteration_waitq)) {
  118. struct vdo_waiter *waiter = vdo_waitq_dequeue_waiter(&iteration_waitq);
  119. vdo_waitq_enqueue_waiter((waiter_match(waiter, match_context) ?
  120. matched_waitq : waitq), waiter);
  121. }
  122. }
  123. /**
  124. * vdo_waitq_dequeue_waiter() - Remove the first (oldest) waiter from a waitq.
  125. * @waitq: The vdo_wait_queue from which to remove the first entry.
  126. *
  127. * The caller will be responsible for waking the waiter by continuing its
  128. * execution appropriately.
  129. *
  130. * Return: The first (oldest) waiter in the waitq, or NULL if the waitq is empty.
  131. */
  132. struct vdo_waiter *vdo_waitq_dequeue_waiter(struct vdo_wait_queue *waitq)
  133. {
  134. struct vdo_waiter *first_waiter = vdo_waitq_get_first_waiter(waitq);
  135. struct vdo_waiter *last_waiter = waitq->last_waiter;
  136. if (first_waiter == NULL)
  137. return NULL;
  138. if (first_waiter == last_waiter) {
  139. /* The waitq has a single entry, so empty it by nulling the tail. */
  140. waitq->last_waiter = NULL;
  141. } else {
  142. /*
  143. * The waitq has multiple waiters, so splice the first waiter out
  144. * of the circular waitq.
  145. */
  146. last_waiter->next_waiter = first_waiter->next_waiter;
  147. }
  148. /* The waiter is no longer in a waitq. */
  149. first_waiter->next_waiter = NULL;
  150. waitq->length -= 1;
  151. return first_waiter;
  152. }
  153. /**
  154. * vdo_waitq_notify_next_waiter() - Notify the next entry waiting in a waitq.
  155. * @waitq: The vdo_wait_queue containing the waiter to notify.
  156. * @callback: The function to call to notify the waiter, or NULL to invoke the callback field
  157. * registered in the waiter.
  158. * @context: The context to pass to the callback function.
  159. *
  160. * Notifies the next entry waiting in a waitq to continue execution by invoking a callback function
  161. * on it after removing it from the waitq.
  162. *
  163. * Return: true if there was a waiter in the waitq.
  164. */
  165. bool vdo_waitq_notify_next_waiter(struct vdo_wait_queue *waitq,
  166. vdo_waiter_callback_fn callback, void *context)
  167. {
  168. struct vdo_waiter *waiter = vdo_waitq_dequeue_waiter(waitq);
  169. if (waiter == NULL)
  170. return false;
  171. if (callback == NULL)
  172. callback = waiter->callback;
  173. callback(waiter, context);
  174. return true;
  175. }