Implement sceKernelCancelMutex().

This commit is contained in:
Unknown W. Brackets 2013-08-25 15:37:14 -07:00
parent 18832f3ca7
commit d547d2b391
3 changed files with 72 additions and 9 deletions

View File

@ -685,14 +685,14 @@ const HLEFunction ThreadManForUser[] =
//{0x31327F19,0, "_sceKernelLockLwMutexCB"},
//{0xBEED3A47,0, "_sceKernelUnlockLwMutex"},
{0xf8170fbe,&WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
{0xB011B11F,&WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex", HLE_NOT_DISPATCH_SUSPENDED},
{0x5bf4dd27,&WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB", HLE_NOT_DISPATCH_SUSPENDED},
{0x6b30100f,&WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
{0xb7d098c6,&WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
{0x0DDCD2C9,&WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
{0xA9C2CB9A,&WrapI_IU<sceKernelReferMutexStatus>, "sceKernelReferMutexStatus"},
{0x87D9223C,0, "sceKernelCancelMutex"},
{0xf8170fbe,WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
{0xB011B11F,WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex", HLE_NOT_DISPATCH_SUSPENDED},
{0x5bf4dd27,WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB", HLE_NOT_DISPATCH_SUSPENDED},
{0x6b30100f,WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
{0xb7d098c6,WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
{0x0DDCD2C9,WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
{0xA9C2CB9A,WrapI_IU<sceKernelReferMutexStatus>, "sceKernelReferMutexStatus"},
{0x87D9223C,WrapI_IIU<sceKernelCancelMutex>, "sceKernelCancelMutex"},
{0xFCCFAD26,WrapI_I<sceKernelCancelWakeupThread>,"sceKernelCancelWakeupThread"},
{0x1AF94D03,0,"sceKernelDonateWakeupThread"},

View File

@ -405,11 +405,11 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
int sceKernelDeleteMutex(SceUID id)
{
DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id);
u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
if (mutex)
{
DEBUG_LOG(HLE, "sceKernelDeleteMutex(%i)", id);
bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end;
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
@ -425,7 +425,10 @@ int sceKernelDeleteMutex(SceUID id)
return kernelObjects.Destroy<Mutex>(id);
}
else
{
DEBUG_LOG(HLE, "sceKernelDeleteMutex(%i): invalid mutex", id);
return error;
}
}
bool __KernelLockMutexCheck(Mutex *mutex, int count, u32 &error)
@ -567,6 +570,65 @@ void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
}
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
{
u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(uid, error);
if (mutex)
{
bool lockable = count <= 0 || __KernelLockMutexCheck(mutex, count, error);
if (!lockable)
{
// May still be okay. As long as the count/etc. are valid.
if (error != 0 && error != PSP_MUTEX_ERROR_LOCK_OVERFLOW && error != PSP_MUTEX_ERROR_ALREADY_LOCKED)
{
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x): invalid count", uid, count, numWaitThreadsPtr);
return error;
}
}
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr);
// Remove threads no longer waiting on this first (so the numWaitThreads value is correct.)
for (auto iter = mutex->waitingThreads.begin(); iter != mutex->waitingThreads.end(); ++iter)
{
SceUID waitID = __KernelGetWaitID(*iter, WAITTYPE_MUTEX, error);
// The thread is no longer waiting for this, clean it up.
if (waitID != uid)
mutex->waitingThreads.erase(iter--);
}
if (Memory::IsValidAddress(numWaitThreadsPtr))
Memory::Write_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr);
bool wokeThreads = false;
for (auto iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_CANCEL);
if (mutex->nm.lockThread != -1)
__KernelMutexEraseLock(mutex);
mutex->waitingThreads.clear();
if (count <= 0)
{
mutex->nm.lockLevel = 0;
mutex->nm.lockThread = -1;
}
else
__KernelMutexAcquireLock(mutex, count);
if (wokeThreads)
hleReSchedule("mutex canceled");
return 0;
}
else
{
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr);
return error;
}
}
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
{

View File

@ -17,6 +17,7 @@
#pragma once
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr);
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr);
int sceKernelDeleteMutex(SceUID id);
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr);