diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 66df42da2..699d842fd 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -13,6 +13,7 @@ #include "core/hle/kernel/object_address_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" +#include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/sync_object.h" @@ -471,6 +472,53 @@ static void SleepThread(s64 nanoseconds) { Core::System::GetInstance().PrepareReschedule(); } +/// Signal process wide key atomic +static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr semaphore_addr, + Handle thread_handle, s64 nano_seconds) { + LOG_TRACE(Kernel_SVC, + "called mutex_addr=%llx, semaphore_addr=%llx, thread_handle=0x%08X, timeout=%d", + mutex_addr, semaphore_addr, thread_handle, nano_seconds); + + SharedPtr thread = g_handle_table.Get(thread_handle); + ASSERT(thread); + + SharedPtr mutex = g_object_address_table.Get(mutex_addr); + if (!mutex) { + // Create a new mutex for the specified address if one does not already exist + mutex = Mutex::Create(thread, mutex_addr); + mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr); + } + + SharedPtr semaphore = g_object_address_table.Get(semaphore_addr); + if (!semaphore) { + // Create a new semaphore for the specified address if one does not already exist + semaphore = Semaphore::Create(semaphore_addr, mutex_addr).Unwrap(); + semaphore->name = Common::StringFromFormat("semaphore-%llx", semaphore_addr); + } + + ASSERT(semaphore->available_count == 0); + ASSERT(semaphore->mutex_addr == mutex_addr); + + CASCADE_CODE(WaitSynchronization1( + semaphore, thread.get(), nano_seconds, + [mutex](ThreadWakeupReason reason, SharedPtr thread, SharedPtr object) { + ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); + + if (reason == ThreadWakeupReason::Timeout) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return; + } + + ASSERT(reason == ThreadWakeupReason::Signal); + thread->SetWaitSynchronizationResult(WaitSynchronization1(mutex, thread.get())); + thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); + })); + + mutex->Release(thread.get()); + + return RESULT_SUCCESS; +} + /// Signal process wide key static ResultCode SignalProcessWideKey(VAddr addr, u32 target) { LOG_WARNING(Kernel_SVC, "(STUBBED) called, address=0x%llx, target=0x%08x", addr, target); @@ -522,7 +570,7 @@ static const FunctionDef SVC_Table[] = { {0x19, nullptr, "CancelSynchronization"}, {0x1A, SvcWrap, "LockMutex"}, {0x1B, SvcWrap, "UnlockMutex"}, - {0x1C, nullptr, "WaitProcessWideKeyAtomic"}, + {0x1C, SvcWrap, "WaitProcessWideKeyAtomic"}, {0x1D, SvcWrap, "SignalProcessWideKey"}, {0x1E, nullptr, "GetSystemTick"}, {0x1F, SvcWrap, "ConnectToPort"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 65b64cb3c..f8e50a24f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -85,6 +85,11 @@ void SvcWrap() { FuncReturn(func(PARAM(1), PARAM(2), (s64)PARAM(3)).raw); } +template +void SvcWrap() { + FuncReturn(func(PARAM(0), PARAM(1), (u32)PARAM(2), (s64)PARAM(3)).raw); +} + template void SvcWrap() { u64 param_1 = 0;