| 510 | } |
| 511 | |
| 512 | bool TaskScheduler::GetNextHiPriTask(TaskBundle *nextTask, std::vector<TaskBundle> *taskBuffer) { |
| 513 | unsigned const currentThreadIndex = GetCurrentThreadIndex(); |
| 514 | ThreadLocalStorage &tls = m_tls[currentThreadIndex]; |
| 515 | |
| 516 | bool result = false; |
| 517 | |
| 518 | // Try to pop from our own queue |
| 519 | while (tls.HiPriTaskQueue.Pop(nextTask)) { |
| 520 | if (TaskIsReadyToExecute(nextTask)) { |
| 521 | result = true; |
| 522 | // Break to cleanup |
| 523 | goto cleanup; // NOLINT(cppcoreguidelines-avoid-goto) |
| 524 | } |
| 525 | |
| 526 | // It's a ReadyTask whose fiber hasn't switched away yet |
| 527 | // Add it to the buffer |
| 528 | taskBuffer->emplace_back(*nextTask); |
| 529 | } |
| 530 | |
| 531 | // Force a scope so the `goto cleanup` above doesn't skip initialization |
| 532 | { |
| 533 | // Ours is empty, try to steal from the others' |
| 534 | const unsigned threadIndex = tls.HiPriLastSuccessfulSteal; |
| 535 | for (unsigned i = 0; i < m_numThreads; ++i) { |
| 536 | const unsigned threadIndexToStealFrom = (threadIndex + i) % m_numThreads; |
| 537 | if (threadIndexToStealFrom == currentThreadIndex) { |
| 538 | continue; |
| 539 | } |
| 540 | ThreadLocalStorage &otherTLS = m_tls[threadIndexToStealFrom]; |
| 541 | |
| 542 | while (otherTLS.HiPriTaskQueue.Steal(nextTask)) { |
| 543 | tls.HiPriLastSuccessfulSteal = threadIndexToStealFrom; |
| 544 | |
| 545 | if (TaskIsReadyToExecute(nextTask)) { |
| 546 | result = true; |
| 547 | // Break to cleanup |
| 548 | goto cleanup; |
| 549 | } |
| 550 | |
| 551 | // It's a ReadyTask whose fiber hasn't switched away yet |
| 552 | // Add it to the buffer |
| 553 | taskBuffer->emplace_back(*nextTask); |
| 554 | } |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | cleanup: |
| 559 | if (!taskBuffer->empty()) { |
| 560 | // Re-push all the tasks we found that we're ready to execute |
| 561 | // We (or another thread) will get them next round |
| 562 | do { |
| 563 | // Push them in the opposite order we popped them, to restore the order |
| 564 | tls.HiPriTaskQueue.Push(taskBuffer->back()); |
| 565 | taskBuffer->pop_back(); |
| 566 | } while (!taskBuffer->empty()); |
| 567 | |
| 568 | // If we're using Sleep mode, we need to wake up the other threads |
| 569 | // They may have looked for tasks while we had them all in our temp buffer and thus not |
no test coverage detected