turnstile.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Copyright (c) 2017 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. * Priority propagation capable sleep queues.
  19. *
  20. * Turnstiles are used to build sleeping synchronization primitives where
  21. * ownership applies, such as mutexes. They allow threads with different
  22. * priorities to contend on the same synchronization object without
  23. * unbounded priority inversion.
  24. */
  25. #ifndef KERN_TURNSTILE_H
  26. #define KERN_TURNSTILE_H
  27. #include <stdbool.h>
  28. #include <stddef.h>
  29. #include <stdint.h>
  30. #include <kern/init.h>
  31. #include <kern/plist.h>
  32. #include <kern/spinlock.h>
  33. #include <kern/sync.h>
  34. #include <kern/thread.h>
  35. #include <kern/turnstile_types.h>
  36. struct turnstile;
  37. // Turnstile thread data.
  38. struct turnstile_td;
  39. static inline bool
  40. turnstile_td_locked (const struct turnstile_td *td)
  41. {
  42. return (spinlock_locked (&td->lock));
  43. }
  44. // Initialize turnstile thread data.
  45. static inline void
  46. turnstile_td_init (struct turnstile_td *td)
  47. {
  48. spinlock_init (&td->lock);
  49. td->turnstile = NULL;
  50. td->waiter = NULL;
  51. plist_init (&td->owned_turnstiles);
  52. td->top_global_priority = 0;
  53. }
  54. // Turnstile thread data locking functions.
  55. static inline void
  56. turnstile_td_lock (struct turnstile_td *td)
  57. {
  58. spinlock_lock (&td->lock);
  59. }
  60. static inline int
  61. turnstile_td_trylock (struct turnstile_td *td)
  62. {
  63. return (spinlock_trylock (&td->lock));
  64. }
  65. static inline void
  66. turnstile_td_unlock (struct turnstile_td *td)
  67. {
  68. spinlock_unlock (&td->lock);
  69. }
  70. // Functions managing the turnstile a thread is sleeping in.
  71. static inline void
  72. turnstile_td_set_turnstile (struct turnstile_td *td,
  73. struct turnstile *turnstile)
  74. {
  75. td->turnstile = turnstile;
  76. }
  77. static inline struct turnstile*
  78. turnstile_td_get_turnstile (const struct turnstile_td *td)
  79. {
  80. return (td->turnstile);
  81. }
  82. // Propagate priority starting at the thread containing the given thread data.
  83. void turnstile_td_propagate_priority (struct turnstile_td *td);
  84. // Create/destroy a turnstile.
  85. struct turnstile* turnstile_create (void);
  86. void turnstile_destroy (struct turnstile *turnstile);
  87. /*
  88. * Acquire/release a turnstile.
  89. *
  90. * Acquiring a turnstile serializes all access and disables preemption.
  91. */
  92. struct turnstile* turnstile_acquire_key (const union sync_key *key);
  93. void turnstile_release (struct turnstile *turnstile);
  94. static inline struct turnstile*
  95. turnstile_acquire (const void *sync_obj)
  96. {
  97. union sync_key key;
  98. sync_key_init (&key, sync_obj);
  99. return (turnstile_acquire_key (&key));
  100. }
  101. /*
  102. * Lend/return a turnstile.
  103. *
  104. * A thread lends its private turnstile to the turnstile module in
  105. * order to prepare its sleep. The turnstile obtained on lending
  106. * is either the thread's turnstile, or an already existing turnstile
  107. * for this synchronization object if another thread is waiting.
  108. *
  109. * When multiple threads are waiting on the same turnstile, the extra
  110. * turnstiles lent are kept in an internal free list, used when threads
  111. * are awoken to return a turnstile to them.
  112. *
  113. * Note that the turnstile returned may not be the one lent.
  114. *
  115. * The turnstile obtained when lending is automatically acquired.
  116. */
  117. struct turnstile* turnstile_lend_key (const union sync_key *key);
  118. void turnstile_return (struct turnstile *turnstile);
  119. static inline struct turnstile*
  120. turnstile_lend (const void *sync_obj)
  121. {
  122. union sync_key key;
  123. sync_key_init (&key, sync_obj);
  124. return (turnstile_lend_key (&key));
  125. }
  126. /*
  127. * Return true if the given turnstile has no waiters.
  128. *
  129. * The turnstile must be acquired when calling this function.
  130. */
  131. bool turnstile_empty (const struct turnstile *turnstile);
  132. /*
  133. * Wait for a wake up on the given turnstile.
  134. *
  135. * The turnstile must be lent when calling this function. It is
  136. * released and later reacquired before returning from this function.
  137. *
  138. * Unless a timeout occurs, the calling thread is considered a waiter
  139. * as long as it didn't reacquire the turnstile. This means that signalling
  140. * a turnstile has no immediate visible effect on the number of waiters,
  141. * e.g. if a single thread is waiting and another signals the turnstile,
  142. * the turnstile is not immediately considered empty.
  143. *
  144. * If owner isn't NULL, it must refer to the thread currently owning
  145. * the associated synchronization object. The priority of the caller
  146. * is propagated to the chain of turnstiles and owners as necessary
  147. * to prevent unbounded priority inversion.
  148. *
  149. * When bounding the duration of the wait, the caller must pass an absolute
  150. * time in ticks, and ETIMEDOUT is returned if that time is reached before
  151. * the turnstile is signalled. In addition, if a timeout occurs, the calling
  152. * thread isn't considered a waiter any more. Other threads may be able to
  153. * acquire the turnstile and consider it empty, despite the fact that threads
  154. * may not have returned from this function yet.
  155. */
  156. int turnstile_wait (struct turnstile *turnstile, const char *wchan,
  157. struct thread *owner);
  158. int turnstile_timedwait (struct turnstile *turnstile, const char *wchan,
  159. struct thread *owner, uint64_t ticks);
  160. /*
  161. * Wake up one or all threads waiting on the given turnstile, if any.
  162. *
  163. * The turnstile must be acquired when calling this function.
  164. * Since a turnstile must be lent (and in turn is automatically
  165. * acquired) when waiting, and acquired in order to signal it,
  166. * wake-ups are serialized and cannot be missed.
  167. */
  168. void turnstile_signal (struct turnstile *turnstile);
  169. void turnstile_broadcast (struct turnstile *turnstile);
  170. /*
  171. * Own/disown a turnstile.
  172. *
  173. * The turnstile must be lent when taking ownership, acquired when
  174. * releasing it.
  175. *
  176. * Ownership must be updated atomically with regard to the ownership
  177. * of the associated synchronization object.
  178. */
  179. void turnstile_own (struct turnstile *turnstile);
  180. void turnstile_disown (struct turnstile *turnstile);
  181. // Check whether a thread owns a turnstile.
  182. bool turnstile_owned_by (struct turnstile *turnstile, struct thread *thread);
  183. /*
  184. * Handle turnstiles owned by a thread upon exiting.
  185. *
  186. * This is necessary for futexes to work correctly. Since PI futexes are
  187. * implemented on top of turnstiles, we need a safe way to cleanup any
  188. * remaining turnstiles when a user thread exits without releasing them.
  189. */
  190. void turnstile_td_exit (struct turnstile_td *td);
  191. /*
  192. * This init operation provides :
  193. * - turnstile creation
  194. * - module fully initialized
  195. */
  196. INIT_OP_DECLARE (turnstile_setup);
  197. #endif