Merge pull request #4899 from lioncash/fiberimpl

common/fiber: Move all member variables into impl class
This commit is contained in:
bunnei 2020-11-06 20:01:03 -08:00 committed by GitHub
commit f6a89edb67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 89 deletions

View File

@ -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;
} }

View File

@ -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