Notify wakes one or all waiting threads. Must be called after changing the associated wait predicate.
| 130 | // Notify wakes one or all waiting threads. |
| 131 | // Must be called after changing the associated wait predicate. |
| 132 | void Notify(bool notifyAll) { |
| 133 | std::atomic_thread_fence(std::memory_order_seq_cst); |
| 134 | uint64_t state = state_.load(std::memory_order_acquire); |
| 135 | for (;;) { |
| 136 | CheckState(state); |
| 137 | const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift; |
| 138 | const uint64_t signals = (state & kSignalMask) >> kSignalShift; |
| 139 | // Easy case: no waiters. |
| 140 | if ((state & kStackMask) == kStackMask && waiters == signals) return; |
| 141 | uint64_t newstate; |
| 142 | if (notifyAll) { |
| 143 | // Empty wait stack and set signal to number of pre-wait threads. |
| 144 | newstate = |
| 145 | (state & kWaiterMask) | (waiters << kSignalShift) | kStackMask; |
| 146 | } else if (signals < waiters) { |
| 147 | // There is a thread in pre-wait state, unblock it. |
| 148 | newstate = state + kSignalInc; |
| 149 | } else { |
| 150 | // Pop a waiter from list and unpark it. |
| 151 | Waiter* w = &waiters_[state & kStackMask]; |
| 152 | uint64_t next = w->next.load(std::memory_order_relaxed); |
| 153 | newstate = (state & (kWaiterMask | kSignalMask)) | next; |
| 154 | } |
| 155 | CheckState(newstate); |
| 156 | if (state_.compare_exchange_weak(state, newstate, |
| 157 | std::memory_order_acq_rel)) { |
| 158 | if (!notifyAll && (signals < waiters)) |
| 159 | return; // unblocked pre-wait thread |
| 160 | if ((state & kStackMask) == kStackMask) return; |
| 161 | Waiter* w = &waiters_[state & kStackMask]; |
| 162 | if (!notifyAll) w->next.store(kStackMask, std::memory_order_relaxed); |
| 163 | Unpark(w); |
| 164 | return; |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | class Waiter { |
| 170 | friend class EventCount; |