|
24 | 24 | #include <utility> |
25 | 25 | #include <vector> |
26 | 26 |
|
| 27 | +#include "xenia/base/assert.h" |
| 28 | + |
27 | 29 | namespace xe { |
28 | 30 | namespace threading { |
29 | 31 |
|
| 32 | +// This is more like an Event with self-reset when returning from Wait() |
30 | 33 | class Fence { |
31 | 34 | public: |
32 | | - Fence() : signaled_(false) {} |
| 35 | + Fence() : signal_state_(0) {} |
| 36 | + |
33 | 37 | void Signal() { |
34 | 38 | std::unique_lock<std::mutex> lock(mutex_); |
35 | | - signaled_ = true; |
| 39 | + signal_state_ |= SIGMASK_; |
36 | 40 | cond_.notify_all(); |
37 | 41 | } |
| 42 | + |
| 43 | + // Wait for the Fence to be signaled. Clears the signal on return. |
38 | 44 | void Wait() { |
39 | 45 | std::unique_lock<std::mutex> lock(mutex_); |
40 | | - cond_.wait(lock, [this] { return signaled_; }); |
41 | | - signaled_ = false; |
| 46 | + assert_true((signal_state_ & ~SIGMASK_) < (SIGMASK_ - 1) && |
| 47 | + "Too many threads?"); |
| 48 | + |
| 49 | + // keep local copy to minimize loads |
| 50 | + auto signal_state = ++signal_state_; |
| 51 | + for (; !(signal_state & SIGMASK_); signal_state = signal_state_) { |
| 52 | + cond_.wait(lock); |
| 53 | + } |
| 54 | + |
| 55 | + // We can't just clear the signal as other threads may not have read it yet |
| 56 | + assert_true((signal_state & ~SIGMASK_) > 0); // wait_count > 0 |
| 57 | + if (signal_state == (1 | SIGMASK_)) { // wait_count == 1 |
| 58 | + // Last one out turn off the lights |
| 59 | + signal_state_ = 0; |
| 60 | + } else { |
| 61 | + // Oops, another thread is still waiting, set the new count and keep the |
| 62 | + // signal. |
| 63 | + signal_state_ = --signal_state; |
| 64 | + } |
42 | 65 | } |
43 | 66 |
|
44 | 67 | private: |
| 68 | + using state_t_ = uint_fast32_t; |
| 69 | + static constexpr state_t_ SIGMASK_ = state_t_(1) |
| 70 | + << (sizeof(state_t_) * 8 - 1); |
| 71 | + |
45 | 72 | std::mutex mutex_; |
46 | 73 | std::condition_variable cond_; |
47 | | - bool signaled_; |
| 74 | + // Use the highest bit (sign bit) as the signal flag and the rest to count |
| 75 | + // waiting threads. |
| 76 | + volatile state_t_ signal_state_; |
48 | 77 | }; |
49 | 78 |
|
50 | 79 | // Returns the total number of logical processors in the host system. |
|
0 commit comments