From b53aa06505b1e1d32a597440c1812b1a5317ef35 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 29 Dec 2025 20:37:49 +0100 Subject: [common] fix fibers by using older boost instead of minicoro (#2665) Revert of a previous commit that added minicoro for a reason god knows why Signed-off-by: lizzie Co-authored-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2665 Reviewed-by: DraVee Reviewed-by: Maufeat Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/fiber.cpp | 157 +++++++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 69 deletions(-) (limited to 'src/common/fiber.cpp') diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 8c3bae7c16..4f0f2b6430 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -5,47 +8,87 @@ #include "common/assert.h" #include "common/fiber.h" -#define MCO_USE_VMEM_ALLOCATOR -#define MINICORO_IMPL -#include "common/minicoro.h" +#include "common/virtual_buffer.h" + +#include namespace Common { +constexpr std::size_t default_stack_size = 512 * 1024; + struct Fiber::FiberImpl { - FiberImpl() {} + FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {} + + VirtualBuffer stack; + VirtualBuffer rewind_stack; std::mutex guard; - bool released{}; - bool is_thread_fiber{}; - Fiber* next_fiber{}; - Fiber** next_fiber_ptr; std::function entry_point; + std::function rewind_point; + std::shared_ptr previous_fiber; + bool is_thread_fiber{}; + bool released{}; - mco_coro* context; + u8* stack_limit{}; + u8* rewind_stack_limit{}; + boost::context::detail::fcontext_t context{}; + boost::context::detail::fcontext_t rewind_context{}; }; -Fiber::Fiber() : impl{std::make_unique()} { - impl->is_thread_fiber = true; +void Fiber::SetRewindPoint(std::function&& 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(transfer.data); + fiber->Start(transfer); +} + +void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { + auto* fiber = static_cast(transfer.data); + fiber->OnRewind(transfer); } Fiber::Fiber(std::function&& entry_point_func) : impl{std::make_unique()} { impl->entry_point = std::move(entry_point_func); - auto desc = mco_desc_init( - [](mco_coro* coro) { reinterpret_cast(coro->user_data)->impl->entry_point(); }, 0); - desc.user_data = this; - mco_result res = mco_create(&impl->context, &desc); - ASSERT(res == MCO_SUCCESS); + 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); } +Fiber::Fiber() : impl{std::make_unique()} {} + Fiber::~Fiber() { if (impl->released) { return; } - DestroyPre(); - if (impl->is_thread_fiber) { - DestroyThreadFiber(); - } else { - DestroyWorkFiber(); + // 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(); } } @@ -54,66 +97,42 @@ void Fiber::Exit() { if (!impl->is_thread_fiber) { return; } - DestroyPre(); - DestroyThreadFiber(); -} - -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->guard.unlock(); impl->released = true; } -void Fiber::DestroyWorkFiber() { - mco_result res = mco_destroy(impl->context); - ASSERT(res == MCO_SUCCESS); -} - -void Fiber::DestroyThreadFiber() { - if (*impl->next_fiber_ptr) { - *impl->next_fiber_ptr = nullptr; - } +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::YieldTo(std::weak_ptr weak_from, Fiber& to) { + to.impl->guard.lock(); + to.impl->previous_fiber = weak_from.lock(); + + auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to); + + // "from" might no longer be valid if the thread was killed if (auto from = weak_from.lock()) { - 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(); + if (from->impl->previous_fiber == nullptr) { + ASSERT_MSG(false, "previous_fiber is nullptr!"); + return; } + from->impl->previous_fiber->impl->context = transfer.fctx; + from->impl->previous_fiber->impl->guard.unlock(); + from->impl->previous_fiber.reset(); } } std::shared_ptr Fiber::ThreadToFiber() { - return std::shared_ptr{new Fiber()}; + std::shared_ptr fiber = std::shared_ptr{new Fiber()}; + fiber->impl->guard.lock(); + fiber->impl->is_thread_fiber = true; + return fiber; } } // namespace Common -- cgit v1.2.3