aboutsummaryrefslogtreecommitdiff
path: root/src/common/fiber.cpp
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2025-12-29 20:37:49 +0100
committercrueter <crueter@eden-emu.dev>2025-12-29 20:37:49 +0100
commitb53aa06505b1e1d32a597440c1812b1a5317ef35 (patch)
treebb6c942cd22164491fd311c54ed8335286f9f913 /src/common/fiber.cpp
parentb95c4d2d5d0cce6cc266027b6661020e9e5a2256 (diff)
[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 <lizzie@eden-emu.dev> Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2665 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: Maufeat <sahyno1996@gmail.com> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
Diffstat (limited to 'src/common/fiber.cpp')
-rw-r--r--src/common/fiber.cpp157
1 files changed, 88 insertions, 69 deletions
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 <boost/context/detail/fcontext.hpp>
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<u8> stack;
+ VirtualBuffer<u8> rewind_stack;
std::mutex guard;
- bool released{};
- bool is_thread_fiber{};
- Fiber* next_fiber{};
- Fiber** next_fiber_ptr;
std::function<void()> entry_point;
+ std::function<void()> rewind_point;
+ std::shared_ptr<Fiber> 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<FiberImpl>()} {
- impl->is_thread_fiber = true;
+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(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func);
- 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);
+ 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<FiberImpl>()} {}
+
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<Fiber> 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> Fiber::ThreadToFiber() {
- return std::shared_ptr<Fiber>{new Fiber()};
+ std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
+ fiber->impl->guard.lock();
+ fiber->impl->is_thread_fiber = true;
+ return fiber;
}
} // namespace Common