| 160 | } |
| 161 | |
| 162 | void CompatWorker::Worker() |
| 163 | { |
| 164 | // Note: this must be first to ensure an ordering between Worker() and |
| 165 | // Start(). It must also be outside of the loop to ensure the lock is |
| 166 | // held across wakeup and retesting the predicates. |
| 167 | std::unique_lock<std::mutex> lock(mutex_); |
| 168 | |
| 169 | if (callbacks_) { |
| 170 | lock.unlock(); |
| 171 | callbacks_->OnWorkerStart(this); |
| 172 | lock.lock(); |
| 173 | } |
| 174 | |
| 175 | typedef std::chrono::system_clock Clock; |
| 176 | typedef std::chrono::time_point<Clock> TimePoint; |
| 177 | |
| 178 | auto can_work = [this]() -> bool { |
| 179 | return state_ == Worker_Running && !work_.empty(); |
| 180 | }; |
| 181 | |
| 182 | ke::Maybe<TimePoint> wait; |
| 183 | unsigned int work_in_frame = 0; |
| 184 | for (;;) { |
| 185 | if (state_ == Worker_Stopped) |
| 186 | break; |
| 187 | |
| 188 | if (!can_work()) { |
| 189 | // Wait for work or a Stop. |
| 190 | work_cv_.wait(lock); |
| 191 | continue; |
| 192 | } |
| 193 | |
| 194 | if (wait.isValid()) { |
| 195 | // Wait until the specified time has passed. If we wake up with a |
| 196 | // timeout, then the wait has elapsed, so reset the holder. |
| 197 | if (work_cv_.wait_until(lock, wait.get()) == std::cv_status::timeout) |
| 198 | wait = ke::Nothing(); |
| 199 | continue; |
| 200 | } |
| 201 | |
| 202 | assert(state_ == Worker_Running); |
| 203 | assert(!work_.empty()); |
| 204 | |
| 205 | SWThreadHandle* handle = ke::PopFront(&work_); |
| 206 | RunWorkLocked(&lock, handle); |
| 207 | work_in_frame++; |
| 208 | |
| 209 | // If we've reached our max jobs per "frame", signal that the next |
| 210 | // immediate job must be delayed. We retain the old ThreadWorker |
| 211 | // behavior by checking if the queue has more work. Thus, a delay |
| 212 | // only occurs if two jobs would be processed in the same wakeup. |
| 213 | if (work_in_frame >= jobs_per_wakeup_ && wait_between_jobs_ && can_work()) |
| 214 | wait = ke::Some(Clock::now() + std::chrono::milliseconds(wait_between_jobs_)); |
| 215 | } |
| 216 | |
| 217 | assert(lock.owns_lock()); |
| 218 | |
| 219 | while (!work_.empty()) { |
nothing calls this directly
no test coverage detected