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