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:
Unknown W. Brackets 2012-11-19 07:31:36 -08:00
parent a81c138004
commit 8da2fb074c
4 changed files with 50 additions and 34 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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);