mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-22 23:05:40 +01:00
Merge pull request #8532 from liamwhite/fiber-supplements
common/fiber: make fibers easier to use
This commit is contained in:
commit
07e3c56f0d
@ -20,10 +20,8 @@ struct Fiber::FiberImpl {
|
||||
VirtualBuffer<u8> rewind_stack;
|
||||
|
||||
std::mutex guard;
|
||||
std::function<void(void*)> entry_point;
|
||||
std::function<void(void*)> rewind_point;
|
||||
void* rewind_parameter{};
|
||||
void* start_parameter{};
|
||||
std::function<void()> entry_point;
|
||||
std::function<void()> rewind_point;
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
bool is_thread_fiber{};
|
||||
bool released{};
|
||||
@ -34,13 +32,8 @@ struct Fiber::FiberImpl {
|
||||
boost::context::detail::fcontext_t rewind_context{};
|
||||
};
|
||||
|
||||
void Fiber::SetStartParameter(void* new_parameter) {
|
||||
impl->start_parameter = new_parameter;
|
||||
}
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
||||
void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
|
||||
impl->rewind_point = std::move(rewind_func);
|
||||
impl->rewind_parameter = rewind_param;
|
||||
}
|
||||
|
||||
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||
@ -48,7 +41,7 @@ void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||
impl->previous_fiber->impl->context = transfer.fctx;
|
||||
impl->previous_fiber->impl->guard.unlock();
|
||||
impl->previous_fiber.reset();
|
||||
impl->entry_point(impl->start_parameter);
|
||||
impl->entry_point();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@ -59,7 +52,7 @@ 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;
|
||||
impl->rewind_point(impl->rewind_parameter);
|
||||
impl->rewind_point();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@ -73,10 +66,8 @@ void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
|
||||
fiber->OnRewind(transfer);
|
||||
}
|
||||
|
||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
||||
: impl{std::make_unique<FiberImpl>()} {
|
||||
Fiber::Fiber(std::function<void()>&& entry_point_func) : 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;
|
||||
|
@ -29,7 +29,7 @@ namespace Common {
|
||||
*/
|
||||
class Fiber {
|
||||
public:
|
||||
Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter);
|
||||
Fiber(std::function<void()>&& entry_point_func);
|
||||
~Fiber();
|
||||
|
||||
Fiber(const Fiber&) = delete;
|
||||
@ -43,16 +43,13 @@ public:
|
||||
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
|
||||
void SetRewindPoint(std::function<void()>&& rewind_func);
|
||||
|
||||
void Rewind();
|
||||
|
||||
/// Only call from main thread's fiber
|
||||
void Exit();
|
||||
|
||||
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
|
||||
void SetStartParameter(void* new_parameter);
|
||||
|
||||
private:
|
||||
Fiber();
|
||||
|
||||
|
@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
|
||||
return GuestThreadFunction;
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
|
||||
return IdleThreadFunction;
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
|
||||
return ShutdownThreadFunction;
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunGuestThread();
|
||||
void CpuManager::GuestThreadFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestThread();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunGuestThread();
|
||||
SingleCoreRunGuestThread();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestRewindFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunGuestLoop();
|
||||
void CpuManager::GuestRewindFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestLoop();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunGuestLoop();
|
||||
SingleCoreRunGuestLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::IdleThreadFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunIdleThread();
|
||||
void CpuManager::IdleThreadFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunIdleThread();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunIdleThread();
|
||||
SingleCoreRunIdleThread();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
|
||||
static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
|
||||
}
|
||||
|
||||
void* CpuManager::GetStartFuncParameter() {
|
||||
return this;
|
||||
void CpuManager::ShutdownThreadFunction() {
|
||||
ShutdownThread();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
|
||||
auto& host_context = thread->GetHostContext();
|
||||
host_context->SetRewindPoint(GuestRewindFunction, this);
|
||||
host_context->SetRewindPoint([this] { GuestRewindFunction(); });
|
||||
MultiCoreRunGuestLoop();
|
||||
}
|
||||
|
||||
@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
|
||||
auto& host_context = thread->GetHostContext();
|
||||
host_context->SetRewindPoint(GuestRewindFunction, this);
|
||||
host_context->SetRewindPoint([this] { GuestRewindFunction(); });
|
||||
SingleCoreRunGuestLoop();
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,15 @@ public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
static std::function<void(void*)> GetGuestThreadStartFunc();
|
||||
static std::function<void(void*)> GetIdleThreadStartFunc();
|
||||
static std::function<void(void*)> GetShutdownThreadStartFunc();
|
||||
void* GetStartFuncParameter();
|
||||
std::function<void()> GetGuestThreadStartFunc() {
|
||||
return [this] { GuestThreadFunction(); };
|
||||
}
|
||||
std::function<void()> GetIdleThreadStartFunc() {
|
||||
return [this] { IdleThreadFunction(); };
|
||||
}
|
||||
std::function<void()> GetShutdownThreadStartFunc() {
|
||||
return [this] { ShutdownThreadFunction(); };
|
||||
}
|
||||
|
||||
void PreemptSingleCore(bool from_running_enviroment = true);
|
||||
|
||||
@ -62,10 +67,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void GuestThreadFunction(void* cpu_manager);
|
||||
static void GuestRewindFunction(void* cpu_manager);
|
||||
static void IdleThreadFunction(void* cpu_manager);
|
||||
static void ShutdownThreadFunction(void* cpu_manager);
|
||||
void GuestThreadFunction();
|
||||
void GuestRewindFunction();
|
||||
void IdleThreadFunction();
|
||||
void ShutdownThreadFunction();
|
||||
|
||||
void MultiCoreRunGuestThread();
|
||||
void MultiCoreRunGuestLoop();
|
||||
|
@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
||||
}
|
||||
|
||||
KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
|
||||
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
||||
switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
|
||||
state.needs_scheduling.store(true);
|
||||
state.interrupt_task_thread_runnable = false;
|
||||
state.should_count_idle = false;
|
||||
@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
|
||||
next_scheduler.SwitchContextStep2();
|
||||
}
|
||||
|
||||
void KScheduler::OnSwitch(void* this_scheduler) {
|
||||
KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
|
||||
sched->SwitchToCurrent();
|
||||
}
|
||||
|
||||
void KScheduler::SwitchToCurrent() {
|
||||
while (true) {
|
||||
{
|
||||
|
@ -170,7 +170,6 @@ private:
|
||||
*/
|
||||
void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
|
||||
|
||||
static void OnSwitch(void* this_scheduler);
|
||||
void SwitchToCurrent();
|
||||
|
||||
KThread* prev_thread{};
|
||||
|
@ -246,14 +246,12 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
|
||||
|
||||
Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
|
||||
VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
|
||||
ThreadType type, std::function<void(void*)>&& init_func,
|
||||
void* init_func_parameter) {
|
||||
ThreadType type, std::function<void()>&& init_func) {
|
||||
// Initialize the thread.
|
||||
R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
|
||||
|
||||
// Initialize emulation parameters.
|
||||
thread->host_context =
|
||||
std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
|
||||
thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
|
||||
thread->is_single_core = !Settings::values.use_multi_core.GetValue();
|
||||
|
||||
return ResultSuccess;
|
||||
@ -265,15 +263,13 @@ Result KThread::InitializeDummyThread(KThread* thread) {
|
||||
|
||||
Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
|
||||
return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
|
||||
Core::CpuManager::GetIdleThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
system.GetCpuManager().GetIdleThreadStartFunc());
|
||||
}
|
||||
|
||||
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
|
||||
KThreadFunction func, uintptr_t arg, s32 virt_core) {
|
||||
return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
|
||||
Core::CpuManager::GetShutdownThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
system.GetCpuManager().GetShutdownThreadStartFunc());
|
||||
}
|
||||
|
||||
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
|
||||
@ -281,8 +277,7 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
|
||||
KProcess* owner) {
|
||||
system.Kernel().GlobalSchedulerContext().AddThread(thread);
|
||||
return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
|
||||
ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
ThreadType::User, system.GetCpuManager().GetGuestThreadStartFunc());
|
||||
}
|
||||
|
||||
void KThread::PostDestroy(uintptr_t arg) {
|
||||
|
@ -729,8 +729,7 @@ private:
|
||||
[[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
|
||||
uintptr_t arg, VAddr user_stack_top, s32 prio,
|
||||
s32 core, KProcess* owner, ThreadType type,
|
||||
std::function<void(void*)>&& init_func,
|
||||
void* init_func_parameter);
|
||||
std::function<void()>&& init_func);
|
||||
|
||||
static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
|
||||
|
||||
|
@ -43,7 +43,15 @@ class TestControl1 {
|
||||
public:
|
||||
TestControl1() = default;
|
||||
|
||||
void DoWork();
|
||||
void DoWork() {
|
||||
const u32 id = thread_ids.Get();
|
||||
u32 value = items[id];
|
||||
for (u32 i = 0; i < id; i++) {
|
||||
value++;
|
||||
}
|
||||
results[id] = value;
|
||||
Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
|
||||
}
|
||||
|
||||
void ExecuteThread(u32 id);
|
||||
|
||||
@ -54,35 +62,16 @@ public:
|
||||
std::vector<u32> results;
|
||||
};
|
||||
|
||||
static void WorkControl1(void* control) {
|
||||
auto* test_control = static_cast<TestControl1*>(control);
|
||||
test_control->DoWork();
|
||||
}
|
||||
|
||||
void TestControl1::DoWork() {
|
||||
const u32 id = thread_ids.Get();
|
||||
u32 value = items[id];
|
||||
for (u32 i = 0; i < id; i++) {
|
||||
value++;
|
||||
}
|
||||
results[id] = value;
|
||||
Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
|
||||
}
|
||||
|
||||
void TestControl1::ExecuteThread(u32 id) {
|
||||
thread_ids.Register(id);
|
||||
auto thread_fiber = Fiber::ThreadToFiber();
|
||||
thread_fibers[id] = thread_fiber;
|
||||
work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
|
||||
work_fibers[id] = std::make_shared<Fiber>([this] { DoWork(); });
|
||||
items[id] = rand() % 256;
|
||||
Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
|
||||
thread_fibers[id]->Exit();
|
||||
}
|
||||
|
||||
static void ThreadStart1(u32 id, TestControl1& test_control) {
|
||||
test_control.ExecuteThread(id);
|
||||
}
|
||||
|
||||
/** This test checks for fiber setup configuration and validates that fibers are
|
||||
* doing all the work required.
|
||||
*/
|
||||
@ -95,7 +84,7 @@ TEST_CASE("Fibers::Setup", "[common]") {
|
||||
test_control.results.resize(num_threads, 0);
|
||||
std::vector<std::thread> threads;
|
||||
for (u32 i = 0; i < num_threads; i++) {
|
||||
threads.emplace_back(ThreadStart1, i, std::ref(test_control));
|
||||
threads.emplace_back([&test_control, i] { test_control.ExecuteThread(i); });
|
||||
}
|
||||
for (u32 i = 0; i < num_threads; i++) {
|
||||
threads[i].join();
|
||||
@ -167,21 +156,6 @@ public:
|
||||
std::shared_ptr<Common::Fiber> fiber3;
|
||||
};
|
||||
|
||||
static void WorkControl2_1(void* control) {
|
||||
auto* test_control = static_cast<TestControl2*>(control);
|
||||
test_control->DoWork1();
|
||||
}
|
||||
|
||||
static void WorkControl2_2(void* control) {
|
||||
auto* test_control = static_cast<TestControl2*>(control);
|
||||
test_control->DoWork2();
|
||||
}
|
||||
|
||||
static void WorkControl2_3(void* control) {
|
||||
auto* test_control = static_cast<TestControl2*>(control);
|
||||
test_control->DoWork3();
|
||||
}
|
||||
|
||||
void TestControl2::ExecuteThread(u32 id) {
|
||||
thread_ids.Register(id);
|
||||
auto thread_fiber = Fiber::ThreadToFiber();
|
||||
@ -193,18 +167,6 @@ void TestControl2::Exit() {
|
||||
thread_fibers[id]->Exit();
|
||||
}
|
||||
|
||||
static void ThreadStart2_1(u32 id, TestControl2& test_control) {
|
||||
test_control.ExecuteThread(id);
|
||||
test_control.CallFiber1();
|
||||
test_control.Exit();
|
||||
}
|
||||
|
||||
static void ThreadStart2_2(u32 id, TestControl2& test_control) {
|
||||
test_control.ExecuteThread(id);
|
||||
test_control.CallFiber2();
|
||||
test_control.Exit();
|
||||
}
|
||||
|
||||
/** This test checks for fiber thread exchange configuration and validates that fibers are
|
||||
* that a fiber has been successfully transferred from one thread to another and that the TLS
|
||||
* region of the thread is kept while changing fibers.
|
||||
@ -212,14 +174,19 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) {
|
||||
TEST_CASE("Fibers::InterExchange", "[common]") {
|
||||
TestControl2 test_control{};
|
||||
test_control.thread_fibers.resize(2);
|
||||
test_control.fiber1 =
|
||||
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_1}, &test_control);
|
||||
test_control.fiber2 =
|
||||
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_2}, &test_control);
|
||||
test_control.fiber3 =
|
||||
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_3}, &test_control);
|
||||
std::thread thread1(ThreadStart2_1, 0, std::ref(test_control));
|
||||
std::thread thread2(ThreadStart2_2, 1, std::ref(test_control));
|
||||
test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
|
||||
test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
|
||||
test_control.fiber3 = std::make_shared<Fiber>([&test_control] { test_control.DoWork3(); });
|
||||
std::thread thread1{[&test_control] {
|
||||
test_control.ExecuteThread(0);
|
||||
test_control.CallFiber1();
|
||||
test_control.Exit();
|
||||
}};
|
||||
std::thread thread2{[&test_control] {
|
||||
test_control.ExecuteThread(1);
|
||||
test_control.CallFiber2();
|
||||
test_control.Exit();
|
||||
}};
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
REQUIRE(test_control.assert1);
|
||||
@ -270,16 +237,6 @@ public:
|
||||
std::shared_ptr<Common::Fiber> fiber2;
|
||||
};
|
||||
|
||||
static void WorkControl3_1(void* control) {
|
||||
auto* test_control = static_cast<TestControl3*>(control);
|
||||
test_control->DoWork1();
|
||||
}
|
||||
|
||||
static void WorkControl3_2(void* control) {
|
||||
auto* test_control = static_cast<TestControl3*>(control);
|
||||
test_control->DoWork2();
|
||||
}
|
||||
|
||||
void TestControl3::ExecuteThread(u32 id) {
|
||||
thread_ids.Register(id);
|
||||
auto thread_fiber = Fiber::ThreadToFiber();
|
||||
@ -291,12 +248,6 @@ void TestControl3::Exit() {
|
||||
thread_fibers[id]->Exit();
|
||||
}
|
||||
|
||||
static void ThreadStart3(u32 id, TestControl3& test_control) {
|
||||
test_control.ExecuteThread(id);
|
||||
test_control.CallFiber1();
|
||||
test_control.Exit();
|
||||
}
|
||||
|
||||
/** This test checks for one two threads racing for starting the same fiber.
|
||||
* It checks execution occurred in an ordered manner and by no time there were
|
||||
* two contexts at the same time.
|
||||
@ -304,12 +255,15 @@ static void ThreadStart3(u32 id, TestControl3& test_control) {
|
||||
TEST_CASE("Fibers::StartRace", "[common]") {
|
||||
TestControl3 test_control{};
|
||||
test_control.thread_fibers.resize(2);
|
||||
test_control.fiber1 =
|
||||
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_1}, &test_control);
|
||||
test_control.fiber2 =
|
||||
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_2}, &test_control);
|
||||
std::thread thread1(ThreadStart3, 0, std::ref(test_control));
|
||||
std::thread thread2(ThreadStart3, 1, std::ref(test_control));
|
||||
test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
|
||||
test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
|
||||
const auto race_function{[&test_control](u32 id) {
|
||||
test_control.ExecuteThread(id);
|
||||
test_control.CallFiber1();
|
||||
test_control.Exit();
|
||||
}};
|
||||
std::thread thread1([&] { race_function(0); });
|
||||
std::thread thread2([&] { race_function(1); });
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
REQUIRE(test_control.value1 == 1);
|
||||
@ -319,12 +273,10 @@ TEST_CASE("Fibers::StartRace", "[common]") {
|
||||
|
||||
class TestControl4;
|
||||
|
||||
static void WorkControl4(void* control);
|
||||
|
||||
class TestControl4 {
|
||||
public:
|
||||
TestControl4() {
|
||||
fiber1 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl4}, this);
|
||||
fiber1 = std::make_shared<Fiber>([this] { DoWork(); });
|
||||
goal_reached = false;
|
||||
rewinded = false;
|
||||
}
|
||||
@ -336,7 +288,7 @@ public:
|
||||
}
|
||||
|
||||
void DoWork() {
|
||||
fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this);
|
||||
fiber1->SetRewindPoint([this] { DoWork(); });
|
||||
if (rewinded) {
|
||||
goal_reached = true;
|
||||
Fiber::YieldTo(fiber1, *thread_fiber);
|
||||
@ -351,11 +303,6 @@ public:
|
||||
bool rewinded;
|
||||
};
|
||||
|
||||
static void WorkControl4(void* control) {
|
||||
auto* test_control = static_cast<TestControl4*>(control);
|
||||
test_control->DoWork();
|
||||
}
|
||||
|
||||
TEST_CASE("Fibers::Rewind", "[common]") {
|
||||
TestControl4 test_control{};
|
||||
test_control.Execute();
|
||||
|
Loading…
Reference in New Issue
Block a user