Consider threads still waiting until they wake.

This seems to match the actual behavior of timeouts much better.
This commit is contained in:
Unknown W. Brackets 2012-11-30 23:04:24 -08:00
parent 48c5efd0c2
commit 998104e2eb
3 changed files with 42 additions and 20 deletions

View File

@ -215,6 +215,10 @@ void sceKernelDeleteMutex(SceUID id)
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
// The waitID may be different after a timeout.
if (waitID != id)
continue;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0 && mutexWaitTimer != 0)
@ -288,9 +292,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error)
// TODO: PSP_MUTEX_ATTR_PRIORITY
bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end;
retry:
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
// The waitID may be different after a timeout.
if (waitID != mutex->GetUID())
{
mutex->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
@ -325,14 +337,6 @@ void __KernelMutexTimeout(u64 userdata, int cyclesLate)
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
Mutex *mutex = kernelObjects.Get<Mutex>(mutexID, error);
if (mutex)
{
// This thread isn't waiting anymore.
mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end());
}
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
@ -543,6 +547,10 @@ void sceKernelDeleteLwMutex(u32 workareaPtr)
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error);
// The waitID may be different after a timeout.
if (waitID != mutex->GetUID())
continue;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0 && lwMutexWaitTimer != 0)
@ -631,9 +639,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error)
// TODO: PSP_MUTEX_ATTR_PRIORITY
bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end;
retry:
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error);
// The waitID may be different after a timeout.
if (waitID != mutex->GetUID())
{
mutex->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
@ -669,14 +685,6 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate)
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error);
LwMutex *mutex = kernelObjects.Get<LwMutex>(mutexID, error);
if (mutex)
{
// This thread isn't waiting anymore.
mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end());
}
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}

View File

@ -80,9 +80,13 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason)
std::vector<SceUID>::iterator iter;
for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter)
{
SceUID threadID = *iter;
u32 error;
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
// The waitID may be different after a timeout.
if (waitID != s->GetUID())
continue;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0 && semaWaitTimer != 0)
{
@ -242,6 +246,13 @@ retry:
for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
// The waitID may be different after a timeout.
if (waitID != s->GetUID())
{
s->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
@ -288,8 +299,7 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate)
Semaphore *s = kernelObjects.Get<Semaphore>(semaID, error);
if (s)
{
// This thread isn't waiting anymore.
s->waitingThreads.erase(std::remove(s->waitingThreads.begin(), s->waitingThreads.end(), threadID), s->waitingThreads.end());
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
s->ns.numWaitThreads--;
}

View File

@ -1545,6 +1545,10 @@ void __KernelSwitchContext(Thread *target, const char *reason)
__KernelLoadContext(&currentThread->context);
DEBUG_LOG(HLE,"Context loaded (%s): %i - %s - pc: %08x", reason, currentThread->GetUID(), currentThread->GetName(), currentMIPS->pc);
// No longer waiting.
currentThread->nt.waitType = WAITTYPE_NONE;
currentThread->nt.waitID = 0;
__KernelExecutePendingMipsCalls();
}