// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // UNFINISHED #include "HLE.h" #include "../MIPS/MIPS.h" #include "sceKernel.h" #include "sceKernelMutex.h" #include "sceKernelThread.h" #define PSP_MUTEX_ATTR_FIFO 0 #define PSP_MUTEX_ATTR_PRIORITY 0x100 #define PSP_MUTEX_ATTR_ALLOW_RECURSIVE 0x200 // Not sure about the names of these #define PSP_MUTEX_ERROR_NOT_LOCKED 0x800201C7 #define PSP_MUTEX_ERROR_NO_SUCH_MUTEX 0x800201C3 // Guesswork - not exposed anyway struct NativeMutex { SceSize size; char name[32]; SceUInt attr; int lockLevel; int lockThread; // The thread holding the lock }; struct Mutex : public KernelObject { const char *GetName() {return nm.name;} const char *GetTypeName() {return "Mutex";} static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } // Not sure? int GetIDType() const { return SCE_KERNEL_TMID_Mutex; } NativeMutex nm; std::vector waitingThreads; }; struct LWMutex : public KernelObject { const char *GetName() {return nm.name;} const char *GetTypeName() {return "LWMutex";} static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } // Not sure? int GetIDType() const { return SCE_KERNEL_TMID_LwMutex; } NativeMutex nm; std::vector waitingThreads; }; u32 sceKernelCreateMutex(const char *name, u32 attr, u32 options) { DEBUG_LOG(HLE,"sceKernelCreateMutex(%s, %08x, %08x)", name, attr, options); Mutex *mutex = new Mutex(); SceUID id = kernelObjects.Create(mutex); mutex->nm.size = sizeof(mutex); mutex->nm.attr = attr; mutex->nm.lockLevel = 0; mutex->nm.lockThread = -1; strncpy(mutex->nm.name, name, 32); return id; } u32 sceKernelDeleteMutex(u32 id) { DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (!mutex) return PSP_MUTEX_ERROR_NO_SUCH_MUTEX; kernelObjects.Destroy(id); return 0; } u32 sceKernelLockMutex(u32 id, u32 count, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (!mutex) return PSP_MUTEX_ERROR_NO_SUCH_MUTEX; if (mutex->nm.lockLevel == 0) { mutex->nm.lockLevel += count; mutex->nm.lockThread = __KernelGetCurThread(); // Nobody had it locked - no need to block } else if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) && mutex->nm.lockThread == __KernelGetCurThread()) { // Recursive mutex, let's just increase the lock count and keep going mutex->nm.lockLevel += count; } else { // Yeah, we need to block. Somehow. ERROR_LOG(HLE,"Mutex should block!"); } return 0; } u32 sceKernelLockMutexCB(u32 id, u32 count, u32 timeoutPtr) { ERROR_LOG(HLE,"UNIMPL sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); return 0; } u32 sceKernelUnlockMutex(u32 id, u32 count) { DEBUG_LOG(HLE,"UNFINISHED sceKernelUnlockMutex(%i, %i)", id, count); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (!mutex) return PSP_MUTEX_ERROR_NO_SUCH_MUTEX; if (mutex->nm.lockLevel == 0) return PSP_MUTEX_ERROR_NOT_LOCKED; mutex->nm.lockLevel -= count; // TODO.... return 0; } struct NativeLwMutex { SceSize size; char name[32]; SceUInt attr; SceUID mutexUid; SceUInt opaqueWorkAreaAddr; int numWaitThreads; int locked; int threadid; // thread holding the lock }; void sceKernelCreateLwMutex() { ERROR_LOG(HLE,"UNIMPL sceKernelCreateLwMutex()"); RETURN(0); } void sceKernelDeleteLwMutex() { ERROR_LOG(HLE,"UNIMPL sceKernelDeleteLwMutex()"); RETURN(0); } void sceKernelTryLockLwMutex() { ERROR_LOG(HLE,"UNIMPL sceKernelTryLockLwMutex()"); RETURN(0); } void sceKernelLockLwMutex() { ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutex()"); RETURN(0); } void sceKernelLockLwMutexCB() { ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutexCB()"); RETURN(0); } void sceKernelUnlockLwMutex() { ERROR_LOG(HLE,"UNIMPL void sceKernelUnlockLwMutex()"); RETURN(0); }