- if ((wakeMask & kWaitingE) != 0) {
- // If there are multiple lock() pending only one of them will
- // actually get to wake up, so issuing futexWakeAll will make
- // a thundering herd. There's nothing stopping us from issuing
- // futexWake(1) instead, so long as the wait bits are still an
- // accurate reflection of the waiters. If our pending lock() counter
- // hasn't saturated we can decrement it. If it has saturated,
- // then we can clear it by noticing that futexWake(1) returns 0
- // (indicating no actual waiters) and then retrying via the normal
- // clear+futexWakeAll path.
- //
- // It is possible that we wake an E waiter but an outside S grabs
- // the lock instead, at which point we should wake pending U and
- // S waiters. Rather than tracking state to make the failing E
- // regenerate the wakeup, we just disable the optimization in the
- // case that there are waiting U or S that we are eligible to wake.
- //
- // Note that in the contended scenario it is quite likely that the
- // waiter's futexWait call will fail with EAGAIN (expected value
- // mismatch), at which point the awaiting-exclusive count will be
- // larger than the actual number of waiters. At this point the
- // counter is effectively saturated. Since this is likely, it is
- // actually less efficient to have a larger counter. 2 bits seems
- // to be the best.
- while ((state & kWaitingE) != 0 &&
- (state & wakeMask & (kWaitingU | kWaitingS)) == 0) {
- if ((state & kWaitingE) != kWaitingE) {
- // not saturated
- if (!state_.compare_exchange_strong(state, state - kIncrWaitingE)) {
- continue;
- }
- state -= kIncrWaitingE;
- }
-
- if (state_.futexWake(1, kWaitingE) > 0) {
- return;
- }
-
- // Despite the non-zero awaiting-exclusive count, there aren't
- // actually any pending writers. Fall through to the logic below
- // to wake up other classes of locks and to clear the saturated
- // counter (if necessary).
- break;
- }
+ // If there are multiple lock() pending only one of them will actually
+ // get to wake up, so issuing futexWakeAll will make a thundering herd.
+ // There's nothing stopping us from issuing futexWake(1) instead,
+ // so long as the wait bits are still an accurate reflection of
+ // the waiters. If we notice (via futexWake's return value) that
+ // nobody woke up then we can try again with the normal wake-all path.
+ // Note that we can't just clear the bits at that point; we need to
+ // clear the bits and then issue another wakeup.
+ //
+ // It is possible that we wake an E waiter but an outside S grabs the
+ // lock instead, at which point we should wake pending U and S waiters.
+ // Rather than tracking state to make the failing E regenerate the
+ // wakeup, we just disable the optimization in the case that there
+ // are waiting U or S that we are eligible to wake.
+ if ((wakeMask & kWaitingE) == kWaitingE &&
+ (state & wakeMask) == kWaitingE &&
+ state_.futexWake(1, kWaitingE) > 0) {
+ // somebody woke up, so leave state_ as is and clear it later
+ return;