Merge pull request #1287 from unknownbrackets/callbacks

Callback fixes, event flags edition
This commit is contained in:
Henrik Rydgård committed 2013-04-15 01:20:19 -07:00
commit e34c919c3f
3 files changed
+133 -2

No files matched your search

+124 -2
View File
@@ -45,6 +45,7 @@ struct EventFlagTh
u32 bits;
u32 wait;
u32 outAddr;
u64 pausedTimeout;
};
class EventFlag : public KernelObject
@@ -70,11 +71,14 @@ public:
p.Do(nef);
EventFlagTh eft = {0};
p.Do(waitingThreads, eft);
p.Do(pausedWaits);
p.DoMarker("EventFlag");
}
NativeEventFlag nef;
std::vector<EventFlagTh> waitingThreads;
// Key is the callback id it was for, or if no callback, the thread id.
std::map<SceUID, EventFlagTh> pausedWaits;
};
@@ -102,9 +106,13 @@ enum PspEventFlagWaitTypes
int eventFlagWaitTimer = -1;
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId);
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &returnValue);
void __KernelEventFlagInit()
{
eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", __KernelEventFlagTimeout);
__KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback);
}
void __KernelEventFlagDoState(PointerWrap &p)
@@ -186,6 +194,109 @@ bool __KernelClearEventFlagThreads(EventFlag *e, int reason)
return wokeThreads;
}
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId)
{
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
u32 error;
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
EventFlag *flag = flagID == 0 ? NULL : kernelObjects.Get<EventFlag>(flagID, error);
if (flag)
{
// This means two callbacks in a row. PSP crashes if the same callback runs inside itself.
// TODO: Handle this better?
if (flag->pausedWaits.find(pauseKey) != flag->pausedWaits.end())
return;
EventFlagTh waitData = {0};
for (size_t i = 0; i < flag->waitingThreads.size(); i++)
{
EventFlagTh *t = &flag->waitingThreads[i];
if (t->tid == threadID)
{
waitData = *t;
// TODO: Hmm, what about priority/fifo order? Does it lose its place in line?
flag->waitingThreads.erase(flag->waitingThreads.begin() + i);
flag->nef.numWaitThreads--;
break;
}
}
if (waitData.tid != threadID)
{
ERROR_LOG_REPORT(HLE, "sceKernelWaitEventFlagCB: wait not found to pause for callback");
return;
}
if (timeoutPtr != 0 && eventFlagWaitTimer != -1)
{
s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, threadID);
waitData.pausedTimeout = CoreTiming::GetTicks() + cyclesLeft;
}
else
waitData.pausedTimeout = 0;
flag->pausedWaits[pauseKey] = waitData;
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB: Suspending lock wait for callback");
}
else
WARN_LOG_REPORT(HLE, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?");
}
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &returnValue)
{
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
u32 error;
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
EventFlag *flag = flagID == 0 ? NULL : kernelObjects.Get<EventFlag>(flagID, error);
if (!flag || flag->pausedWaits.find(pauseKey) == flag->pausedWaits.end())
{
// TODO: Since it was deleted, we don't know how long was actually left.
// For now, we just say the full time was taken.
if (timeoutPtr != 0 && eventFlagWaitTimer != -1)
Memory::Write_U32(0, timeoutPtr);
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE);
return;
}
EventFlagTh waitData = flag->pausedWaits[pauseKey];
u64 waitDeadline = waitData.pausedTimeout;
flag->pausedWaits.erase(pauseKey);
flag->nef.numWaitThreads++;
// TODO: Don't wake up if __KernelCurHasReadyCallbacks()?
bool wokeThreads;
// Attempt to unlock.
if (__KernelUnlockEventFlagForThread(flag, waitData, error, 0, wokeThreads))
return;
// We only check if it timed out if it couldn't unlock.
s64 cyclesLeft = waitDeadline - CoreTiming::GetTicks();
if (cyclesLeft < 0 && waitDeadline != 0)
{
if (timeoutPtr != 0 && eventFlagWaitTimer != -1)
Memory::Write_U32(0, timeoutPtr);
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
else
{
if (timeoutPtr != 0 && eventFlagWaitTimer != -1)
CoreTiming::ScheduleEvent(cyclesLeft, eventFlagWaitTimer, __KernelGetCurThread());
// TODO: Should this not go at the end?
flag->waitingThreads.push_back(waitData);
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB: Resuming lock wait for callback");
}
}
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr)
{
@@ -454,7 +565,15 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
if (e)
{
EventFlagTh th;
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
bool doWait = !__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr);
bool doCallbackWait = false;
if (__KernelCurHasReadyCallbacks())
{
doWait = true;
doCallbackWait = true;
}
if (doWait)
{
// If this thread was left in waitingThreads after a timeout, remove it.
// Otherwise we might write the outBitsPtr in the wrong place.
@@ -478,7 +597,10 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
e->waitingThreads.push_back(th);
__KernelSetEventFlagTimeout(e, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited");
if (doCallbackWait)
__KernelWaitCallbacksCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr);
else
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited");
}
else
hleCheckCurrentCallbacks();
+6
View File
@@ -343,6 +343,9 @@ void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &retur
}
else
{
if (timeoutPtr != 0 && mutexWaitTimer != -1)
CoreTiming::ScheduleEvent(cyclesLeft, mutexWaitTimer, __KernelGetCurThread());
// TODO: Should this not go at the end?
mutex->waitingThreads.push_back(threadID);
@@ -986,6 +989,9 @@ void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &ret
}
else
{
if (timeoutPtr != 0 && lwMutexWaitTimer != -1)
CoreTiming::ScheduleEvent(cyclesLeft, lwMutexWaitTimer, __KernelGetCurThread());
// TODO: Should this not go at the end?
mutex->waitingThreads.push_back(threadID);
+3
View File
@@ -209,6 +209,9 @@ void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &return
}
else
{
if (timeoutPtr != 0 && semaWaitTimer != -1)
CoreTiming::ScheduleEvent(cyclesLeft, semaWaitTimer, __KernelGetCurThread());
// TODO: Should this not go at the end?
s->waitingThreads.push_back(threadID);