void Suspend(std::function<void()> on_suspend) { fiber_base * f = (fiber_base *) FiberCurrent(); BASIS_ASSERT(!f->onExit); f->onExit = on_suspend; FiberSwitch(GetNextFiber()); }
static void CheckForExitCondition() { if (Scheduler->exitRequested) { Scheduler->inactive.push_back(FiberCurrent()); TACO_PROFILER_EMIT(taco::profiler::event_object::fiber, taco::profiler::event_action::complete); FiberInvoke(FiberRoot()); BASIS_ASSERT_FAILED; } }
void condition::_wait(std::function<void()> on_suspend) { TACO_PROFILER_LOG("condition::wait <%p>", this); fiber * cur = FiberCurrent(); BASIS_ASSERT(cur); Suspend([&]() -> void { std::unique_lock<mutex> lock(m_mutex); m_waiting.push_back(cur); on_suspend(); }); }
void Switch() { fiber_base * f = (fiber_base *) FiberCurrent(); f->onExit = [&]() -> void { if (f->threadId < 0) { Scheduler->sharedFibers.push_back((fiber *)f); } else { Scheduler->privateFibers.push_back((fiber *)f); } }; FiberSwitch(GetNextFiber()); }
static bool WorkerIteration() { fiber * self = FiberCurrent(); fiber_base * base = (fiber_base *) self; task_entry todo; if (GetPrivateTask(todo)) { Scheduler->privateTaskCount.fetch_sub(1, std::memory_order_relaxed); base->threadId = Scheduler->threadId; base->data = nullptr; base->name = todo.name; todo(); base->name = ""; basis::strfree(todo.name); return true; } else if (GetSharedTask(todo)) { base->threadId = -int(Scheduler->threadId + 1); base->data = nullptr; base->name = todo.name; todo(); base->name = ""; basis::strfree(todo.name); return true; } else { fiber * next = GetNextScheduledFiber(); if (next) { Scheduler->inactive.push_back(self); FiberSwitch(next); return true; } } return false; }
void BeginBlocking() { fiber * f = FiberCurrent(); fiber_base * base = (fiber_base *) f; BASIS_ASSERT(!base->onExit); blocking_thread * thread = nullptr; while (!thread && !BlockingThreads.pop_front(thread)) { int cur = BlockingThreadCount.fetch_add(1); if (cur == BLOCKING_THREAD_LIMIT) { BlockingThreadCount.store(cur); Switch(); } else { thread = new blocking_thread; thread->exitRequested = false; thread->current = nullptr; thread->thread = std::thread([=]() -> void { BlockingThread(thread); }); } } base->onExit = [=]() -> void { base->isBlocking = true; { std::unique_lock<std::mutex> lock(thread->workMutex); thread->current = f; } thread->workCondition.notify_one(); }; FiberInvoke(GetNextFiber()); }
void EndBlocking() { fiber * f = FiberCurrent(); fiber_base * base = (fiber_base *) f; BASIS_ASSERT(!base->onExit); base->onExit = [=]() -> void { base->isBlocking = false; if (base->threadId < 0) { SchedulerList[-(base->threadId + 1)].sharedFibers.push_back(f); SignalScheduler(SchedulerList - (base->threadId + 1)); } else { BASIS_ASSERT((unsigned)base->threadId < Scheduler->threadId); Scheduler->privateFibers.push_back(f); SignalScheduler(Scheduler); } }; FiberInvoke(FiberRoot()); }
const char * GetTaskName() { fiber_base * f = (fiber_base *) FiberCurrent(); return f->name; }
void * GetTaskLocalData() { fiber_base * f = (fiber_base *) FiberCurrent(); return f->data; }
void SetTaskLocalData(void * data) { fiber_base * f = (fiber_base *) FiberCurrent(); f->data = data; }