Bug 1139856 - do not lose wakeups. r=luke
authorLars T Hansen <lhansen@mozilla.com>
Wed, 13 May 2015 10:35:42 +0200
changeset 243660 2e7ce565cfc4df4aba77fe0de31893c524a96ca7
parent 243659 9bbb797f3e28edd6c850f10d55e3e7e189430d2b
child 243661 c48d5ce78376f7e19afc4702c7940db2f0838726
push id28744
push userkwierso@gmail.com
push dateWed, 13 May 2015 18:12:16 +0000
treeherdermozilla-central@324c3423deaf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1139856
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1139856 - do not lose wakeups. r=luke
js/src/builtin/AtomicsObject.cpp
js/src/builtin/AtomicsObject.h
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -1027,17 +1027,23 @@ js::FutexRuntime::destroyInstance()
 {
     if (cond_)
         PR_DestroyCondVar(cond_);
 }
 
 bool
 js::FutexRuntime::isWaiting()
 {
-    return state_ == Waiting || state_ == WaitingInterrupted;
+    // When a worker is awoken for an interrupt it goes into state
+    // WaitingNotifiedForInterrupt for a short time before it actually
+    // wakes up and goes into WaitingInterrupted.  In those states the
+    // worker is still waiting, and if an explicit wake arrives the
+    // worker transitions to Woken.  See further comments in
+    // FutexRuntime::wait().
+    return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt;
 }
 
 bool
 js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWaitResult* result)
 {
     MOZ_ASSERT(&cx->runtime()->fx == this);
     MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(state_ == Idle || state_ == WaitingInterrupted);
@@ -1097,27 +1103,27 @@ js::FutexRuntime::wait(JSContext* cx, do
                 }
             }
             break;
 
           case FutexRuntime::Woken:
             *result = AtomicsObject::FutexOK;
             goto finished;
 
-          case FutexRuntime::WokenForJSInterrupt:
+          case FutexRuntime::WaitingNotifiedForInterrupt:
             // The interrupt handler may reenter the engine.  In that case
             // there are two complications:
             //
             // - The waiting thread is not actually waiting on the
             //   condition variable so we have to record that it
             //   should be woken when the interrupt handler returns.
             //   To that end, we flag the thread as interrupted around
             //   the interrupt and check state_ when the interrupt
             //   handler returns.  A futexWake() call that reaches the
-            //   runtime during the interrupt sets state_ to woken.
+            //   runtime during the interrupt sets state_ to Woken.
             //
             // - It is in principle possible for futexWait() to be
             //   reentered on the same thread/runtime and waiting on the
             //   same location and to yet again be interrupted and enter
             //   the interrupt handler.  In this case, it is important
             //   that when another agent wakes waiters, all waiters using
             //   the same runtime on the same location are woken in LIFO
             //   order; FIFO may be the required order, but FIFO would
@@ -1155,26 +1161,28 @@ finished:
 }
 
 void
 js::FutexRuntime::wake(WakeReason reason)
 {
     MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(isWaiting());
 
-    if (state_ == WaitingInterrupted && reason == WakeExplicit) {
+    if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) {
         state_ = Woken;
         return;
     }
     switch (reason) {
       case WakeExplicit:
         state_ = Woken;
         break;
       case WakeForJSInterrupt:
-        state_ = WokenForJSInterrupt;
+        if (state_ == WaitingNotifiedForInterrupt)
+            return;
+        state_ = WaitingNotifiedForInterrupt;
         break;
       default:
         MOZ_CRASH();
     }
     PR_NotifyCondVar(cond_);
 }
 
 const JSFunctionSpec AtomicsMethods[] = {
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -92,29 +92,32 @@ public:
     // If the thread is not waiting then this method does nothing.
     //
     // If the thread is waiting in a call to futexWait() and the
     // reason is WakeExplicit then the futexWait() call will return
     // with Woken.
     //
     // If the thread is waiting in a call to futexWait() and the
     // reason is WakeForJSInterrupt then the futexWait() will return
-    // with WokenForJSInterrupt; in the latter case the caller of
-    // futexWait() must handle the interrupt.
+    // with WaitingNotifiedForInterrupt; in the latter case the caller
+    // of futexWait() must handle the interrupt.
     void wake(WakeReason reason);
 
     bool isWaiting();
 
   private:
     enum FutexState {
-        Idle,                   // We are not waiting or woken
-        Waiting,                // We are waiting, nothing has happened yet
-        WaitingInterrupted,     // We are waiting, but have been interrupted
-        Woken,                  // Woken by a script call to futexWake
-        WokenForJSInterrupt     // Woken by an interrupt handler
+        Idle,                        // We are not waiting or woken
+        Waiting,                     // We are waiting, nothing has happened yet
+        WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
+                                     //   and have not yet started running the
+                                     //   interrupt handler
+        WaitingInterrupted,          // We are waiting, but have been interrupted
+                                     //   and are running the interrupt handler
+        Woken                        // Woken by a script call to futexWake
     };
 
     // Condition variable that this runtime will wait on.
     PRCondVar* cond_;
 
     // Current futex state for this runtime.  When not in a wait this
     // is Idle; when in a wait it is Waiting or the reason the futex
     // is about to wake up.