mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-25 11:19:03 +01:00
Merge pull request #1287 from unknownbrackets/callbacks
Callback fixes, event flags edition
This commit is contained in:
commit
e34c919c3f
3 files changed
+133
-2
No files matched your search
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in new issue
Block a user