diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp index 16827d0f..4c55c2b0 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp @@ -128,9 +128,23 @@ namespace coreinit else { // loop until lock acquired - while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread)) + if (coreinit::__CemuIsMulticoreMode()) { - OSYieldThread(); + while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread)) + { + _mm_pause(); + } + } + else + { + // we are in single-core mode and the lock will never be released unless we let other threads resume work + // to avoid an infinite loop we have no choice but to yield the thread even it is in an uninterruptible state + if( !OSIsInterruptEnabled() ) + cemuLog_log(LogType::APIErrors, "OSUninterruptibleSpinLock_Acquire(): Lock is occupied which requires a wait but current thread is already in an uninterruptible state (Avoid cascaded OSDisableInterrupts and/or OSUninterruptibleSpinLock)"); + while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread)) + { + OSYieldThread(); + } } } __OSBoostThread(currentThread); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp index 406068eb..90ab8fb9 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp @@ -66,6 +66,11 @@ namespace coreinit std::unordered_map s_threadToFiber; + bool __CemuIsMulticoreMode() + { + return g_isMulticoreMode; + } + // create host thread (fiber) that will be used to run the PPC instance // note that host threads are fibers and not actual threads void __OSCreateHostThread(OSThread_t* thread) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h index 3c41d9dc..615e51d9 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h @@ -488,6 +488,8 @@ namespace coreinit void InitializeThread(); void InitializeConcurrency(); + bool __CemuIsMulticoreMode(); + OSThread_t* OSGetDefaultThread(sint32 coreIndex); void* OSGetDefaultThreadStack(sint32 coreIndex, uint32& size);