mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
For mutexes/semaphores, register a global timer.
Instead of leaking one per each. Should be faster. Since we can only wait on one thing per thread at a time, this is fine.
This commit is contained in:
parent
a81c138004
commit
8da2fb074c
4 changed files with 50 additions and 34 deletions
|
@ -57,7 +57,6 @@ struct Mutex : public KernelObject
|
|||
int GetIDType() const { return SCE_KERNEL_TMID_Mutex; }
|
||||
NativeMutex nm;
|
||||
std::vector<SceUID> waitingThreads;
|
||||
int waitTimer;
|
||||
};
|
||||
|
||||
// Guesswork - not exposed anyway
|
||||
|
@ -99,11 +98,25 @@ struct LwMutex : public KernelObject
|
|||
int GetIDType() const { return SCE_KERNEL_TMID_LwMutex; }
|
||||
NativeLwMutex nm;
|
||||
std::vector<SceUID> waitingThreads;
|
||||
int waitTimer;
|
||||
};
|
||||
|
||||
bool mutexInitComplete = false;
|
||||
int mutexWaitTimer = 0;
|
||||
int lwMutexWaitTimer = 0;
|
||||
|
||||
void __KernelMutexInit()
|
||||
{
|
||||
mutexWaitTimer = CoreTiming::RegisterEvent("MutexTimeout", &__KernelMutexTimeout);
|
||||
// TODO: Write / enable.
|
||||
//lwMutexWaitTimer = CoreTiming::RegisterEvent("LwMutexTimeout", &__KernelLwMutexTimeout);
|
||||
mutexInitComplete = true;
|
||||
}
|
||||
|
||||
void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr)
|
||||
{
|
||||
if (!mutexInitComplete)
|
||||
__KernelMutexInit();
|
||||
|
||||
u32 error = 0;
|
||||
if (!name)
|
||||
error = SCE_KERNEL_ERROR_ERROR;
|
||||
|
@ -132,7 +145,6 @@ void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 opti
|
|||
mutex->nm.lockThread = -1;
|
||||
else
|
||||
mutex->nm.lockThread = __KernelGetCurThread();
|
||||
mutex->waitTimer = 0;
|
||||
|
||||
if (optionsPtr != 0)
|
||||
WARN_LOG(HLE,"sceKernelCreateMutex(%s) unsupported options parameter.", name);
|
||||
|
@ -155,10 +167,10 @@ void sceKernelDeleteMutex(SceUID id)
|
|||
SceUID threadID = *iter;
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && mutex->waitTimer != 0)
|
||||
if (timeoutPtr != 0 && mutexWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID);
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID);
|
||||
Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
|
@ -166,8 +178,6 @@ void sceKernelDeleteMutex(SceUID id)
|
|||
}
|
||||
mutex->waitingThreads.empty();
|
||||
|
||||
// TODO: Any way to erase the CoreTiming event type? We leak.
|
||||
|
||||
RETURN(kernelObjects.Destroy<Mutex>(id));
|
||||
__KernelReSchedule("mutex deleted");
|
||||
}
|
||||
|
@ -231,15 +241,12 @@ void __KernelMutexTimeout(u64 userdata, int cyclesLate)
|
|||
|
||||
void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0)
|
||||
if (timeoutPtr == 0 || mutexWaitTimer == 0)
|
||||
return;
|
||||
|
||||
if (mutex->waitTimer == 0)
|
||||
mutex->waitTimer = CoreTiming::RegisterEvent("MutexTimeout", &__KernelMutexTimeout);
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutex->waitTimer, __KernelGetCurThread());
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
|
||||
|
@ -356,10 +363,10 @@ void sceKernelUnlockMutex(SceUID id, int count)
|
|||
mutex->nm.lockThread = threadID;
|
||||
mutex->nm.lockLevel = wVal;
|
||||
|
||||
if (timeoutPtr != 0 && mutex->waitTimer != 0)
|
||||
if (timeoutPtr != 0 && mutexWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID);
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID);
|
||||
Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
|
@ -375,6 +382,9 @@ void sceKernelUnlockMutex(SceUID id, int count)
|
|||
|
||||
void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr)
|
||||
{
|
||||
if (!mutexInitComplete)
|
||||
__KernelMutexInit();
|
||||
|
||||
DEBUG_LOG(HLE,"sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr);
|
||||
|
||||
u32 error = 0;
|
||||
|
@ -398,7 +408,6 @@ void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int ini
|
|||
mutex->nm.name[31] = 0;
|
||||
mutex->nm.attr = attr;
|
||||
mutex->nm.workareaPtr = workareaPtr;
|
||||
mutex->waitTimer = 0;
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
workarea.init();
|
||||
|
@ -443,10 +452,10 @@ void sceKernelDeleteLwMutex(u32 workareaPtr)
|
|||
SceUID threadID = *iter;
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && mutex->waitTimer != 0)
|
||||
if (timeoutPtr != 0 && lwMutexWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(mutex->waitTimer, threadID);
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID);
|
||||
Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
|
@ -454,8 +463,6 @@ void sceKernelDeleteLwMutex(u32 workareaPtr)
|
|||
}
|
||||
mutex->waitingThreads.empty();
|
||||
|
||||
// TODO: Any way to erase the CoreTiming event type? We leak.
|
||||
|
||||
RETURN(kernelObjects.Destroy<LwMutex>(workarea.uid));
|
||||
workarea.clear();
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
|
|
|
@ -29,4 +29,7 @@ void sceKernelDeleteLwMutex(u32 workareaPtr);
|
|||
void sceKernelTryLockLwMutex();
|
||||
void sceKernelLockLwMutex();
|
||||
void sceKernelLockLwMutexCB();
|
||||
void sceKernelUnlockLwMutex();
|
||||
void sceKernelUnlockLwMutex();
|
||||
|
||||
void __KernelMutexTimeout(u64 userdata, int cyclesLate);
|
||||
void __KernelLwMutexTimeout(u64 userdata, int cyclesLate);
|
||||
|
|
|
@ -59,9 +59,17 @@ struct Semaphore : public KernelObject
|
|||
|
||||
NativeSemaphore ns;
|
||||
std::vector<SceUID> waitingThreads;
|
||||
int waitTimer;
|
||||
};
|
||||
|
||||
bool semaInitComplete = false;
|
||||
int semaWaitTimer = 0;
|
||||
|
||||
void __KernelSemaInit()
|
||||
{
|
||||
semaWaitTimer = CoreTiming::RegisterEvent("SemaphoreTimeout", &__KernelSemaTimeout);
|
||||
semaInitComplete = true;
|
||||
}
|
||||
|
||||
// Resume all waiting threads (for delete / cancel.)
|
||||
// Returns true if it woke any threads.
|
||||
bool __KernelClearSemaThreads(Semaphore *s, int reason)
|
||||
|
@ -76,21 +84,18 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason)
|
|||
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && s->waitTimer != 0)
|
||||
if (timeoutPtr != 0 && semaWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(s->waitTimer, threadID);
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID);
|
||||
Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, reason);
|
||||
wokeThreads = true;
|
||||
// TODO: set timeoutPtr.
|
||||
}
|
||||
s->waitingThreads.empty();
|
||||
|
||||
// TODO: Any way to erase the CoreTiming event type? We leak.
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
|
@ -139,6 +144,9 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
|
|||
// void because it changes threads.
|
||||
void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
|
||||
{
|
||||
if (!semaInitComplete)
|
||||
__KernelSemaInit();
|
||||
|
||||
if (!name)
|
||||
{
|
||||
RETURN(SCE_KERNEL_ERROR_ERROR);
|
||||
|
@ -156,7 +164,6 @@ void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u3
|
|||
s->ns.currentCount = s->ns.initCount;
|
||||
s->ns.maxCount = maxVal;
|
||||
s->ns.numWaitThreads = 0;
|
||||
s->waitTimer = 0;
|
||||
|
||||
DEBUG_LOG(HLE,"%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr);
|
||||
|
||||
|
@ -247,10 +254,10 @@ retry:
|
|||
s->ns.currentCount -= wVal;
|
||||
s->ns.numWaitThreads--;
|
||||
|
||||
if (timeoutPtr != 0 && s->waitTimer != 0)
|
||||
if (timeoutPtr != 0 && semaWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(s->waitTimer, threadID);
|
||||
int cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID);
|
||||
Memory::Write_U32(cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
|
@ -297,15 +304,12 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate)
|
|||
|
||||
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0)
|
||||
if (timeoutPtr == 0 || semaWaitTimer == 0)
|
||||
return;
|
||||
|
||||
if (s->waitTimer == 0)
|
||||
s->waitTimer = CoreTiming::RegisterEvent("SemaphoreTimeout", &__KernelSemaTimeout);
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), s->waitTimer, __KernelGetCurThread());
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks)
|
||||
|
|
|
@ -25,3 +25,5 @@ void sceKernelReferSemaStatus(SceUID id, u32 infoPtr);
|
|||
void sceKernelSignalSema(SceUID id, int signal);
|
||||
void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr);
|
||||
void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);
|
||||
|
||||
void __KernelSemaTimeout(u64 userdata, int cycleslate);
|
||||
|
|
Loading…
Add table
Reference in a new issue