summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-08-26 01:55:44 +0000
committerGravatar ReinUsesLisp2020-08-26 02:56:05 +0000
commitccdd84a778244eb1ebbf7ea6e39d5fca79f16e2a (patch)
treeaab98e92a63c4ed5a3fcabef34dce8f8445278cf
parentMerge pull request #4572 from lioncash/xbyak (diff)
downloadyuzu-ccdd84a778244eb1ebbf7ea6e39d5fca79f16e2a.tar.gz
yuzu-ccdd84a778244eb1ebbf7ea6e39d5fca79f16e2a.tar.xz
yuzu-ccdd84a778244eb1ebbf7ea6e39d5fca79f16e2a.zip
hle/scheduler: Fix data race in is_context_switch_pending
As reported by tsan, SelectThreads could write to is_context_switch_pending holding a mutex while SwitchToCurrent reads it without holding any. It is assumed that the author didn't want an atomic here, so the code is reordered so that whenever is_context_switch_pending is read inside SwitchToContext, the mutex is locked.
-rw-r--r--src/core/hle/kernel/scheduler.cpp8
1 files changed, 6 insertions, 2 deletions
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index a4b234424..5cbd3b912 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -756,7 +756,11 @@ void Scheduler::SwitchToCurrent() {
756 current_thread = selected_thread; 756 current_thread = selected_thread;
757 is_context_switch_pending = false; 757 is_context_switch_pending = false;
758 } 758 }
759 while (!is_context_switch_pending) { 759 const auto is_switch_pending = [this] {
760 std::scoped_lock lock{guard};
761 return is_context_switch_pending;
762 };
763 do {
760 if (current_thread != nullptr && !current_thread->IsHLEThread()) { 764 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
761 current_thread->context_guard.lock(); 765 current_thread->context_guard.lock();
762 if (!current_thread->IsRunnable()) { 766 if (!current_thread->IsRunnable()) {
@@ -775,7 +779,7 @@ void Scheduler::SwitchToCurrent() {
775 next_context = &idle_thread->GetHostContext(); 779 next_context = &idle_thread->GetHostContext();
776 } 780 }
777 Common::Fiber::YieldTo(switch_fiber, *next_context); 781 Common::Fiber::YieldTo(switch_fiber, *next_context);
778 } 782 } while (!is_switch_pending());
779 } 783 }
780} 784}
781 785