|
7 | 7 | */ |
8 | 8 |
|
9 | 9 | #include "roc_pipeline/state_tracker.h" |
| 10 | +#include "roc_core/log.h" |
10 | 11 | #include "roc_core/panic.h" |
11 | 12 |
|
12 | 13 | namespace roc { |
13 | 14 | namespace pipeline { |
14 | 15 |
|
15 | 16 | StateTracker::StateTracker() |
16 | | - : halt_state_(-1) |
| 17 | + : sem_(0) |
| 18 | + , halt_state_(-1) |
17 | 19 | , active_sessions_(0) |
18 | | - , pending_packets_(0) { |
| 20 | + , pending_packets_(0) |
| 21 | + , sem_is_occupied_(0) |
| 22 | + , waiting_mask_(0) |
| 23 | + , mutex_() |
| 24 | + , waiting_con_(mutex_) { |
| 25 | +} |
| 26 | + |
| 27 | +// StateTracker::~StateTracker() { |
| 28 | +// mutex_.unlock(); |
| 29 | +// } |
| 30 | + |
| 31 | +// This method should block until the state becomes any of the states specified by the |
| 32 | +// mask, or deadline expires. E.g. if mask is ACTIVE | PAUSED, it should block until state |
| 33 | +// becomes either ACTIVE or PAUSED. (Currently only two states are used, but later more |
| 34 | +// states will be needed). Deadline should be an absolute timestamp. |
| 35 | + |
| 36 | +// Questions: |
| 37 | +// - When should the function return true vs false |
| 38 | +bool StateTracker::wait_state(unsigned int state_mask, core::nanoseconds_t deadline) { |
| 39 | + |
| 40 | + mutex_.lock(); |
| 41 | + for (;;) { |
| 42 | + // If no state is specified in state_mask, return immediately |
| 43 | + if (state_mask == 0) { |
| 44 | + return true; |
| 45 | + } |
| 46 | + |
| 47 | + if (static_cast<unsigned>(get_state()) & state_mask) { |
| 48 | + return true; |
| 49 | + } |
| 50 | + |
| 51 | + if (deadline >= 0 && deadline <= core::timestamp(core::ClockMonotonic)) { |
| 52 | + return false; |
| 53 | + } |
| 54 | + |
| 55 | + if (sem_is_occupied_.compare_exchange(0, 1)) { |
| 56 | + |
| 57 | + if (deadline >= 0) { |
| 58 | + mutex_.unlock(); |
| 59 | + (void)sem_.timed_wait(deadline); |
| 60 | + |
| 61 | + } else { |
| 62 | + mutex_.unlock(); |
| 63 | + sem_.wait(); |
| 64 | + } |
| 65 | + |
| 66 | + mutex_.lock(); |
| 67 | + sem_is_occupied_ = 0; |
| 68 | + waiting_con_.broadcast(); |
| 69 | + |
| 70 | + } else { |
| 71 | + if (deadline >= 0) { |
| 72 | + (void)waiting_con_.timed_wait(deadline); |
| 73 | + } else { |
| 74 | + waiting_con_.wait(); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
19 | 78 | } |
20 | 79 |
|
21 | 80 | sndio::DeviceState StateTracker::get_state() const { |
@@ -65,22 +124,50 @@ size_t StateTracker::num_sessions() const { |
65 | 124 | } |
66 | 125 |
|
67 | 126 | void StateTracker::register_session() { |
68 | | - active_sessions_++; |
| 127 | + if (active_sessions_++ == 0) { |
| 128 | + signal_state_change(); |
| 129 | + } |
69 | 130 | } |
70 | 131 |
|
71 | 132 | void StateTracker::unregister_session() { |
72 | | - if (--active_sessions_ < 0) { |
| 133 | + int prev_sessions = active_sessions_--; |
| 134 | + if (prev_sessions == 0) { |
73 | 135 | roc_panic("state tracker: unpaired register/unregister session"); |
| 136 | + } else if (prev_sessions == 1 && pending_packets_ == 0) { |
| 137 | + signal_state_change(); |
74 | 138 | } |
| 139 | + |
| 140 | + // if (--active_sessions_ < 0) { |
| 141 | + // roc_panic("state tracker: unpaired register/unregister session"); |
| 142 | + // } |
75 | 143 | } |
76 | 144 |
|
77 | 145 | void StateTracker::register_packet() { |
78 | | - pending_packets_++; |
| 146 | + if (pending_packets_++ == 0 && active_sessions_ == 0) { |
| 147 | + signal_state_change(); |
| 148 | + } |
79 | 149 | } |
80 | 150 |
|
81 | 151 | void StateTracker::unregister_packet() { |
82 | | - if (--pending_packets_ < 0) { |
| 152 | + int prev_packets = pending_packets_--; |
| 153 | + if (prev_packets == 0) { |
83 | 154 | roc_panic("state tracker: unpaired register/unregister packet"); |
| 155 | + } else if (prev_packets == 1 && active_sessions_ == 0) { |
| 156 | + signal_state_change(); |
| 157 | + } |
| 158 | + |
| 159 | + // if (--pending_packets_ < 0) { |
| 160 | + // roc_panic("state tracker: unpaired register/unregister packet"); |
| 161 | + // } |
| 162 | +} |
| 163 | + |
| 164 | +void StateTracker::signal_state_change() { |
| 165 | + // if (waiting_mask_ != 0 && (static_cast<unsigned>(get_state()) & waiting_mask_)) { |
| 166 | + // sem_.post(); |
| 167 | + // } |
| 168 | + if (sem_is_occupied_) { |
| 169 | + roc_log(LogDebug, "signaling"); |
| 170 | + sem_.post(); |
84 | 171 | } |
85 | 172 | } |
86 | 173 |
|
|
0 commit comments