diff options
Diffstat (limited to 'src/common/fiber.cpp')
| -rw-r--r-- | src/common/fiber.cpp | 154 |
1 files changed, 69 insertions, 85 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index c991b7cf1a..eb2063c6e7 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -5,87 +5,47 @@ #include "common/assert.h" #include "common/fiber.h" -#include "common/virtual_buffer.h" - -#include <boost/context/detail/fcontext.hpp> +#define MINICORO_IMPL +#include "common/minicoro.h" namespace Common { -constexpr std::size_t default_stack_size = 512 * 1024; - struct Fiber::FiberImpl { - FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {} - - VirtualBuffer<u8> stack; - VirtualBuffer<u8> rewind_stack; + FiberImpl() {} std::mutex guard; - std::function<void()> entry_point; - std::function<void()> rewind_point; - std::shared_ptr<Fiber> previous_fiber; - bool is_thread_fiber{}; bool released{}; + bool is_thread_fiber{}; + Fiber *next_fiber{}; + Fiber **next_fiber_ptr; + std::function<void()> entry_point; - u8* stack_limit{}; - u8* rewind_stack_limit{}; - boost::context::detail::fcontext_t context{}; - boost::context::detail::fcontext_t rewind_context{}; + mco_coro *context; }; -void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) { - impl->rewind_point = std::move(rewind_func); -} - -void Fiber::Start(boost::context::detail::transfer_t& transfer) { - ASSERT(impl->previous_fiber != nullptr); - impl->previous_fiber->impl->context = transfer.fctx; - impl->previous_fiber->impl->guard.unlock(); - impl->previous_fiber.reset(); - impl->entry_point(); - UNREACHABLE(); -} - -void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transfer) { - ASSERT(impl->context != nullptr); - impl->context = impl->rewind_context; - impl->rewind_context = nullptr; - u8* tmp = impl->stack_limit; - impl->stack_limit = impl->rewind_stack_limit; - impl->rewind_stack_limit = tmp; - impl->rewind_point(); - UNREACHABLE(); -} - -void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { - auto* fiber = static_cast<Fiber*>(transfer.data); - fiber->Start(transfer); -} - -void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { - auto* fiber = static_cast<Fiber*>(transfer.data); - fiber->OnRewind(transfer); +Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} { + impl->is_thread_fiber = true; } Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} { impl->entry_point = std::move(entry_point_func); - impl->stack_limit = impl->stack.data(); - impl->rewind_stack_limit = impl->rewind_stack.data(); - u8* stack_base = impl->stack_limit + default_stack_size; - impl->context = - boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); + auto desc = mco_desc_init([] (mco_coro *coro) { + reinterpret_cast<Fiber*>(coro->user_data)->impl->entry_point(); + }, 0); + desc.user_data = this; + mco_result res = mco_create(&impl->context, &desc); + ASSERT(res == MCO_SUCCESS); } -Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} - Fiber::~Fiber() { if (impl->released) { return; } - // Make sure the Fiber is not being used - const bool locked = impl->guard.try_lock(); - ASSERT_MSG(locked, "Destroying a fiber that's still running"); - if (locked) { - impl->guard.unlock(); + DestroyPre(); + if (impl->is_thread_fiber) { + DestroyThreadFiber(); + } else { + DestroyWorkFiber(); } } @@ -94,42 +54,66 @@ void Fiber::Exit() { if (!impl->is_thread_fiber) { return; } - impl->guard.unlock(); - impl->released = true; + DestroyPre(); + DestroyThreadFiber(); } -void Fiber::Rewind() { - ASSERT(impl->rewind_point); - ASSERT(impl->rewind_context == nullptr); - u8* stack_base = impl->rewind_stack_limit + default_stack_size; - impl->rewind_context = - boost::context::detail::make_fcontext(stack_base, impl->stack.size(), RewindStartFunc); - boost::context::detail::jump_fcontext(impl->rewind_context, this); +void Fiber::DestroyPre() { + // Make sure the Fiber is not being used + const bool locked = impl->guard.try_lock(); + ASSERT_MSG(locked, "Destroying a fiber that's still running"); + if (locked) { + impl->guard.unlock(); + } + impl->released = true; } -void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { - to.impl->guard.lock(); - to.impl->previous_fiber = weak_from.lock(); +void Fiber::DestroyWorkFiber() { + mco_result res = mco_destroy(impl->context); + ASSERT(res == MCO_SUCCESS); +} - auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to); +void Fiber::DestroyThreadFiber() { + if (*impl->next_fiber_ptr) { + *impl->next_fiber_ptr = nullptr; + } +} - // "from" might no longer be valid if the thread was killed +void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { if (auto from = weak_from.lock()) { - if (from->impl->previous_fiber == nullptr) { - ASSERT_MSG(false, "previous_fiber is nullptr!"); - return; + if (!from->impl->is_thread_fiber) { + // Set next fiber + from->impl->next_fiber = &to; + // Yield from thread + if (!from->impl->released) { + from->impl->guard.unlock(); + mco_yield(from->impl->context); + } + } else { + from->impl->guard.lock(); + // Keep running next fiber until they've ran out + auto& next_fiber_ptr = from->impl->next_fiber_ptr; + next_fiber_ptr = &from->impl->next_fiber; + *next_fiber_ptr = &to; + for ([[maybe_unused]] unsigned round = 0; *next_fiber_ptr; round++) { + auto next = *next_fiber_ptr; + *next_fiber_ptr = nullptr; + next_fiber_ptr = &next->impl->next_fiber; + // Stop if new thread is thread fiber + if (next->impl->is_thread_fiber) + break; + // Resume new thread + next->impl->guard.lock(); + mco_result res = mco_resume(next->impl->context); + ASSERT(res == MCO_SUCCESS); + } + from->impl->guard.unlock(); } - from->impl->previous_fiber->impl->context = transfer.fctx; - from->impl->previous_fiber->impl->guard.unlock(); - from->impl->previous_fiber.reset(); } } std::shared_ptr<Fiber> Fiber::ThreadToFiber() { - std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; - fiber->impl->guard.lock(); - fiber->impl->is_thread_fiber = true; - return fiber; + return std::shared_ptr<Fiber>{new Fiber()}; } } // namespace Common |
