linux_futex.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /* $OpenBSD: linux_futex.c,v 1.16 2014/08/20 06:03:20 doug Exp $ */
  2. /* $NetBSD: linux_futex.c,v 1.26 2010/07/07 01:30:35 chs Exp $ */
  3. /*-
  4. * Copyright (c) 2011 Paul Irofti <pirofti@openbsd.org>
  5. * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. All advertising materials mentioning features or use of this software
  16. * must display the following acknowledgement:
  17. * This product includes software developed by Emmanuel Dreyfus
  18. * 4. The name of the author may not be used to endorse or promote
  19. * products derived from this software without specific prior written
  20. * permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  24. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  25. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
  26. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <sys/param.h>
  35. #include <sys/ucred.h>
  36. #include <sys/malloc.h>
  37. #include <sys/mount.h>
  38. #include <sys/signal.h>
  39. #include <sys/stdint.h>
  40. #include <sys/time.h>
  41. #include <sys/systm.h>
  42. #include <sys/proc.h>
  43. #include <sys/pool.h>
  44. #include <sys/kernel.h>
  45. #include <sys/syscallargs.h>
  46. #include <compat/linux/linux_types.h>
  47. #include <compat/linux/linux_fcntl.h>
  48. #include <compat/linux/linux_misc.h>
  49. #include <compat/linux/linux_mmap.h>
  50. #include <compat/linux/linux_sched.h>
  51. #include <compat/linux/linux_signal.h>
  52. #include <compat/linux/linux_syscallargs.h>
  53. #include <compat/linux/linux_util.h>
  54. #include <compat/linux/linux_dirent.h>
  55. #include <compat/linux/linux_emuldata.h>
  56. #include <compat/linux/linux_time.h>
  57. #include <compat/linux/linux_futex.h>
  58. #ifdef COMPATFUTEX_DEBUG
  59. #define DPRINTF(x) printf x
  60. #else
  61. #define DPRINTF(x)
  62. #endif
  63. struct pool futex_pool;
  64. struct pool futex_wp_pool;
  65. int futex_pool_initialized;
  66. struct futex;
  67. struct waiting_proc {
  68. struct proc *p;
  69. struct futex *wp_new_futex;
  70. TAILQ_ENTRY(waiting_proc) wp_list;
  71. TAILQ_ENTRY(waiting_proc) wp_rqlist;
  72. };
  73. struct futex {
  74. void *f_uaddr;
  75. int f_refcount;
  76. LIST_ENTRY(futex) f_list;
  77. TAILQ_HEAD(, waiting_proc) f_waiting_proc;
  78. TAILQ_HEAD(, waiting_proc) f_requeue_proc;
  79. };
  80. static LIST_HEAD(futex_list, futex) futex_list;
  81. struct mutex futex_lock;
  82. void futex_pool_init(void);
  83. int linux_do_futex(struct proc *, const struct linux_sys_futex_args *,
  84. register_t *, struct timespec *);
  85. struct futex * futex_get(void *);
  86. void futex_ref(struct futex *);
  87. void futex_put(struct futex *);
  88. int futex_sleep(struct futex **, struct proc *, int, struct waiting_proc *);
  89. int futex_wake(struct futex *, int, struct futex *, int);
  90. int futex_atomic_op(struct proc *, int, void *);
  91. int futex_itimespecfix(struct timespec *ts);
  92. int
  93. linux_sys_futex(struct proc *p, void *v, register_t *retval)
  94. {
  95. struct linux_sys_futex_args /* {
  96. syscallarg(int *) uaddr;
  97. syscallarg(int) op;
  98. syscallarg(int) val;
  99. syscallarg(const struct linux_timespec *) timeout;
  100. syscallarg(int *) uaddr2;
  101. syscallarg(int) val3;
  102. } */ *uap = v;
  103. struct linux_timespec lts;
  104. struct timespec ts = {0, 0};
  105. int error;
  106. if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT &&
  107. SCARG(uap, timeout) != NULL) {
  108. if ((error = copyin(SCARG(uap, timeout),
  109. &lts, sizeof(lts))) != 0) {
  110. return error;
  111. }
  112. linux_to_bsd_timespec(&ts, &lts);
  113. }
  114. return linux_do_futex(p, uap, retval, &ts);
  115. }
  116. int
  117. linux_do_futex(struct proc *p, const struct linux_sys_futex_args *uap,
  118. register_t *retval, struct timespec *ts)
  119. {
  120. /* {
  121. syscallarg(int *) uaddr;
  122. syscallarg(int) op;
  123. syscallarg(int) val;
  124. syscallarg(const struct linux_timespec *) timeout;
  125. syscallarg(int *) uaddr2;
  126. syscallarg(int) val3;
  127. } */
  128. int ret;
  129. int error = 0;
  130. struct futex *f;
  131. struct futex *newf;
  132. int timeout_hz;
  133. struct timeval tv;
  134. struct futex *f2;
  135. struct waiting_proc *wp;
  136. int op_ret;
  137. int uaddr_val;
  138. int args_val = SCARG(uap, val);
  139. #ifdef COMPATFUTEX_DEBUG
  140. int tid = p->p_pid + THREAD_PID_OFFSET;
  141. #endif
  142. /*
  143. * Our implementation provides only private futexes. Most of the apps
  144. * should use private futexes but don't claim so. Therefore we treat
  145. * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
  146. * in most cases (ie. when futexes are not shared on file descriptor
  147. * or between different processes).
  148. */
  149. switch (SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) {
  150. case LINUX_FUTEX_WAIT:
  151. DPRINTF(("FUTEX_WAIT\n"));
  152. mtx_enter(&futex_lock);
  153. if ((error = copyin(SCARG(uap, uaddr),
  154. &uaddr_val, sizeof(uaddr_val))) != 0) {
  155. mtx_leave(&futex_lock);
  156. return error;
  157. }
  158. DPRINTF(("FUTEX_WAIT %d: Sleep if [%8.8X] %d == %d\n", tid,
  159. SCARG(uap, uaddr), uaddr_val, args_val));
  160. /* Sleep only if [uaddr] == val */
  161. if (uaddr_val != args_val) {
  162. mtx_leave(&futex_lock);
  163. return EWOULDBLOCK;
  164. }
  165. /* Check for infinity */
  166. if (ts->tv_sec == 0 && ts->tv_nsec == 0) {
  167. timeout_hz = 0;
  168. } else {
  169. if ((error = futex_itimespecfix(ts)) != 0) {
  170. mtx_leave(&futex_lock);
  171. return error;
  172. }
  173. TIMESPEC_TO_TIMEVAL(&tv, ts);
  174. timeout_hz = tvtohz(&tv);
  175. }
  176. /*
  177. * If the user process requests a non null timeout,
  178. * make sure we do not turn it into an infinite
  179. * timeout because timeout_hz is 0.
  180. *
  181. * We use a minimal timeout of 1/hz. Maybe it would make
  182. * sense to just return ETIMEDOUT without sleeping.
  183. */
  184. if (SCARG(uap, timeout) != NULL && timeout_hz == 0)
  185. timeout_hz = 1;
  186. DPRINTF(("FUTEX_WAIT %d: Sleep for %lld.%09lds (%dhz)\n",
  187. tid, (long long)ts->tv_sec, ts->tv_nsec, timeout_hz));
  188. wp = pool_get(&futex_wp_pool, PR_NOWAIT);
  189. if (wp == NULL) {
  190. DPRINTF(("FUTEX_WAIT %d: Couldn't fetch a new wp from"
  191. "futex_wp_pool.\n", tid));
  192. mtx_leave(&futex_lock);
  193. return EAGAIN;
  194. }
  195. DPRINTF(("FUTEX_WAIT: get wp %p\n", wp));
  196. f = futex_get(SCARG(uap, uaddr));
  197. ret = futex_sleep(&f, p, timeout_hz, wp);
  198. futex_put(f);
  199. mtx_leave(&futex_lock);
  200. DPRINTF(("FUTEX_WAIT: put wp %p\n", wp));
  201. pool_put(&futex_wp_pool, wp);
  202. DPRINTF(("FUTEX_WAIT %d: Woke up from uaddr %8.8X with "
  203. "ret = %d\n", tid, SCARG(uap, uaddr), ret));
  204. *retval = ret ? -1 : 0;
  205. switch (ret) {
  206. case EWOULDBLOCK: /* timeout */
  207. return ETIMEDOUT;
  208. break;
  209. case EINTR: /* signal */
  210. return EINTR;
  211. break;
  212. case 0: /* FUTEX_WAKE received */
  213. DPRINTF(("FUTEX_WAIT %d: uaddr = %p, got it\n",
  214. tid, SCARG(uap, uaddr)));
  215. return 0;
  216. break;
  217. default:
  218. DPRINTF(("FUTEX_WAIT: unexpected ret = %d\n", ret));
  219. break;
  220. }
  221. /* NOTREACHED */
  222. break;
  223. case LINUX_FUTEX_WAKE:
  224. /*
  225. * XXX: Linux is able cope with different addresses
  226. * corresponding to the same mapped memory in the sleeping
  227. * and the waker process(es).
  228. */
  229. DPRINTF(("FUTEX_WAKE %d: uaddr = %p, val = %d\n",
  230. tid, SCARG(uap, uaddr), args_val));
  231. if (args_val < 0)
  232. return EINVAL;
  233. mtx_enter(&futex_lock);
  234. f = futex_get(SCARG(uap, uaddr));
  235. *retval = futex_wake(f, args_val, NULL, 0);
  236. futex_put(f);
  237. mtx_leave(&futex_lock);
  238. break;
  239. case LINUX_FUTEX_CMP_REQUEUE:
  240. DPRINTF(("FUTEX_CMP_REQUEUE\n"));
  241. if (args_val < 0)
  242. return EINVAL;
  243. /*
  244. * Don't allow using the same address for requeueing.
  245. *
  246. * glibc seems to cope with this.
  247. */
  248. if (SCARG(uap, uaddr) == SCARG(uap, uaddr2)) {
  249. return EINVAL;
  250. }
  251. mtx_enter(&futex_lock);
  252. if ((error = copyin(SCARG(uap, uaddr),
  253. &uaddr_val, sizeof(uaddr_val))) != 0) {
  254. mtx_leave(&futex_lock);
  255. return error;
  256. }
  257. DPRINTF(("FUTEX_CMP_REQUEUE %d: Check for possible race "
  258. "condition [%8.8X] %d != %d", tid, SCARG(uap, uaddr),
  259. uaddr_val, SCARG(uap, val3)));
  260. if (uaddr_val != SCARG(uap, val3)) {
  261. mtx_leave(&futex_lock);
  262. return EAGAIN;
  263. }
  264. /* Following code is the same as REQUEUE */
  265. DPRINTF(("FUTEX_CMP_REQUEUE %d: Wakeup %d processes and requeue"
  266. " waiters at %8.8X\n", tid, SCARG(uap, val),
  267. SCARG(uap, uaddr2)));
  268. f = futex_get(SCARG(uap, uaddr));
  269. newf = futex_get(SCARG(uap, uaddr2));
  270. /*
  271. * Check if uaddr2 is in use.
  272. * If true, return EINVAL to avoid deadlock.
  273. *
  274. * glibc seems to cope with this.
  275. */
  276. if (newf->f_refcount != 1) {
  277. futex_put(f);
  278. futex_put(newf);
  279. mtx_leave(&futex_lock);
  280. return (EINVAL);
  281. }
  282. *retval = futex_wake(f, args_val, newf,
  283. (int)(unsigned long)SCARG(uap, timeout));
  284. futex_put(f);
  285. futex_put(newf);
  286. mtx_leave(&futex_lock);
  287. break;
  288. case LINUX_FUTEX_REQUEUE:
  289. DPRINTF(("FUTEX_REQUEUE %d: Wakeup %d processes and requeue "
  290. "waiters at %8.8X\n", tid, SCARG(uap, val),
  291. SCARG(uap, uaddr2)));
  292. if (args_val < 0)
  293. return EINVAL;
  294. mtx_enter(&futex_lock);
  295. f = futex_get(SCARG(uap, uaddr));
  296. newf = futex_get(SCARG(uap, uaddr2));
  297. *retval = futex_wake(f, args_val, newf,
  298. (int)(unsigned long)SCARG(uap, timeout));
  299. futex_put(f);
  300. futex_put(newf);
  301. mtx_leave(&futex_lock);
  302. break;
  303. case LINUX_FUTEX_FD:
  304. DPRINTF(("linux_sys_futex: unimplemented op %d\n",
  305. SCARG(uap, op)));
  306. return ENOSYS;
  307. case LINUX_FUTEX_WAKE_OP:
  308. DPRINTF(("FUTEX_WAKE_OP %d: uaddr = %p, op = %d, "
  309. "val = %d, uaddr2 = %p, val3 = %d\n",
  310. tid, SCARG(uap, uaddr), SCARG(uap, op), args_val,
  311. SCARG(uap, uaddr2), SCARG(uap, val3)));
  312. if (args_val < 0)
  313. return EINVAL;
  314. mtx_enter(&futex_lock);
  315. f = futex_get(SCARG(uap, uaddr));
  316. f2 = futex_get(SCARG(uap, uaddr2));
  317. mtx_leave(&futex_lock);
  318. /*
  319. * This function returns a positive number as results and
  320. * negative as errors
  321. */
  322. op_ret = futex_atomic_op(p, SCARG(uap, val3),
  323. SCARG(uap, uaddr2));
  324. if (op_ret < 0) {
  325. futex_put(f);
  326. futex_put(f2);
  327. return -op_ret;
  328. }
  329. mtx_enter(&futex_lock);
  330. ret = futex_wake(f, args_val, NULL, 0);
  331. futex_put(f);
  332. if (op_ret > 0) {
  333. op_ret = 0;
  334. /*
  335. * Linux abuses the address of the timespec parameter
  336. * as the number of retries
  337. */
  338. op_ret += futex_wake(f2,
  339. (int)(unsigned long)SCARG(uap, timeout), NULL, 0);
  340. ret += op_ret;
  341. }
  342. futex_put(f2);
  343. mtx_leave(&futex_lock);
  344. *retval = ret;
  345. break;
  346. default:
  347. DPRINTF(("linux_sys_futex: unknown op %d\n",
  348. SCARG(uap, op)));
  349. return ENOSYS;
  350. }
  351. return 0;
  352. }
  353. void
  354. futex_pool_init(void)
  355. {
  356. DPRINTF(("Inside futex_pool_init()\n"));
  357. if (!futex_pool_initialized) {
  358. pool_init(&futex_pool, sizeof(struct futex), 0, 0, PR_DEBUGCHK,
  359. "futexpl", &pool_allocator_nointr);
  360. pool_init(&futex_wp_pool, sizeof(struct waiting_proc), 0, 0,
  361. PR_DEBUGCHK, "futexwppl", &pool_allocator_nointr);
  362. futex_pool_initialized = 1;
  363. }
  364. }
  365. /*
  366. * Get a futex.
  367. * If we have an existing one, we will return that with the refcount bumped.
  368. * Otherwise we will allocate and hook up a new one.
  369. * Must be called with futex_lock held, but we may unlock it in order to
  370. * sleep for allocation.
  371. */
  372. struct futex *
  373. futex_get(void *uaddr)
  374. {
  375. struct futex *f, *newf;
  376. MUTEX_ASSERT_LOCKED(&futex_lock);
  377. LIST_FOREACH(f, &futex_list, f_list) {
  378. if (f->f_uaddr == uaddr) {
  379. f->f_refcount++;
  380. return f;
  381. }
  382. }
  383. mtx_leave(&futex_lock);
  384. /* Not found, create it */
  385. newf = pool_get(&futex_pool, PR_WAITOK|PR_ZERO);
  386. DPRINTF(("futex_get: get %p\n", newf));
  387. mtx_enter(&futex_lock);
  388. /* Did someone else create it in the meantime? */
  389. LIST_FOREACH(f, &futex_list, f_list) {
  390. if (f->f_uaddr == uaddr) {
  391. f->f_refcount++;
  392. DPRINTF(("futex_get: put %p (found %p)\n", newf, f));
  393. pool_put(&futex_pool, newf);
  394. return f;
  395. }
  396. }
  397. newf->f_uaddr = uaddr;
  398. newf->f_refcount = 1;
  399. TAILQ_INIT(&newf->f_waiting_proc);
  400. TAILQ_INIT(&newf->f_requeue_proc);
  401. LIST_INSERT_HEAD(&futex_list, newf, f_list);
  402. return newf;
  403. }
  404. /*
  405. * Grab a reference on a futex.
  406. * The futex lock must be locked.
  407. */
  408. void
  409. futex_ref(struct futex *f)
  410. {
  411. MUTEX_ASSERT_LOCKED(&futex_lock);
  412. f->f_refcount++;
  413. }
  414. /*
  415. * Release our reference on the futex.
  416. * must be called with the futex_lock held.
  417. */
  418. void
  419. futex_put(struct futex *f)
  420. {
  421. DPRINTF(("futex_put: put %p ref %d\n", f, f->f_refcount));
  422. MUTEX_ASSERT_LOCKED(&futex_lock);
  423. KASSERT(f->f_refcount > 0);
  424. f->f_refcount--;
  425. if (f->f_refcount == 0) {
  426. KASSERT(TAILQ_EMPTY(&f->f_waiting_proc));
  427. KASSERT(TAILQ_EMPTY(&f->f_requeue_proc));
  428. LIST_REMOVE(f, f_list);
  429. pool_put(&futex_pool, f);
  430. }
  431. }
  432. int
  433. futex_sleep(struct futex **fp, struct proc *p, int timeout,
  434. struct waiting_proc *wp)
  435. {
  436. struct futex *f, *newf;
  437. int ret;
  438. MUTEX_ASSERT_LOCKED(&futex_lock);
  439. f = *fp;
  440. wp->p = p;
  441. wp->wp_new_futex = NULL;
  442. DPRINTF(("futex_sleep: sleep on futex %p\n", f));
  443. do {
  444. TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
  445. ret = msleep(f, &futex_lock, PUSER | PCATCH, "futex_sleep",
  446. timeout);
  447. TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
  448. /* did futex_wake() tells us to requeue? if not, we're done! */
  449. newf = wp->wp_new_futex;
  450. if (newf == NULL)
  451. break;
  452. /* yes, so clean up our requeue bits... */
  453. DPRINTF(("futex_sleep: requeue futex %p\n", newf));
  454. wp->wp_new_futex = NULL;
  455. TAILQ_REMOVE(&newf->f_requeue_proc, wp, wp_rqlist);
  456. /*
  457. * ...and discard our reference to the old futex.
  458. * The requeuing has already given us a reference
  459. * to the new one.
  460. */
  461. futex_put(f);
  462. *fp = f = newf;
  463. /* only restart if msleep() didn't fail (timeout or signal) */
  464. } while (ret == 0);
  465. return ret;
  466. }
  467. int
  468. futex_wake(struct futex *f, int n, struct futex *newf, int n2)
  469. {
  470. struct waiting_proc *wp;
  471. int count = 0;
  472. KASSERT(newf != f);
  473. MUTEX_ASSERT_LOCKED(&futex_lock);
  474. /*
  475. * first, wake up any threads sleeping on this futex.
  476. * note that sleeping threads are not in the process of requeueing.
  477. */
  478. if (!TAILQ_EMPTY(&f->f_waiting_proc))
  479. wakeup(f); /* only call wakeup once */
  480. TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) {
  481. KASSERT(wp->wp_new_futex == NULL);
  482. DPRINTF(("futex_wake: signal futex %p ref %d\n",
  483. f, f->f_refcount));
  484. if (count <= n) {
  485. count++;
  486. } else {
  487. if (newf == NULL)
  488. break;
  489. /* matching futex_put() is called by the other thread */
  490. futex_ref(newf);
  491. wp->wp_new_futex = newf;
  492. TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist);
  493. DPRINTF(("futex_wake: requeue newf %p ref %d\n",
  494. newf, newf->f_refcount));
  495. if (count - n >= n2)
  496. goto out;
  497. }
  498. }
  499. /*
  500. * next, deal with threads that are requeuing to this futex.
  501. * we don't need to signal these threads, any thread on the
  502. * requeue list has already been signaled but hasn't had a chance
  503. * to run and requeue itself yet. if we would normally wake
  504. * a thread, just remove the requeue info. if we would normally
  505. * requeue a thread, change the requeue target.
  506. */
  507. while ((wp = TAILQ_FIRST(&f->f_requeue_proc)) != NULL) {
  508. /* XXX: talk to oga, should mtx_enter again, recursive */
  509. KASSERT(wp->wp_new_futex == f);
  510. DPRINTF(("futex_wake: unrequeue f %p ref %d\n",
  511. f, f->f_refcount));
  512. wp->wp_new_futex = NULL;
  513. TAILQ_REMOVE(&f->f_requeue_proc, wp, wp_rqlist);
  514. futex_put(f);
  515. if (count <= n) {
  516. count++;
  517. } else {
  518. if (newf == NULL) {
  519. break;
  520. }
  521. /*matching futex_put() is called by the other thread.*/
  522. futex_ref(newf);
  523. wp->wp_new_futex = newf;
  524. TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist);
  525. DPRINTF(("futex_wake: rerequeue newf %p ref %d\n",
  526. newf, newf->f_refcount));
  527. if (count - n >= n2)
  528. break;
  529. }
  530. }
  531. out:
  532. return count;
  533. }
  534. int
  535. futex_atomic_op(struct proc *p, int encoded_op, void *uaddr)
  536. {
  537. const int op = (encoded_op >> 28) & 7;
  538. const int cmp = (encoded_op >> 24) & 15;
  539. const int cmparg = (encoded_op << 20) >> 20;
  540. int oparg = (encoded_op << 8) >> 20;
  541. int error, oldval, cval;
  542. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  543. oparg = 1 << oparg;
  544. if (copyin(uaddr, &cval, sizeof(int)) != 0)
  545. return -EFAULT;
  546. for (;;) {
  547. int nval;
  548. switch (op) {
  549. case FUTEX_OP_SET:
  550. nval = oparg;
  551. break;
  552. case FUTEX_OP_ADD:
  553. nval = cval + oparg;
  554. break;
  555. case FUTEX_OP_OR:
  556. nval = cval | oparg;
  557. break;
  558. case FUTEX_OP_ANDN:
  559. nval = cval & ~oparg;
  560. break;
  561. case FUTEX_OP_XOR:
  562. nval = cval ^ oparg;
  563. break;
  564. default:
  565. return -ENOSYS;
  566. }
  567. oldval = nval;
  568. error = futex_atomic_ucas_int32(uaddr, cval, nval);
  569. if (oldval == cval || error) {
  570. break;
  571. }
  572. cval = oldval;
  573. }
  574. if (error)
  575. return -EFAULT;
  576. switch (cmp) {
  577. case FUTEX_OP_CMP_EQ:
  578. return (oldval == cmparg);
  579. case FUTEX_OP_CMP_NE:
  580. return (oldval != cmparg);
  581. case FUTEX_OP_CMP_LT:
  582. return (oldval < cmparg);
  583. case FUTEX_OP_CMP_GE:
  584. return (oldval >= cmparg);
  585. case FUTEX_OP_CMP_LE:
  586. return (oldval <= cmparg);
  587. case FUTEX_OP_CMP_GT:
  588. return (oldval > cmparg);
  589. default:
  590. return -ENOSYS;
  591. }
  592. }
  593. int
  594. linux_sys_set_robust_list(struct proc *p, void *v, register_t *retval)
  595. {
  596. struct linux_sys_set_robust_list_args /* {
  597. syscallarg(struct linux_robust_list_head *) head;
  598. syscallarg(size_t) len;
  599. } */ *uap = v;
  600. struct linux_emuldata *led;
  601. if (SCARG(uap, len) != sizeof(struct linux_robust_list_head))
  602. return EINVAL;
  603. led = p->p_emuldata;
  604. led->led_robust_head = SCARG(uap, head);
  605. *retval = 0;
  606. return 0;
  607. }
  608. int
  609. linux_sys_get_robust_list(struct proc *p, void *v, register_t *retval)
  610. {
  611. struct linux_sys_get_robust_list_args /* {
  612. syscallarg(int) pid;
  613. syscallarg(struct linux_robust_list_head **) head;
  614. syscallarg(size_t *) len;
  615. } */ *uap = v;
  616. struct proc *q;
  617. struct linux_emuldata *led;
  618. struct linux_robust_list_head *head;
  619. size_t len;
  620. int error = 0;
  621. if (!SCARG(uap, pid)) {
  622. led = p->p_emuldata;
  623. head = led->led_robust_head;
  624. } else {
  625. if (!SCARG(uap, pid))
  626. q = p;
  627. else if ((q = pfind(SCARG(uap, pid))) == NULL)
  628. return ESRCH;
  629. else if (p->p_p != q->p_p)
  630. return EPERM;
  631. led = q->p_emuldata;
  632. head = led->led_robust_head;
  633. }
  634. len = sizeof(*head);
  635. error = copyout(&len, SCARG(uap, len), sizeof(len));
  636. if (error)
  637. return error;
  638. return copyout(&head, SCARG(uap, head), sizeof(head));
  639. }
  640. int
  641. futex_itimespecfix(struct timespec *ts)
  642. {
  643. if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
  644. return EINVAL;
  645. if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000)
  646. ts->tv_nsec = tick * 1000;
  647. return 0;
  648. }