diff options
Diffstat (limited to 'src/common/fiber.cpp')
-rw-r--r-- | src/common/fiber.cpp | 194 |
1 files changed, 55 insertions, 139 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 1c1d09ccb..3c1eefcb7 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -4,129 +4,51 @@ #include "common/assert.h" #include "common/fiber.h" -#if defined(_WIN32) || defined(WIN32) -#include <windows.h> -#else +#include "common/spin_lock.h" +#include "common/virtual_buffer.h" + #include <boost/context/detail/fcontext.hpp> -#endif namespace Common { -constexpr std::size_t default_stack_size = 256 * 1024; // 256kb - -#if defined(_WIN32) || defined(WIN32) +constexpr std::size_t default_stack_size = 256 * 1024; struct Fiber::FiberImpl { - LPVOID handle = nullptr; - LPVOID rewind_handle = nullptr; + FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {} + + VirtualBuffer<u8> stack; + VirtualBuffer<u8> rewind_stack; + + SpinLock guard{}; + std::function<void(void*)> entry_point; + std::function<void(void*)> rewind_point; + void* rewind_parameter{}; + void* start_parameter{}; + std::shared_ptr<Fiber> previous_fiber; + bool is_thread_fiber{}; + bool released{}; + + u8* stack_limit{}; + u8* rewind_stack_limit{}; + boost::context::detail::fcontext_t context{}; + boost::context::detail::fcontext_t rewind_context{}; }; -void Fiber::Start() { - ASSERT(previous_fiber != nullptr); - previous_fiber->guard.unlock(); - previous_fiber.reset(); - entry_point(start_parameter); - UNREACHABLE(); -} - -void Fiber::OnRewind() { - ASSERT(impl->handle != nullptr); - DeleteFiber(impl->handle); - impl->handle = impl->rewind_handle; - impl->rewind_handle = nullptr; - rewind_point(rewind_parameter); - UNREACHABLE(); -} - -void Fiber::FiberStartFunc(void* fiber_parameter) { - auto fiber = static_cast<Fiber*>(fiber_parameter); - fiber->Start(); -} - -void Fiber::RewindStartFunc(void* fiber_parameter) { - auto fiber = static_cast<Fiber*>(fiber_parameter); - fiber->OnRewind(); -} - -Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) - : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { - impl = std::make_unique<FiberImpl>(); - impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); -} - -Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} - -Fiber::~Fiber() { - if (released) { - return; - } - // Make sure the Fiber is not being used - const bool locked = guard.try_lock(); - ASSERT_MSG(locked, "Destroying a fiber that's still running"); - if (locked) { - guard.unlock(); - } - DeleteFiber(impl->handle); -} - -void Fiber::Exit() { - ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); - if (!is_thread_fiber) { - return; - } - ConvertFiberToThread(); - guard.unlock(); - released = true; -} - -void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { - rewind_point = std::move(rewind_func); - rewind_parameter = start_parameter; -} - -void Fiber::Rewind() { - ASSERT(rewind_point); - ASSERT(impl->rewind_handle == nullptr); - impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this); - SwitchToFiber(impl->rewind_handle); -} - -void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { - ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); - ASSERT_MSG(to != nullptr, "Next fiber is null!"); - to->guard.lock(); - to->previous_fiber = from; - SwitchToFiber(to->impl->handle); - ASSERT(from->previous_fiber != nullptr); - from->previous_fiber->guard.unlock(); - from->previous_fiber.reset(); +void Fiber::SetStartParameter(void* new_parameter) { + impl->start_parameter = new_parameter; } -std::shared_ptr<Fiber> Fiber::ThreadToFiber() { - std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; - fiber->guard.lock(); - fiber->impl->handle = ConvertThreadToFiber(nullptr); - fiber->is_thread_fiber = true; - return fiber; +void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) { + impl->rewind_point = std::move(rewind_func); + impl->rewind_parameter = rewind_param; } -#else - -struct Fiber::FiberImpl { - alignas(64) std::array<u8, default_stack_size> stack; - alignas(64) std::array<u8, default_stack_size> rewind_stack; - u8* stack_limit; - u8* rewind_stack_limit; - boost::context::detail::fcontext_t context; - boost::context::detail::fcontext_t rewind_context; -}; - void Fiber::Start(boost::context::detail::transfer_t& transfer) { - ASSERT(previous_fiber != nullptr); - previous_fiber->impl->context = transfer.fctx; - previous_fiber->guard.unlock(); - previous_fiber.reset(); - entry_point(start_parameter); + 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(impl->start_parameter); UNREACHABLE(); } @@ -137,23 +59,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf u8* tmp = impl->stack_limit; impl->stack_limit = impl->rewind_stack_limit; impl->rewind_stack_limit = tmp; - rewind_point(rewind_parameter); + impl->rewind_point(impl->rewind_parameter); UNREACHABLE(); } void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { - auto fiber = static_cast<Fiber*>(transfer.data); + 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); + auto* fiber = static_cast<Fiber*>(transfer.data); fiber->OnRewind(transfer); } Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) - : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { - impl = std::make_unique<FiberImpl>(); + : impl{std::make_unique<FiberImpl>()} { + impl->entry_point = std::move(entry_point_func); + impl->start_parameter = start_parameter; impl->stack_limit = impl->stack.data(); impl->rewind_stack_limit = impl->rewind_stack.data(); u8* stack_base = impl->stack_limit + default_stack_size; @@ -161,37 +84,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); } -void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { - rewind_point = std::move(rewind_func); - rewind_parameter = start_parameter; -} - Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} Fiber::~Fiber() { - if (released) { + if (impl->released) { return; } // Make sure the Fiber is not being used - const bool locked = guard.try_lock(); + const bool locked = impl->guard.try_lock(); ASSERT_MSG(locked, "Destroying a fiber that's still running"); if (locked) { - guard.unlock(); + impl->guard.unlock(); } } void Fiber::Exit() { - - ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); - if (!is_thread_fiber) { + ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber"); + if (!impl->is_thread_fiber) { return; } - guard.unlock(); - released = true; + impl->guard.unlock(); + impl->released = true; } void Fiber::Rewind() { - ASSERT(rewind_point); + ASSERT(impl->rewind_point); ASSERT(impl->rewind_context == nullptr); u8* stack_base = impl->rewind_stack_limit + default_stack_size; impl->rewind_context = @@ -199,24 +116,23 @@ void Fiber::Rewind() { boost::context::detail::jump_fcontext(impl->rewind_context, this); } -void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { +void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); ASSERT_MSG(to != nullptr, "Next fiber is null!"); - to->guard.lock(); - to->previous_fiber = from; + to->impl->guard.lock(); + to->impl->previous_fiber = from; auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); - ASSERT(from->previous_fiber != nullptr); - from->previous_fiber->impl->context = transfer.fctx; - from->previous_fiber->guard.unlock(); - from->previous_fiber.reset(); + ASSERT(from->impl->previous_fiber != nullptr); + 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->guard.lock(); - fiber->is_thread_fiber = true; + fiber->impl->guard.lock(); + fiber->impl->is_thread_fiber = true; return fiber; } -#endif } // namespace Common |