futex: Disable notifs when waking waiters
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 15 Oct 2018 20:48:26 +0000 (16:48 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 22 Oct 2018 23:35:51 +0000 (19:35 -0400)
When you call cpu_relax_vc() as a uthread, it simply spins, with the
assumption that we'd find out about the preemption via a
notification/IPI.  Although that is true, parlib will only prioritize
vcore context code.  A 2LS won't know to run particular uthread, since
the "spinning-on" relationship is unknown to the 2LS.

By putting the thread that is the target of the busy-wait in vcore
context (or pretending to, with notifs disabled), we get the behavior we
want.

Note the old version of futex code also had this problem when we
busy-waited on awaiter.data = NULL.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/pthread/futex.c

index 12d4355..62ce345 100644 (file)
@@ -96,6 +96,10 @@ static inline int futex_wake(int *uaddr, int count)
        struct futex_element *e, *temp;
        struct futex_queue q = TAILQ_HEAD_INITIALIZER(q);
 
+       /* The waiter spins on us with cpu_relax_any().  That code assumes the
+        * target of the wait/spin is in vcore context, or at least has notifs
+        * disabled. */
+       uth_disable_notifs();
        mcs_pdr_lock(&__futex.lock);
        TAILQ_FOREACH_SAFE(e, &__futex.queue, link, temp) {
                if (count <= 0)
@@ -111,13 +115,13 @@ static inline int futex_wake(int *uaddr, int count)
                }
        }
        mcs_pdr_unlock(&__futex.lock);
-
        TAILQ_FOREACH_SAFE(e, &q, link, temp) {
                TAILQ_REMOVE(&q, e, link);
                uth_cond_var_signal(&e->cv);
                /* Do not touch e after marking it. */
                e->waker_using = false;
        }
+       uth_enable_notifs();
 
        return max - count;
 }