turnstile.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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/thread.h>
  34. #include <kern/turnstile_types.h>
  35. struct turnstile;
  36. // Turnstile thread data.
  37. struct turnstile_td;
  38. static inline bool
  39. turnstile_td_locked (const struct turnstile_td *td)
  40. {
  41. return (spinlock_locked (&td->lock));
  42. }
  43. // Initialize turnstile thread data.
  44. static inline void
  45. turnstile_td_init (struct turnstile_td *td)
  46. {
  47. spinlock_init (&td->lock);
  48. td->turnstile = NULL;
  49. td->waiter = NULL;
  50. plist_init (&td->owned_turnstiles);
  51. td->top_global_priority = 0;
  52. }
  53. // Turnstile thread data locking functions.
  54. static inline void
  55. turnstile_td_lock (struct turnstile_td *td)
  56. {
  57. spinlock_lock (&td->lock);
  58. }
  59. static inline int
  60. turnstile_td_trylock (struct turnstile_td *td)
  61. {
  62. return (spinlock_trylock (&td->lock));
  63. }
  64. static inline void
  65. turnstile_td_unlock (struct turnstile_td *td)
  66. {
  67. spinlock_unlock (&td->lock);
  68. }
  69. // Functions managing the turnstile a thread is sleeping in.
  70. static inline void
  71. turnstile_td_set_turnstile (struct turnstile_td *td,
  72. struct turnstile *turnstile)
  73. {
  74. td->turnstile = turnstile;
  75. }
  76. static inline struct turnstile*
  77. turnstile_td_get_turnstile (const struct turnstile_td *td)
  78. {
  79. return (td->turnstile);
  80. }
  81. // Propagate priority starting at the thread containing the given thread data.
  82. void turnstile_td_propagate_priority (struct turnstile_td *td);
  83. // Create/destroy a turnstile.
  84. struct turnstile* turnstile_create (void);
  85. void turnstile_destroy (struct turnstile *turnstile);
  86. /*
  87. * Acquire/release a turnstile.
  88. *
  89. * Acquiring a turnstile serializes all access and disables preemption.
  90. */
  91. struct turnstile* turnstile_acquire (const void *sync_obj);
  92. void turnstile_release (struct turnstile *turnstile);
  93. /*
  94. * Lend/return a turnstile.
  95. *
  96. * A thread lends its private turnstile to the turnstile module in
  97. * order to prepare its sleep. The turnstile obtained on lending
  98. * is either the thread's turnstile, or an already existing turnstile
  99. * for this synchronization object if another thread is waiting.
  100. *
  101. * When multiple threads are waiting on the same turnstile, the extra
  102. * turnstiles lent are kept in an internal free list, used when threads
  103. * are awoken to return a turnstile to them.
  104. *
  105. * Note that the turnstile returned may not be the one lent.
  106. *
  107. * The turnstile obtained when lending is automatically acquired.
  108. */
  109. struct turnstile* turnstile_lend (const void *sync_obj);
  110. void turnstile_return (struct turnstile *turnstile);
  111. /*
  112. * Return true if the given turnstile has no waiters.
  113. *
  114. * The turnstile must be acquired when calling this function.
  115. */
  116. bool turnstile_empty (const struct turnstile *turnstile);
  117. /*
  118. * Wait for a wake up on the given turnstile.
  119. *
  120. * The turnstile must be lent when calling this function. It is
  121. * released and later reacquired before returning from this function.
  122. *
  123. * Unless a timeout occurs, the calling thread is considered a waiter
  124. * as long as it didn't reacquire the turnstile. This means that signalling
  125. * a turnstile has no immediate visible effect on the number of waiters,
  126. * e.g. if a single thread is waiting and another signals the turnstile,
  127. * the turnstile is not immediately considered empty.
  128. *
  129. * If owner isn't NULL, it must refer to the thread currently owning
  130. * the associated synchronization object. The priority of the caller
  131. * is propagated to the chain of turnstiles and owners as necessary
  132. * to prevent unbounded priority inversion.
  133. *
  134. * When bounding the duration of the wait, the caller must pass an absolute
  135. * time in ticks, and ETIMEDOUT is returned if that time is reached before
  136. * the turnstile is signalled. In addition, if a timeout occurs, the calling
  137. * thread isn't considered a waiter any more. Other threads may be able to
  138. * acquire the turnstile and consider it empty, despite the fact that threads
  139. * may not have returned from this function yet.
  140. */
  141. void turnstile_wait (struct turnstile *turnstile, const char *wchan,
  142. struct thread *owner);
  143. int turnstile_timedwait (struct turnstile *turnstile, const char *wchan,
  144. struct thread *owner, uint64_t ticks);
  145. /*
  146. * Wake up a thread waiting on the given turnstile, if any.
  147. *
  148. * The turnstile must be acquired when calling this function.
  149. * Since a turnstile must be lent (and in turn is automatically
  150. * acquired) when waiting, and acquired in order to signal it,
  151. * wake-ups are serialized and cannot be missed.
  152. */
  153. void turnstile_signal (struct turnstile *turnstile);
  154. /*
  155. * Own/disown a turnstile.
  156. *
  157. * The turnstile must be lent when taking ownership, acquired when
  158. * releasing it.
  159. *
  160. * Ownership must be updated atomically with regard to the ownership
  161. * of the associated synchronization object.
  162. */
  163. void turnstile_own (struct turnstile *turnstile);
  164. void turnstile_disown (struct turnstile *turnstile);
  165. /*
  166. * This init operation provides :
  167. * - turnstile creation
  168. * - module fully initialized
  169. */
  170. INIT_OP_DECLARE (turnstile_setup);
  171. #endif