diff options
| -rw-r--r-- | src/common/fiber.cpp | 21 | ||||
| -rw-r--r-- | src/common/fiber.h | 7 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 51 | ||||
| -rw-r--r-- | src/core/cpu_manager.h | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 3 | ||||
| -rw-r--r-- | src/tests/common/fibers.cpp | 123 |
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 | ||
| 37 | void Fiber::SetStartParameter(void* new_parameter) { | 35 | void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) { |
| 38 | impl->start_parameter = new_parameter; | ||
| 39 | } | ||
| 40 | |||
| 41 | void 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 | ||
| 46 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { | 39 | void 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 | ||
| 76 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 69 | Fiber::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 | */ |
| 30 | class Fiber { | 30 | class Fiber { |
| 31 | public: | 31 | public: |
| 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 | |||
| 56 | private: | 53 | private: |
| 57 | Fiber(); | 54 | Fiber(); |
| 58 | 55 | ||
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index fd6928105..f184b904b 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 | ||
| 44 | std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { | 44 | void CpuManager::GuestThreadFunction() { |
| 45 | return GuestThreadFunction; | 45 | if (is_multicore) { |
| 46 | } | 46 | MultiCoreRunGuestThread(); |
| 47 | |||
| 48 | std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() { | ||
| 49 | return IdleThreadFunction; | ||
| 50 | } | ||
| 51 | |||
| 52 | std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() { | ||
| 53 | return ShutdownThreadFunction; | ||
| 54 | } | ||
| 55 | |||
| 56 | void 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 | ||
| 65 | void CpuManager::GuestRewindFunction(void* cpu_manager_) { | 52 | void 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 | ||
| 74 | void CpuManager::IdleThreadFunction(void* cpu_manager_) { | 60 | void 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 | ||
| 83 | void CpuManager::ShutdownThreadFunction(void* cpu_manager) { | 68 | void CpuManager::ShutdownThreadFunction() { |
| 84 | static_cast<CpuManager*>(cpu_manager)->ShutdownThread(); | 69 | ShutdownThread(); |
| 85 | } | ||
| 86 | |||
| 87 | void* 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 | ||
| 64 | private: | 69 | private: |
| 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 | ||
| 624 | KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} { | 624 | KScheduler::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 | ||
| 781 | void KScheduler::OnSwitch(void* this_scheduler) { | ||
| 782 | KScheduler* sched = static_cast<KScheduler*>(this_scheduler); | ||
| 783 | sched->SwitchToCurrent(); | ||
| 784 | } | ||
| 785 | |||
| 786 | void KScheduler::SwitchToCurrent() { | 781 | void 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 3f90656ee..bd66bffc4 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h | |||
| @@ -165,7 +165,6 @@ private: | |||
| 165 | */ | 165 | */ |
| 166 | void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); | 166 | void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); |
| 167 | 167 | ||
| 168 | static void OnSwitch(void* this_scheduler); | ||
| 169 | void SwitchToCurrent(); | 168 | void SwitchToCurrent(); |
| 170 | 169 | ||
| 171 | KThread* prev_thread{}; | 170 | 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 | ||
| 247 | Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, | 247 | Result 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 | ||
| 266 | Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 264 | Result 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 | ||
| 272 | Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, | 269 | Result 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 | ||
| 279 | Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, | 275 | Result 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 | ||
| 288 | void KThread::PostDestroy(uintptr_t arg) { | 283 | void 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 { | |||
| 43 | public: | 43 | public: |
| 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 | ||
| 57 | static void WorkControl1(void* control) { | ||
| 58 | auto* test_control = static_cast<TestControl1*>(control); | ||
| 59 | test_control->DoWork(); | ||
| 60 | } | ||
| 61 | |||
| 62 | void 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 | |||
| 72 | void TestControl1::ExecuteThread(u32 id) { | 65 | void 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 | ||
| 82 | static 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 | ||
| 170 | static void WorkControl2_1(void* control) { | ||
| 171 | auto* test_control = static_cast<TestControl2*>(control); | ||
| 172 | test_control->DoWork1(); | ||
| 173 | } | ||
| 174 | |||
| 175 | static void WorkControl2_2(void* control) { | ||
| 176 | auto* test_control = static_cast<TestControl2*>(control); | ||
| 177 | test_control->DoWork2(); | ||
| 178 | } | ||
| 179 | |||
| 180 | static void WorkControl2_3(void* control) { | ||
| 181 | auto* test_control = static_cast<TestControl2*>(control); | ||
| 182 | test_control->DoWork3(); | ||
| 183 | } | ||
| 184 | |||
| 185 | void TestControl2::ExecuteThread(u32 id) { | 159 | void 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 | ||
| 196 | static void ThreadStart2_1(u32 id, TestControl2& test_control) { | ||
| 197 | test_control.ExecuteThread(id); | ||
| 198 | test_control.CallFiber1(); | ||
| 199 | test_control.Exit(); | ||
| 200 | } | ||
| 201 | |||
| 202 | static 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) { | |||
| 212 | TEST_CASE("Fibers::InterExchange", "[common]") { | 174 | TEST_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 | ||
| 273 | static void WorkControl3_1(void* control) { | ||
| 274 | auto* test_control = static_cast<TestControl3*>(control); | ||
| 275 | test_control->DoWork1(); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void WorkControl3_2(void* control) { | ||
| 279 | auto* test_control = static_cast<TestControl3*>(control); | ||
| 280 | test_control->DoWork2(); | ||
| 281 | } | ||
| 282 | |||
| 283 | void TestControl3::ExecuteThread(u32 id) { | 240 | void 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 | ||
| 294 | static 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) { | |||
| 304 | TEST_CASE("Fibers::StartRace", "[common]") { | 255 | TEST_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 | ||
| 320 | class TestControl4; | 274 | class TestControl4; |
| 321 | 275 | ||
| 322 | static void WorkControl4(void* control); | ||
| 323 | |||
| 324 | class TestControl4 { | 276 | class TestControl4 { |
| 325 | public: | 277 | public: |
| 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 | ||
| 354 | static void WorkControl4(void* control) { | ||
| 355 | auto* test_control = static_cast<TestControl4*>(control); | ||
| 356 | test_control->DoWork(); | ||
| 357 | } | ||
| 358 | |||
| 359 | TEST_CASE("Fibers::Rewind", "[common]") { | 306 | TEST_CASE("Fibers::Rewind", "[common]") { |
| 360 | TestControl4 test_control{}; | 307 | TestControl4 test_control{}; |
| 361 | test_control.Execute(); | 308 | test_control.Execute(); |