diff options
| author | 2021-03-08 13:51:37 -0800 | |
|---|---|---|
| committer | 2021-03-08 13:51:37 -0800 | |
| commit | 69ce5e41ebd266b2cd04cb609663eaca21c8ded9 (patch) | |
| tree | ed8f8429c89814266ac72db1fdf7591d03ab4c9a | |
| parent | Merge pull request #6047 from lioncash/dynarmic (diff) | |
| parent | common: Fiber: use a reference for YieldTo. (diff) | |
| download | yuzu-69ce5e41ebd266b2cd04cb609663eaca21c8ded9.tar.gz yuzu-69ce5e41ebd266b2cd04cb609663eaca21c8ded9.tar.xz yuzu-69ce5e41ebd266b2cd04cb609663eaca21c8ded9.zip | |
Merge pull request #6041 from bunnei/fiber-leaks
common: fiber: Use weak_ptr when yielding.
Diffstat (limited to '')
| -rw-r--r-- | src/common/fiber.cpp | 23 | ||||
| -rw-r--r-- | src/common/fiber.h | 2 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 11 | ||||
| -rw-r--r-- | src/tests/common/fibers.cpp | 28 |
5 files changed, 35 insertions, 37 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 3c1eefcb7..39532ff58 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -116,16 +116,19 @@ void Fiber::Rewind() { | |||
| 116 | boost::context::detail::jump_fcontext(impl->rewind_context, this); | 116 | boost::context::detail::jump_fcontext(impl->rewind_context, this); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 119 | void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) { |
| 120 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 120 | to.impl->guard.lock(); |
| 121 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 121 | to.impl->previous_fiber = weak_from.lock(); |
| 122 | to->impl->guard.lock(); | 122 | |
| 123 | to->impl->previous_fiber = from; | 123 | auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to); |
| 124 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); | 124 | |
| 125 | ASSERT(from->impl->previous_fiber != nullptr); | 125 | // "from" might no longer be valid if the thread was killed |
| 126 | from->impl->previous_fiber->impl->context = transfer.fctx; | 126 | if (auto from = weak_from.lock()) { |
| 127 | from->impl->previous_fiber->impl->guard.unlock(); | 127 | ASSERT(from->impl->previous_fiber != nullptr); |
| 128 | from->impl->previous_fiber.reset(); | 128 | from->impl->previous_fiber->impl->context = transfer.fctx; |
| 129 | from->impl->previous_fiber->impl->guard.unlock(); | ||
| 130 | from->impl->previous_fiber.reset(); | ||
| 131 | } | ||
| 129 | } | 132 | } |
| 130 | 133 | ||
| 131 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 134 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
diff --git a/src/common/fiber.h b/src/common/fiber.h index f7f587f8c..f2a8ff29a 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h | |||
| @@ -41,7 +41,7 @@ public: | |||
| 41 | 41 | ||
| 42 | /// Yields control from Fiber 'from' to Fiber 'to' | 42 | /// Yields control from Fiber 'from' to Fiber 'to' |
| 43 | /// Fiber 'from' must be the currently running fiber. | 43 | /// Fiber 'from' must be the currently running fiber. |
| 44 | static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); | 44 | static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); |
| 45 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); | 45 | [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); |
| 46 | 46 | ||
| 47 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); | 47 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 8f04fb8f5..bdb374792 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -148,7 +148,7 @@ void CpuManager::MultiCoreRunSuspendThread() { | |||
| 148 | auto core = kernel.GetCurrentHostThreadID(); | 148 | auto core = kernel.GetCurrentHostThreadID(); |
| 149 | auto& scheduler = *kernel.CurrentScheduler(); | 149 | auto& scheduler = *kernel.CurrentScheduler(); |
| 150 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 150 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); | 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); |
| 152 | ASSERT(scheduler.ContextSwitchPending()); | 152 | ASSERT(scheduler.ContextSwitchPending()); |
| 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 154 | scheduler.RescheduleCurrentCore(); | 154 | scheduler.RescheduleCurrentCore(); |
| @@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 245 | auto core = kernel.GetCurrentHostThreadID(); | 245 | auto core = kernel.GetCurrentHostThreadID(); |
| 246 | auto& scheduler = *kernel.CurrentScheduler(); | 246 | auto& scheduler = *kernel.CurrentScheduler(); |
| 247 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 247 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 248 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); | 248 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); |
| 249 | ASSERT(scheduler.ContextSwitchPending()); | 249 | ASSERT(scheduler.ContextSwitchPending()); |
| 250 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 250 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 251 | scheduler.RescheduleCurrentCore(); | 251 | scheduler.RescheduleCurrentCore(); |
| @@ -271,7 +271,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 271 | scheduler.Unload(scheduler.GetCurrentThread()); | 271 | scheduler.Unload(scheduler.GetCurrentThread()); |
| 272 | 272 | ||
| 273 | auto& next_scheduler = kernel.Scheduler(current_core); | 273 | auto& next_scheduler = kernel.Scheduler(current_core); |
| 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | // May have changed scheduler | 277 | // May have changed scheduler |
| @@ -363,7 +363,7 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 363 | 363 | ||
| 364 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 364 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 365 | data.is_running = true; | 365 | data.is_running = true; |
| 366 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); | 366 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); |
| 367 | data.is_running = false; | 367 | data.is_running = false; |
| 368 | data.is_paused = true; | 368 | data.is_paused = true; |
| 369 | data.exit_barrier->Wait(); | 369 | data.exit_barrier->Wait(); |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 6e89c3042..e7de48476 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -734,7 +734,7 @@ void KScheduler::ScheduleImpl() { | |||
| 734 | } | 734 | } |
| 735 | guard.unlock(); | 735 | guard.unlock(); |
| 736 | 736 | ||
| 737 | Common::Fiber::YieldTo(*old_context, switch_fiber); | 737 | Common::Fiber::YieldTo(*old_context, *switch_fiber); |
| 738 | /// When a thread wakes up, the scheduler may have changed to other in another core. | 738 | /// When a thread wakes up, the scheduler may have changed to other in another core. |
| 739 | auto& next_scheduler = *system.Kernel().CurrentScheduler(); | 739 | auto& next_scheduler = *system.Kernel().CurrentScheduler(); |
| 740 | next_scheduler.SwitchContextStep2(); | 740 | next_scheduler.SwitchContextStep2(); |
| @@ -769,13 +769,8 @@ void KScheduler::SwitchToCurrent() { | |||
| 769 | break; | 769 | break; |
| 770 | } | 770 | } |
| 771 | } | 771 | } |
| 772 | std::shared_ptr<Common::Fiber>* next_context; | 772 | auto thread = next_thread ? next_thread : idle_thread; |
| 773 | if (next_thread != nullptr) { | 773 | Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); |
| 774 | next_context = &next_thread->GetHostContext(); | ||
| 775 | } else { | ||
| 776 | next_context = &idle_thread->GetHostContext(); | ||
| 777 | } | ||
| 778 | Common::Fiber::YieldTo(switch_fiber, *next_context); | ||
| 779 | } while (!is_switch_pending()); | 774 | } while (!is_switch_pending()); |
| 780 | } | 775 | } |
| 781 | } | 776 | } |
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index d94492fc6..751cbe196 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp | |||
| @@ -67,7 +67,7 @@ void TestControl1::DoWork() { | |||
| 67 | value++; | 67 | value++; |
| 68 | } | 68 | } |
| 69 | results[id] = value; | 69 | results[id] = value; |
| 70 | Fiber::YieldTo(work_fibers[id], thread_fibers[id]); | 70 | Fiber::YieldTo(work_fibers[id], *thread_fibers[id]); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void TestControl1::ExecuteThread(u32 id) { | 73 | void TestControl1::ExecuteThread(u32 id) { |
| @@ -76,7 +76,7 @@ void TestControl1::ExecuteThread(u32 id) { | |||
| 76 | thread_fibers[id] = thread_fiber; | 76 | thread_fibers[id] = thread_fiber; |
| 77 | work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); | 77 | work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); |
| 78 | items[id] = rand() % 256; | 78 | items[id] = rand() % 256; |
| 79 | Fiber::YieldTo(thread_fibers[id], work_fibers[id]); | 79 | Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); |
| 80 | thread_fibers[id]->Exit(); | 80 | thread_fibers[id]->Exit(); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| @@ -117,11 +117,11 @@ public: | |||
| 117 | for (u32 i = 0; i < 12000; i++) { | 117 | for (u32 i = 0; i < 12000; i++) { |
| 118 | value1 += i; | 118 | value1 += i; |
| 119 | } | 119 | } |
| 120 | Fiber::YieldTo(fiber1, fiber3); | 120 | Fiber::YieldTo(fiber1, *fiber3); |
| 121 | const u32 id = thread_ids.Get(); | 121 | const u32 id = thread_ids.Get(); |
| 122 | assert1 = id == 1; | 122 | assert1 = id == 1; |
| 123 | value2 += 5000; | 123 | value2 += 5000; |
| 124 | Fiber::YieldTo(fiber1, thread_fibers[id]); | 124 | Fiber::YieldTo(fiber1, *thread_fibers[id]); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void DoWork2() { | 127 | void DoWork2() { |
| @@ -129,7 +129,7 @@ public: | |||
| 129 | ; | 129 | ; |
| 130 | value2 = 2000; | 130 | value2 = 2000; |
| 131 | trap = false; | 131 | trap = false; |
| 132 | Fiber::YieldTo(fiber2, fiber1); | 132 | Fiber::YieldTo(fiber2, *fiber1); |
| 133 | assert3 = false; | 133 | assert3 = false; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| @@ -137,19 +137,19 @@ public: | |||
| 137 | const u32 id = thread_ids.Get(); | 137 | const u32 id = thread_ids.Get(); |
| 138 | assert2 = id == 0; | 138 | assert2 = id == 0; |
| 139 | value1 += 1000; | 139 | value1 += 1000; |
| 140 | Fiber::YieldTo(fiber3, thread_fibers[id]); | 140 | Fiber::YieldTo(fiber3, *thread_fibers[id]); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | void ExecuteThread(u32 id); | 143 | void ExecuteThread(u32 id); |
| 144 | 144 | ||
| 145 | void CallFiber1() { | 145 | void CallFiber1() { |
| 146 | const u32 id = thread_ids.Get(); | 146 | const u32 id = thread_ids.Get(); |
| 147 | Fiber::YieldTo(thread_fibers[id], fiber1); | 147 | Fiber::YieldTo(thread_fibers[id], *fiber1); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | void CallFiber2() { | 150 | void CallFiber2() { |
| 151 | const u32 id = thread_ids.Get(); | 151 | const u32 id = thread_ids.Get(); |
| 152 | Fiber::YieldTo(thread_fibers[id], fiber2); | 152 | Fiber::YieldTo(thread_fibers[id], *fiber2); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | void Exit(); | 155 | void Exit(); |
| @@ -241,23 +241,23 @@ public: | |||
| 241 | 241 | ||
| 242 | void DoWork1() { | 242 | void DoWork1() { |
| 243 | value1 += 1; | 243 | value1 += 1; |
| 244 | Fiber::YieldTo(fiber1, fiber2); | 244 | Fiber::YieldTo(fiber1, *fiber2); |
| 245 | const u32 id = thread_ids.Get(); | 245 | const u32 id = thread_ids.Get(); |
| 246 | value3 += 1; | 246 | value3 += 1; |
| 247 | Fiber::YieldTo(fiber1, thread_fibers[id]); | 247 | Fiber::YieldTo(fiber1, *thread_fibers[id]); |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | void DoWork2() { | 250 | void DoWork2() { |
| 251 | value2 += 1; | 251 | value2 += 1; |
| 252 | const u32 id = thread_ids.Get(); | 252 | const u32 id = thread_ids.Get(); |
| 253 | Fiber::YieldTo(fiber2, thread_fibers[id]); | 253 | Fiber::YieldTo(fiber2, *thread_fibers[id]); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | void ExecuteThread(u32 id); | 256 | void ExecuteThread(u32 id); |
| 257 | 257 | ||
| 258 | void CallFiber1() { | 258 | void CallFiber1() { |
| 259 | const u32 id = thread_ids.Get(); | 259 | const u32 id = thread_ids.Get(); |
| 260 | Fiber::YieldTo(thread_fibers[id], fiber1); | 260 | Fiber::YieldTo(thread_fibers[id], *fiber1); |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | void Exit(); | 263 | void Exit(); |
| @@ -332,7 +332,7 @@ public: | |||
| 332 | 332 | ||
| 333 | void Execute() { | 333 | void Execute() { |
| 334 | thread_fiber = Fiber::ThreadToFiber(); | 334 | thread_fiber = Fiber::ThreadToFiber(); |
| 335 | Fiber::YieldTo(thread_fiber, fiber1); | 335 | Fiber::YieldTo(thread_fiber, *fiber1); |
| 336 | thread_fiber->Exit(); | 336 | thread_fiber->Exit(); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| @@ -340,7 +340,7 @@ public: | |||
| 340 | fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); | 340 | fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); |
| 341 | if (rewinded) { | 341 | if (rewinded) { |
| 342 | goal_reached = true; | 342 | goal_reached = true; |
| 343 | Fiber::YieldTo(fiber1, thread_fiber); | 343 | Fiber::YieldTo(fiber1, *thread_fiber); |
| 344 | } | 344 | } |
| 345 | rewinded = true; | 345 | rewinded = true; |
| 346 | fiber1->Rewind(); | 346 | fiber1->Rewind(); |