sleepq.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (c) 2017-2018 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * Generic sleep queues.
  19. *
  20. * Sleep queues are used to build sleeping synchronization primitives
  21. * such as mutexes and condition variables.
  22. *
  23. * Although the sleep queues are mostly generic, this implementation
  24. * relies on knowing whether a synchronization object is a condition
  25. * variable or not, because waiting on a condition variable unlocks
  26. * the associated mutex, at which point two sleep queues are locked.
  27. * Handling condition variable sleep queues slightly differently
  28. * allows preventing deadlocks while keeping overall complexity low.
  29. */
  30. #ifndef KERN_SLEEPQ_H
  31. #define KERN_SLEEPQ_H
  32. #include <stdbool.h>
  33. #include <stdint.h>
  34. #include <kern/hlist.h>
  35. #include <kern/init.h>
  36. #include <kern/sync.h>
  37. #include <kern/types.h>
  38. struct sleepq_bucket;
  39. struct sleepq_waiter;
  40. /*
  41. * Waiters are queued in FIFO order and inserted at the head of the
  42. * list of waiters. The pointer to the "oldest" waiter is used as
  43. * a marker between threads waiting for a signal/broadcast (from the
  44. * beginning up to and including the oldest waiter) and threads pending
  45. * for wake-up (all the following threads up to the end of the list).
  46. */
  47. struct sleepq
  48. {
  49. __cacheline_aligned struct sleepq_bucket *bucket;
  50. struct hlist_node node;
  51. union sync_key sync_key;
  52. struct list waiters;
  53. struct sleepq_waiter *oldest_waiter;
  54. struct sleepq *next_free;
  55. struct sleepq **free_link;
  56. };
  57. // Create/destroy a sleep queue.
  58. struct sleepq* sleepq_create (void);
  59. void sleepq_destroy (struct sleepq *sleepq);
  60. /*
  61. * Acquire/release a sleep queue.
  62. *
  63. * Acquiring a sleep queue serializes all access and disables preemption.
  64. *
  65. * The condition argument must be true if the synchronization object
  66. * is a condition variable.
  67. *
  68. * If no sleep queue has been lent for the synchronization object, NULL
  69. * is returned. Note that, in the case of the non-blocking variant,
  70. * the call may also return NULL if internal state shared by unrelated
  71. * synchronization objects is locked.
  72. */
  73. struct sleepq* sleepq_acquire_key (const union sync_key *key);
  74. struct sleepq* sleepq_tryacquire_key (const union sync_key *key);
  75. void sleepq_release (struct sleepq *sleepq);
  76. static inline struct sleepq*
  77. sleepq_acquire (const void *sync_obj)
  78. {
  79. union sync_key key;
  80. sync_key_init (&key, sync_obj);
  81. return (sleepq_acquire_key (&key));
  82. }
  83. static inline struct sleepq*
  84. sleepq_tryacquire (const void *sync_obj)
  85. {
  86. union sync_key key;
  87. sync_key_init (&key, sync_obj);
  88. return (sleepq_tryacquire_key (&key));
  89. }
  90. /*
  91. * Versions of the sleep queue acquisition functions that also disable
  92. * interrupts.
  93. */
  94. struct sleepq* sleepq_acquire_key_intr (const union sync_key *key,
  95. cpu_flags_t *flags);
  96. struct sleepq* sleepq_tryacquire_key_intr (const union sync_key *key,
  97. cpu_flags_t *flags);
  98. void sleepq_release_intr_restore (struct sleepq *sleepq, cpu_flags_t flags);
  99. static inline struct sleepq*
  100. sleepq_acquire_intr_save (const void *sync_obj, cpu_flags_t *flags)
  101. {
  102. union sync_key key;
  103. sync_key_init (&key, sync_obj);
  104. return (sleepq_acquire_key_intr (&key, flags));
  105. }
  106. static inline struct sleepq*
  107. sleepq_tryacquire_intr_save (const void *sync_obj, cpu_flags_t *flags)
  108. {
  109. union sync_key key;
  110. sync_key_init (&key, sync_obj);
  111. return (sleepq_tryacquire_key_intr (&key, flags));
  112. }
  113. /*
  114. * Lend/return a sleep queue.
  115. *
  116. * Most often, a thread lends its private sleep queue to the sleepq
  117. * module in order to prepare its sleep. The sleep queue obtained
  118. * on lending is either the thread's queue, or an already existing
  119. * queue for this synchronization object if another thread is waiting.
  120. *
  121. * When multiple threads lend their sleep queue for the same synchronization
  122. * object, the extra queues lent are kept in an internal free list, used
  123. * when threads are awoken to return a queue to them. As a result, the
  124. * sleep queue returned may not be the one lent.
  125. *
  126. * The sleep queue obtained when lending is automatically acquired.
  127. *
  128. * The condition argument must be true if the synchronization object
  129. * is a condition variable.
  130. */
  131. struct sleepq* sleepq_lend_key (const union sync_key *key);
  132. void sleepq_return (struct sleepq *sleepq);
  133. static inline struct sleepq*
  134. sleepq_lend (const void *sync_obj)
  135. {
  136. union sync_key key;
  137. sync_key_init (&key, sync_obj);
  138. return (sleepq_lend_key (&key));
  139. }
  140. /*
  141. * Versions of the sleep queue lending functions that also disable
  142. * interrupts.
  143. */
  144. struct sleepq* sleepq_lend_key_intr (const union sync_key *key,
  145. cpu_flags_t *flags);
  146. void sleepq_return_intr_restore (struct sleepq *sleepq, cpu_flags_t flags);
  147. static inline struct sleepq*
  148. sleepq_lend_intr_save (const void *sync_obj, cpu_flags_t *flags)
  149. {
  150. union sync_key key;
  151. sync_key_init (&key, sync_obj);
  152. return (sleepq_lend_key_intr (&key, flags));
  153. }
  154. /*
  155. * Return true if the given sleep queue has no waiters.
  156. *
  157. * The sleep queue must be acquired when calling this function.
  158. */
  159. static inline bool
  160. sleepq_empty (const struct sleepq *sleepq)
  161. {
  162. return (list_empty (&sleepq->waiters));
  163. }
  164. /*
  165. * Wait for a wake-up on the given sleep queue.
  166. *
  167. * The sleep queue must be lent when calling this function. It is
  168. * released and later reacquired before returning from this function.
  169. *
  170. * The calling thread is considered a waiter as long as it didn't
  171. * reacquire the sleep queue. This means that signalling a sleep queue
  172. * has no visible effect on the number of waiters until the queue is
  173. * released, e.g. if a single thread is waiting and another signals
  174. * the queue, the queue is not immediately considered empty.
  175. *
  176. * When bounding the duration of the wait, the caller must pass an absolute
  177. * time in ticks, and ETIMEDOUT is returned if that time is reached before
  178. * the sleep queue is signalled.
  179. */
  180. void sleepq_wait (struct sleepq *sleepq, const char *wchan);
  181. int sleepq_timedwait (struct sleepq *sleepq, const char *wchan, uint64_t ticks);
  182. int sleepq_wait_movable (struct sleepq **sleepq, const char *wchan,
  183. uint64_t *ticksp);
  184. /*
  185. * Wake up a thread waiting on the given sleep queue, if any.
  186. *
  187. * The sleep queue must be acquired when calling this function.
  188. * A sleep queue may be signalled from interrupt context.
  189. *
  190. * Since a sleep queue must be lent (and in turn is automatically
  191. * acquired) when waiting, and acquired in order to signal it,
  192. * wake-ups are serialized and cannot be missed.
  193. *
  194. * At least one thread is awoken if any threads are waiting on the sleep
  195. * queue.
  196. *
  197. * Broadcasting a sleep queue wakes up all waiting threads.
  198. */
  199. void sleepq_signal (struct sleepq *sleepq);
  200. void sleepq_broadcast (struct sleepq *sleepq);
  201. /*
  202. * Test that a thread that is currently holding a sleepq spinlock will
  203. * not cause a deadlock when contending against another thread.
  204. *
  205. * This is an internal function used by the adaptive lock module to
  206. * reliably detect when it's safe to spin on a thread instead of going
  207. * to sleep.
  208. */
  209. static inline bool
  210. sleepq_test_circular (struct sleepq *sleepq, const void *wchan_addr)
  211. {
  212. return ((void *)sleepq->bucket == wchan_addr);
  213. }
  214. /*
  215. * Rearrange the waiting queues so that waiters in SRC_KEY are moved and
  216. * instead wait on DST_KEY. Move one or all waiters (depending on MOVE_ALL),
  217. * and optionally wake one of the waiters (if WAKE_ONE is true).
  218. */
  219. void sleepq_move (const union sync_key *dst_key, const union sync_key *src_key,
  220. bool wake_one, bool move_all);
  221. /*
  222. * This init operation provides :
  223. * - sleepq creation
  224. * - module fully initialized
  225. */
  226. INIT_OP_DECLARE (sleepq_setup);
  227. #endif