Skip to content

Commit 1ee9d5c

Browse files
committed
coreinit: Tweak JD2019 workaround to avoid XCX softlock
1 parent aadd2f4 commit 1ee9d5c

File tree

4 files changed

+13
-12
lines changed

4 files changed

+13
-12
lines changed

src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ namespace coreinit
310310
currentThread->mutexQueue.removeMutex(mutex);
311311
mutex->owner = nullptr;
312312
if (!mutex->threadQueue.isEmpty())
313-
mutex->threadQueue.wakeupSingleThreadWaitQueue(true);
313+
mutex->threadQueue.wakeupSingleThreadWaitQueue(true, true);
314314
}
315315
// currentThread->cancelState = currentThread->cancelState & ~0x10000;
316316
}

src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -758,14 +758,14 @@ namespace coreinit
758758
}
759759

760760
// returns true if thread runs on same core and has higher priority
761-
bool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread)
761+
bool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread, bool sharedPriorityAndAffinityWorkaround)
762762
{
763763
uint32 coreIndex = OSGetCoreId();
764764
if (!newThread->context.hasCoreAffinitySet(coreIndex))
765765
return false;
766766
// special case: if current and new thread are running only on the same core then reschedule even if priority is equal
767767
// this resolves a deadlock in Just Dance 2019 where one thread would always reacquire the same mutex within it's timeslice, blocking another thread on the same core from acquiring it
768-
if ((1<<coreIndex) == newThread->context.affinity && currentThread->context.affinity == newThread->context.affinity && currentThread->effectivePriority == newThread->effectivePriority)
768+
if (sharedPriorityAndAffinityWorkaround && (1<<coreIndex) == newThread->context.affinity && currentThread->context.affinity == newThread->context.affinity && currentThread->effectivePriority == newThread->effectivePriority)
769769
return true;
770770
// otherwise reschedule if new thread has higher priority
771771
return newThread->effectivePriority < currentThread->effectivePriority;
@@ -791,7 +791,7 @@ namespace coreinit
791791
// todo - only set this once?
792792
thread->wakeUpTime = PPCInterpreter_getMainCoreCycleCounter();
793793
// reschedule if thread has higher priority
794-
if (PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread))
794+
if (PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, false))
795795
PPCCore_switchToSchedulerWithLock();
796796
}
797797
return previousSuspendCount;
@@ -948,7 +948,7 @@ namespace coreinit
948948
OSThread_t* currentThread = OSGetCurrentThread();
949949
if (currentThread && currentThread != thread)
950950
{
951-
if (__OSCoreShouldSwitchToThread(currentThread, thread))
951+
if (__OSCoreShouldSwitchToThread(currentThread, thread, false))
952952
PPCCore_switchToSchedulerWithLock();
953953
}
954954
__OSUnlockScheduler();

src/Cafe/OS/libs/coreinit/coreinit_Thread.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ namespace coreinit
126126

127127
// counterparts for queueAndWait
128128
void cancelWait(OSThread_t* thread);
129-
void wakeupEntireWaitQueue(bool reschedule);
130-
void wakeupSingleThreadWaitQueue(bool reschedule);
129+
void wakeupEntireWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround = false);
130+
void wakeupSingleThreadWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround = false);
131131

132132
private:
133133
OSThread_t* takeFirstFromQueue(size_t linkOffset)
@@ -611,7 +611,7 @@ namespace coreinit
611611

612612
// internal
613613
void __OSAddReadyThreadToRunQueue(OSThread_t* thread);
614-
bool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread);
614+
bool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread, bool sharedPriorityAndAffinityWorkaround);
615615
void __OSQueueThreadDeallocation(OSThread_t* thread);
616616

617617
bool __OSIsThreadActive(OSThread_t* thread);

src/Cafe/OS/libs/coreinit/coreinit_ThreadQueue.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ namespace coreinit
128128

129129
// counterpart for queueAndWait
130130
// if reschedule is true then scheduler will switch to woken up thread (if it is runnable on the same core)
131-
void OSThreadQueueInternal::wakeupEntireWaitQueue(bool reschedule)
131+
// sharedPriorityAndAffinityWorkaround is currently a hack/placeholder for some special cases. A proper fix likely involves handling all the nuances of thread effective priority
132+
void OSThreadQueueInternal::wakeupEntireWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround)
132133
{
133134
cemu_assert_debug(__OSHasSchedulerLock());
134135
bool shouldReschedule = false;
@@ -139,7 +140,7 @@ namespace coreinit
139140
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
140141
thread->currentWaitQueue = nullptr;
141142
coreinit::__OSAddReadyThreadToRunQueue(thread);
142-
if (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread))
143+
if (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, sharedPriorityAndAffinityWorkaround))
143144
shouldReschedule = true;
144145
}
145146
if (shouldReschedule)
@@ -148,7 +149,7 @@ namespace coreinit
148149

149150
// counterpart for queueAndWait
150151
// if reschedule is true then scheduler will switch to woken up thread (if it is runnable on the same core)
151-
void OSThreadQueueInternal::wakeupSingleThreadWaitQueue(bool reschedule)
152+
void OSThreadQueueInternal::wakeupSingleThreadWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround)
152153
{
153154
cemu_assert_debug(__OSHasSchedulerLock());
154155
OSThread_t* thread = takeFirstFromQueue(offsetof(OSThread_t, waitQueueLink));
@@ -159,7 +160,7 @@ namespace coreinit
159160
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
160161
thread->currentWaitQueue = nullptr;
161162
coreinit::__OSAddReadyThreadToRunQueue(thread);
162-
if (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread))
163+
if (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, sharedPriorityAndAffinityWorkaround))
163164
shouldReschedule = true;
164165
}
165166
if (shouldReschedule)

0 commit comments

Comments
 (0)