void TaskScheduler::MainFiberStart(intptr_t arg) { MainFiberStartArgs *mainFiberArgs = reinterpret_cast<MainFiberStartArgs *>(arg); TaskScheduler *taskScheduler = mainFiberArgs->taskScheduler; // Call the main task procedure mainFiberArgs->MainTask(taskScheduler, mainFiberArgs->Arg); // Request that all the threads quit taskScheduler->m_quit.store(true, std::memory_order_release); // Switch to the thread fibers ThreadLocalStorage &tls = taskScheduler->m_tls[taskScheduler->GetCurrentThreadIndex()]; taskScheduler->m_fibers[tls.CurrentFiberIndex].SwitchToFiber(&tls.ThreadFiber); // We should never get here printf("Error: FiberStart should never return"); }
void TaskScheduler::FiberStart(intptr_t arg) { TaskScheduler *taskScheduler = reinterpret_cast<TaskScheduler *>(arg); while (!taskScheduler->m_quit.load(std::memory_order_acquire)) { // Clean up from the last fiber to run on this thread taskScheduler->CleanUpOldFiber(); // Check if any of the waiting tasks are ready std::size_t waitingFiberIndex = FTL_INVALID_INDEX; for (std::size_t i = 0; i < taskScheduler->m_fiberPoolSize; ++i) { // Double lock if (!taskScheduler->m_waitingFibers[i].load(std::memory_order_relaxed)) { continue; } if (!taskScheduler->m_waitingFibers[i].load(std::memory_order_acquire)) { continue; } // Found a waiting fiber // Test if it's ready WaitingBundle *bundle = &taskScheduler->m_waitingBundles[i]; if (bundle->Counter->load(std::memory_order_relaxed) != bundle->TargetValue) { continue; } bool expected = true; if (std::atomic_compare_exchange_weak_explicit(&taskScheduler->m_waitingFibers[i], &expected, false, std::memory_order_release, std::memory_order_relaxed)) { waitingFiberIndex = i; break; } } if (waitingFiberIndex != FTL_INVALID_INDEX) { // Found a waiting task that is ready to continue ThreadLocalStorage &tls = taskScheduler->m_tls[taskScheduler->GetCurrentThreadIndex()]; tls.OldFiberIndex = tls.CurrentFiberIndex; tls.CurrentFiberIndex = waitingFiberIndex; tls.OldFiberDestination = FiberDestination::ToPool; // Switch taskScheduler->m_fibers[tls.OldFiberIndex].SwitchToFiber(&taskScheduler->m_fibers[tls.CurrentFiberIndex]); // And we're back } else { // Get a new task from the queue, and execute it TaskBundle nextTask; if (!taskScheduler->GetNextTask(&nextTask)) { // Spin } else { nextTask.TaskToExecute.Function(taskScheduler, nextTask.TaskToExecute.ArgData); nextTask.Counter->fetch_sub(1); } } } // Start the quit sequence // Switch to the thread fibers ThreadLocalStorage &tls = taskScheduler->m_tls[taskScheduler->GetCurrentThreadIndex()]; taskScheduler->m_fibers[tls.CurrentFiberIndex].SwitchToFiber(&tls.ThreadFiber); // We should never get here printf("Error: FiberStart should never return"); }