Refactor wait timeouts.

Also, make them not write the timeout ptr if the thread stopped waiting.
Feels safer.
This commit is contained in:
Unknown W. Brackets 2013-09-03 22:27:28 -07:00
parent 2a7e9a5afc
commit 543df7ca7a
6 changed files with 32 additions and 87 deletions

View File

@ -25,6 +25,26 @@
namespace HLEKernel
{
// Should be called from the CoreTiming handler for the wait func.
template <typename KO, WaitType waitType>
inline void WaitExecTimeout(SceUID threadID) {
u32 error;
SceUID uid = __KernelGetWaitID(threadID, waitType, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
KO *ko = uid == 0 ? NULL : kernelObjects.Get<KO>(uid, error);
if (ko)
{
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
}
// Move a thead from the waiting thread list to the paused thread list.
// This version is for vectors which contain structs, which must have SceUID threadID and u64 pausedTimeout.
// Should not be called directly.

View File

@ -355,15 +355,16 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate)
{
SceUID threadID = (SceUID)userdata;
// This still needs to set the result pointer from the wait.
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
EventFlag *e = kernelObjects.Get<EventFlag>(flagID, error);
if (e)
{
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
for (size_t i = 0; i < e->waitingThreads.size(); i++)
{
EventFlagTh *t = &e->waitingThreads[i];

View File

@ -257,24 +257,7 @@ void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId)
void __KernelMbxTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID)userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID mbxID = __KernelGetWaitID(threadID, WAITTYPE_MBX, error);
Mbx *m = kernelObjects.Get<Mbx>(mbxID, error);
if (m)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
// TODO: Should numWaitThreads be decreased yet?
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<Mbx, WAITTYPE_MBX>(threadID);
}
void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)

View File

@ -457,22 +457,7 @@ int sceKernelDeleteFpl(SceUID uid)
void __KernelFplTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_FPL, error);
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
if (fpl)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<FPL, WAITTYPE_FPL>(threadID);
}
void __KernelSetFplTimeout(u32 timeoutPtr)
@ -1383,22 +1368,7 @@ bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, const ch
void __KernelVplTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_VPL, error);
VPL *vpl = kernelObjects.Get<VPL>(uid, error);
if (vpl)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<VPL, WAITTYPE_VPL>(threadID);
}
void __KernelSetVplTimeout(u32 timeoutPtr)

View File

@ -25,6 +25,7 @@
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/KernelWaitHelpers.h"
#include "Common/ChunkFile.h"
#define SCE_KERNEL_MPA_THFIFO_S 0x0000
@ -297,23 +298,8 @@ KernelObject *__KernelMsgPipeObject()
void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) (userdata & 0xFFFFFFFF);
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_MSGPIPE, error);
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
if (m)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but whhile it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
SceUID threadID = (SceUID) userdata;
HLEKernel::WaitExecTimeout<MsgPipe, WAITTYPE_MSGPIPE>(threadID);
}
bool __KernelSetMsgPipeTimeout(u32 timeoutPtr)

View File

@ -334,22 +334,7 @@ retry:
void __KernelSemaTimeout(u64 userdata, int cycleslate)
{
SceUID threadID = (SceUID)userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID semaID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
Semaphore *s = kernelObjects.Get<Semaphore>(semaID, error);
if (s)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<Semaphore, WAITTYPE_SEMA>(threadID);
}
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)