Eigen::EventCount Class Reference

#include <EventCount.h>

Classes

class  Waiter
 

Public Member Functions

 EventCount (MaxSizeVector< Waiter > &waiters)
 
 EventCount (const EventCount &)=delete
 
void operator= (const EventCount &)=delete
 
 ~EventCount ()
 
void Prewait ()
 
void CommitWait (Waiter *w)
 
void CancelWait ()
 
void Notify (bool notifyAll)
 

Private Member Functions

void Park (Waiter *w)
 
void Unpark (Waiter *w)
 

Static Private Member Functions

static void CheckState (uint64_t state, bool waiter=false)
 

Private Attributes

std::atomic< uint64_t > state_
 
MaxSizeVector< Waiter > & waiters_
 

Static Private Attributes

static const uint64_t kWaiterBits = 14
 
static const uint64_t kStackMask = (1ull << kWaiterBits) - 1
 
static const uint64_t kWaiterShift = kWaiterBits
 
static const uint64_t kWaiterMask = ((1ull << kWaiterBits) - 1) << kWaiterShift
 
static const uint64_t kWaiterInc = 1ull << kWaiterShift
 
static const uint64_t kSignalShift = 2 * kWaiterBits
 
static const uint64_t kSignalMask = ((1ull << kWaiterBits) - 1) << kSignalShift
 
static const uint64_t kSignalInc = 1ull << kSignalShift
 
static const uint64_t kEpochShift = 3 * kWaiterBits
 
static const uint64_t kEpochBits = 64 - kEpochShift
 
static const uint64_t kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift
 
static const uint64_t kEpochInc = 1ull << kEpochShift
 

Constructor & Destructor Documentation

◆ EventCount() [1/2]

Eigen::EventCount::EventCount ( MaxSizeVector< Waiter > &  waiters)
inline
56  : state_(kStackMask), waiters_(waiters) {
57  eigen_plain_assert(waiters.size() < (1 << kWaiterBits) - 1);
58  }
#define eigen_plain_assert(condition)
Definition: Assert.h:148
MaxSizeVector< Waiter > & waiters_
Definition: EventCount.h:236
std::atomic< uint64_t > state_
Definition: EventCount.h:235
static const uint64_t kStackMask
Definition: EventCount.h:171
static const uint64_t kWaiterBits
Definition: EventCount.h:170

References eigen_plain_assert, kWaiterBits, and Eigen::MaxSizeVector< T >::size().

◆ EventCount() [2/2]

Eigen::EventCount::EventCount ( const EventCount )
delete

◆ ~EventCount()

Eigen::EventCount::~EventCount ( )
inline
63  {
64  // Ensure there are no waiters.
66  }

References eigen_plain_assert, kStackMask, and state_.

Member Function Documentation

◆ CancelWait()

void Eigen::EventCount::CancelWait ( )
inline
110  {
111  uint64_t state = state_.load(std::memory_order_relaxed);
112  for (;;) {
113  CheckState(state, true);
114  uint64_t newstate = state - kWaiterInc;
115  // We don't know if the thread was also notified or not,
116  // so we should not consume a signal unconditionally.
117  // Only if number of waiters is equal to number of signals,
118  // we know that the thread was notified and we must take away the signal.
119  if (((state & kWaiterMask) >> kWaiterShift) == ((state & kSignalMask) >> kSignalShift)) newstate -= kSignalInc;
120  CheckState(newstate);
121  if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) return;
122  }
123  }
static const uint64_t kSignalInc
Definition: EventCount.h:177
static const uint64_t kWaiterMask
Definition: EventCount.h:173
static const uint64_t kWaiterInc
Definition: EventCount.h:174
static const uint64_t kWaiterShift
Definition: EventCount.h:172
static void CheckState(uint64_t state, bool waiter=false)
Definition: EventCount.h:201
static const uint64_t kSignalMask
Definition: EventCount.h:176
static const uint64_t kSignalShift
Definition: EventCount.h:175
std::uint64_t uint64_t
Definition: Meta.h:42

References CheckState(), kSignalInc, kSignalMask, kSignalShift, kWaiterInc, kWaiterMask, kWaiterShift, and state_.

Referenced by test_basic_eventcount(), test_stress_eventcount(), and Eigen::ThreadPoolTempl< Environment >::WaitForWork().

◆ CheckState()

static void Eigen::EventCount::CheckState ( uint64_t  state,
bool  waiter = false 
)
inlinestaticprivate
201  {
202  static_assert(kEpochBits >= 20, "not enough bits to prevent ABA problem");
203  const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
204  const uint64_t signals = (state & kSignalMask) >> kSignalShift;
205  eigen_plain_assert(waiters >= signals);
206  eigen_plain_assert(waiters < (1 << kWaiterBits) - 1);
207  eigen_plain_assert(!waiter || waiters > 0);
208  (void)waiters;
209  (void)signals;
210  }
static const uint64_t kEpochBits
Definition: EventCount.h:179

References eigen_plain_assert, kEpochBits, kSignalMask, kSignalShift, kWaiterBits, kWaiterMask, and kWaiterShift.

Referenced by CancelWait(), CommitWait(), Notify(), and Prewait().

◆ CommitWait()

void Eigen::EventCount::CommitWait ( Waiter w)
inline
82  {
83  eigen_plain_assert((w->epoch & ~kEpochMask) == 0);
84  w->state = Waiter::kNotSignaled;
85  const uint64_t me = (w - &waiters_[0]) | w->epoch;
86  uint64_t state = state_.load(std::memory_order_seq_cst);
87  for (;;) {
88  CheckState(state, true);
89  uint64_t newstate;
90  if ((state & kSignalMask) != 0) {
91  // Consume the signal and return immediately.
92  newstate = state - kWaiterInc - kSignalInc;
93  } else {
94  // Remove this thread from pre-wait counter and add to the waiter stack.
95  newstate = ((state & kWaiterMask) - kWaiterInc) | me;
96  w->next.store(state & (kStackMask | kEpochMask), std::memory_order_relaxed);
97  }
98  CheckState(newstate);
99  if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
100  if ((state & kSignalMask) == 0) {
101  w->epoch += kEpochInc;
102  Park(w);
103  }
104  return;
105  }
106  }
107  }
RowVector3d w
Definition: Matrix_resize_int.cpp:3
@ kNotSignaled
Definition: EventCount.h:188
static const uint64_t kEpochMask
Definition: EventCount.h:180
static const uint64_t kEpochInc
Definition: EventCount.h:181
void Park(Waiter *w)
Definition: EventCount.h:212

References CheckState(), eigen_plain_assert, kEpochInc, kEpochMask, Eigen::EventCount::Waiter::kNotSignaled, kSignalInc, kSignalMask, kStackMask, kWaiterInc, kWaiterMask, Park(), state_, w, and waiters_.

Referenced by test_basic_eventcount(), test_stress_eventcount(), and Eigen::ThreadPoolTempl< Environment >::WaitForWork().

◆ Notify()

void Eigen::EventCount::Notify ( bool  notifyAll)
inline
127  {
128  std::atomic_thread_fence(std::memory_order_seq_cst);
129  uint64_t state = state_.load(std::memory_order_acquire);
130  for (;;) {
131  CheckState(state);
132  const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
133  const uint64_t signals = (state & kSignalMask) >> kSignalShift;
134  // Easy case: no waiters.
135  if ((state & kStackMask) == kStackMask && waiters == signals) return;
136  uint64_t newstate;
137  if (notifyAll) {
138  // Empty wait stack and set signal to number of pre-wait threads.
139  newstate = (state & kWaiterMask) | (waiters << kSignalShift) | kStackMask;
140  } else if (signals < waiters) {
141  // There is a thread in pre-wait state, unblock it.
142  newstate = state + kSignalInc;
143  } else {
144  // Pop a waiter from list and unpark it.
145  Waiter* w = &waiters_[state & kStackMask];
146  uint64_t next = w->next.load(std::memory_order_relaxed);
147  newstate = (state & (kWaiterMask | kSignalMask)) | next;
148  }
149  CheckState(newstate);
150  if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
151  if (!notifyAll && (signals < waiters)) return; // unblocked pre-wait thread
152  if ((state & kStackMask) == kStackMask) return;
153  Waiter* w = &waiters_[state & kStackMask];
154  if (!notifyAll) w->next.store(kStackMask, std::memory_order_relaxed);
155  Unpark(w);
156  return;
157  }
158  }
159  }
void Unpark(Waiter *w)
Definition: EventCount.h:220

References CheckState(), kSignalInc, kSignalMask, kSignalShift, kStackMask, kWaiterMask, kWaiterShift, state_, Unpark(), w, and waiters_.

Referenced by Eigen::ThreadPoolTempl< Environment >::Cancel(), Eigen::ThreadPoolTempl< Environment >::ScheduleWithHint(), test_basic_eventcount(), test_stress_eventcount(), Eigen::ThreadPoolTempl< Environment >::WaitForWork(), and Eigen::ThreadPoolTempl< Environment >::~ThreadPoolTempl().

◆ operator=()

void Eigen::EventCount::operator= ( const EventCount )
delete

◆ Park()

void Eigen::EventCount::Park ( Waiter w)
inlineprivate
212  {
213  EIGEN_MUTEX_LOCK lock(w->mu);
214  while (w->state != Waiter::kSignaled) {
215  w->state = Waiter::kWaiting;
216  w->cv.wait(lock);
217  }
218  }
@ kWaiting
Definition: EventCount.h:189
@ kSignaled
Definition: EventCount.h:190

References Eigen::EventCount::Waiter::kSignaled, Eigen::EventCount::Waiter::kWaiting, and w.

Referenced by CommitWait().

◆ Prewait()

void Eigen::EventCount::Prewait ( )
inline
71  {
72  uint64_t state = state_.load(std::memory_order_relaxed);
73  for (;;) {
74  CheckState(state);
75  uint64_t newstate = state + kWaiterInc;
76  CheckState(newstate);
77  if (state_.compare_exchange_weak(state, newstate, std::memory_order_seq_cst)) return;
78  }
79  }

References CheckState(), kWaiterInc, and state_.

Referenced by test_basic_eventcount(), test_stress_eventcount(), and Eigen::ThreadPoolTempl< Environment >::WaitForWork().

◆ Unpark()

void Eigen::EventCount::Unpark ( Waiter w)
inlineprivate
220  {
221  for (Waiter* next; w; w = next) {
222  uint64_t wnext = w->next.load(std::memory_order_relaxed) & kStackMask;
223  next = wnext == kStackMask ? nullptr : &waiters_[internal::convert_index<size_t>(wnext)];
224  unsigned state;
225  {
226  EIGEN_MUTEX_LOCK lock(w->mu);
227  state = w->state;
228  w->state = Waiter::kSignaled;
229  }
230  // Avoid notifying if it wasn't waiting.
231  if (state == Waiter::kWaiting) w->cv.notify_one();
232  }
233  }

References Eigen::EventCount::Waiter::kSignaled, kStackMask, Eigen::EventCount::Waiter::kWaiting, w, and waiters_.

Referenced by Notify().

Member Data Documentation

◆ kEpochBits

const uint64_t Eigen::EventCount::kEpochBits = 64 - kEpochShift
staticprivate

Referenced by CheckState().

◆ kEpochInc

const uint64_t Eigen::EventCount::kEpochInc = 1ull << kEpochShift
staticprivate

Referenced by CommitWait().

◆ kEpochMask

const uint64_t Eigen::EventCount::kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift
staticprivate

Referenced by CommitWait().

◆ kEpochShift

const uint64_t Eigen::EventCount::kEpochShift = 3 * kWaiterBits
staticprivate

◆ kSignalInc

const uint64_t Eigen::EventCount::kSignalInc = 1ull << kSignalShift
staticprivate

Referenced by CancelWait(), CommitWait(), and Notify().

◆ kSignalMask

const uint64_t Eigen::EventCount::kSignalMask = ((1ull << kWaiterBits) - 1) << kSignalShift
staticprivate

◆ kSignalShift

const uint64_t Eigen::EventCount::kSignalShift = 2 * kWaiterBits
staticprivate

Referenced by CancelWait(), CheckState(), and Notify().

◆ kStackMask

const uint64_t Eigen::EventCount::kStackMask = (1ull << kWaiterBits) - 1
staticprivate

◆ kWaiterBits

const uint64_t Eigen::EventCount::kWaiterBits = 14
staticprivate

Referenced by CheckState(), and EventCount().

◆ kWaiterInc

const uint64_t Eigen::EventCount::kWaiterInc = 1ull << kWaiterShift
staticprivate

Referenced by CancelWait(), CommitWait(), and Prewait().

◆ kWaiterMask

const uint64_t Eigen::EventCount::kWaiterMask = ((1ull << kWaiterBits) - 1) << kWaiterShift
staticprivate

◆ kWaiterShift

const uint64_t Eigen::EventCount::kWaiterShift = kWaiterBits
staticprivate

Referenced by CancelWait(), CheckState(), and Notify().

◆ state_

std::atomic<uint64_t> Eigen::EventCount::state_
private

◆ waiters_

MaxSizeVector<Waiter>& Eigen::EventCount::waiters_
private

Referenced by CommitWait(), Notify(), and Unpark().


The documentation for this class was generated from the following file: