summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar liamwhite2022-07-05 18:20:39 -0400
committerGravatar GitHub2022-07-05 18:20:39 -0400
commit07e3c56f0de7a1567b1ae443abb64b767a31ed8c (patch)
tree3bd7d56181d79c69988d3f6d1310d9137cbb482f
parentMerge pull request #8477 from Docteh/less_global (diff)
parentcommon/fiber: make fibers easier to use (diff)
downloadyuzu-07e3c56f0de7a1567b1ae443abb64b767a31ed8c.tar.gz
yuzu-07e3c56f0de7a1567b1ae443abb64b767a31ed8c.tar.xz
yuzu-07e3c56f0de7a1567b1ae443abb64b767a31ed8c.zip
Merge pull request #8532 from liamwhite/fiber-supplements
common/fiber: make fibers easier to use
-rw-r--r--src/common/fiber.cpp21
-rw-r--r--src/common/fiber.h7
-rw-r--r--src/core/cpu_manager.cpp51
-rw-r--r--src/core/cpu_manager.h21
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp7
-rw-r--r--src/core/hle/kernel/k_scheduler.h1
-rw-r--r--src/core/hle/kernel/k_thread.cpp15
-rw-r--r--src/core/hle/kernel/k_thread.h3
-rw-r--r--src/tests/common/fibers.cpp123
9 files changed, 79 insertions, 170 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index f9aeb692a..bc92b360b 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -20,10 +20,8 @@ struct Fiber::FiberImpl {
20 VirtualBuffer<u8> rewind_stack; 20 VirtualBuffer<u8> rewind_stack;
21 21
22 std::mutex guard; 22 std::mutex guard;
23 std::function<void(void*)> entry_point; 23 std::function<void()> entry_point;
24 std::function<void(void*)> rewind_point; 24 std::function<void()> rewind_point;
25 void* rewind_parameter{};
26 void* start_parameter{};
27 std::shared_ptr<Fiber> previous_fiber; 25 std::shared_ptr<Fiber> previous_fiber;
28 bool is_thread_fiber{}; 26 bool is_thread_fiber{};
29 bool released{}; 27 bool released{};
@@ -34,13 +32,8 @@ struct Fiber::FiberImpl {
34 boost::context::detail::fcontext_t rewind_context{}; 32 boost::context::detail::fcontext_t rewind_context{};
35}; 33};
36 34
37void Fiber::SetStartParameter(void* new_parameter) { 35void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
38 impl->start_parameter = new_parameter;
39}
40
41void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
42 impl->rewind_point = std::move(rewind_func); 36 impl->rewind_point = std::move(rewind_func);
43 impl->rewind_parameter = rewind_param;
44} 37}
45 38
46void Fiber::Start(boost::context::detail::transfer_t& transfer) { 39void Fiber::Start(boost::context::detail::transfer_t& transfer) {
@@ -48,7 +41,7 @@ void Fiber::Start(boost::context::detail::transfer_t& transfer) {
48 impl->previous_fiber->impl->context = transfer.fctx; 41 impl->previous_fiber->impl->context = transfer.fctx;
49 impl->previous_fiber->impl->guard.unlock(); 42 impl->previous_fiber->impl->guard.unlock();
50 impl->previous_fiber.reset(); 43 impl->previous_fiber.reset();
51 impl->entry_point(impl->start_parameter); 44 impl->entry_point();
52 UNREACHABLE(); 45 UNREACHABLE();
53} 46}
54 47
@@ -59,7 +52,7 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
59 u8* tmp = impl->stack_limit; 52 u8* tmp = impl->stack_limit;
60 impl->stack_limit = impl->rewind_stack_limit; 53 impl->stack_limit = impl->rewind_stack_limit;
61 impl->rewind_stack_limit = tmp; 54 impl->rewind_stack_limit = tmp;
62 impl->rewind_point(impl->rewind_parameter); 55 impl->rewind_point();
63 UNREACHABLE(); 56 UNREACHABLE();
64} 57}
65 58
@@ -73,10 +66,8 @@ void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
73 fiber->OnRewind(transfer); 66 fiber->OnRewind(transfer);
74} 67}
75 68
76Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) 69Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
77 : impl{std::make_unique<FiberImpl>()} {
78 impl->entry_point = std::move(entry_point_func); 70 impl->entry_point = std::move(entry_point_func);
79 impl->start_parameter = start_parameter;
80 impl->stack_limit = impl->stack.data(); 71 impl->stack_limit = impl->stack.data();
81 impl->rewind_stack_limit = impl->rewind_stack.data(); 72 impl->rewind_stack_limit = impl->rewind_stack.data();
82 u8* stack_base = impl->stack_limit + default_stack_size; 73 u8* stack_base = impl->stack_limit + default_stack_size;
diff --git a/src/common/fiber.h b/src/common/fiber.h
index 873604bc6..f24d333a3 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -29,7 +29,7 @@ namespace Common {
29 */ 29 */
30class Fiber { 30class Fiber {
31public: 31public:
32 Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter); 32 Fiber(std::function<void()>&& entry_point_func);
33 ~Fiber(); 33 ~Fiber();
34 34
35 Fiber(const Fiber&) = delete; 35 Fiber(const Fiber&) = delete;
@@ -43,16 +43,13 @@ public:
43 static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); 43 static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
44 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); 44 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
45 45
46 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); 46 void SetRewindPoint(std::function<void()>&& rewind_func);
47 47
48 void Rewind(); 48 void Rewind();
49 49
50 /// Only call from main thread's fiber 50 /// Only call from main thread's fiber
51 void Exit(); 51 void Exit();
52 52
53 /// Changes the start parameter of the fiber. Has no effect if the fiber already started
54 void SetStartParameter(void* new_parameter);
55
56private: 53private:
57 Fiber(); 54 Fiber();
58 55
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 9fc78f033..37d3d83b9 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
41 } 41 }
42} 42}
43 43
44std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { 44void CpuManager::GuestThreadFunction() {
45 return GuestThreadFunction; 45 if (is_multicore) {
46} 46 MultiCoreRunGuestThread();
47
48std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
49 return IdleThreadFunction;
50}
51
52std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
53 return ShutdownThreadFunction;
54}
55
56void CpuManager::GuestThreadFunction(void* cpu_manager_) {
57 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
58 if (cpu_manager->is_multicore) {
59 cpu_manager->MultiCoreRunGuestThread();
60 } else { 47 } else {
61 cpu_manager->SingleCoreRunGuestThread(); 48 SingleCoreRunGuestThread();
62 } 49 }
63} 50}
64 51
65void CpuManager::GuestRewindFunction(void* cpu_manager_) { 52void CpuManager::GuestRewindFunction() {
66 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 53 if (is_multicore) {
67 if (cpu_manager->is_multicore) { 54 MultiCoreRunGuestLoop();
68 cpu_manager->MultiCoreRunGuestLoop();
69 } else { 55 } else {
70 cpu_manager->SingleCoreRunGuestLoop(); 56 SingleCoreRunGuestLoop();
71 } 57 }
72} 58}
73 59
74void CpuManager::IdleThreadFunction(void* cpu_manager_) { 60void CpuManager::IdleThreadFunction() {
75 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 61 if (is_multicore) {
76 if (cpu_manager->is_multicore) { 62 MultiCoreRunIdleThread();
77 cpu_manager->MultiCoreRunIdleThread();
78 } else { 63 } else {
79 cpu_manager->SingleCoreRunIdleThread(); 64 SingleCoreRunIdleThread();
80 } 65 }
81} 66}
82 67
83void CpuManager::ShutdownThreadFunction(void* cpu_manager) { 68void CpuManager::ShutdownThreadFunction() {
84 static_cast<CpuManager*>(cpu_manager)->ShutdownThread(); 69 ShutdownThread();
85}
86
87void* CpuManager::GetStartFuncParameter() {
88 return this;
89} 70}
90 71
91/////////////////////////////////////////////////////////////////////////////// 72///////////////////////////////////////////////////////////////////////////////
@@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
97 kernel.CurrentScheduler()->OnThreadStart(); 78 kernel.CurrentScheduler()->OnThreadStart();
98 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); 79 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
99 auto& host_context = thread->GetHostContext(); 80 auto& host_context = thread->GetHostContext();
100 host_context->SetRewindPoint(GuestRewindFunction, this); 81 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
101 MultiCoreRunGuestLoop(); 82 MultiCoreRunGuestLoop();
102} 83}
103 84
@@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
134 kernel.CurrentScheduler()->OnThreadStart(); 115 kernel.CurrentScheduler()->OnThreadStart();
135 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); 116 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
136 auto& host_context = thread->GetHostContext(); 117 auto& host_context = thread->GetHostContext();
137 host_context->SetRewindPoint(GuestRewindFunction, this); 118 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
138 SingleCoreRunGuestLoop(); 119 SingleCoreRunGuestLoop();
139} 120}
140 121
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index f0751fc58..76dc58ee1 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -50,10 +50,15 @@ public:
50 void Initialize(); 50 void Initialize();
51 void Shutdown(); 51 void Shutdown();
52 52
53 static std::function<void(void*)> GetGuestThreadStartFunc(); 53 std::function<void()> GetGuestThreadStartFunc() {
54 static std::function<void(void*)> GetIdleThreadStartFunc(); 54 return [this] { GuestThreadFunction(); };
55 static std::function<void(void*)> GetShutdownThreadStartFunc(); 55 }
56 void* GetStartFuncParameter(); 56 std::function<void()> GetIdleThreadStartFunc() {
57 return [this] { IdleThreadFunction(); };
58 }
59 std::function<void()> GetShutdownThreadStartFunc() {
60 return [this] { ShutdownThreadFunction(); };
61 }
57 62
58 void PreemptSingleCore(bool from_running_enviroment = true); 63 void PreemptSingleCore(bool from_running_enviroment = true);
59 64
@@ -62,10 +67,10 @@ public:
62 } 67 }
63 68
64private: 69private:
65 static void GuestThreadFunction(void* cpu_manager); 70 void GuestThreadFunction();
66 static void GuestRewindFunction(void* cpu_manager); 71 void GuestRewindFunction();
67 static void IdleThreadFunction(void* cpu_manager); 72 void IdleThreadFunction();
68 static void ShutdownThreadFunction(void* cpu_manager); 73 void ShutdownThreadFunction();
69 74
70 void MultiCoreRunGuestThread(); 75 void MultiCoreRunGuestThread();
71 void MultiCoreRunGuestLoop(); 76 void MultiCoreRunGuestLoop();
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d586b3f5c..d599d2bcb 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
622} 622}
623 623
624KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} { 624KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
625 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); 625 switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
626 state.needs_scheduling.store(true); 626 state.needs_scheduling.store(true);
627 state.interrupt_task_thread_runnable = false; 627 state.interrupt_task_thread_runnable = false;
628 state.should_count_idle = false; 628 state.should_count_idle = false;
@@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
778 next_scheduler.SwitchContextStep2(); 778 next_scheduler.SwitchContextStep2();
779} 779}
780 780
781void KScheduler::OnSwitch(void* this_scheduler) {
782 KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
783 sched->SwitchToCurrent();
784}
785
786void KScheduler::SwitchToCurrent() { 781void KScheduler::SwitchToCurrent() {
787 while (true) { 782 while (true) {
788 { 783 {
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index cc3da33f5..6a4760eca 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -170,7 +170,6 @@ private:
170 */ 170 */
171 void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); 171 void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
172 172
173 static void OnSwitch(void* this_scheduler);
174 void SwitchToCurrent(); 173 void SwitchToCurrent();
175 174
176 KThread* prev_thread{}; 175 KThread* prev_thread{};
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 8d7faa662..23bf7425a 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -246,14 +246,12 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
246 246
247Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, 247Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
248 VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, 248 VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
249 ThreadType type, std::function<void(void*)>&& init_func, 249 ThreadType type, std::function<void()>&& init_func) {
250 void* init_func_parameter) {
251 // Initialize the thread. 250 // Initialize the thread.
252 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); 251 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
253 252
254 // Initialize emulation parameters. 253 // Initialize emulation parameters.
255 thread->host_context = 254 thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
256 std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
257 thread->is_single_core = !Settings::values.use_multi_core.GetValue(); 255 thread->is_single_core = !Settings::values.use_multi_core.GetValue();
258 256
259 return ResultSuccess; 257 return ResultSuccess;
@@ -265,15 +263,13 @@ Result KThread::InitializeDummyThread(KThread* thread) {
265 263
266Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { 264Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
267 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, 265 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
268 Core::CpuManager::GetIdleThreadStartFunc(), 266 system.GetCpuManager().GetIdleThreadStartFunc());
269 system.GetCpuManager().GetStartFuncParameter());
270} 267}
271 268
272Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, 269Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
273 KThreadFunction func, uintptr_t arg, s32 virt_core) { 270 KThreadFunction func, uintptr_t arg, s32 virt_core) {
274 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, 271 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
275 Core::CpuManager::GetShutdownThreadStartFunc(), 272 system.GetCpuManager().GetShutdownThreadStartFunc());
276 system.GetCpuManager().GetStartFuncParameter());
277} 273}
278 274
279Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, 275Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
@@ -281,8 +277,7 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
281 KProcess* owner) { 277 KProcess* owner) {
282 system.Kernel().GlobalSchedulerContext().AddThread(thread); 278 system.Kernel().GlobalSchedulerContext().AddThread(thread);
283 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, 279 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
284 ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), 280 ThreadType::User, system.GetCpuManager().GetGuestThreadStartFunc());
285 system.GetCpuManager().GetStartFuncParameter());
286} 281}
287 282
288void KThread::PostDestroy(uintptr_t arg) { 283void KThread::PostDestroy(uintptr_t arg) {
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 94c4cd1c8..28cd7ecb0 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -729,8 +729,7 @@ private:
729 [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func, 729 [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
730 uintptr_t arg, VAddr user_stack_top, s32 prio, 730 uintptr_t arg, VAddr user_stack_top, s32 prio,
731 s32 core, KProcess* owner, ThreadType type, 731 s32 core, KProcess* owner, ThreadType type,
732 std::function<void(void*)>&& init_func, 732 std::function<void()>&& init_func);
733 void* init_func_parameter);
734 733
735 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread); 734 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
736 735
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp
index cfc84d423..4e29f9199 100644
--- a/src/tests/common/fibers.cpp
+++ b/src/tests/common/fibers.cpp
@@ -43,7 +43,15 @@ class TestControl1 {
43public: 43public:
44 TestControl1() = default; 44 TestControl1() = default;
45 45
46 void DoWork(); 46 void DoWork() {
47 const u32 id = thread_ids.Get();
48 u32 value = items[id];
49 for (u32 i = 0; i < id; i++) {
50 value++;
51 }
52 results[id] = value;
53 Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
54 }
47 55
48 void ExecuteThread(u32 id); 56 void ExecuteThread(u32 id);
49 57
@@ -54,35 +62,16 @@ public:
54 std::vector<u32> results; 62 std::vector<u32> results;
55}; 63};
56 64
57static void WorkControl1(void* control) {
58 auto* test_control = static_cast<TestControl1*>(control);
59 test_control->DoWork();
60}
61
62void TestControl1::DoWork() {
63 const u32 id = thread_ids.Get();
64 u32 value = items[id];
65 for (u32 i = 0; i < id; i++) {
66 value++;
67 }
68 results[id] = value;
69 Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
70}
71
72void TestControl1::ExecuteThread(u32 id) { 65void TestControl1::ExecuteThread(u32 id) {
73 thread_ids.Register(id); 66 thread_ids.Register(id);
74 auto thread_fiber = Fiber::ThreadToFiber(); 67 auto thread_fiber = Fiber::ThreadToFiber();
75 thread_fibers[id] = thread_fiber; 68 thread_fibers[id] = thread_fiber;
76 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); 69 work_fibers[id] = std::make_shared<Fiber>([this] { DoWork(); });
77 items[id] = rand() % 256; 70 items[id] = rand() % 256;
78 Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); 71 Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
79 thread_fibers[id]->Exit(); 72 thread_fibers[id]->Exit();
80} 73}
81 74
82static void ThreadStart1(u32 id, TestControl1& test_control) {
83 test_control.ExecuteThread(id);
84}
85
86/** This test checks for fiber setup configuration and validates that fibers are 75/** This test checks for fiber setup configuration and validates that fibers are
87 * doing all the work required. 76 * doing all the work required.
88 */ 77 */
@@ -95,7 +84,7 @@ TEST_CASE("Fibers::Setup", "[common]") {
95 test_control.results.resize(num_threads, 0); 84 test_control.results.resize(num_threads, 0);
96 std::vector<std::thread> threads; 85 std::vector<std::thread> threads;
97 for (u32 i = 0; i < num_threads; i++) { 86 for (u32 i = 0; i < num_threads; i++) {
98 threads.emplace_back(ThreadStart1, i, std::ref(test_control)); 87 threads.emplace_back([&test_control, i] { test_control.ExecuteThread(i); });
99 } 88 }
100 for (u32 i = 0; i < num_threads; i++) { 89 for (u32 i = 0; i < num_threads; i++) {
101 threads[i].join(); 90 threads[i].join();
@@ -167,21 +156,6 @@ public:
167 std::shared_ptr<Common::Fiber> fiber3; 156 std::shared_ptr<Common::Fiber> fiber3;
168}; 157};
169 158
170static void WorkControl2_1(void* control) {
171 auto* test_control = static_cast<TestControl2*>(control);
172 test_control->DoWork1();
173}
174
175static void WorkControl2_2(void* control) {
176 auto* test_control = static_cast<TestControl2*>(control);
177 test_control->DoWork2();
178}
179
180static void WorkControl2_3(void* control) {
181 auto* test_control = static_cast<TestControl2*>(control);
182 test_control->DoWork3();
183}
184
185void TestControl2::ExecuteThread(u32 id) { 159void TestControl2::ExecuteThread(u32 id) {
186 thread_ids.Register(id); 160 thread_ids.Register(id);
187 auto thread_fiber = Fiber::ThreadToFiber(); 161 auto thread_fiber = Fiber::ThreadToFiber();
@@ -193,18 +167,6 @@ void TestControl2::Exit() {
193 thread_fibers[id]->Exit(); 167 thread_fibers[id]->Exit();
194} 168}
195 169
196static void ThreadStart2_1(u32 id, TestControl2& test_control) {
197 test_control.ExecuteThread(id);
198 test_control.CallFiber1();
199 test_control.Exit();
200}
201
202static void ThreadStart2_2(u32 id, TestControl2& test_control) {
203 test_control.ExecuteThread(id);
204 test_control.CallFiber2();
205 test_control.Exit();
206}
207
208/** This test checks for fiber thread exchange configuration and validates that fibers are 170/** This test checks for fiber thread exchange configuration and validates that fibers are
209 * that a fiber has been successfully transferred from one thread to another and that the TLS 171 * that a fiber has been successfully transferred from one thread to another and that the TLS
210 * region of the thread is kept while changing fibers. 172 * region of the thread is kept while changing fibers.
@@ -212,14 +174,19 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) {
212TEST_CASE("Fibers::InterExchange", "[common]") { 174TEST_CASE("Fibers::InterExchange", "[common]") {
213 TestControl2 test_control{}; 175 TestControl2 test_control{};
214 test_control.thread_fibers.resize(2); 176 test_control.thread_fibers.resize(2);
215 test_control.fiber1 = 177 test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
216 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_1}, &test_control); 178 test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
217 test_control.fiber2 = 179 test_control.fiber3 = std::make_shared<Fiber>([&test_control] { test_control.DoWork3(); });
218 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_2}, &test_control); 180 std::thread thread1{[&test_control] {
219 test_control.fiber3 = 181 test_control.ExecuteThread(0);
220 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_3}, &test_control); 182 test_control.CallFiber1();
221 std::thread thread1(ThreadStart2_1, 0, std::ref(test_control)); 183 test_control.Exit();
222 std::thread thread2(ThreadStart2_2, 1, std::ref(test_control)); 184 }};
185 std::thread thread2{[&test_control] {
186 test_control.ExecuteThread(1);
187 test_control.CallFiber2();
188 test_control.Exit();
189 }};
223 thread1.join(); 190 thread1.join();
224 thread2.join(); 191 thread2.join();
225 REQUIRE(test_control.assert1); 192 REQUIRE(test_control.assert1);
@@ -270,16 +237,6 @@ public:
270 std::shared_ptr<Common::Fiber> fiber2; 237 std::shared_ptr<Common::Fiber> fiber2;
271}; 238};
272 239
273static void WorkControl3_1(void* control) {
274 auto* test_control = static_cast<TestControl3*>(control);
275 test_control->DoWork1();
276}
277
278static void WorkControl3_2(void* control) {
279 auto* test_control = static_cast<TestControl3*>(control);
280 test_control->DoWork2();
281}
282
283void TestControl3::ExecuteThread(u32 id) { 240void TestControl3::ExecuteThread(u32 id) {
284 thread_ids.Register(id); 241 thread_ids.Register(id);
285 auto thread_fiber = Fiber::ThreadToFiber(); 242 auto thread_fiber = Fiber::ThreadToFiber();
@@ -291,12 +248,6 @@ void TestControl3::Exit() {
291 thread_fibers[id]->Exit(); 248 thread_fibers[id]->Exit();
292} 249}
293 250
294static void ThreadStart3(u32 id, TestControl3& test_control) {
295 test_control.ExecuteThread(id);
296 test_control.CallFiber1();
297 test_control.Exit();
298}
299
300/** This test checks for one two threads racing for starting the same fiber. 251/** This test checks for one two threads racing for starting the same fiber.
301 * It checks execution occurred in an ordered manner and by no time there were 252 * It checks execution occurred in an ordered manner and by no time there were
302 * two contexts at the same time. 253 * two contexts at the same time.
@@ -304,12 +255,15 @@ static void ThreadStart3(u32 id, TestControl3& test_control) {
304TEST_CASE("Fibers::StartRace", "[common]") { 255TEST_CASE("Fibers::StartRace", "[common]") {
305 TestControl3 test_control{}; 256 TestControl3 test_control{};
306 test_control.thread_fibers.resize(2); 257 test_control.thread_fibers.resize(2);
307 test_control.fiber1 = 258 test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
308 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_1}, &test_control); 259 test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
309 test_control.fiber2 = 260 const auto race_function{[&test_control](u32 id) {
310 std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_2}, &test_control); 261 test_control.ExecuteThread(id);
311 std::thread thread1(ThreadStart3, 0, std::ref(test_control)); 262 test_control.CallFiber1();
312 std::thread thread2(ThreadStart3, 1, std::ref(test_control)); 263 test_control.Exit();
264 }};
265 std::thread thread1([&] { race_function(0); });
266 std::thread thread2([&] { race_function(1); });
313 thread1.join(); 267 thread1.join();
314 thread2.join(); 268 thread2.join();
315 REQUIRE(test_control.value1 == 1); 269 REQUIRE(test_control.value1 == 1);
@@ -319,12 +273,10 @@ TEST_CASE("Fibers::StartRace", "[common]") {
319 273
320class TestControl4; 274class TestControl4;
321 275
322static void WorkControl4(void* control);
323
324class TestControl4 { 276class TestControl4 {
325public: 277public:
326 TestControl4() { 278 TestControl4() {
327 fiber1 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl4}, this); 279 fiber1 = std::make_shared<Fiber>([this] { DoWork(); });
328 goal_reached = false; 280 goal_reached = false;
329 rewinded = false; 281 rewinded = false;
330 } 282 }
@@ -336,7 +288,7 @@ public:
336 } 288 }
337 289
338 void DoWork() { 290 void DoWork() {
339 fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); 291 fiber1->SetRewindPoint([this] { DoWork(); });
340 if (rewinded) { 292 if (rewinded) {
341 goal_reached = true; 293 goal_reached = true;
342 Fiber::YieldTo(fiber1, *thread_fiber); 294 Fiber::YieldTo(fiber1, *thread_fiber);
@@ -351,11 +303,6 @@ public:
351 bool rewinded; 303 bool rewinded;
352}; 304};
353 305
354static void WorkControl4(void* control) {
355 auto* test_control = static_cast<TestControl4*>(control);
356 test_control->DoWork();
357}
358
359TEST_CASE("Fibers::Rewind", "[common]") { 306TEST_CASE("Fibers::Rewind", "[common]") {
360 TestControl4 test_control{}; 307 TestControl4 test_control{};
361 test_control.Execute(); 308 test_control.Execute();