turnstile.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  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. * This implementation is based on "Solaris(tm) Internals: Solaris 10 and
  19. * OpenSolaris Kernel Architecture, Second Edition" by Richard McDougall
  20. * and Jim Mauro. See "Part Six: Platform Specifics, Chapter 17: Locking
  21. * and Synchronization, Section 7 Turnstiles and Priority Inheritance".
  22. *
  23. * The differences are outlined below.
  24. *
  25. * This implementation doesn't support read/write locks, only mutual
  26. * exclusion, because ownership doesn't apply well to read/write locks.
  27. *
  28. * Instead of using an external sleep queue object, this module implements
  29. * that functionality itself. The reasons behind this decision are :
  30. * - the use of expensive priority lists used to queue threads, that
  31. * a simpler sleep queue implementation shouldn't use
  32. * - increased coupling with the scheduler
  33. *
  34. * Locking order : bucket (turnstile) -> turnstile_td -> thread_runq
  35. *
  36. * This order allows changing the owner of a turnstile without unlocking it
  37. * which is important because a turnstile is normally used to synchronize
  38. * access to the owner. Unlocking a turnstile would allow the owner to
  39. * change and make complex transient states visible. The drawback is that
  40. * a thread cannot be requeued atomically when its priority is changed.
  41. * That deferred requeue is done during priority propagation.
  42. *
  43. */
  44. #include <assert.h>
  45. #include <stdalign.h>
  46. #include <stdbool.h>
  47. #include <stddef.h>
  48. #include <stdint.h>
  49. #include <kern/hlist.h>
  50. #include <kern/init.h>
  51. #include <kern/kmem.h>
  52. #include <kern/list.h>
  53. #include <kern/macros.h>
  54. #include <kern/plist.h>
  55. #include <kern/spinlock.h>
  56. #include <kern/thread.h>
  57. #include <kern/turnstile.h>
  58. #include <kern/turnstile_types.h>
  59. #include <machine/cpu.h>
  60. /*
  61. * Locking keys :
  62. * (b) bucket
  63. */
  64. struct turnstile_bucket
  65. {
  66. __cacheline_aligned struct spinlock lock;
  67. struct hlist turnstiles; // (b)
  68. };
  69. /*
  70. * Adding/removing waiters to/from a turnstile are performed while
  71. * holding both the waiter's thread data and the turnstile locks.
  72. *
  73. * Changing the owner of a turnstile and linking/unlinking the turnstile
  74. * into/from the owner's list of owned turnstiles are done atomically,
  75. * while holding both the owner's thread data and the turnstile locks.
  76. *
  77. * Locking keys :
  78. * (b) bucket
  79. * (t) turnstile_td
  80. *
  81. * (*) A turnstile is referenced in thread data after/before being
  82. * added/removed to/from its bucket. Referencing a turnstile in
  83. * thread data requires holding the thread data lock. This implies
  84. * that, while holding the thread data lock, if the referenced
  85. * turnstile isn't NULL, the bucket pointer is also not NULL and
  86. * stable.
  87. */
  88. struct turnstile
  89. {
  90. struct turnstile_bucket *bucket; // (b*)
  91. struct hlist_node node; // (b)
  92. union sync_key sync_key; // (b)
  93. struct plist waiters; // (b,t)
  94. struct turnstile *next_free; // (b)
  95. struct turnstile_waiter *top_waiter; // (b,t)
  96. struct thread *owner; // (b,t)
  97. struct plist_node td_node; // (t)
  98. bool broadcasting; // (b)
  99. };
  100. /*
  101. * Locking keys :
  102. * (b) bucket
  103. * (t) turnstile_td
  104. */
  105. struct turnstile_waiter
  106. {
  107. struct plist_node node; // (b,t)
  108. struct thread *thread; // (b,t)
  109. bool awoken; // (b)
  110. };
  111. #define TURNSTILE_HTABLE_SIZE 128
  112. #if !ISP2 (TURNSTILE_HTABLE_SIZE)
  113. #error "hash table size must be a power of two"
  114. #endif
  115. #define TURNSTILE_HTABLE_MASK (TURNSTILE_HTABLE_SIZE - 1)
  116. static struct turnstile_bucket turnstile_htable[TURNSTILE_HTABLE_SIZE];
  117. static struct kmem_cache turnstile_cache;
  118. static void
  119. turnstile_waiter_init (struct turnstile_waiter *waiter, struct thread *thread)
  120. {
  121. plist_node_init (&waiter->node, thread_real_global_priority (thread));
  122. waiter->thread = thread;
  123. waiter->awoken = false;
  124. }
  125. static unsigned int
  126. turnstile_waiter_priority (const struct turnstile_waiter *waiter)
  127. {
  128. return (plist_node_priority (&waiter->node));
  129. }
  130. static bool
  131. turnstile_waiter_awaken (const struct turnstile_waiter *waiter)
  132. {
  133. return (waiter->awoken);
  134. }
  135. static void
  136. turnstile_waiter_set_awaken (struct turnstile_waiter *waiter)
  137. {
  138. waiter->awoken = true;
  139. }
  140. static void
  141. turnstile_waiter_clear_awaken (struct turnstile_waiter *waiter)
  142. {
  143. waiter->awoken = false;
  144. }
  145. static void
  146. turnstile_waiter_wakeup (struct turnstile_waiter *waiter)
  147. {
  148. if (turnstile_waiter_awaken (waiter))
  149. return;
  150. thread_wakeup (waiter->thread);
  151. turnstile_waiter_set_awaken (waiter);
  152. }
  153. static void
  154. turnstile_update_top_waiter (struct turnstile *turnstile)
  155. {
  156. if (turnstile_empty (turnstile))
  157. {
  158. turnstile->top_waiter = NULL;
  159. return;
  160. }
  161. turnstile->top_waiter = plist_last_entry (&turnstile->waiters,
  162. struct turnstile_waiter, node);
  163. }
  164. static void
  165. turnstile_add_waiter (struct turnstile *turnstile,
  166. struct turnstile_waiter *waiter)
  167. {
  168. assert (!turnstile_waiter_awaken (waiter));
  169. plist_add (&turnstile->waiters, &waiter->node);
  170. turnstile_update_top_waiter (turnstile);
  171. }
  172. static void
  173. turnstile_remove_waiter (struct turnstile *turnstile,
  174. struct turnstile_waiter *waiter)
  175. {
  176. plist_remove (&turnstile->waiters, &waiter->node);
  177. turnstile_update_top_waiter (turnstile);
  178. }
  179. static void
  180. turnstile_requeue_waiter (struct turnstile *turnstile,
  181. struct turnstile_waiter *waiter)
  182. {
  183. uint32_t global_priority = thread_real_global_priority (waiter->thread);
  184. assert (global_priority != plist_node_priority (&waiter->node));
  185. plist_remove (&turnstile->waiters, &waiter->node);
  186. plist_node_set_priority (&waiter->node, global_priority);
  187. plist_add (&turnstile->waiters, &waiter->node);
  188. turnstile_update_top_waiter (turnstile);
  189. }
  190. static void
  191. turnstile_td_set_waiter (struct turnstile_td *td,
  192. struct turnstile_waiter *waiter)
  193. {
  194. td->waiter = waiter;
  195. }
  196. static struct turnstile_waiter*
  197. turnstile_td_get_waiter (const struct turnstile_td *td)
  198. {
  199. return (td->waiter);
  200. }
  201. static void
  202. turnstile_td_update_top_priority (struct turnstile_td *td)
  203. {
  204. if (plist_empty (&td->owned_turnstiles))
  205. {
  206. td->top_global_priority = 0;
  207. return;
  208. }
  209. _Auto top_turnstile = plist_last_entry (&td->owned_turnstiles,
  210. struct turnstile, td_node);
  211. _Auto top_waiter = top_turnstile->top_waiter;
  212. if (! top_waiter)
  213. td->top_global_priority = 0;
  214. else
  215. {
  216. td->top_global_priority = turnstile_waiter_priority (top_waiter);
  217. td->top_sched_policy = thread_real_sched_policy (top_waiter->thread);
  218. td->top_priority = thread_real_priority (top_waiter->thread);
  219. }
  220. }
  221. static void
  222. turnstile_td_own (struct turnstile_td *td, struct turnstile *turnstile)
  223. {
  224. assert (!turnstile->owner);
  225. _Auto top_waiter = turnstile->top_waiter;
  226. assert (top_waiter != NULL);
  227. uint32_t top_priority = thread_real_global_priority (top_waiter->thread);
  228. plist_node_init (&turnstile->td_node, top_priority);
  229. plist_add (&td->owned_turnstiles, &turnstile->td_node);
  230. turnstile_td_update_top_priority (td);
  231. turnstile->owner = structof (td, struct thread, turnstile_td);
  232. }
  233. static void
  234. turnstile_td_disown (struct turnstile_td *td, struct turnstile *turnstile)
  235. {
  236. assert (turnstile->owner == structof (td, struct thread, turnstile_td));
  237. assert (!plist_node_unlinked (&turnstile->td_node));
  238. plist_remove (&td->owned_turnstiles, &turnstile->td_node);
  239. turnstile_td_update_top_priority (td);
  240. turnstile->owner = NULL;
  241. }
  242. // A turnstile must be "reowned" whenever its top waiter has changed.
  243. static void
  244. turnstile_td_reown (struct turnstile_td *td, struct turnstile *turnstile)
  245. {
  246. assert (turnstile->owner == structof (td, struct thread, turnstile_td));
  247. assert (!plist_node_unlinked (&turnstile->td_node));
  248. plist_remove (&td->owned_turnstiles, &turnstile->td_node);
  249. turnstile->owner = NULL;
  250. turnstile_td_own (td, turnstile);
  251. }
  252. /*
  253. * The caller must hold the turnstile thread data lock and no turnstile
  254. * locks when calling this function. The thread data are unlocked on return.
  255. *
  256. * In addition, this function drops a reference on the thread associated
  257. * with the given thread data.
  258. */
  259. static void
  260. turnstile_td_propagate_priority_loop (struct turnstile_td *td)
  261. {
  262. /*
  263. * At the very least, this function must make sure that :
  264. * - the given thread has its intended priority, which is the
  265. * highest among its own and all the waiters in the turnstiles
  266. * it owns, and
  267. * - the thread is at its intended position in the turnstile it's
  268. * waiting on, if any.
  269. */
  270. struct turnstile *turnstile;
  271. while (1)
  272. {
  273. struct thread *thread = structof (td, struct thread, turnstile_td);
  274. uint32_t user_priority = thread_user_global_priority (thread),
  275. real_priority = thread_real_global_priority (thread),
  276. top_priority = td->top_global_priority;
  277. uint8_t policy;
  278. uint16_t priority;
  279. if (top_priority > user_priority)
  280. {
  281. policy = td->top_sched_policy;
  282. priority = td->top_priority;
  283. }
  284. else
  285. {
  286. top_priority = user_priority;
  287. policy = thread_user_sched_policy (thread);
  288. priority = thread_user_priority (thread);
  289. }
  290. if (top_priority != real_priority)
  291. thread_pi_setscheduler (thread, policy, priority);
  292. _Auto waiter = turnstile_td_get_waiter (td);
  293. if (!waiter ||
  294. top_priority == turnstile_waiter_priority (waiter))
  295. {
  296. spinlock_unlock (&td->lock);
  297. thread_unref (thread);
  298. return;
  299. }
  300. turnstile = turnstile_td_get_turnstile (td);
  301. assert (turnstile);
  302. int error = spinlock_trylock (&turnstile->bucket->lock);
  303. if (error)
  304. {
  305. spinlock_unlock (&td->lock);
  306. spinlock_lock (&td->lock);
  307. continue;
  308. }
  309. /*
  310. * This couldn't be done while changing the thread's priority
  311. * because of locking restrictions. Do it now.
  312. */
  313. turnstile_requeue_waiter (turnstile, waiter);
  314. spinlock_unlock (&td->lock);
  315. thread_unref (thread);
  316. thread = turnstile->owner;
  317. if (! thread)
  318. break;
  319. td = thread_turnstile_td (thread);
  320. thread_ref (thread);
  321. spinlock_lock (&td->lock);
  322. turnstile_td_reown (td, turnstile);
  323. spinlock_unlock (&turnstile->bucket->lock);
  324. }
  325. spinlock_unlock (&turnstile->bucket->lock);
  326. }
  327. void
  328. turnstile_td_propagate_priority (struct turnstile_td *td)
  329. {
  330. struct thread *thread = structof (td, struct thread, turnstile_td);
  331. thread_ref (thread);
  332. spinlock_lock (&td->lock);
  333. turnstile_td_propagate_priority_loop (td);
  334. }
  335. static bool
  336. turnstile_init_state_valid (const struct turnstile *turnstile)
  337. {
  338. return (!turnstile->bucket &&
  339. sync_key_isclear (&turnstile->sync_key) &&
  340. plist_empty (&turnstile->waiters) &&
  341. !turnstile->next_free &&
  342. !turnstile->top_waiter);
  343. }
  344. static void
  345. turnstile_use (struct turnstile *turnstile, const union sync_key *key)
  346. {
  347. assert (!sync_key_isclear (key));
  348. turnstile->sync_key = *key;
  349. }
  350. static void
  351. turnstile_unuse (struct turnstile *turnstile)
  352. {
  353. assert (!sync_key_isclear (&turnstile->sync_key));
  354. sync_key_clear (&turnstile->sync_key);
  355. }
  356. static bool
  357. turnstile_in_use (const struct turnstile *turnstile)
  358. {
  359. return (!sync_key_isclear (&turnstile->sync_key));
  360. }
  361. static bool
  362. turnstile_in_use_by (const struct turnstile *turnstile,
  363. const union sync_key *key)
  364. {
  365. return (sync_key_eq (&turnstile->sync_key, key));
  366. }
  367. static void
  368. turnstile_bucket_init (struct turnstile_bucket *bucket)
  369. {
  370. spinlock_init (&bucket->lock);
  371. hlist_init (&bucket->turnstiles);
  372. }
  373. static struct turnstile_bucket*
  374. turnstile_bucket_get (const union sync_key *key)
  375. {
  376. uintptr_t index = sync_key_hash (key) & TURNSTILE_HTABLE_MASK;
  377. assert (index < ARRAY_SIZE (turnstile_htable));
  378. return (&turnstile_htable[index]);
  379. }
  380. static void
  381. turnstile_bucket_add (struct turnstile_bucket *bucket,
  382. struct turnstile *turnstile)
  383. {
  384. assert (!turnstile->bucket);
  385. turnstile->bucket = bucket;
  386. hlist_insert_head (&bucket->turnstiles, &turnstile->node);
  387. }
  388. static void
  389. turnstile_bucket_remove (struct turnstile_bucket *bucket,
  390. struct turnstile *turnstile)
  391. {
  392. assert (turnstile->bucket == bucket);
  393. turnstile->bucket = NULL;
  394. hlist_remove (&turnstile->node);
  395. }
  396. static struct turnstile*
  397. turnstile_bucket_lookup (const struct turnstile_bucket *bucket,
  398. const union sync_key *key)
  399. {
  400. struct turnstile *turnstile;
  401. hlist_for_each_entry (&bucket->turnstiles, turnstile, node)
  402. if (turnstile_in_use_by (turnstile, key))
  403. return (turnstile);
  404. return (NULL);
  405. }
  406. static void
  407. turnstile_ctor (void *ptr)
  408. {
  409. struct turnstile *turnstile = ptr;
  410. turnstile->bucket = NULL;
  411. sync_key_clear (&turnstile->sync_key);
  412. plist_init (&turnstile->waiters);
  413. turnstile->next_free = NULL;
  414. turnstile->top_waiter = NULL;
  415. turnstile->owner = NULL;
  416. turnstile->broadcasting = false;
  417. }
  418. static int __init
  419. turnstile_setup (void)
  420. {
  421. for (size_t i = 0; i < ARRAY_SIZE (turnstile_htable); i++)
  422. turnstile_bucket_init (&turnstile_htable[i]);
  423. kmem_cache_init (&turnstile_cache, "turnstile", sizeof (struct turnstile),
  424. CPU_L1_SIZE, turnstile_ctor, 0);
  425. return (0);
  426. }
  427. INIT_OP_DEFINE (turnstile_setup,
  428. INIT_OP_DEP (kmem_setup, true));
  429. struct turnstile*
  430. turnstile_create (void)
  431. {
  432. struct turnstile *turnstile = kmem_cache_alloc (&turnstile_cache);
  433. assert (!turnstile || turnstile_init_state_valid (turnstile));
  434. return (turnstile);
  435. }
  436. void
  437. turnstile_destroy (struct turnstile *turnstile)
  438. {
  439. assert (turnstile_init_state_valid (turnstile));
  440. kmem_cache_free (&turnstile_cache, turnstile);
  441. }
  442. struct turnstile*
  443. turnstile_acquire_key (const union sync_key *key)
  444. {
  445. assert (!sync_key_isclear (key));
  446. _Auto bucket = turnstile_bucket_get (key);
  447. spinlock_lock (&bucket->lock);
  448. _Auto turnstile = turnstile_bucket_lookup (bucket, key);
  449. if (! turnstile)
  450. spinlock_unlock (&bucket->lock);
  451. return (turnstile);
  452. }
  453. void
  454. turnstile_release (struct turnstile *turnstile)
  455. {
  456. spinlock_unlock (&turnstile->bucket->lock);
  457. }
  458. static void
  459. turnstile_push_free (struct turnstile *turnstile,
  460. struct turnstile *free_turnstile)
  461. {
  462. assert (free_turnstile->next_free == NULL);
  463. free_turnstile->next_free = turnstile->next_free;
  464. turnstile->next_free = free_turnstile;
  465. }
  466. static struct turnstile*
  467. turnstile_pop_free (struct turnstile *turnstile)
  468. {
  469. struct turnstile *free_turnstile = turnstile->next_free;
  470. if (! free_turnstile)
  471. return (NULL);
  472. turnstile->next_free = free_turnstile->next_free;
  473. free_turnstile->next_free = NULL;
  474. return (free_turnstile);
  475. }
  476. struct turnstile*
  477. turnstile_lend_key (const union sync_key *key)
  478. {
  479. assert (!sync_key_isclear (key));
  480. _Auto turnstile = thread_turnstile_lend ();
  481. assert (turnstile_init_state_valid (turnstile));
  482. _Auto td = thread_turnstile_td (thread_self ());
  483. _Auto bucket = turnstile_bucket_get (key);
  484. spinlock_lock (&bucket->lock);
  485. _Auto prev = turnstile_bucket_lookup (bucket, key);
  486. if (! prev)
  487. {
  488. turnstile_use (turnstile, key);
  489. turnstile_bucket_add (bucket, turnstile);
  490. }
  491. else
  492. {
  493. turnstile_push_free (prev, turnstile);
  494. turnstile = prev;
  495. }
  496. spinlock_lock (&td->lock);
  497. turnstile_td_set_turnstile (td, turnstile);
  498. spinlock_unlock (&td->lock);
  499. return (turnstile);
  500. }
  501. void
  502. turnstile_return (struct turnstile *turnstile)
  503. {
  504. assert (turnstile_in_use (turnstile));
  505. _Auto td = thread_turnstile_td (thread_self ());
  506. spinlock_lock (&td->lock);
  507. turnstile_td_set_turnstile (td, NULL);
  508. spinlock_unlock (&td->lock);
  509. _Auto bucket = turnstile->bucket;
  510. _Auto free_turnstile = turnstile_pop_free (turnstile);
  511. if (! free_turnstile)
  512. {
  513. turnstile_bucket_remove (bucket, turnstile);
  514. turnstile_unuse (turnstile);
  515. free_turnstile = turnstile;
  516. }
  517. spinlock_unlock (&bucket->lock);
  518. assert (turnstile_init_state_valid (free_turnstile));
  519. thread_turnstile_return (free_turnstile);
  520. }
  521. bool
  522. turnstile_empty (const struct turnstile *turnstile)
  523. {
  524. return (plist_empty (&turnstile->waiters));
  525. }
  526. static void
  527. turnstile_update_owner (struct turnstile *turnstile, struct thread *owner)
  528. {
  529. assert (owner);
  530. assert (!turnstile->owner || turnstile->owner == owner);
  531. _Auto td = thread_turnstile_td (owner);
  532. thread_ref (owner);
  533. spinlock_lock (&td->lock);
  534. if (turnstile_empty (turnstile))
  535. {
  536. if (turnstile->owner)
  537. turnstile_td_disown (td, turnstile);
  538. }
  539. else if (!turnstile->owner)
  540. turnstile_td_own (td, turnstile);
  541. else
  542. turnstile_td_reown (td, turnstile);
  543. spinlock_unlock (&turnstile->bucket->lock);
  544. turnstile_td_propagate_priority_loop (td);
  545. spinlock_lock (&turnstile->bucket->lock);
  546. }
  547. static void
  548. turnstile_signal_first (struct turnstile *turnstile)
  549. {
  550. _Auto waiter = plist_last_entry (&turnstile->waiters,
  551. struct turnstile_waiter, node);
  552. turnstile_waiter_wakeup (waiter);
  553. }
  554. static int
  555. turnstile_wait_common (struct turnstile *turnstile, const char *wchan,
  556. struct thread *owner, bool timed, uint64_t ticks)
  557. {
  558. int error = 0;
  559. struct thread *thread = thread_self ();
  560. assert (thread != owner);
  561. _Auto td = thread_turnstile_td (thread);
  562. spinlock_lock (&td->lock);
  563. struct turnstile_waiter waiter;
  564. turnstile_waiter_init (&waiter, thread);
  565. turnstile_add_waiter (turnstile, &waiter);
  566. turnstile_td_set_waiter (td, &waiter);
  567. spinlock_unlock (&td->lock);
  568. if (owner)
  569. // This function temporarily unlocks the turnstile.
  570. turnstile_update_owner (turnstile, owner);
  571. else if (turnstile->top_waiter == &waiter)
  572. turnstile_waiter_set_awaken (&waiter);
  573. while (1)
  574. {
  575. if (!turnstile_waiter_awaken (&waiter))
  576. {
  577. if (! timed)
  578. thread_sleep (&turnstile->bucket->lock,
  579. &turnstile->sync_key, wchan);
  580. else
  581. {
  582. error = thread_timedsleep (&turnstile->bucket->lock,
  583. &turnstile->sync_key, wchan, ticks);
  584. if (error)
  585. {
  586. if (turnstile_waiter_awaken (&waiter))
  587. error = 0;
  588. else
  589. break;
  590. }
  591. }
  592. }
  593. // Handle spurious wakeups.
  594. if (!turnstile_waiter_awaken (&waiter))
  595. continue;
  596. /*
  597. * The real priority of a thread may change between waking up
  598. * and reacquiring the turnstile.
  599. */
  600. if (turnstile->top_waiter == &waiter || turnstile->broadcasting)
  601. break;
  602. // Otherwise, make sure the new top waiter is awoken.
  603. turnstile_waiter_wakeup (turnstile->top_waiter);
  604. turnstile_waiter_clear_awaken (&waiter);
  605. }
  606. spinlock_lock (&td->lock);
  607. turnstile_td_set_waiter (td, NULL);
  608. turnstile_remove_waiter (turnstile, &waiter);
  609. if (!turnstile->broadcasting)
  610. ;
  611. else if (turnstile_empty (turnstile))
  612. turnstile->broadcasting = false;
  613. else
  614. turnstile_signal_first (turnstile);
  615. spinlock_unlock (&td->lock);
  616. if (error && turnstile->owner)
  617. // This function temporarily unlocks the turnstile.
  618. turnstile_update_owner (turnstile, turnstile->owner);
  619. return (error);
  620. }
  621. int
  622. turnstile_wait (struct turnstile *turnstile, const char *wchan,
  623. struct thread *owner)
  624. {
  625. int error = turnstile_wait_common (turnstile, wchan, owner, false, 0);
  626. assert (! error);
  627. return (error);
  628. }
  629. int
  630. turnstile_timedwait (struct turnstile *turnstile, const char *wchan,
  631. struct thread *owner, uint64_t ticks)
  632. {
  633. return (turnstile_wait_common (turnstile, wchan, owner, true, ticks));
  634. }
  635. void
  636. turnstile_signal (struct turnstile *turnstile)
  637. {
  638. if (turnstile_empty (turnstile))
  639. return;
  640. turnstile_signal_first (turnstile);
  641. }
  642. void
  643. turnstile_broadcast (struct turnstile *turnstile)
  644. {
  645. if (turnstile_empty (turnstile))
  646. return;
  647. turnstile->broadcasting = true;
  648. turnstile_signal_first (turnstile);
  649. }
  650. void
  651. turnstile_own (struct turnstile *turnstile)
  652. {
  653. assert (!turnstile->owner);
  654. if (turnstile_empty (turnstile))
  655. return;
  656. struct thread *owner = thread_self ();
  657. uint32_t top_priority = turnstile_waiter_priority (turnstile->top_waiter);
  658. assert (thread_real_global_priority (owner) >= top_priority);
  659. _Auto td = thread_turnstile_td (owner);
  660. spinlock_lock (&td->lock);
  661. turnstile_td_own (td, turnstile);
  662. spinlock_unlock (&td->lock);
  663. }
  664. void
  665. turnstile_disown (struct turnstile *turnstile)
  666. {
  667. if (!turnstile->owner)
  668. return;
  669. struct thread *owner = thread_self ();
  670. assert (turnstile->owner == owner);
  671. assert (!turnstile_empty (turnstile));
  672. _Auto td = thread_turnstile_td (owner);
  673. spinlock_lock (&td->lock);
  674. turnstile_td_disown (td, turnstile);
  675. spinlock_unlock (&td->lock);
  676. }
  677. bool
  678. turnstile_owned_by (struct turnstile *turnstile, struct thread *thread)
  679. {
  680. return (turnstile->owner == thread);
  681. }
  682. void
  683. turnstile_td_exit (struct turnstile_td *td)
  684. {
  685. if (likely (plist_empty (&td->owned_turnstiles)))
  686. return;
  687. struct turnstile *turnstile;
  688. plist_for_each_entry (&td->owned_turnstiles, turnstile, td_node)
  689. {
  690. spinlock_lock (&turnstile->bucket->lock);
  691. turnstile_disown (turnstile);
  692. turnstile_broadcast (turnstile);
  693. turnstile_release (turnstile);
  694. }
  695. thread_propagate_priority ();
  696. }