futex.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. * Copyright (c) 2023 Agustina Arzille.
  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 <kern/clock.h>
  19. #include <kern/sleepq.h>
  20. #include <kern/turnstile.h>
  21. #include <kern/unwind.h>
  22. #include <kern/user.h>
  23. #include <vm/map.h>
  24. #include <vm/object.h>
  25. #define FUTEX_DATA_SHARED FUTEX_SHARED
  26. #define FUTEX_DATA_WAIT 0x02
  27. #define FUTEX_DATA_WAKE 0x04
  28. // Operations used in 'futex_map_addr' below.
  29. #define FUTEX_OP_CMP 0
  30. #define FUTEX_OP_SET 1
  31. #define FUTEX_OP_ROBUST_CLEAR 2
  32. #define FUTEX_OP_LOCK_PI 3
  33. struct futex_data;
  34. /*
  35. * Futex operations.
  36. *
  37. * Since the operations themselves are very similar across futexes'
  38. * "flavors", this structure aims to encapsulate the subtleties among them.
  39. */
  40. struct futex_ops
  41. {
  42. void* (*acquire) (const union sync_key *);
  43. void (*release) (void *);
  44. union
  45. {
  46. int (*wait) (struct futex_data *, int, uint32_t, uint64_t);
  47. int (*wake) (void *, uint32_t);
  48. };
  49. };
  50. struct futex_data
  51. {
  52. int *addr;
  53. struct vm_map *map;
  54. union sync_key key;
  55. uint32_t mode;
  56. void *wait_obj;
  57. const struct futex_ops *ops;
  58. };
  59. static int
  60. futex_check_addr (int *addr)
  61. {
  62. if (!user_check_range (addr, sizeof (int)))
  63. return (EFAULT);
  64. else if (((uintptr_t)addr % sizeof (int)) != 0)
  65. return (EINVAL);
  66. return (0);
  67. }
  68. static int
  69. futex_key_init (union sync_key *key, struct vm_map *map,
  70. int *addr, uint32_t flags)
  71. {
  72. if (likely (!(flags & FUTEX_SHARED)))
  73. /*
  74. * For task-local futexes the key is made up of the virtual address
  75. * itself and the calling thread's VM map.
  76. */
  77. sync_key_local_init (key, addr, map);
  78. else
  79. {
  80. /*
  81. * For task-shared futexes, the key is made of the <VM object, offset>
  82. * pair, obtained by performing a VM lookup on the virtual address.
  83. */
  84. struct vm_map_entry entry;
  85. int error = vm_map_lookup (map, (uintptr_t)addr, &entry);
  86. if (error)
  87. return (error);
  88. else if ((uintptr_t)addr < entry.start)
  89. {
  90. vm_map_entry_put (&entry);
  91. return (EFAULT);
  92. }
  93. sync_key_shared_init (key, entry.object, entry.offset);
  94. }
  95. return (0);
  96. }
  97. static void*
  98. futex_sleepq_lend (const union sync_key *key)
  99. {
  100. return (sleepq_lend_key (key));
  101. }
  102. static void*
  103. futex_pi_lend (const union sync_key *key)
  104. {
  105. return (turnstile_lend_key (key));
  106. }
  107. static void
  108. futex_sleepq_return (void *obj)
  109. {
  110. sleepq_return ((struct sleepq *)obj);
  111. }
  112. static void
  113. futex_pi_return (void *obj)
  114. {
  115. turnstile_return ((struct turnstile *)obj);
  116. }
  117. static void*
  118. futex_sleepq_acquire (const union sync_key *key)
  119. {
  120. return (sleepq_acquire_key (key));
  121. }
  122. static void*
  123. futex_pi_acquire (const union sync_key *key)
  124. {
  125. return (turnstile_acquire_key (key));
  126. }
  127. static void
  128. futex_sleepq_release (void *obj)
  129. {
  130. sleepq_release ((struct sleepq *)obj);
  131. }
  132. static void
  133. futex_pi_release (void *obj)
  134. {
  135. turnstile_release ((struct turnstile *)obj);
  136. thread_propagate_priority ();
  137. }
  138. static int
  139. futex_sleepq_wait (struct futex_data *data, int value __unused,
  140. uint32_t flags, uint64_t ticks)
  141. {
  142. uint64_t *timep = NULL;
  143. if (flags & FUTEX_TIMED)
  144. {
  145. timep = &ticks;
  146. if (!(flags & FUTEX_ABSTIME))
  147. ticks += clock_get_time () + 1;
  148. }
  149. return (sleepq_wait_movable ((struct sleepq **)&data->wait_obj,
  150. "futex", timep));
  151. }
  152. static int futex_map_addr (struct futex_data *, int, int);
  153. static int
  154. futex_pi_wait (struct futex_data *data, int value,
  155. uint32_t flags, uint64_t ticks)
  156. {
  157. if (! value)
  158. return (EAGAIN);
  159. struct thread *thr = thread_by_kuid ((uint32_t)value & FUTEX_TID_MASK);
  160. if (! thr)
  161. return (ESRCH);
  162. else if (thr == thread_self ())
  163. {
  164. thread_unref (thr);
  165. return (EALREADY);
  166. }
  167. int error;
  168. if (!(flags & FUTEX_TIMED))
  169. error = turnstile_wait (data->wait_obj, "futex-pi", thr);
  170. else
  171. {
  172. if (!(flags & FUTEX_ABSTIME))
  173. ticks += clock_get_time () + 1;
  174. error = turnstile_timedwait (data->wait_obj, "futex-pi", thr, ticks);
  175. }
  176. thread_unref (thr);
  177. if (error)
  178. return (error);
  179. /*
  180. * PI futexes have ownership semantics. In order to apply them, we
  181. * need to change the futex word's value after a succesful wait.
  182. */
  183. error = futex_map_addr (data, thread_id (thread_self ()), FUTEX_OP_LOCK_PI);
  184. if (! error)
  185. turnstile_own (data->wait_obj);
  186. return (error);
  187. }
  188. static int
  189. futex_sleepq_wake (void *sleepq, uint32_t flags)
  190. {
  191. if (flags & FUTEX_BROADCAST)
  192. sleepq_broadcast ((struct sleepq *)sleepq);
  193. else
  194. sleepq_signal ((struct sleepq *)sleepq);
  195. return (0);
  196. }
  197. static int
  198. futex_pi_wake (void *obj, uint32_t flags)
  199. {
  200. struct turnstile *turnstile = (struct turnstile *)obj;
  201. if (!turnstile_owned_by (turnstile, thread_self ()))
  202. return (EPERM);
  203. turnstile_disown (turnstile);
  204. if (flags & FUTEX_BROADCAST)
  205. turnstile_broadcast (turnstile);
  206. else
  207. turnstile_signal (turnstile);
  208. return (0);
  209. }
  210. // Set of operations used when waiting on a futex.
  211. static const struct futex_ops futex_wait_ops[] =
  212. {
  213. {
  214. .acquire = futex_sleepq_lend,
  215. .release = futex_sleepq_return,
  216. .wait = futex_sleepq_wait
  217. },
  218. {
  219. .acquire = futex_pi_lend,
  220. .release = futex_pi_return,
  221. .wait = futex_pi_wait
  222. }
  223. };
  224. // Operations used when waking futex waiters.
  225. static const struct futex_ops futex_wake_ops[] =
  226. {
  227. {
  228. .acquire = futex_sleepq_acquire,
  229. .release = futex_sleepq_release,
  230. .wake = futex_sleepq_wake
  231. },
  232. {
  233. .acquire = futex_pi_acquire,
  234. .release = futex_pi_release,
  235. .wake = futex_pi_wake
  236. }
  237. };
  238. static const struct futex_ops*
  239. futex_select_ops (uint32_t flags, uint32_t mode)
  240. {
  241. uint32_t idx = (flags & FUTEX_PI) / FUTEX_PI;
  242. assert (idx <= 1);
  243. return ((mode & FUTEX_DATA_WAIT) ?
  244. &futex_wait_ops[idx] : &futex_wake_ops[idx]);
  245. }
  246. static int
  247. futex_data_init (struct futex_data *data, int *addr,
  248. uint32_t flags, uint32_t mode)
  249. {
  250. data->wait_obj = NULL;
  251. data->mode = 0;
  252. int error = futex_check_addr (addr);
  253. if (error)
  254. return (error);
  255. data->map = vm_map_self ();
  256. data->addr = addr;
  257. error = futex_key_init (&data->key, data->map, addr, flags);
  258. if (error)
  259. return (error);
  260. data->mode = mode | ((flags & FUTEX_SHARED) ? FUTEX_DATA_SHARED : 0);
  261. data->ops = futex_select_ops (flags, mode);
  262. return (0);
  263. }
  264. static void
  265. futex_data_release (struct futex_data *data)
  266. {
  267. if (!data->wait_obj)
  268. return;
  269. data->ops->release (data->wait_obj);
  270. data->wait_obj = NULL;
  271. }
  272. static inline void
  273. futex_object_unref (struct vm_object *obj)
  274. {
  275. if (obj)
  276. vm_object_unref (obj);
  277. }
  278. static void
  279. futex_data_fini (void *arg)
  280. {
  281. struct futex_data *data = arg;
  282. if (data->mode & FUTEX_DATA_SHARED)
  283. futex_object_unref (data->key.shared.object);
  284. futex_data_release (data);
  285. }
  286. static int
  287. futex_robust_clear (int *addr, int value)
  288. {
  289. while (1)
  290. {
  291. int tmp = atomic_load_rlx (addr);
  292. if ((tmp & FUTEX_TID_MASK) != (uint32_t)value)
  293. return (0);
  294. else if (atomic_cas_bool_rel (addr, tmp, tmp | FUTEX_OWNER_DIED))
  295. /*
  296. * Use a negative value to indicate that a wakeup is needed. This is
  297. * done so that it doesn't clash with any errno value.
  298. */
  299. return ((tmp & FUTEX_WAITERS) ? -1 : 0);
  300. atomic_spin_nop ();
  301. }
  302. }
  303. static int
  304. futex_map_addr (struct futex_data *data, int value, int op)
  305. {
  306. int prot = op == FUTEX_OP_CMP ? VM_PROT_READ : VM_PROT_RDWR;
  307. struct unw_fixup fixup;
  308. int error = unw_fixup_save (&fixup);
  309. if (error)
  310. {
  311. /*
  312. * There was a page fault when accessing the address. Test if this
  313. * was simply because it needs to be paged in, and we couldn't do it
  314. * earlier due to us holding a spinlock, or because there was another
  315. * issue (like a protection error).
  316. */
  317. thread_pagefault_enable ();
  318. if (error != EAGAIN)
  319. return (error);
  320. // Drop the lock on the wait queue and page in the address.
  321. futex_data_release (data);
  322. cpu_flags_t flags;
  323. cpu_intr_save (&flags);
  324. error = vm_map_fault (data->map, (uintptr_t)data->addr, prot);
  325. cpu_intr_restore (flags);
  326. if (error)
  327. return (error);
  328. data->wait_obj = data->ops->acquire (&data->key);
  329. error = 0;
  330. }
  331. thread_pagefault_disable ();
  332. switch (op)
  333. {
  334. case FUTEX_OP_CMP:
  335. error = value == *data->addr ? 0 : EAGAIN;
  336. break;
  337. case FUTEX_OP_SET:
  338. *data->addr = value;
  339. break;
  340. case FUTEX_OP_ROBUST_CLEAR:
  341. error = futex_robust_clear (data->addr, value);
  342. break;
  343. case FUTEX_OP_LOCK_PI:
  344. error = atomic_cas_bool_acq (data->addr, 0, value | FUTEX_WAITERS) ?
  345. 0 : EAGAIN;
  346. break;
  347. }
  348. thread_pagefault_enable ();
  349. return (error);
  350. }
  351. int
  352. futex_wait (int *addr, int value, uint32_t flags, uint64_t ticks)
  353. {
  354. CLEANUP (futex_data_fini) struct futex_data data;
  355. int error = futex_data_init (&data, addr, flags, FUTEX_DATA_WAIT);
  356. if (error)
  357. return (error);
  358. data.wait_obj = data.ops->acquire (&data.key);
  359. error = futex_map_addr (&data, value, FUTEX_OP_CMP);
  360. if (! error)
  361. error = data.ops->wait (&data, value, flags, ticks);
  362. return (error);
  363. }
  364. int
  365. futex_wake (int *addr, uint32_t flags, int value)
  366. {
  367. CLEANUP (futex_data_fini) struct futex_data data;
  368. int error = futex_data_init (&data, addr, flags, FUTEX_DATA_WAKE);
  369. if (error)
  370. return (error);
  371. data.wait_obj = data.ops->acquire (&data.key);
  372. if (flags & FUTEX_MUTATE)
  373. {
  374. error = futex_map_addr (&data, value, FUTEX_OP_SET);
  375. if (error)
  376. return (error);
  377. }
  378. if (data.wait_obj)
  379. error = data.ops->wake (data.wait_obj, flags);
  380. return (0);
  381. }
  382. int
  383. futex_requeue (int *dst_addr, int *src_addr, int wake_one, uint32_t flags)
  384. {
  385. if (flags & FUTEX_PI)
  386. return (EINVAL);
  387. int error = futex_check_addr (dst_addr);
  388. if (error)
  389. return (error);
  390. error = futex_check_addr (src_addr);
  391. if (error)
  392. return (error);
  393. union sync_key dkey, skey;
  394. struct vm_map *map = vm_map_self ();
  395. error = futex_key_init (&dkey, map, dst_addr, flags);
  396. if (error)
  397. return (error);
  398. error = futex_key_init (&skey, map, src_addr, flags);
  399. if (error)
  400. {
  401. if (flags & FUTEX_SHARED)
  402. futex_object_unref (dkey.shared.object);
  403. return (error);
  404. }
  405. sleepq_move (&dkey, &skey, wake_one, (flags & FUTEX_BROADCAST));
  406. if (flags & FUTEX_SHARED)
  407. {
  408. futex_object_unref (dkey.shared.object);
  409. futex_object_unref (skey.shared.object);
  410. }
  411. return (0);
  412. }
  413. static int
  414. futex_robust_list_handle (struct futex_robust_list *list,
  415. int *addr, int tid)
  416. {
  417. CLEANUP (futex_data_fini) struct futex_data data;
  418. int error = futex_data_init (&data, addr, list->flags, FUTEX_DATA_WAKE);
  419. if (error)
  420. return (error);
  421. data.wait_obj = data.ops->acquire (&data.key);
  422. error = futex_map_addr (&data, tid, FUTEX_OP_ROBUST_CLEAR);
  423. if (error < 0)
  424. { // There are waiters on this robust futex. Wake them all.
  425. if (data.wait_obj)
  426. data.ops->wake (data.wait_obj, list->flags | FUTEX_BROADCAST);
  427. error = 0;
  428. }
  429. return (error);
  430. }
  431. void
  432. futex_td_exit (struct futex_td *td)
  433. {
  434. int tid = thread_id (thread_self ());
  435. struct futex_td rtd;
  436. if (!td || user_copy_from (&rtd, td, sizeof (rtd)) != 0)
  437. return;
  438. if (rtd.pending &&
  439. (!user_check_range (rtd.pending, sizeof (rtd.pending)) ||
  440. futex_robust_list_handle (rtd.pending, (int *)rtd.pending, tid) != 0))
  441. return;
  442. uint32_t nmax = 1024; // Handle this many robust futexes.
  443. while (rtd.list)
  444. {
  445. struct futex_robust_list tmp;
  446. if (user_copy_from (&tmp, rtd.list, sizeof (tmp)) != 0 ||
  447. futex_robust_list_handle (&tmp, (int *)rtd.list, tid) != 0 ||
  448. --nmax == 0)
  449. break;
  450. rtd.list = (void *)(uintptr_t)tmp.next;
  451. }
  452. }