summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2021-03-08 13:51:37 -0800
committerGravatar GitHub2021-03-08 13:51:37 -0800
commit69ce5e41ebd266b2cd04cb609663eaca21c8ded9 (patch)
treeed8f8429c89814266ac72db1fdf7591d03ab4c9a
parentMerge pull request #6047 from lioncash/dynarmic (diff)
parentcommon: Fiber: use a reference for YieldTo. (diff)
downloadyuzu-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.cpp23
-rw-r--r--src/common/fiber.h2
-rw-r--r--src/core/cpu_manager.cpp8
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp11
-rw-r--r--src/tests/common/fibers.cpp28
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
119void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { 119void 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
131std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 134std::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
73void TestControl1::ExecuteThread(u32 id) { 73void 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();