Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/compat/linux/common simplify and fix futex requeuing:
details: https://anonhg.NetBSD.org/src/rev/f09304468a80
branches: trunk
changeset: 345344:f09304468a80
user: chs <chs%NetBSD.org@localhost>
date: Fri May 20 13:54:34 2016 +0000
description:
simplify and fix futex requeuing:
don't wake up all the threads being requeued to have them move themselves
from one list to another (thus defeating the purpose), just change the lists
directly in futex_wake().
diffstat:
sys/compat/linux/common/linux_futex.c | 121 ++++++++++++---------------------
1 files changed, 44 insertions(+), 77 deletions(-)
diffs (204 lines):
diff -r e01aebe9be28 -r f09304468a80 sys/compat/linux/common/linux_futex.c
--- a/sys/compat/linux/common/linux_futex.c Fri May 20 08:17:14 2016 +0000
+++ b/sys/compat/linux/common/linux_futex.c Fri May 20 13:54:34 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_futex.c,v 1.33 2014/02/11 16:00:13 maxv Exp $ */
+/* $NetBSD: linux_futex.c,v 1.34 2016/05/20 13:54:34 chs Exp $ */
/*-
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.33 2014/02/11 16:00:13 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.34 2016/05/20 13:54:34 chs Exp $");
#include <sys/param.h>
#include <sys/time.h>
@@ -58,11 +58,10 @@
struct futex;
struct waiting_proc {
- lwp_t *wp_l;
- struct futex *wp_new_futex;
+ struct futex *wp_futex;
kcondvar_t wp_futex_cv;
TAILQ_ENTRY(waiting_proc) wp_list;
- TAILQ_ENTRY(waiting_proc) wp_rqlist;
+ bool wp_onlist;
};
struct futex {
void *f_uaddr;
@@ -70,7 +69,6 @@
uint32_t f_bitset;
LIST_ENTRY(futex) f_list;
TAILQ_HEAD(, waiting_proc) f_waiting_proc;
- TAILQ_HEAD(, waiting_proc) f_requeue_proc;
};
static LIST_HEAD(futex_list, futex) futex_list;
@@ -432,7 +430,6 @@
f->f_bitset = bitset;
f->f_refcount = 1;
TAILQ_INIT(&f->f_waiting_proc);
- TAILQ_INIT(&f->f_requeue_proc);
LIST_INSERT_HEAD(&futex_list, f, f_list);
return f;
@@ -456,7 +453,6 @@
f->f_refcount--;
if (f->f_refcount == 0) {
KASSERT(TAILQ_EMPTY(&f->f_waiting_proc));
- KASSERT(TAILQ_EMPTY(&f->f_requeue_proc));
LIST_REMOVE(f, f_list);
kmem_free(f, sizeof(*f));
}
@@ -465,107 +461,78 @@
static int
futex_sleep(struct futex **fp, lwp_t *l, int timeout, struct waiting_proc *wp)
{
- struct futex *f, *newf;
+ struct futex *f;
int ret;
FUTEX_LOCKASSERT;
f = *fp;
- wp->wp_l = l;
- wp->wp_new_futex = NULL;
-
-requeue:
+ wp->wp_futex = f;
TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
+ wp->wp_onlist = true;
ret = cv_timedwait_sig(&wp->wp_futex_cv, &futex_lock, timeout);
- TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
- /* if futex_wake() tells us to requeue ... */
- newf = wp->wp_new_futex;
- if (ret == 0 && newf != NULL) {
- /* ... requeue ourselves on the new futex */
- futex_put(f);
- wp->wp_new_futex = NULL;
- TAILQ_REMOVE(&newf->f_requeue_proc, wp, wp_rqlist);
- *fp = f = newf;
- goto requeue;
+ /*
+ * we may have been requeued to a different futex before we were
+ * woken up, so let the caller know which futex to put. if we were
+ * woken by futex_wake() then it took us off the waiting list,
+ * but if our sleep was interrupted or timed out then we might
+ * need to take ourselves off the waiting list.
+ */
+
+ f = wp->wp_futex;
+ if (wp->wp_onlist) {
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
}
+ *fp = f;
return ret;
}
static int
futex_wake(struct futex *f, int n, struct futex *newf, int n2)
{
- struct waiting_proc *wp, *wpnext;
- int count;
+ struct waiting_proc *wp;
+ int count = 0;
FUTEX_LOCKASSERT;
- count = newf ? 0 : 1;
-
/*
- * first, wake up any threads sleeping on this futex.
- * note that sleeping threads are not in the process of requeueing.
+ * wake up up to n threads waiting on this futex.
*/
- TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) {
- KASSERT(wp->wp_new_futex == NULL);
+ while (n--) {
+ wp = TAILQ_FIRST(&f->f_waiting_proc);
+ if (wp == NULL)
+ return count;
- FUTEXPRINTF(("%s: signal f %p l %p ref %d\n", __func__,
- f, wp->wp_l, f->f_refcount));
+ KASSERT(f == wp->wp_futex);
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+ wp->wp_onlist = false;
cv_signal(&wp->wp_futex_cv);
- if (count <= n) {
- count++;
- } else {
- if (newf == NULL)
- break;
-
- /* matching futex_put() is called by the other thread. */
- futex_ref(newf);
- wp->wp_new_futex = newf;
- TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist);
- FUTEXPRINTF(("%s: requeue newf %p l %p ref %d\n",
- __func__, newf, wp->wp_l, newf->f_refcount));
- if (count - n >= n2)
- goto out;
- }
+ count++;
}
+ if (newf == NULL)
+ return count;
/*
- * next, deal with threads that are requeuing to this futex.
- * we don't need to signal these threads, any thread on the
- * requeue list has already been signaled but hasn't had a chance
- * to run and requeue itself yet. if we would normally wake
- * a thread, just remove the requeue info. if we would normally
- * requeue a thread, change the requeue target.
+ * then requeue up to n2 additional threads to newf
+ * (without waking them up).
*/
- TAILQ_FOREACH_SAFE(wp, &f->f_requeue_proc, wp_rqlist, wpnext) {
- KASSERT(wp->wp_new_futex == f);
+ while (n2--) {
+ wp = TAILQ_FIRST(&f->f_waiting_proc);
+ if (wp == NULL)
+ return count;
- FUTEXPRINTF(("%s: unrequeue f %p l %p ref %d\n", __func__,
- f, wp->wp_l, f->f_refcount));
- wp->wp_new_futex = NULL;
- TAILQ_REMOVE(&f->f_requeue_proc, wp, wp_rqlist);
+ KASSERT(f == wp->wp_futex);
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
futex_put(f);
- if (count <= n) {
- count++;
- } else {
- if (newf == NULL)
- break;
-
- /* matching futex_put() is called by the other thread. */
- futex_ref(newf);
- wp->wp_new_futex = newf;
- TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist);
- FUTEXPRINTF(("%s: rerequeue newf %p l %p ref %d\n",
- __func__, newf, wp->wp_l, newf->f_refcount));
- if (count - n >= n2)
- break;
- }
+ wp->wp_futex = newf;
+ futex_ref(newf);
+ TAILQ_INSERT_TAIL(&newf->f_waiting_proc, wp, wp_list);
+ count++;
}
-
-out:
return count;
}
Home |
Main Index |
Thread Index |
Old Index