10#ifndef EIGEN_CXX11_THREADPOOL_EVENTCOUNT_H
11#define EIGEN_CXX11_THREADPOOL_EVENTCOUNT_H
14#include "./InternalHeaderCheck.h"
56 EventCount(MaxSizeVector<Waiter>& waiters) : state_(kStackMask), waiters_(waiters) {
57 eigen_plain_assert(waiters.size() < (1 << kWaiterBits) - 1);
62 eigen_plain_assert(state_.load() == kStackMask);
69 uint64_t state = state_.load(std::memory_order_relaxed);
72 uint64_t newstate = state + kWaiterInc;
74 if (state_.compare_exchange_weak(state, newstate, std::memory_order_seq_cst))
return;
79 void CommitWait(Waiter* w) {
80 eigen_plain_assert((w->epoch & ~kEpochMask) == 0);
81 w->state = Waiter::kNotSignaled;
82 const uint64_t me = (w - &waiters_[0]) | w->epoch;
83 uint64_t state = state_.load(std::memory_order_seq_cst);
85 CheckState(state,
true);
87 if ((state & kSignalMask) != 0) {
89 newstate = state - kWaiterInc - kSignalInc;
92 newstate = ((state & kWaiterMask) - kWaiterInc) | me;
93 w->next.store(state & (kStackMask | kEpochMask), std::memory_order_relaxed);
96 if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
97 if ((state & kSignalMask) == 0) {
98 w->epoch += kEpochInc;
108 uint64_t state = state_.load(std::memory_order_relaxed);
110 CheckState(state,
true);
111 uint64_t newstate = state - kWaiterInc;
116 if (((state & kWaiterMask) >> kWaiterShift) == ((state & kSignalMask) >> kSignalShift)) newstate -= kSignalInc;
117 CheckState(newstate);
118 if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel))
return;
124 void Notify(
bool notifyAll) {
125 std::atomic_thread_fence(std::memory_order_seq_cst);
126 uint64_t state = state_.load(std::memory_order_acquire);
129 const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
130 const uint64_t signals = (state & kSignalMask) >> kSignalShift;
132 if ((state & kStackMask) == kStackMask && waiters == signals)
return;
136 newstate = (state & kWaiterMask) | (waiters << kSignalShift) | kStackMask;
137 }
else if (signals < waiters) {
139 newstate = state + kSignalInc;
142 Waiter* w = &waiters_[state & kStackMask];
143 uint64_t next = w->next.load(std::memory_order_relaxed);
144 newstate = (state & (kWaiterMask | kSignalMask)) | next;
146 CheckState(newstate);
147 if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
148 if (!notifyAll && (signals < waiters))
return;
149 if ((state & kStackMask) == kStackMask)
return;
150 Waiter* w = &waiters_[state & kStackMask];
151 if (!notifyAll) w->next.store(kStackMask, std::memory_order_relaxed);
159 friend class EventCount;
162 EIGEN_ALIGN_TO_BOUNDARY(128) std::atomic<uint64_t> next;
166 unsigned state = kNotSignaled;
183 static const uint64_t kWaiterBits = 14;
184 static const uint64_t kStackMask = (1ull << kWaiterBits) - 1;
185 static const uint64_t kWaiterShift = kWaiterBits;
186 static const uint64_t kWaiterMask = ((1ull << kWaiterBits) - 1) << kWaiterShift;
187 static const uint64_t kWaiterInc = 1ull << kWaiterShift;
188 static const uint64_t kSignalShift = 2 * kWaiterBits;
189 static const uint64_t kSignalMask = ((1ull << kWaiterBits) - 1) << kSignalShift;
190 static const uint64_t kSignalInc = 1ull << kSignalShift;
191 static const uint64_t kEpochShift = 3 * kWaiterBits;
192 static const uint64_t kEpochBits = 64 - kEpochShift;
193 static const uint64_t kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift;
194 static const uint64_t kEpochInc = 1ull << kEpochShift;
195 std::atomic<uint64_t> state_;
196 MaxSizeVector<Waiter>& waiters_;
198 static void CheckState(uint64_t state,
bool waiter =
false) {
199 static_assert(kEpochBits >= 20,
"not enough bits to prevent ABA problem");
200 const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
201 const uint64_t signals = (state & kSignalMask) >> kSignalShift;
202 eigen_plain_assert(waiters >= signals);
203 eigen_plain_assert(waiters < (1 << kWaiterBits) - 1);
204 eigen_plain_assert(!waiter || waiters > 0);
209 void Park(Waiter* w) {
210 EIGEN_MUTEX_LOCK lock(w->mu);
211 while (w->state != Waiter::kSignaled) {
212 w->state = Waiter::kWaiting;
217 void Unpark(Waiter* w) {
218 for (Waiter* next; w; w = next) {
219 uint64_t wnext = w->next.load(std::memory_order_relaxed) & kStackMask;
220 next = wnext == kStackMask ? nullptr : &waiters_[internal::convert_index<size_t>(wnext)];
223 EIGEN_MUTEX_LOCK lock(w->mu);
225 w->state = Waiter::kSignaled;
228 if (state == Waiter::kWaiting) w->cv.notify_one();
232 EventCount(
const EventCount&) =
delete;
233 void operator=(
const EventCount&) =
delete;
Namespace containing all symbols from the Eigen library.
Definition Core:137