diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2013-01-15 10:47:36 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2013-01-15 10:47:36 +0000 |
commit | 33a4e21e5bc9b901acecda1a99b1779f3144526e (patch) | |
tree | 06a43a2f3669b9b806f7e3787c8df19589b9f4cf | |
parent | 55ac75c645206ed63f24982caa972f948c4f9165 (diff) |
Process futex requeuing even when the thread times out or is signaled.
Bug report from frantisek holop (minusf at obiit.org)
ok pirofiti@
-rw-r--r-- | sys/compat/linux/linux_futex.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 3edfa44dd72..04a37c51eaf 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_futex.c,v 1.10 2012/11/19 15:03:55 pirofti Exp $ */ +/* $OpenBSD: linux_futex.c,v 1.11 2013/01/15 10:47:35 guenther Exp $ */ /* $NetBSD: linux_futex.c,v 1.26 2010/07/07 01:30:35 chs Exp $ */ /*- @@ -497,24 +497,36 @@ futex_sleep(struct futex **fp, struct proc *p, int timeout, wp->wp_new_futex = NULL; DPRINTF(("futex_sleep: sleep on futex %p\n", f)); -requeue: - TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list); - ret = msleep(f, &futex_lock, PUSER | PCATCH, "futex_sleep", timeout); + do { + TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list); - TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); + ret = msleep(f, &futex_lock, PUSER | PCATCH, "futex_sleep", + timeout); - /* if futex_wake() tells us to requeue ... */ - newf = wp->wp_new_futex; - if (ret == 0 && newf != NULL) { - /* ... requeue ourselves on the new futex */ + TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); + + /* did futex_wake() tells us to requeue? if not, we're done! */ + newf = wp->wp_new_futex; + if (newf == NULL) + break; + + /* yes, so clean up our requeue bits... */ DPRINTF(("futex_sleep: requeue futex %p\n", newf)); - futex_put(f); wp->wp_new_futex = NULL; TAILQ_REMOVE(&newf->f_requeue_proc, wp, wp_rqlist); + + /* + * ...and discard our reference to the old futex. + * The requeuing has already given us a reference + * to the new one. + */ + futex_put(f); *fp = f = newf; - goto requeue; - } + + /* only restart if msleep() didn't fail (timeout or signal) */ + } while (ret == 0); + return ret; } |