| 301 | } |
| 302 | |
| 303 | std::unique_lock<MutexLock> LaunchWorker::SyncCmdWithLock(std::unique_lock<utils::MutexLock> lock, |
| 304 | std::shared_ptr<HwCommand> hw_cmd) |
| 305 | { |
| 306 | XASSERT(hw_cmd->Synchronizable(), "The HwCommand should be synchronizable"); |
| 307 | |
| 308 | while (true) { |
| 309 | // Wait if the worker is paused. |
| 310 | while (true) { |
| 311 | // Check if it is already completed. |
| 312 | // Here checking every loop is necessary because the lock could have been released |
| 313 | // in the last inner/outer loop and the HwCommand may have been set to |
| 314 | // kCommandStateCompleted by other threads. |
| 315 | // It will cause bugs if not checking in the outer loop when the app is syncing this |
| 316 | // HwCommand, and the XQueue is suspened in the lock-released period in the last |
| 317 | // outer loop, i.e., unlock(); cmd->sync(); lock(); |
| 318 | // It will also cause bugs if not checking in the inner loop when: |
| 319 | // 1. the XQueue is suspended |
| 320 | // 2. this thread is waiting on cv_.wait(lock); |
| 321 | // 3. lock is released and the XQueue is resumed |
| 322 | // 4. hw_cmd is set to completed by another thread |
| 323 | // 5. the XQueue is again suspended |
| 324 | // 6. this thread wakes up and locks, finds the XQueue is suspended |
| 325 | if (hw_cmd->GetState() >= kCommandStateCompleted) return lock; |
| 326 | |
| 327 | if (state_ == kWorkerStateRunning) { |
| 328 | break; |
| 329 | } else if (state_ == kWorkerStatePaused) { |
| 330 | cv_.wait(lock); |
| 331 | } else if (state_ == kWorkerStateTerminated) { |
| 332 | return lock; |
| 333 | } else { |
| 334 | XASSERT(false, "Invalid worker state"); |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | XCommandState state = hw_cmd->GetState(); |
| 339 | XASSERT(state >= kCommandStateInFlight, "The syncing HwCommand is not launched"); |
| 340 | if (state == kCommandStateCompleted) break; |
| 341 | |
| 342 | int64_t current_pause_cnt = pause_count_; |
| 343 | |
| 344 | lock.unlock(); |
| 345 | hw_cmd->Synchronize(); |
| 346 | lock.lock(); |
| 347 | |
| 348 | // Check if preemption happened during hw_cmd->Synchronize(). |
| 349 | if (current_pause_cnt == pause_count_) break; |
| 350 | } |
| 351 | |
| 352 | // Pop and delete all HwCommands launched in previous. |
| 353 | const int64_t current_command_idx = hw_cmd->GetIdx(); |
| 354 | |
| 355 | while (sync_cmd_log_.size() > 0) { |
| 356 | if (sync_cmd_log_.front()->GetIdx() > current_command_idx) break; |
| 357 | sync_cmd_log_.pop_front(); |
| 358 | } |
| 359 | |
| 360 | while (cmd_log_.size() > 0) { |
nothing calls this directly
no test coverage detected