sleepq.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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. #include <assert.h>
  19. #include <stdalign.h>
  20. #include <stdbool.h>
  21. #include <stddef.h>
  22. #include <stdint.h>
  23. #include <kern/hlist.h>
  24. #include <kern/init.h>
  25. #include <kern/kmem.h>
  26. #include <kern/list.h>
  27. #include <kern/macros.h>
  28. #include <kern/sleepq.h>
  29. #include <kern/spinlock.h>
  30. #include <kern/thread.h>
  31. #include <machine/cpu.h>
  32. struct sleepq_bucket
  33. {
  34. __cacheline_aligned struct spinlock lock;
  35. struct hlist sleepqs;
  36. };
  37. struct sleepq_waiter
  38. {
  39. struct list node;
  40. struct thread *thread;
  41. struct sleepq *sleepq;
  42. bool pending_wakeup;
  43. };
  44. #define SLEEPQ_HTABLE_SIZE 128
  45. #if !ISP2(SLEEPQ_HTABLE_SIZE) || !ISP2(SLEEPQ_COND_HTABLE_SIZE)
  46. #error "hash table size must be a power of two"
  47. #endif
  48. #define SLEEPQ_HTABLE_MASK (SLEEPQ_HTABLE_SIZE - 1)
  49. static struct sleepq_bucket sleepq_htable[SLEEPQ_HTABLE_SIZE];
  50. static struct kmem_cache sleepq_cache;
  51. static void
  52. sleepq_waiter_init (struct sleepq_waiter *waiter,
  53. struct thread *thread, struct sleepq *sleepq)
  54. {
  55. waiter->thread = thread;
  56. waiter->sleepq = sleepq;
  57. waiter->pending_wakeup = false;
  58. }
  59. static bool
  60. sleepq_waiter_pending_wakeup (const struct sleepq_waiter *waiter)
  61. {
  62. return (waiter->pending_wakeup);
  63. }
  64. static void
  65. sleepq_waiter_set_pending_wakeup (struct sleepq_waiter *waiter)
  66. {
  67. waiter->pending_wakeup = true;
  68. }
  69. static void
  70. sleepq_waiter_wakeup (struct sleepq_waiter *waiter, struct sleepq *sleepq)
  71. {
  72. if (!sleepq_waiter_pending_wakeup (waiter))
  73. return;
  74. waiter->sleepq = sleepq;
  75. thread_wakeup (waiter->thread);
  76. }
  77. static bool
  78. sleepq_init_state_valid (const struct sleepq *sleepq)
  79. {
  80. return (!sleepq->bucket &&
  81. sync_key_isclear (&sleepq->sync_key) &&
  82. list_empty (&sleepq->waiters) &&
  83. !sleepq->oldest_waiter &&
  84. !sleepq->next_free);
  85. }
  86. static void
  87. sleepq_use (struct sleepq *sleepq, const union sync_key *key)
  88. {
  89. assert (sync_key_isclear (&sleepq->sync_key));
  90. sleepq->sync_key = *key;
  91. }
  92. static void
  93. sleepq_unuse (struct sleepq *sleepq)
  94. {
  95. sync_key_clear (&sleepq->sync_key);
  96. }
  97. static bool
  98. sleepq_in_use (const struct sleepq *sleepq)
  99. {
  100. return (!sync_key_isclear (&sleepq->sync_key));
  101. }
  102. static bool
  103. sleepq_in_use_by (const struct sleepq *sleepq, const union sync_key *key)
  104. {
  105. return (sync_key_eq (&sleepq->sync_key, key));
  106. }
  107. static void
  108. sleepq_bucket_init (struct sleepq_bucket *bucket)
  109. {
  110. spinlock_init (&bucket->lock);
  111. hlist_init (&bucket->sleepqs);
  112. }
  113. static struct sleepq_bucket*
  114. sleepq_bucket_get (const union sync_key *key)
  115. {
  116. uintptr_t index = sync_key_hash (key) & SLEEPQ_HTABLE_MASK;
  117. assert (index < ARRAY_SIZE (sleepq_htable));
  118. return (&sleepq_htable[index]);
  119. }
  120. static void
  121. sleepq_bucket_add (struct sleepq_bucket *bucket, struct sleepq *sleepq)
  122. {
  123. assert (!sleepq->bucket);
  124. sleepq->bucket = bucket;
  125. hlist_insert_head (&bucket->sleepqs, &sleepq->node);
  126. }
  127. static void
  128. sleepq_bucket_remove (struct sleepq_bucket *bucket, struct sleepq *sleepq)
  129. {
  130. assert (sleepq->bucket == bucket);
  131. sleepq->bucket = NULL;
  132. hlist_remove (&sleepq->node);
  133. }
  134. static struct sleepq*
  135. sleepq_bucket_lookup (const struct sleepq_bucket *bucket,
  136. const union sync_key *key)
  137. {
  138. struct sleepq *sleepq;
  139. hlist_for_each_entry (&bucket->sleepqs, sleepq, node)
  140. if (sleepq_in_use_by (sleepq, key))
  141. {
  142. assert (sleepq->bucket == bucket);
  143. return (sleepq);
  144. }
  145. return (NULL);
  146. }
  147. static void
  148. sleepq_ctor (void *ptr)
  149. {
  150. struct sleepq *sleepq = ptr;
  151. sleepq->bucket = NULL;
  152. sync_key_clear (&sleepq->sync_key);
  153. list_init (&sleepq->waiters);
  154. sleepq->oldest_waiter = NULL;
  155. sleepq->next_free = NULL;
  156. sleepq->free_link = NULL;
  157. }
  158. static int __init
  159. sleepq_setup (void)
  160. {
  161. for (size_t i = 0; i < ARRAY_SIZE (sleepq_htable); i++)
  162. sleepq_bucket_init (&sleepq_htable[i]);
  163. kmem_cache_init (&sleepq_cache, "sleepq", sizeof (struct sleepq),
  164. alignof (struct sleepq), sleepq_ctor, 0);
  165. return (0);
  166. }
  167. INIT_OP_DEFINE (sleepq_setup,
  168. INIT_OP_DEP (kmem_setup, true));
  169. struct sleepq*
  170. sleepq_create (void)
  171. {
  172. struct sleepq *sleepq = kmem_cache_alloc (&sleepq_cache);
  173. if (! sleepq)
  174. return (NULL);
  175. assert (sleepq_init_state_valid (sleepq));
  176. return (sleepq);
  177. }
  178. void
  179. sleepq_destroy (struct sleepq *sleepq)
  180. {
  181. assert (sleepq_init_state_valid (sleepq));
  182. kmem_cache_free (&sleepq_cache, sleepq);
  183. }
  184. static struct sleepq*
  185. sleepq_acquire_common (const union sync_key *key, cpu_flags_t *flags)
  186. {
  187. assert (!sync_key_isclear (key));
  188. _Auto bucket = sleepq_bucket_get (key);
  189. if (flags)
  190. spinlock_lock_intr_save (&bucket->lock, flags);
  191. else
  192. spinlock_lock (&bucket->lock);
  193. _Auto sleepq = sleepq_bucket_lookup (bucket, key);
  194. if (! sleepq)
  195. {
  196. if (flags)
  197. spinlock_unlock_intr_restore (&bucket->lock, *flags);
  198. else
  199. spinlock_unlock (&bucket->lock);
  200. }
  201. return (sleepq);
  202. }
  203. static struct sleepq*
  204. sleepq_tryacquire_common (const union sync_key *key, cpu_flags_t *flags)
  205. {
  206. assert (!sync_key_isclear (key));
  207. _Auto bucket = sleepq_bucket_get (key);
  208. int error = flags ? spinlock_trylock_intr_save (&bucket->lock, flags) :
  209. spinlock_trylock (&bucket->lock);
  210. if (error)
  211. return (NULL);
  212. _Auto sleepq = sleepq_bucket_lookup (bucket, key);
  213. if (! sleepq)
  214. {
  215. if (flags)
  216. spinlock_unlock_intr_restore (&bucket->lock, *flags);
  217. else
  218. spinlock_unlock (&bucket->lock);
  219. }
  220. return (sleepq);
  221. }
  222. struct sleepq*
  223. sleepq_acquire_key (const union sync_key *key)
  224. {
  225. return (sleepq_acquire_common (key, NULL));
  226. }
  227. struct sleepq*
  228. sleepq_tryacquire_key (const union sync_key *key)
  229. {
  230. return (sleepq_tryacquire_common (key, NULL));
  231. }
  232. void
  233. sleepq_release (struct sleepq *sleepq)
  234. {
  235. spinlock_unlock (&sleepq->bucket->lock);
  236. }
  237. struct sleepq*
  238. sleepq_acquire_key_intr (const union sync_key *key, cpu_flags_t *flags)
  239. {
  240. return (sleepq_acquire_common (key, flags));
  241. }
  242. struct sleepq*
  243. sleepq_tryacquire_key_intr (const union sync_key *key, cpu_flags_t *flags)
  244. {
  245. return (sleepq_tryacquire_common (key, flags));
  246. }
  247. void
  248. sleepq_release_intr_restore (struct sleepq *sleepq, cpu_flags_t flags)
  249. {
  250. spinlock_unlock_intr_restore (&sleepq->bucket->lock, flags);
  251. }
  252. static void
  253. sleepq_push_free (struct sleepq *sleepq, struct sleepq *free_sleepq)
  254. {
  255. assert (!free_sleepq->next_free);
  256. free_sleepq->next_free = sleepq->next_free;
  257. if (!sleepq->next_free)
  258. sleepq->free_link = &free_sleepq->next_free;
  259. sleepq->next_free = free_sleepq;
  260. }
  261. static struct sleepq*
  262. sleepq_pop_free (struct sleepq *sleepq)
  263. {
  264. struct sleepq *free_sleepq = sleepq->next_free;
  265. if (! free_sleepq)
  266. return (NULL);
  267. sleepq->next_free = free_sleepq->next_free;
  268. free_sleepq->next_free = NULL;
  269. if (!sleepq->next_free)
  270. sleepq->free_link = NULL;
  271. return (free_sleepq);
  272. }
  273. static struct sleepq*
  274. sleepq_lend_common (const union sync_key *key, cpu_flags_t *flags)
  275. {
  276. assert (!sync_key_isclear (key));
  277. _Auto self = thread_self ();
  278. _Auto sleepq = thread_sleepq_lend (self);
  279. assert (sleepq_init_state_valid (sleepq));
  280. _Auto bucket = sleepq_bucket_get (key);
  281. self->wchan_addr = bucket;
  282. if (flags)
  283. spinlock_lock_intr_save (&bucket->lock, flags);
  284. else
  285. spinlock_lock (&bucket->lock);
  286. struct sleepq *prev = sleepq_bucket_lookup (bucket, key);
  287. if (! prev)
  288. {
  289. sleepq_use (sleepq, key);
  290. sleepq_bucket_add (bucket, sleepq);
  291. }
  292. else
  293. {
  294. sleepq_push_free (prev, sleepq);
  295. sleepq = prev;
  296. }
  297. self->wchan_addr = NULL;
  298. return (sleepq);
  299. }
  300. static void
  301. sleepq_return_common (struct sleepq *sleepq, cpu_flags_t *flags)
  302. {
  303. assert (sleepq_in_use (sleepq));
  304. _Auto bucket = sleepq->bucket;
  305. _Auto free_sleepq = sleepq_pop_free (sleepq);
  306. if (! free_sleepq)
  307. {
  308. sleepq_bucket_remove (bucket, sleepq);
  309. sleepq_unuse (sleepq);
  310. free_sleepq = sleepq;
  311. }
  312. if (flags)
  313. spinlock_unlock_intr_restore (&bucket->lock, *flags);
  314. else
  315. spinlock_unlock (&bucket->lock);
  316. assert (sleepq_init_state_valid (free_sleepq));
  317. thread_sleepq_return (free_sleepq);
  318. }
  319. struct sleepq*
  320. sleepq_lend_key (const union sync_key *key)
  321. {
  322. return (sleepq_lend_common (key, NULL));
  323. }
  324. void
  325. sleepq_return (struct sleepq *sleepq)
  326. {
  327. sleepq_return_common (sleepq, NULL);
  328. }
  329. struct sleepq*
  330. sleepq_lend_key_intr (const union sync_key *key, cpu_flags_t *flags)
  331. {
  332. return (sleepq_lend_common (key, flags));
  333. }
  334. void
  335. sleepq_return_intr_restore (struct sleepq *sleepq, cpu_flags_t flags)
  336. {
  337. sleepq_return_common (sleepq, &flags);
  338. }
  339. static void
  340. sleepq_shift_oldest_waiter (struct sleepq *sleepq)
  341. {
  342. assert (sleepq->oldest_waiter);
  343. struct list *node = list_next (&sleepq->oldest_waiter->node);
  344. sleepq->oldest_waiter = list_end (&sleepq->waiters, node) ?
  345. NULL : list_entry (node, struct sleepq_waiter, node);
  346. }
  347. static void
  348. sleepq_add_waiter (struct sleepq *sleepq, struct sleepq_waiter *waiter)
  349. {
  350. list_insert_tail (&sleepq->waiters, &waiter->node);
  351. if (!sleepq->oldest_waiter)
  352. sleepq->oldest_waiter = waiter;
  353. }
  354. static void
  355. sleepq_remove_waiter (struct sleepq *sleepq, struct sleepq_waiter *waiter)
  356. {
  357. if (sleepq->oldest_waiter == waiter)
  358. sleepq_shift_oldest_waiter (sleepq);
  359. list_remove (&waiter->node);
  360. }
  361. static struct sleepq_waiter*
  362. sleepq_get_last_waiter (struct sleepq *sleepq)
  363. {
  364. return (list_empty (&sleepq->waiters) ?
  365. NULL : list_first_entry (&sleepq->waiters, struct sleepq_waiter, node));
  366. }
  367. static int
  368. sleepq_wait_common (struct sleepq_waiter *waiter, const char *wchan,
  369. bool timed, uint64_t ticks)
  370. {
  371. _Auto sleepq = waiter->sleepq;
  372. struct spinlock *lock = &sleepq->bucket->lock;
  373. sleepq_add_waiter (sleepq, waiter);
  374. int error;
  375. do
  376. {
  377. if (! timed)
  378. {
  379. thread_sleep (lock, waiter, wchan);
  380. error = 0;
  381. }
  382. else
  383. {
  384. error = thread_timedsleep (lock, waiter, wchan, ticks);
  385. if (error)
  386. {
  387. if (sleepq_waiter_pending_wakeup (waiter))
  388. error = 0;
  389. else
  390. break;
  391. }
  392. }
  393. }
  394. while (!sleepq_waiter_pending_wakeup (waiter));
  395. struct sleepq *nsq = atomic_load_rlx (&waiter->sleepq);
  396. if (unlikely (nsq != sleepq))
  397. {
  398. spinlock_unlock (lock);
  399. sleepq = nsq;
  400. spinlock_lock (&sleepq->bucket->lock);
  401. }
  402. sleepq_remove_waiter (sleepq, waiter);
  403. /*
  404. * Chain wake-ups here to prevent broadacasting from walking a list
  405. * with preemption disabled. Note that this doesn't guard against
  406. * the thundering herd effect for condition variables.
  407. */
  408. struct sleepq_waiter *next = sleepq_get_last_waiter (sleepq);
  409. /*
  410. * Checking against the oldest waiter is enough as waiters are awoken
  411. * in strict FIFO order.
  412. */
  413. if (next && next != sleepq->oldest_waiter)
  414. {
  415. sleepq_waiter_set_pending_wakeup (next);
  416. sleepq_waiter_wakeup (next, sleepq);
  417. }
  418. return (error);
  419. }
  420. void
  421. sleepq_wait (struct sleepq *sleepq, const char *wchan)
  422. {
  423. struct sleepq_waiter waiter;
  424. sleepq_waiter_init (&waiter, thread_self (), sleepq);
  425. int error = sleepq_wait_common (&waiter, wchan, false, 0);
  426. assert (! error);
  427. }
  428. int
  429. sleepq_timedwait (struct sleepq *sleepq, const char *wchan, uint64_t ticks)
  430. {
  431. struct sleepq_waiter waiter;
  432. sleepq_waiter_init (&waiter, thread_self (), sleepq);
  433. return (sleepq_wait_common (&waiter, wchan, true, ticks));
  434. }
  435. int
  436. sleepq_wait_movable (struct sleepq **sleepq, const char *wchan,
  437. uint64_t *ticksp)
  438. {
  439. struct sleepq_waiter waiter;
  440. sleepq_waiter_init (&waiter, thread_self (), *sleepq);
  441. int error = ticksp ? sleepq_wait_common (&waiter, wchan, true, *ticksp) :
  442. sleepq_wait_common (&waiter, wchan, false, 0);
  443. *sleepq = waiter.sleepq;
  444. return (error);
  445. }
  446. void
  447. sleepq_signal (struct sleepq *sleepq)
  448. {
  449. struct sleepq_waiter *waiter = sleepq->oldest_waiter;
  450. if (! waiter)
  451. return;
  452. sleepq_shift_oldest_waiter (sleepq);
  453. sleepq_waiter_set_pending_wakeup (waiter);
  454. sleepq_waiter_wakeup (waiter, sleepq);
  455. }
  456. void
  457. sleepq_broadcast (struct sleepq *sleepq)
  458. {
  459. struct sleepq_waiter *waiter = sleepq->oldest_waiter;
  460. if (! waiter)
  461. return;
  462. sleepq->oldest_waiter = NULL;
  463. sleepq_waiter_set_pending_wakeup (waiter);
  464. sleepq_waiter_wakeup (waiter, sleepq);
  465. }
  466. static inline void
  467. sleepq_transfer (struct sleepq *dst, struct sleepq *src,
  468. struct sleepq_waiter *waiter)
  469. {
  470. // Remove oldest waiter from source queue.
  471. list_remove (&waiter->node);
  472. sleepq_add_waiter (dst, waiter);
  473. src->oldest_waiter = NULL;
  474. // Concatenate source and destination waiter queues.
  475. list_concat (&dst->waiters, &src->waiters);
  476. list_init (&src->waiters);
  477. // Transfer all the queues in the free list.
  478. if (src->free_link)
  479. {
  480. *src->free_link = dst->next_free;
  481. dst->next_free = src->next_free;
  482. src->next_free = NULL;
  483. src->free_link = NULL;
  484. }
  485. // Remove source queue from its bucket and clear its key.
  486. sleepq_bucket_remove (src->bucket, src);
  487. sleepq_unuse (src);
  488. sleepq_push_free (dst, src);
  489. }
  490. void
  491. sleepq_move (const union sync_key *dst_key, const union sync_key *src_key,
  492. bool wake_one, bool move_all)
  493. {
  494. assert (dst_key && !sync_key_isclear (dst_key));
  495. assert (src_key && !sync_key_isclear (src_key));
  496. if (sync_key_eq (dst_key, src_key))
  497. return;
  498. _Auto dbucket = sleepq_bucket_get (dst_key);
  499. _Auto sbucket = sleepq_bucket_get (src_key);
  500. // Lock the buckets in order to avoid any deadlocks.
  501. if (dbucket == sbucket)
  502. spinlock_lock (&dbucket->lock);
  503. else if (dbucket < sbucket)
  504. {
  505. spinlock_lock (&dbucket->lock);
  506. spinlock_lock (&sbucket->lock);
  507. }
  508. else
  509. {
  510. spinlock_lock (&sbucket->lock);
  511. spinlock_lock (&dbucket->lock);
  512. }
  513. _Auto dsq = sleepq_bucket_lookup (dbucket, dst_key);
  514. _Auto ssq = sleepq_bucket_lookup (sbucket, src_key);
  515. if (!dsq || !ssq || sleepq_empty (ssq))
  516. goto out;
  517. _Auto prev = ssq->oldest_waiter;
  518. if (move_all || list_singular (&ssq->waiters))
  519. // The source queue will be empty after this operation.
  520. sleepq_transfer (dsq, ssq, prev);
  521. else
  522. {
  523. sleepq_remove_waiter (ssq, prev);
  524. sleepq_add_waiter (dsq, prev);
  525. _Auto free_sleepq = sleepq_pop_free (ssq);
  526. if (free_sleepq)
  527. sleepq_push_free (dsq, free_sleepq);
  528. }
  529. if (wake_one)
  530. sleepq_signal (dsq);
  531. out:
  532. spinlock_unlock (&dbucket->lock);
  533. if (dbucket != sbucket)
  534. spinlock_unlock (&sbucket->lock);
  535. }