public int sceKernelReferLwMutexStatusByID(int uid, int addr) { Memory mem = Processor.memory; if (log.isDebugEnabled()) { log.debug( "sceKernelReferLwMutexStatus (uid=0x" + Integer.toHexString(uid) + ", addr=0x" + addr + ")"); } SceKernelLwMutexInfo info = lwMutexMap.get(uid); if (info == null) { log.warn("sceKernelReferLwMutexStatus unknown UID " + Integer.toHexString(uid)); return ERROR_KERNEL_LWMUTEX_NOT_FOUND; } if (!Memory.isAddressGood(addr)) { log.warn("sceKernelReferLwMutexStatus bad address 0x" + Integer.toHexString(addr)); return -1; } info.write(mem, addr); return 0; }
public int sceKernelUnlockLwMutex(int workAreaAddr, int count) { Memory mem = Processor.memory; int uid = mem.read32(workAreaAddr); if (log.isDebugEnabled()) { log.debug( "sceKernelUnlockLwMutex (workAreaAddr=0x" + Integer.toHexString(workAreaAddr) + ", count=" + count + ")"); } SceKernelLwMutexInfo info = lwMutexMap.get(uid); if (info == null) { log.warn("sceKernelUnlockLwMutex unknown uid"); return ERROR_KERNEL_LWMUTEX_NOT_FOUND; } if (info.lockedCount == 0) { log.debug("sceKernelUnlockLwMutex not locked"); return ERROR_KERNEL_LWMUTEX_UNLOCKED; } if (info.lockedCount < 0) { log.warn("sceKernelUnlockLwMutex underflow"); return ERROR_KERNEL_LWMUTEX_UNLOCK_UNDERFLOW; } info.lockedCount -= count; if (info.lockedCount == 0) { onLwMutexModified(info); } return 0; }
public int sceKernelCreateLwMutex( int workAreaAddr, int name_addr, int attr, int count, int option_addr) { Memory mem = Processor.memory; String name = Utilities.readStringNZ(mem, name_addr, 32); if (log.isDebugEnabled()) { log.debug( "sceKernelCreateLwMutex (workAreaAddr='" + Integer.toHexString(workAreaAddr) + "', name='" + name + "', attr=0x" + Integer.toHexString(attr) + ", count=0x" + Integer.toHexString(count) + ", option_addr=0x" + Integer.toHexString(option_addr) + ")"); } SceKernelLwMutexInfo info = new SceKernelLwMutexInfo(workAreaAddr, name, count, attr); lwMutexMap.put(info.uid, info); // If the initial count is 0, the lwmutex is not acquired. if (count > 0) { info.threadid = Modules.ThreadManForUserModule.getCurrentThreadID(); } // Return 0 in case of no error, do not return the UID of the created mutex return 0; }
private int hleKernelLockLwMutex( int uid, int count, int timeout_addr, boolean wait, boolean doCallbacks) { SceKernelLwMutexInfo info = lwMutexMap.get(uid); if (info == null) { log.warn( String.format( "hleKernelLockLwMutex uid=%d, count=%d, timeout_addr=0x%08X, wait=%b, doCallbacks=%b - - unknown UID", uid, count, timeout_addr, wait, doCallbacks)); return ERROR_KERNEL_LWMUTEX_NOT_FOUND; } ThreadManForUser threadMan = Modules.ThreadManForUserModule; SceKernelThreadInfo currentThread = threadMan.getCurrentThread(); if (!tryLockLwMutex(info, count, currentThread)) { if (log.isDebugEnabled()) { log.debug( String.format( "hleKernelLockLwMutex %s, count=%d, timeout_addr=0x%08X, wait=%b, doCallbacks=%b - fast check failed", info.toString(), count, timeout_addr, wait, doCallbacks)); } if (wait && info.threadid != currentThread.uid) { // Failed, but it's ok, just wait a little info.numWaitThreads++; // Wait on a specific lwmutex currentThread.wait.LwMutex_id = uid; currentThread.wait.LwMutex_count = count; threadMan.hleKernelThreadEnterWaitState( PSP_WAIT_LWMUTEX, uid, lwMutexWaitStateChecker, timeout_addr, doCallbacks); } else { if ((info.attr & PSP_LWMUTEX_ATTR_ALLOW_RECURSIVE) != PSP_LWMUTEX_ATTR_ALLOW_RECURSIVE) { return ERROR_KERNEL_LWMUTEX_RECURSIVE_NOT_ALLOWED; } return ERROR_KERNEL_LWMUTEX_LOCKED; } } else { // Success, do not reschedule the current thread. if (log.isDebugEnabled()) { log.debug( String.format( "hleKernelLockLwMutex %s, count=%d, timeout_addr=0x%08X, wait=%b, doCallbacks=%b - fast check succeeded", info.toString(), count, timeout_addr, wait, doCallbacks)); } } return 0; }
private boolean tryLockLwMutex(SceKernelLwMutexInfo info, int count, SceKernelThreadInfo thread) { if (info.lockedCount == 0) { // If the lwmutex is not locked, allow this thread to lock it. info.threadid = thread.uid; info.lockedCount += count; return true; } else if (info.threadid == thread.uid) { // If the lwmutex is already locked, but it's trying to be locked by the same thread // that acquired it initially, check if recursive locking is allowed. // If not, return an error. if (((info.attr & PSP_LWMUTEX_ATTR_ALLOW_RECURSIVE) == PSP_LWMUTEX_ATTR_ALLOW_RECURSIVE)) { info.lockedCount += count; return true; } } return false; }
private void onLwMutexModified(SceKernelLwMutexInfo info) { ThreadManForUser threadMan = Modules.ThreadManForUserModule; boolean reschedule = false; if ((info.attr & PSP_LWMUTEX_ATTR_PRIORITY) == PSP_LWMUTEX_ATTR_FIFO) { for (Iterator<SceKernelThreadInfo> it = Modules.ThreadManForUserModule.iterator(); it.hasNext(); ) { SceKernelThreadInfo thread = it.next(); if (thread.isWaitingForType(PSP_WAIT_LWMUTEX) && thread.wait.LwMutex_id == info.uid && tryLockLwMutex(info, thread.wait.LwMutex_count, thread)) { // New thread is taking control of LwMutex. info.threadid = thread.uid; // Update numWaitThreads info.numWaitThreads--; // Return success or failure thread.cpuContext.gpr[2] = 0; // Wakeup threadMan.hleChangeThreadState(thread, PSP_THREAD_READY); reschedule = true; } } } else if ((info.attr & PSP_LWMUTEX_ATTR_PRIORITY) == PSP_LWMUTEX_ATTR_PRIORITY) { for (Iterator<SceKernelThreadInfo> it = Modules.ThreadManForUserModule.iteratorByPriority(); it.hasNext(); ) { SceKernelThreadInfo thread = it.next(); if (thread.isWaitingForType(PSP_WAIT_LWMUTEX) && thread.wait.LwMutex_id == info.uid && tryLockLwMutex(info, thread.wait.LwMutex_count, thread)) { // New thread is taking control of LwMutex. info.threadid = thread.uid; // Update numWaitThreads info.numWaitThreads--; // Return success or failure thread.cpuContext.gpr[2] = 0; // Wakeup threadMan.hleChangeThreadState(thread, PSP_THREAD_READY); reschedule = true; } } } // Reschedule only if threads waked up. if (reschedule) { Modules.ThreadManForUserModule.hleRescheduleCurrentThread(); } }
private boolean removeWaitingThread(SceKernelThreadInfo thread) { // Update numWaitThreads SceKernelLwMutexInfo info = lwMutexMap.get(thread.wait.LwMutex_id); if (info != null) { info.numWaitThreads--; if (info.numWaitThreads < 0) { log.warn( "removing waiting thread " + Integer.toHexString(thread.uid) + ", lwmutex " + Integer.toHexString(info.uid) + " numWaitThreads underflowed"); info.numWaitThreads = 0; } return true; } return false; }