common/fiber: Move all member variables into impl class
Hides all of the implementation details for users of the class. This has the benefit of reducing includes and also making the fiber classes movable again.
This commit is contained in:
parent
91a45834fd
commit
00fb79b2f3
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/fiber.h"
|
#include "common/fiber.h"
|
||||||
|
#include "common/spin_lock.h"
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
#if defined(_WIN32) || defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
|
@ -14,18 +16,45 @@ namespace Common {
|
||||||
|
|
||||||
constexpr std::size_t default_stack_size = 256 * 1024; // 256kb
|
constexpr std::size_t default_stack_size = 256 * 1024; // 256kb
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
struct Fiber::FiberImpl {
|
struct Fiber::FiberImpl {
|
||||||
|
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{};
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(WIN32)
|
||||||
LPVOID handle = nullptr;
|
LPVOID handle = nullptr;
|
||||||
LPVOID rewind_handle = nullptr;
|
LPVOID rewind_handle = nullptr;
|
||||||
|
#else
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Fiber::SetStartParameter(void* new_parameter) {
|
||||||
|
impl->start_parameter = new_parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
||||||
|
impl->rewind_point = std::move(rewind_func);
|
||||||
|
impl->rewind_parameter = rewind_param;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(WIN32)
|
||||||
|
|
||||||
void Fiber::Start() {
|
void Fiber::Start() {
|
||||||
ASSERT(previous_fiber != nullptr);
|
ASSERT(impl->previous_fiber != nullptr);
|
||||||
previous_fiber->guard.unlock();
|
impl->previous_fiber->impl->guard.unlock();
|
||||||
previous_fiber.reset();
|
impl->previous_fiber.reset();
|
||||||
entry_point(start_parameter);
|
impl->entry_point(impl->start_parameter);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,58 +63,54 @@ void Fiber::OnRewind() {
|
||||||
DeleteFiber(impl->handle);
|
DeleteFiber(impl->handle);
|
||||||
impl->handle = impl->rewind_handle;
|
impl->handle = impl->rewind_handle;
|
||||||
impl->rewind_handle = nullptr;
|
impl->rewind_handle = nullptr;
|
||||||
rewind_point(rewind_parameter);
|
impl->rewind_point(impl->rewind_parameter);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::FiberStartFunc(void* fiber_parameter) {
|
void Fiber::FiberStartFunc(void* fiber_parameter) {
|
||||||
auto fiber = static_cast<Fiber*>(fiber_parameter);
|
auto* fiber = static_cast<Fiber*>(fiber_parameter);
|
||||||
fiber->Start();
|
fiber->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::RewindStartFunc(void* fiber_parameter) {
|
void Fiber::RewindStartFunc(void* fiber_parameter) {
|
||||||
auto fiber = static_cast<Fiber*>(fiber_parameter);
|
auto* fiber = static_cast<Fiber*>(fiber_parameter);
|
||||||
fiber->OnRewind();
|
fiber->OnRewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
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->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
|
impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||||
|
|
||||||
Fiber::~Fiber() {
|
Fiber::~Fiber() {
|
||||||
if (released) {
|
if (impl->released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Make sure the Fiber is not being used
|
// 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");
|
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||||
if (locked) {
|
if (locked) {
|
||||||
guard.unlock();
|
impl->guard.unlock();
|
||||||
}
|
}
|
||||||
DeleteFiber(impl->handle);
|
DeleteFiber(impl->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::Exit() {
|
void Fiber::Exit() {
|
||||||
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
|
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
|
||||||
if (!is_thread_fiber) {
|
if (!impl->is_thread_fiber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ConvertFiberToThread();
|
ConvertFiberToThread();
|
||||||
guard.unlock();
|
impl->guard.unlock();
|
||||||
released = true;
|
impl->released = true;
|
||||||
}
|
|
||||||
|
|
||||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
|
||||||
rewind_point = std::move(rewind_func);
|
|
||||||
rewind_parameter = rewind_param;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::Rewind() {
|
void Fiber::Rewind() {
|
||||||
ASSERT(rewind_point);
|
ASSERT(impl->rewind_point);
|
||||||
ASSERT(impl->rewind_handle == nullptr);
|
ASSERT(impl->rewind_handle == nullptr);
|
||||||
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
|
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
|
||||||
SwitchToFiber(impl->rewind_handle);
|
SwitchToFiber(impl->rewind_handle);
|
||||||
|
@ -94,39 +119,30 @@ void Fiber::Rewind() {
|
||||||
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(from != nullptr, "Yielding fiber is null!");
|
||||||
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
||||||
to->guard.lock();
|
to->impl->guard.lock();
|
||||||
to->previous_fiber = from;
|
to->impl->previous_fiber = from;
|
||||||
SwitchToFiber(to->impl->handle);
|
SwitchToFiber(to->impl->handle);
|
||||||
ASSERT(from->previous_fiber != nullptr);
|
ASSERT(from->impl->previous_fiber != nullptr);
|
||||||
from->previous_fiber->guard.unlock();
|
from->impl->previous_fiber->impl->guard.unlock();
|
||||||
from->previous_fiber.reset();
|
from->impl->previous_fiber.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||||
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||||
fiber->guard.lock();
|
fiber->impl->guard.lock();
|
||||||
fiber->impl->handle = ConvertThreadToFiber(nullptr);
|
fiber->impl->handle = ConvertThreadToFiber(nullptr);
|
||||||
fiber->is_thread_fiber = true;
|
fiber->impl->is_thread_fiber = true;
|
||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#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) {
|
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||||
ASSERT(previous_fiber != nullptr);
|
ASSERT(impl->previous_fiber != nullptr);
|
||||||
previous_fiber->impl->context = transfer.fctx;
|
impl->previous_fiber->impl->context = transfer.fctx;
|
||||||
previous_fiber->guard.unlock();
|
impl->previous_fiber->impl->guard.unlock();
|
||||||
previous_fiber.reset();
|
impl->previous_fiber.reset();
|
||||||
entry_point(start_parameter);
|
impl->entry_point(impl->start_parameter);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,23 +153,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
|
||||||
u8* tmp = impl->stack_limit;
|
u8* tmp = impl->stack_limit;
|
||||||
impl->stack_limit = impl->rewind_stack_limit;
|
impl->stack_limit = impl->rewind_stack_limit;
|
||||||
impl->rewind_stack_limit = tmp;
|
impl->rewind_stack_limit = tmp;
|
||||||
rewind_point(rewind_parameter);
|
impl->rewind_point(impl->rewind_parameter);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
|
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);
|
fiber->Start(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::RewindStartFunc(boost::context::detail::transfer_t 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->OnRewind(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
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->stack_limit = impl->stack.data();
|
||||||
impl->rewind_stack_limit = impl->rewind_stack.data();
|
impl->rewind_stack_limit = impl->rewind_stack.data();
|
||||||
u8* stack_base = impl->stack_limit + default_stack_size;
|
u8* stack_base = impl->stack_limit + default_stack_size;
|
||||||
|
@ -161,37 +178,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete
|
||||||
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
|
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
|
||||||
rewind_point = std::move(rewind_func);
|
|
||||||
rewind_parameter = rewind_param;
|
|
||||||
}
|
|
||||||
|
|
||||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||||
|
|
||||||
Fiber::~Fiber() {
|
Fiber::~Fiber() {
|
||||||
if (released) {
|
if (impl->released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Make sure the Fiber is not being used
|
// 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");
|
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||||
if (locked) {
|
if (locked) {
|
||||||
guard.unlock();
|
impl->guard.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::Exit() {
|
void Fiber::Exit() {
|
||||||
|
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
|
||||||
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
|
if (!impl->is_thread_fiber) {
|
||||||
if (!is_thread_fiber) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
guard.unlock();
|
impl->guard.unlock();
|
||||||
released = true;
|
impl->released = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::Rewind() {
|
void Fiber::Rewind() {
|
||||||
ASSERT(rewind_point);
|
ASSERT(impl->rewind_point);
|
||||||
ASSERT(impl->rewind_context == nullptr);
|
ASSERT(impl->rewind_context == nullptr);
|
||||||
u8* stack_base = impl->rewind_stack_limit + default_stack_size;
|
u8* stack_base = impl->rewind_stack_limit + default_stack_size;
|
||||||
impl->rewind_context =
|
impl->rewind_context =
|
||||||
|
@ -202,19 +213,19 @@ void Fiber::Rewind() {
|
||||||
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(from != nullptr, "Yielding fiber is null!");
|
||||||
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
||||||
to->guard.lock();
|
to->impl->guard.lock();
|
||||||
to->previous_fiber = from;
|
to->impl->previous_fiber = from;
|
||||||
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
|
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
|
||||||
ASSERT(from->previous_fiber != nullptr);
|
ASSERT(from->impl->previous_fiber != nullptr);
|
||||||
from->previous_fiber->impl->context = transfer.fctx;
|
from->impl->previous_fiber->impl->context = transfer.fctx;
|
||||||
from->previous_fiber->guard.unlock();
|
from->impl->previous_fiber->impl->guard.unlock();
|
||||||
from->previous_fiber.reset();
|
from->impl->previous_fiber.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||||
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||||
fiber->guard.lock();
|
fiber->impl->guard.lock();
|
||||||
fiber->is_thread_fiber = true;
|
fiber->impl->is_thread_fiber = true;
|
||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,6 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/spin_lock.h"
|
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(WIN32)
|
#if !defined(_WIN32) && !defined(WIN32)
|
||||||
namespace boost::context::detail {
|
namespace boost::context::detail {
|
||||||
struct transfer_t;
|
struct transfer_t;
|
||||||
|
@ -41,8 +38,8 @@ public:
|
||||||
Fiber(const Fiber&) = delete;
|
Fiber(const Fiber&) = delete;
|
||||||
Fiber& operator=(const Fiber&) = delete;
|
Fiber& operator=(const Fiber&) = delete;
|
||||||
|
|
||||||
Fiber(Fiber&&) = delete;
|
Fiber(Fiber&&) = default;
|
||||||
Fiber& operator=(Fiber&&) = delete;
|
Fiber& operator=(Fiber&&) = default;
|
||||||
|
|
||||||
/// Yields control from Fiber 'from' to Fiber 'to'
|
/// Yields control from Fiber 'from' to Fiber 'to'
|
||||||
/// Fiber 'from' must be the currently running fiber.
|
/// Fiber 'from' must be the currently running fiber.
|
||||||
|
@ -57,9 +54,7 @@ public:
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
|
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
|
||||||
void SetStartParameter(void* new_parameter) {
|
void SetStartParameter(void* new_parameter);
|
||||||
start_parameter = new_parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Fiber();
|
Fiber();
|
||||||
|
@ -77,16 +72,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct FiberImpl;
|
struct FiberImpl;
|
||||||
|
|
||||||
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;
|
|
||||||
std::unique_ptr<FiberImpl> impl;
|
std::unique_ptr<FiberImpl> impl;
|
||||||
bool is_thread_fiber{};
|
|
||||||
bool released{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
Reference in New Issue