bool __KernelUnlockMutex(Mutex *mutex, u32 &error) { __KernelMutexEraseLock(mutex); // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; std::vector<SceUID>::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; int wVal = (int)__KernelGetWaitValue(threadID, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); __KernelMutexAcquireLock(mutex, wVal, threadID); if (timeoutPtr != 0 && mutexWaitTimer != 0) { // Remove any event for this thread. u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, 0); wokeThreads = true; mutex->waitingThreads.erase(iter); break; } if (!wokeThreads) mutex->nm.lockThread = -1; return wokeThreads; }
void sceKernelDeleteMutex(SceUID id) { DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id); u32 error; Mutex *mutex = kernelObjects.Get<Mutex>(id, error); if (mutex) { std::vector<SceUID>::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) { SceUID threadID = *iter; u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); if (timeoutPtr != 0 && mutexWaitTimer != 0) { // Remove any event for this thread. u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); } if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); mutex->waitingThreads.empty(); RETURN(kernelObjects.Destroy<Mutex>(id)); __KernelReSchedule("mutex deleted"); } else RETURN(error); }
int sceKernelDeleteMutex(SceUID id) { u32 error; Mutex *mutex = kernelObjects.Get<Mutex>(id, error); if (mutex) { DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMutex(%i)", id); bool wokeThreads = false; std::vector<SceUID>::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); mutex->waitingThreads.clear(); if (wokeThreads) hleReSchedule("mutex deleted"); return kernelObjects.Destroy<Mutex>(id); } else { DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMutex(%i): invalid mutex", id); return error; } }
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(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x): invalid count", uid, count, numWaitThreadsPtr); return error; } } DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); // Remove threads no longer waiting on this first (so the numWaitThreads value is correct.) HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, uid, mutex->waitingThreads); 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(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); return error; } }
bool __KernelUnlockMutex(Mutex *mutex, u32 &error) { __KernelMutexEraseLock(mutex); bool wokeThreads = false; std::vector<SceUID>::iterator iter; while (!wokeThreads && !mutex->waitingThreads.empty()) { if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0) iter = __KernelMutexFindPriority(mutex->waitingThreads); else iter = mutex->waitingThreads.begin(); wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, 0); mutex->waitingThreads.erase(iter); } if (!wokeThreads) mutex->nm.lockThread = -1; return wokeThreads; }