mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Kernel waits: One timeout event for every kind of object
Semaphores, event flags, mutexes, lwmutexes, mbx, msgpipes, fpl, vpl, tlspl and WaitThreadEnd each had their own CoreTiming event, handler registration and savestate entry for wait timeouts, and their own function to schedule one. Now one event (WaitThreadEnd's, renamed) times out all of them, keyed by thread, and dispatches on the thread's wait type to a timeoutFunc registered alongside the begin/end callback functions. __KernelWaitCurThreadWithTimeout() starts such a wait, and the HLEKernel helpers have overloads that use the shared event. Old savestates still load: each object's section reads its old event id and points it at the shared handler, so a timeout pending in the state goes off as before. Checked with a state saved mid-wait by the previous build, and with four games. The one behaviour change: tlspl timeouts now follow the same hardware rule as the others, where they used the raw timeout. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
0c9438e60c
commit
cc5ee42dda
9 files changed
+176
-203
No files matched your search
@@ -44,6 +44,11 @@ inline void WriteRemainingTimeout(int waitTimer, SceUID threadID, u32 timeoutPtr
|
||||
Memory::WriteOrException_U32((u32)cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
// For kernel object waits, which all time out on the same event (see __KernelWaitCurThreadWithTimeout).
|
||||
inline void WriteRemainingTimeout(SceUID threadID, u32 timeoutPtr) {
|
||||
WriteRemainingTimeout(__KernelWaitTimeoutEvent(), threadID, timeoutPtr);
|
||||
}
|
||||
|
||||
// Should be called from the CoreTiming handler for the wait func.
|
||||
template <typename KO, WaitType waitType>
|
||||
inline void WaitExecTimeout(SceUID threadID) {
|
||||
@@ -188,6 +193,12 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac
|
||||
}
|
||||
}
|
||||
|
||||
// The same, for a kernel object wait timing out on the shared event.
|
||||
template <typename KO, WaitType waitType, typename WaitInfoType>
|
||||
WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
return WaitBeginCallback<KO, waitType, WaitInfoType>(threadID, prevCallbackId, __KernelWaitTimeoutEvent());
|
||||
}
|
||||
|
||||
// Meant to be called in a registered end callback function for a wait type.
|
||||
//
|
||||
// The goal of this function is to resume the wait, or to complete it if a wait is no longer needed.
|
||||
@@ -284,6 +295,12 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI
|
||||
return result;
|
||||
}
|
||||
|
||||
// The same, for a kernel object wait timing out on the shared event.
|
||||
template <typename KO, WaitType waitType, typename WaitInfoType, class TryUnlockFunc>
|
||||
WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, TryUnlockFunc TryUnlock) {
|
||||
return WaitEndCallback<KO, waitType, WaitInfoType>(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), TryUnlock);
|
||||
}
|
||||
|
||||
// Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread().
|
||||
// For a waiting thread info struct.
|
||||
template <typename T>
|
||||
|
||||
@@ -66,23 +66,23 @@ enum PspEventFlagWaitTypes {
|
||||
PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR,
|
||||
};
|
||||
|
||||
static int eventFlagWaitTimer = -1;
|
||||
|
||||
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
|
||||
void __KernelEventFlagInit() {
|
||||
eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", __KernelEventFlagTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback, __KernelEventFlagTimeout);
|
||||
}
|
||||
|
||||
void __KernelEventFlagDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceKernelEventFlag", 1);
|
||||
auto s = p.Section("sceKernelEventFlag", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
Do(p, eventFlagWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(eventFlagWaitTimer, "EventFlagTimeout", __KernelEventFlagTimeout);
|
||||
if (s < 2) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "EventFlagTimeout");
|
||||
}
|
||||
}
|
||||
|
||||
KernelObject *__KernelEventFlagObject() {
|
||||
@@ -128,7 +128,7 @@ static bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(eventFlagWaitTimer, th.threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(th.threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(th.threadID, result);
|
||||
wokeThreads = true;
|
||||
@@ -146,7 +146,7 @@ static bool __KernelClearEventFlagThreads(EventFlag *e, int reason) {
|
||||
}
|
||||
|
||||
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
auto result = HLEKernel::WaitBeginCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, eventFlagWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Suspending lock wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -156,7 +156,7 @@ void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
}
|
||||
|
||||
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
auto result = HLEKernel::WaitEndCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, eventFlagWaitTimer, __KernelUnlockEventFlagForThread);
|
||||
auto result = HLEKernel::WaitEndCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, __KernelUnlockEventFlagForThread);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Resuming lock wait from callback");
|
||||
}
|
||||
@@ -298,14 +298,6 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate) {
|
||||
}
|
||||
}
|
||||
|
||||
static void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0 || eventFlagWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), eventFlagWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) {
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) {
|
||||
return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait);
|
||||
@@ -349,8 +341,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
th.outAddr = timeout == 0 ? 0 : outBitsPtr;
|
||||
e->waitingThreads.push_back(th);
|
||||
|
||||
__KernelSetEventFlagTimeout(e, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited");
|
||||
} else {
|
||||
(void)hleLogDebug(Log::sceKernel, 0);
|
||||
}
|
||||
@@ -414,7 +405,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
|
||||
th.outAddr = timeout == 0 ? 0 : outBitsPtr;
|
||||
e->waitingThreads.push_back(th);
|
||||
|
||||
__KernelSetEventFlagTimeout(e, timeoutPtr);
|
||||
__KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr);
|
||||
if (doCallbackWait)
|
||||
__KernelWaitCallbacksCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr);
|
||||
else
|
||||
|
||||
+12
-22
@@ -47,7 +47,6 @@ struct MbxWaitingThread {
|
||||
};
|
||||
void __KernelMbxTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
static int mbxWaitTimer = -1;
|
||||
|
||||
struct NativeMbx {
|
||||
SceSize_le size;
|
||||
@@ -182,18 +181,20 @@ void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
|
||||
void __KernelMbxInit()
|
||||
{
|
||||
mbxWaitTimer = CoreTiming::RegisterEvent("MbxTimeout", __KernelMbxTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MBX, __KernelMbxBeginCallback, __KernelMbxEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MBX, __KernelMbxBeginCallback, __KernelMbxEndCallback, __KernelMbxTimeout);
|
||||
}
|
||||
|
||||
void __KernelMbxDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelMbx", 1);
|
||||
auto s = p.Section("sceKernelMbx", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
Do(p, mbxWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(mbxWaitTimer, "MbxTimeout", __KernelMbxTimeout);
|
||||
if (s < 2) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MbxTimeout");
|
||||
}
|
||||
}
|
||||
|
||||
KernelObject *__KernelMbxObject()
|
||||
@@ -207,7 +208,7 @@ static bool __KernelUnlockMbxForThread(Mbx *m, MbxWaitingThread &th, u32 &error,
|
||||
return true;
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(mbxWaitTimer, th.threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(th.threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(th.threadID, result);
|
||||
wokeThreads = true;
|
||||
@@ -226,7 +227,7 @@ static bool __KernelUnlockMbxForThreadCheck(Mbx *m, MbxWaitingThread &waitData,
|
||||
|
||||
void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<Mbx, WAITTYPE_MBX, MbxWaitingThread>(threadID, prevCallbackId, mbxWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<Mbx, WAITTYPE_MBX, MbxWaitingThread>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Suspending mbx wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -237,7 +238,7 @@ void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<Mbx, WAITTYPE_MBX, MbxWaitingThread>(threadID, prevCallbackId, mbxWaitTimer, __KernelUnlockMbxForThreadCheck);
|
||||
auto result = HLEKernel::WaitEndCallback<Mbx, WAITTYPE_MBX, MbxWaitingThread>(threadID, prevCallbackId, __KernelUnlockMbxForThreadCheck);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Resuming mbx wait from callback");
|
||||
}
|
||||
@@ -248,15 +249,6 @@ void __KernelMbxTimeout(u64 userdata, int cyclesLate)
|
||||
HLEKernel::WaitExecTimeout<Mbx, WAITTYPE_MBX>(threadID);
|
||||
}
|
||||
|
||||
static void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || mbxWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), mbxWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
static std::vector<MbxWaitingThread>::iterator __KernelMbxFindPriority(std::vector<MbxWaitingThread> &waiting)
|
||||
{
|
||||
_dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
|
||||
@@ -436,8 +428,7 @@ int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) {
|
||||
if (__KernelWaitTimesOutAtOnce(timeoutPtr))
|
||||
return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once");
|
||||
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
|
||||
__KernelWaitMbx(m, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited");
|
||||
return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting");
|
||||
}
|
||||
}
|
||||
@@ -457,8 +448,7 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) {
|
||||
if (__KernelWaitTimesOutAtOnce(timeoutPtr))
|
||||
return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once");
|
||||
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
|
||||
__KernelWaitMbx(m, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited");
|
||||
return hleLogDebug(Log::sceKernel, 0, "no message in queue, waiting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,6 @@ BlockAllocator userMemory(256);
|
||||
BlockAllocator kernelMemory(256);
|
||||
BlockAllocator volatileMemory(256);
|
||||
|
||||
static int vplWaitTimer = -1;
|
||||
static int fplWaitTimer = -1;
|
||||
static int tlsplWaitTimer = -1;
|
||||
static bool tlsplUsedIndexes[TLSPL_NUM_INDEXES];
|
||||
|
||||
// Thread -> TLSPL uids for thread end.
|
||||
@@ -332,9 +329,6 @@ void __KernelMemoryInit()
|
||||
|
||||
INFO_LOG(Log::sceKernel, "Kernel and user memory pools initialized");
|
||||
|
||||
vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout);
|
||||
fplWaitTimer = CoreTiming::RegisterEvent("FplTimeout", __KernelFplTimeout);
|
||||
tlsplWaitTimer = CoreTiming::RegisterEvent("TlsplTimeout", __KernelTlsplTimeout);
|
||||
|
||||
flags_ = 0;
|
||||
sdkVersion_ = 0;
|
||||
@@ -343,8 +337,9 @@ void __KernelMemoryInit()
|
||||
|
||||
__KernelListenThreadEnd(&__KernelTlsplThreadEnd);
|
||||
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_VPL, __KernelVplBeginCallback, __KernelVplEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_FPL, __KernelFplBeginCallback, __KernelFplEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_VPL, __KernelVplBeginCallback, __KernelVplEndCallback, __KernelVplTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_FPL, __KernelFplBeginCallback, __KernelFplEndCallback, __KernelFplTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_TLSPL, nullptr, nullptr, __KernelTlsplTimeout);
|
||||
|
||||
// The kernel statically allocates this memory, which has some code in it.
|
||||
// It appears this is used for some common funcs in Kernel_Library (memcpy, lwmutex, suspend intr, etc.)
|
||||
@@ -354,7 +349,7 @@ void __KernelMemoryInit()
|
||||
|
||||
void __KernelMemoryDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelMemory", 1, 4);
|
||||
auto s = p.Section("sceKernelMemory", 1, 5);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@@ -363,10 +358,13 @@ void __KernelMemoryDoState(PointerWrap &p)
|
||||
if (s >= 3)
|
||||
volatileMemory.DoState(p);
|
||||
|
||||
Do(p, vplWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout);
|
||||
Do(p, fplWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(fplWaitTimer, "FplTimeout", __KernelFplTimeout);
|
||||
if (s < 5) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "VplTimeout");
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "FplTimeout");
|
||||
}
|
||||
Do(p, flags_);
|
||||
Do(p, sdkVersion_);
|
||||
Do(p, compilerVersion_);
|
||||
@@ -374,12 +372,11 @@ void __KernelMemoryDoState(PointerWrap &p)
|
||||
if (s >= 2) {
|
||||
Do(p, tlsplThreadEndChecks);
|
||||
}
|
||||
if (s >= 4) {
|
||||
Do(p, tlsplWaitTimer);
|
||||
} else {
|
||||
tlsplWaitTimer = -1;
|
||||
if (s == 4) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "TlsplTimeout");
|
||||
}
|
||||
CoreTiming::RestoreRegisterEvent(tlsplWaitTimer, "TlsplTimeout", __KernelTlsplTimeout);
|
||||
|
||||
MemBlockInfoDoState(p);
|
||||
}
|
||||
@@ -487,7 +484,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(fplWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
wokeThreads = true;
|
||||
@@ -496,7 +493,7 @@ static bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u
|
||||
|
||||
void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId, fplWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Suspending fpl wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -507,7 +504,7 @@ void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId, fplWaitTimer, __KernelUnlockFplForThread);
|
||||
auto result = HLEKernel::WaitEndCallback<FPL, WAITTYPE_FPL, FplWaitingThread>(threadID, prevCallbackId, __KernelUnlockFplForThread);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Resuming mbx wait from callback");
|
||||
}
|
||||
@@ -636,15 +633,6 @@ void __KernelFplTimeout(u64 userdata, int cyclesLate)
|
||||
HLEKernel::WaitExecTimeout<FPL, WAITTYPE_FPL>(threadID);
|
||||
}
|
||||
|
||||
static void __KernelSetFplTimeout(u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || fplWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), fplWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) {
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
@@ -665,8 +653,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) {
|
||||
FplWaitingThread waiting = {threadID, blockPtrAddr};
|
||||
fpl->waitingThreads.push_back(waiting);
|
||||
|
||||
__KernelSetFplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited");
|
||||
}
|
||||
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
@@ -692,8 +679,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) {
|
||||
FplWaitingThread waiting = {threadID, blockPtrAddr};
|
||||
fpl->waitingThreads.push_back(waiting);
|
||||
|
||||
__KernelSetFplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited");
|
||||
}
|
||||
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
@@ -1275,7 +1261,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(vplWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
wokeThreads = true;
|
||||
@@ -1284,7 +1270,7 @@ static bool __KernelUnlockVplForThread(VPL *vpl, VplWaitingThread &threadInfo, u
|
||||
|
||||
void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId, vplWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Suspending vpl wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -1295,7 +1281,7 @@ void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId, vplWaitTimer, __KernelUnlockVplForThread);
|
||||
auto result = HLEKernel::WaitEndCallback<VPL, WAITTYPE_VPL, VplWaitingThread>(threadID, prevCallbackId, __KernelUnlockVplForThread);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Resuming mbx wait from callback");
|
||||
}
|
||||
@@ -1480,15 +1466,6 @@ void __KernelVplTimeout(u64 userdata, int cyclesLate) {
|
||||
}
|
||||
}
|
||||
|
||||
static void __KernelSetVplTimeout(u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || vplWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), vplWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error, ignore;
|
||||
@@ -1508,8 +1485,7 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
|
||||
vpl->waitingThreads.push_back(waiting);
|
||||
}
|
||||
|
||||
__KernelSetVplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, false, "vpl waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_VPL, uid, size, timeoutPtr, false, "vpl waited");
|
||||
}
|
||||
// If anyone else was waiting, the allocation causes a delay.
|
||||
else if (error == 0 && !vpl->waitingThreads.empty())
|
||||
@@ -1540,8 +1516,7 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
|
||||
vpl->waitingThreads.push_back(waiting);
|
||||
}
|
||||
|
||||
__KernelSetVplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, true, "vpl waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_VPL, uid, size, timeoutPtr, true, "vpl waited");
|
||||
}
|
||||
// If anyone else was waiting, the allocation causes a delay.
|
||||
else if (error == 0 && !vpl->waitingThreads.empty())
|
||||
@@ -1828,7 +1803,7 @@ int __KernelFreeTls(TLSPL *tls, SceUID threadID)
|
||||
// _sceKernelAllocateTlspl waits with its address pointer as the wait value, sceKernelGetTlsAddr with 1.
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(tlsplWaitTimer, waitingThreadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(waitingThreadID, timeoutPtr);
|
||||
u32 addrPtr = __KernelGetWaitValue(waitingThreadID, error);
|
||||
if (addrPtr != TLSPL_WAITVALUE_RETURN_ADDR) {
|
||||
Memory::WriteOrException_U32(freedAddress, addrPtr);
|
||||
@@ -2003,7 +1978,7 @@ int sceKernelDeleteTlspl(SceUID uid)
|
||||
// sceKernelGetTlsAddr returns a null address, _sceKernelAllocateTlspl an error.
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(tlsplWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
u32 result = __KernelGetWaitValue(threadID, error) != TLSPL_WAITVALUE_RETURN_ADDR ? SCE_KERNEL_ERROR_WAIT_DELETE : 0;
|
||||
HLEKernel::ResumeFromWait(threadID, WAITTYPE_TLSPL, uid, result);
|
||||
}
|
||||
@@ -2146,11 +2121,7 @@ int _sceKernelAllocateTlspl(SceUID uid, u32 addrPtr, u32 timeoutPtr) {
|
||||
if (allocAddress == 0) {
|
||||
SceUID threadID = __KernelGetCurThread();
|
||||
tls->waitingThreads.push_back(threadID);
|
||||
if (timeoutPtr != 0 && tlsplWaitTimer != -1) {
|
||||
int micro = (int)Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), tlsplWaitTimer, threadID);
|
||||
}
|
||||
__KernelWaitCurThread(WAITTYPE_TLSPL, uid, addrPtr, timeoutPtr, false, "allocate tls");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_TLSPL, uid, addrPtr, timeoutPtr, false, "allocate tls");
|
||||
return hleLogDebug(Log::sceKernel, 0, "waiting for tls alloc");
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ static const u32 MSGPIPE_WAIT_VALUE_SEND = 0;
|
||||
static const u32 MSGPIPE_WAIT_VALUE_RECV = 1;
|
||||
|
||||
// State: the timer for MsgPipe timeouts.
|
||||
static int waitTimer = -1;
|
||||
|
||||
// NativeMsgPipe/MsgPipeWaitingThread/MsgPipe itself now live in sceKernelMsgPipe.h - see the
|
||||
// comment on the class there for why.
|
||||
@@ -67,7 +66,7 @@ void MsgPipeWaitingThread::WriteCurrentTimeout(SceUID waitID) const
|
||||
if (IsStillWaiting(waitID))
|
||||
{
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(waitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +265,7 @@ static void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate)
|
||||
}
|
||||
|
||||
static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0 || waitTimer == -1)
|
||||
if (timeoutPtr == 0)
|
||||
return true;
|
||||
|
||||
// Always at once up to 2us, never from 3us: what threads/msgpipe/send and receive record, where
|
||||
@@ -277,8 +276,7 @@ static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), waitTimer, __KernelGetCurThread());
|
||||
__KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -489,7 +487,7 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
case MSGPIPE_WAIT_VALUE_SEND:
|
||||
if (ko)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<MsgPipeWaitingThread>(threadID, prevCallbackId, waitTimer, ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0);
|
||||
auto result = HLEKernel::WaitBeginCallback<MsgPipeWaitingThread>(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Suspending wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -502,7 +500,7 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
case MSGPIPE_WAIT_VALUE_RECV:
|
||||
if (ko)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<MsgPipeWaitingThread>(threadID, prevCallbackId, waitTimer, ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0);
|
||||
auto result = HLEKernel::WaitBeginCallback<MsgPipeWaitingThread>(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Suspending wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -569,7 +567,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
if (ko == NULL) {
|
||||
// Deleted during the callback.
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0 && waitTimer != -1)
|
||||
if (timeoutPtr != 0)
|
||||
Memory::WriteOrException_U32(0, timeoutPtr);
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
return;
|
||||
@@ -579,7 +577,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
case MSGPIPE_WAIT_VALUE_SEND:
|
||||
{
|
||||
MsgPipeWaitingThread dummy;
|
||||
auto result = HLEKernel::WaitEndCallback<MsgPipe, WAITTYPE_MSGPIPE, MsgPipeWaitingThread>(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits);
|
||||
auto result = HLEKernel::WaitEndCallback<MsgPipe, WAITTYPE_MSGPIPE, MsgPipeWaitingThread>(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) {
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Resuming wait from callback");
|
||||
} else if (result == HLEKernel::WAIT_CB_TIMED_OUT) {
|
||||
@@ -592,7 +590,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
case MSGPIPE_WAIT_VALUE_RECV:
|
||||
{
|
||||
MsgPipeWaitingThread dummy;
|
||||
auto result = HLEKernel::WaitEndCallback<MsgPipe, WAITTYPE_MSGPIPE, MsgPipeWaitingThread>(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits);
|
||||
auto result = HLEKernel::WaitEndCallback<MsgPipe, WAITTYPE_MSGPIPE, MsgPipeWaitingThread>(threadID, prevCallbackId, __KernelWaitTimeoutEvent(), __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) {
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Resuming wait from callback");
|
||||
} else if (result == HLEKernel::WAIT_CB_TIMED_OUT) {
|
||||
@@ -609,19 +607,21 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
|
||||
void __KernelMsgPipeInit()
|
||||
{
|
||||
waitTimer = CoreTiming::RegisterEvent("MsgPipeTimeout", __KernelMsgPipeTimeout);
|
||||
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MSGPIPE, __KernelMsgPipeBeginCallback, __KernelMsgPipeEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MSGPIPE, __KernelMsgPipeBeginCallback, __KernelMsgPipeEndCallback, __KernelMsgPipeTimeout);
|
||||
}
|
||||
|
||||
void __KernelMsgPipeDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelMsgPipe", 1);
|
||||
auto s = p.Section("sceKernelMsgPipe", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
Do(p, waitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(waitTimer, "MsgPipeTimeout", __KernelMsgPipeTimeout);
|
||||
if (s < 2) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MsgPipeTimeout");
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 optionsPtr) {
|
||||
|
||||
+21
-48
@@ -117,8 +117,6 @@ struct LwMutex : public KernelObject
|
||||
std::map<SceUID, u64> pausedWaits;
|
||||
};
|
||||
|
||||
static int mutexWaitTimer = -1;
|
||||
static int lwMutexWaitTimer = -1;
|
||||
// Thread -> Mutex locks for thread end.
|
||||
typedef std::unordered_multimap<SceUID, SceUID> MutexMap;
|
||||
static MutexMap mutexHeldLocks;
|
||||
@@ -130,24 +128,25 @@ void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
|
||||
void __KernelMutexInit()
|
||||
{
|
||||
mutexWaitTimer = CoreTiming::RegisterEvent("MutexTimeout", __KernelMutexTimeout);
|
||||
lwMutexWaitTimer = CoreTiming::RegisterEvent("LwMutexTimeout", __KernelLwMutexTimeout);
|
||||
|
||||
__KernelListenThreadEnd(&__KernelMutexThreadEnd);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MUTEX, __KernelMutexBeginCallback, __KernelMutexEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_LWMUTEX, __KernelLwMutexBeginCallback, __KernelLwMutexEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_MUTEX, __KernelMutexBeginCallback, __KernelMutexEndCallback, __KernelMutexTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_LWMUTEX, __KernelLwMutexBeginCallback, __KernelLwMutexEndCallback, __KernelLwMutexTimeout);
|
||||
}
|
||||
|
||||
void __KernelMutexDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelMutex", 1);
|
||||
auto s = p.Section("sceKernelMutex", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
Do(p, mutexWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(mutexWaitTimer, "MutexTimeout", __KernelMutexTimeout);
|
||||
Do(p, lwMutexWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(lwMutexWaitTimer, "LwMutexTimeout", __KernelLwMutexTimeout);
|
||||
if (s < 2) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "MutexTimeout");
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "LwMutexTimeout");
|
||||
}
|
||||
Do(p, mutexHeldLocks);
|
||||
}
|
||||
|
||||
@@ -232,7 +231,7 @@ static bool __KernelUnlockMutexForThread(PSPMutex *mutex, SceUID threadID, u32 &
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(mutexWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
return true;
|
||||
@@ -246,7 +245,7 @@ static bool __KernelUnlockMutexForThreadCheck(PSPMutex *mutex, SceUID threadID,
|
||||
|
||||
void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPMutex, WAITTYPE_MUTEX, SceUID>(threadID, prevCallbackId, mutexWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPMutex, WAITTYPE_MUTEX, SceUID>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Suspending lock wait for callback");
|
||||
else
|
||||
@@ -255,7 +254,7 @@ void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<PSPMutex, WAITTYPE_MUTEX, SceUID>(threadID, prevCallbackId, mutexWaitTimer, __KernelUnlockMutexForThreadCheck);
|
||||
auto result = HLEKernel::WaitEndCallback<PSPMutex, WAITTYPE_MUTEX, SceUID>(threadID, prevCallbackId, __KernelUnlockMutexForThreadCheck);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Resuming lock wait for callback");
|
||||
}
|
||||
@@ -428,18 +427,6 @@ void __KernelMutexThreadEnd(SceUID threadID) {
|
||||
}
|
||||
|
||||
// The timeoutPtr is assumed to be checked by the caller to either be 0 or valid.
|
||||
static void __KernelWaitMutex(PSPMutex *mutex, u32 timeoutPtr) {
|
||||
_dbg_assert_(mutexWaitTimer != -1); // this could only come from extremely old savestates.
|
||||
|
||||
if (timeoutPtr == 0 || mutexWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadUnchecked_U32(timeoutPtr);
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) {
|
||||
u32 error;
|
||||
PSPMutex *mutex = kernelObjects.Get<PSPMutex>(uid, error);
|
||||
@@ -513,8 +500,7 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) {
|
||||
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
|
||||
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
|
||||
mutex->waitingThreads.push_back(threadID);
|
||||
__KernelWaitMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_MUTEX, id, count, timeoutPtr, false, "mutex waited");
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
@@ -535,8 +521,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) {
|
||||
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
|
||||
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
|
||||
mutex->waitingThreads.push_back(threadID);
|
||||
__KernelWaitMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true, "mutex waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_MUTEX, id, count, timeoutPtr, true, "mutex waited");
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
@@ -546,7 +531,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) {
|
||||
if (__KernelCurHasReadyCallbacks())
|
||||
{
|
||||
// Might actually end up having to wait, so set the timeout.
|
||||
__KernelWaitMutex(mutex, timeoutPtr);
|
||||
__KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr);
|
||||
__KernelWaitCallbacksCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr);
|
||||
|
||||
// Return value will be written to callback's v0, but... that's probably fine?
|
||||
@@ -688,7 +673,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID,
|
||||
}
|
||||
|
||||
const u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(lwMutexWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
return true;
|
||||
@@ -806,16 +791,6 @@ void __KernelLwMutexTimeout(u64 userdata, int cyclesLate)
|
||||
}
|
||||
|
||||
// timeoutPtr is assumed to be checked by the caller to either be 0 or valid.
|
||||
static void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0 || lwMutexWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadUnchecked_U32(timeoutPtr);
|
||||
|
||||
// This should call __KernelLwMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), lwMutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
static bool __KernelUnlockLwMutexForThreadCheck(LwMutex *mutex, SceUID threadID, u32 &error, int result, bool &wokeThreads)
|
||||
{
|
||||
// The lock state lives in the workarea, nm.lockThread is only refreshed when referred.
|
||||
@@ -826,7 +801,7 @@ static bool __KernelUnlockLwMutexForThreadCheck(LwMutex *mutex, SceUID threadID,
|
||||
|
||||
void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<LwMutex, WAITTYPE_LWMUTEX, SceUID>(threadID, prevCallbackId, lwMutexWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<LwMutex, WAITTYPE_LWMUTEX, SceUID>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Suspending lock wait for callback");
|
||||
else
|
||||
@@ -835,7 +810,7 @@ void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<LwMutex, WAITTYPE_LWMUTEX, SceUID>(threadID, prevCallbackId, lwMutexWaitTimer, __KernelUnlockLwMutexForThreadCheck);
|
||||
auto result = HLEKernel::WaitEndCallback<LwMutex, WAITTYPE_LWMUTEX, SceUID>(threadID, prevCallbackId, __KernelUnlockLwMutexForThreadCheck);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Resuming lock wait for callback");
|
||||
}
|
||||
@@ -899,8 +874,7 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
|
||||
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
|
||||
mutex->waitingThreads.push_back(threadID);
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, false, "lwmutex waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, false, "lwmutex waited");
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return hleLogVerbose(Log::sceKernel, 0);
|
||||
@@ -932,8 +906,7 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
|
||||
if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end())
|
||||
mutex->waitingThreads.push_back(threadID);
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, true, "lwmutex cb waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_LWMUTEX, workarea->uid, count, timeoutPtr, true, "lwmutex cb waited");
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return hleLogVerbose(Log::sceKernel, 0);
|
||||
|
||||
@@ -51,25 +51,26 @@ void PSPSemaphore::DoState(PointerWrap &p) {
|
||||
Do(p, pausedWaits);
|
||||
}
|
||||
|
||||
static int semaWaitTimer = -1;
|
||||
|
||||
void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId);
|
||||
|
||||
void __KernelSemaInit()
|
||||
{
|
||||
semaWaitTimer = CoreTiming::RegisterEvent("SemaphoreTimeout", __KernelSemaTimeout);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_SEMA, __KernelSemaBeginCallback, __KernelSemaEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_SEMA, __KernelSemaBeginCallback, __KernelSemaEndCallback, __KernelSemaTimeout);
|
||||
}
|
||||
|
||||
void __KernelSemaDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceKernelSema", 1);
|
||||
auto s = p.Section("sceKernelSema", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
Do(p, semaWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(semaWaitTimer, "SemaphoreTimeout", __KernelSemaTimeout);
|
||||
if (s < 2) {
|
||||
int oldTimeoutEvent = -1;
|
||||
Do(p, oldTimeoutEvent);
|
||||
__KernelRestoreOldWaitTimeoutEvent(oldTimeoutEvent, "SemaphoreTimeout");
|
||||
}
|
||||
}
|
||||
|
||||
KernelObject *__KernelSemaphoreObject()
|
||||
@@ -93,7 +94,7 @@ static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &e
|
||||
}
|
||||
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
HLEKernel::WriteRemainingTimeout(semaWaitTimer, threadID, timeoutPtr);
|
||||
HLEKernel::WriteRemainingTimeout(threadID, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
wokeThreads = true;
|
||||
@@ -102,7 +103,7 @@ static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &e
|
||||
|
||||
void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPSemaphore, WAITTYPE_SEMA, SceUID>(threadID, prevCallbackId, semaWaitTimer);
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPSemaphore, WAITTYPE_SEMA, SceUID>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Suspending sema wait for callback");
|
||||
else
|
||||
@@ -111,7 +112,7 @@ void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<PSPSemaphore, WAITTYPE_SEMA, SceUID>(threadID, prevCallbackId, semaWaitTimer, __KernelUnlockSemaForThread);
|
||||
auto result = HLEKernel::WaitEndCallback<PSPSemaphore, WAITTYPE_SEMA, SceUID>(threadID, prevCallbackId, __KernelUnlockSemaForThread);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Resuming sema wait for callback");
|
||||
}
|
||||
@@ -290,15 +291,6 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) {
|
||||
}
|
||||
}
|
||||
|
||||
static void __KernelSetSemaTimeout(PSPSemaphore *s, u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0 || semaWaitTimer == -1)
|
||||
return;
|
||||
|
||||
u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
// This should call __KernelSemaTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), semaWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCallbacks) {
|
||||
hleEatCycles(900);
|
||||
|
||||
@@ -326,8 +318,7 @@ static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool pro
|
||||
// May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates.
|
||||
if (std::find(s->waitingThreads.begin(), s->waitingThreads.end(), threadID) == s->waitingThreads.end())
|
||||
s->waitingThreads.push_back(threadID);
|
||||
__KernelSetSemaTimeout(s, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks, "sema waited");
|
||||
__KernelWaitCurThreadWithTimeout(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks, "sema waited");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -477,6 +477,7 @@ struct WaitTypeFuncs
|
||||
{
|
||||
WaitBeginCallbackFunc beginFunc;
|
||||
WaitEndCallbackFunc endFunc;
|
||||
WaitTimeoutFunc timeoutFunc;
|
||||
};
|
||||
|
||||
bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter);
|
||||
@@ -534,7 +535,7 @@ static ThreadQueueList threadReadyQueue;
|
||||
static SceUID threadIdleID[2];
|
||||
|
||||
static int eventScheduledWakeup;
|
||||
static int eventThreadEndTimeout;
|
||||
static int eventWaitTimeout;
|
||||
|
||||
static bool dispatchEnabled = true;
|
||||
|
||||
@@ -697,7 +698,7 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
}
|
||||
|
||||
static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPThread, WAITTYPE_THREADEND, SceUID>(threadID, prevCallbackId, eventThreadEndTimeout);
|
||||
auto result = HLEKernel::WaitBeginCallback<PSPThread, WAITTYPE_THREADEND, SceUID>(threadID, prevCallbackId, eventWaitTimeout);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Suspending wait for callback");
|
||||
else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
|
||||
@@ -713,7 +714,7 @@ static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u
|
||||
if (t->nt.status == THREADSTATUS_DORMANT) {
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error);
|
||||
// Note: unlike the helper in KernelWaitHelpers.h, we unschedule even without a timeout ptr.
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThreadID);
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventWaitTimeout, waitingThreadID);
|
||||
cyclesLeft -= usToCycles(WAIT_TIMEOUT_LATENCY_US);
|
||||
if (cyclesLeft < 0)
|
||||
cyclesLeft = 0;
|
||||
@@ -729,7 +730,7 @@ static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u
|
||||
|
||||
static void __KernelThreadEndEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
{
|
||||
auto result = HLEKernel::WaitEndCallback<PSPThread, WAITTYPE_THREADEND, SceUID>(threadID, prevCallbackId, eventThreadEndTimeout, __KernelCheckResumeThreadEnd);
|
||||
auto result = HLEKernel::WaitEndCallback<PSPThread, WAITTYPE_THREADEND, SceUID>(threadID, prevCallbackId, eventWaitTimeout, __KernelCheckResumeThreadEnd);
|
||||
if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Resuming wait from callback");
|
||||
}
|
||||
@@ -761,6 +762,7 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid) {
|
||||
|
||||
void hleScheduledWakeup(u64 userdata, int cyclesLate);
|
||||
void hleThreadEndTimeout(u64 userdata, int cyclesLate);
|
||||
static void __KernelWaitTimeoutFired(u64 userdata, int cyclesLate);
|
||||
|
||||
static void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos) {
|
||||
*ptr = pos;
|
||||
@@ -824,7 +826,7 @@ void __KernelThreadingInit() {
|
||||
}
|
||||
|
||||
eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup);
|
||||
eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
eventWaitTimeout = CoreTiming::RegisterEvent("WaitTimeout", &__KernelWaitTimeoutFired);
|
||||
eventBusySyscallDone = CoreTiming::RegisterEvent("BusySyscallDone", &__KernelBusySyscallDone);
|
||||
busySyscalls.clear();
|
||||
actionAfterMipsCall = __KernelRegisterActionType(ActionAfterMipsCall::Create);
|
||||
@@ -843,7 +845,7 @@ void __KernelThreadingInit() {
|
||||
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_DELAY, __KernelDelayBeginCallback, __KernelDelayEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_SLEEP, __KernelSleepBeginCallback, __KernelSleepEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_THREADEND, __KernelThreadEndBeginCallback, __KernelThreadEndEndCallback);
|
||||
__KernelRegisterWaitTypeFuncs(WAITTYPE_THREADEND, __KernelThreadEndBeginCallback, __KernelThreadEndEndCallback, &hleThreadEndTimeout);
|
||||
}
|
||||
|
||||
void __KernelThreadingDoState(PointerWrap &p)
|
||||
@@ -883,8 +885,8 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
|
||||
Do(p, eventScheduledWakeup);
|
||||
CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup);
|
||||
Do(p, eventThreadEndTimeout);
|
||||
CoreTiming::RestoreRegisterEvent(eventThreadEndTimeout, "ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
Do(p, eventWaitTimeout);
|
||||
CoreTiming::RestoreRegisterEvent(eventWaitTimeout, "WaitTimeout", &__KernelWaitTimeoutFired);
|
||||
Do(p, actionAfterMipsCall);
|
||||
__KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create);
|
||||
Do(p, actionAfterCallback);
|
||||
@@ -1560,15 +1562,44 @@ void hleThreadEndTimeout(u64 userdata, int cyclesLate)
|
||||
HLEKernel::WaitExecTimeout<PSPThread, WAITTYPE_THREADEND>(threadID);
|
||||
}
|
||||
|
||||
static void __KernelScheduleThreadEndTimeout(SceUID threadID, SceUID waitForID, s64 usFromNow)
|
||||
{
|
||||
s64 cycles = usToCycles(usFromNow);
|
||||
CoreTiming::ScheduleEvent(cycles, eventThreadEndTimeout, threadID);
|
||||
// One event times out every kernel object wait (the thread only has one wait at a time), and hands
|
||||
// over to the timeout function registered for the thread's wait type.
|
||||
static void __KernelWaitTimeoutFired(u64 userdata, int cyclesLate) {
|
||||
u32 error;
|
||||
const PSPThread *thread = kernelObjects.Get<PSPThread>((SceUID)userdata, error);
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
const WaitTimeoutFunc func = waitTypeFuncs[thread->nt.waitType].timeoutFunc;
|
||||
if (func) {
|
||||
func(userdata, cyclesLate);
|
||||
}
|
||||
}
|
||||
|
||||
int __KernelWaitTimeoutEvent() {
|
||||
return eventWaitTimeout;
|
||||
}
|
||||
|
||||
void __KernelScheduleWaitTimeout(SceUID threadID, u32 timeoutPtr) {
|
||||
if (timeoutPtr == 0) {
|
||||
return;
|
||||
}
|
||||
const u32 micro = Memory::ReadOrException_U32(timeoutPtr);
|
||||
CoreTiming::ScheduleEvent(usToCycles(__KernelWaitTimeoutUs(micro)), eventWaitTimeout, threadID);
|
||||
}
|
||||
|
||||
void __KernelWaitCurThreadWithTimeout(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason) {
|
||||
__KernelScheduleWaitTimeout(__KernelGetCurThread(), timeoutPtr);
|
||||
__KernelWaitCurThread(type, waitID, waitValue, timeoutPtr, processCallbacks, reason);
|
||||
}
|
||||
|
||||
void __KernelRestoreOldWaitTimeoutEvent(int &eventType, const char *name) {
|
||||
CoreTiming::RestoreRegisterEvent(eventType, name, &__KernelWaitTimeoutFired);
|
||||
}
|
||||
|
||||
void __KernelCancelThreadEndTimeout(SceUID threadID)
|
||||
{
|
||||
CoreTiming::UnscheduleEvent(eventThreadEndTimeout, threadID);
|
||||
CoreTiming::UnscheduleEvent(eventWaitTimeout, threadID);
|
||||
}
|
||||
|
||||
static void __KernelRemoveFromThreadQueue(SceUID threadID) {
|
||||
@@ -1597,7 +1628,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason)
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThread, error);
|
||||
if (HLEKernel::VerifyWait(waitingThread, WAITTYPE_THREADEND, threadID))
|
||||
{
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThread) - usToCycles(WAIT_TIMEOUT_LATENCY_US);
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventWaitTimeout, waitingThread) - usToCycles(WAIT_TIMEOUT_LATENCY_US);
|
||||
if (cyclesLeft < 0)
|
||||
cyclesLeft = 0;
|
||||
if (timeoutPtr != 0)
|
||||
@@ -2852,8 +2883,7 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) {
|
||||
{
|
||||
if (__KernelWaitTimesOutAtOnce(timeoutPtr))
|
||||
return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once");
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, __KernelWaitTimeoutUs(Memory::ReadUnchecked_U32(timeoutPtr)));
|
||||
__KernelScheduleWaitTimeout(currentThread, Memory::IsValidAddress(timeoutPtr) ? timeoutPtr : 0);
|
||||
if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end())
|
||||
t->waitingThreads.push_back(currentThread);
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, false, "thread wait end");
|
||||
@@ -2881,8 +2911,7 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) {
|
||||
{
|
||||
if (__KernelWaitTimesOutAtOnce(timeoutPtr))
|
||||
return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_WAIT_TIMEOUT, "timed out at once");
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, __KernelWaitTimeoutUs(Memory::ReadUnchecked_U32(timeoutPtr)));
|
||||
__KernelScheduleWaitTimeout(currentThread, Memory::IsValidAddress(timeoutPtr) ? timeoutPtr : 0);
|
||||
if (std::find(t->waitingThreads.begin(), t->waitingThreads.end(), currentThread) == t->waitingThreads.end())
|
||||
t->waitingThreads.push_back(currentThread);
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, true, "thread wait end");
|
||||
@@ -3844,10 +3873,11 @@ void __KernelNotifyCallback(SceUID cbId, int notifyArg)
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc)
|
||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc, WaitTimeoutFunc timeoutFunc)
|
||||
{
|
||||
waitTypeFuncs[type].beginFunc = beginFunc;
|
||||
waitTypeFuncs[type].endFunc = endFunc;
|
||||
waitTypeFuncs[type].timeoutFunc = timeoutFunc;
|
||||
}
|
||||
|
||||
std::vector<DebugThreadInfo> GetThreadsInfo() {
|
||||
|
||||
@@ -137,7 +137,9 @@ typedef void (* WaitBeginCallbackFunc)(SceUID threadID, SceUID prevCallbackId);
|
||||
// Resume wait and timeout as a thread exits a callback.
|
||||
typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId);
|
||||
|
||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc);
|
||||
typedef void (*WaitTimeoutFunc)(u64 threadID, int cyclesLate);
|
||||
// timeoutFunc runs when a wait of this type, started with __KernelWaitCurThreadWithTimeout(), times out.
|
||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc, WaitTimeoutFunc timeoutFunc = nullptr);
|
||||
|
||||
#if COMMON_LITTLE_ENDIAN
|
||||
typedef WaitType WaitType_le;
|
||||
@@ -385,6 +387,14 @@ void __KernelWaitCurThread(WaitType type, SceUID waitId, u32 waitValue, u32 time
|
||||
// See the definition for how hardware times waits out.
|
||||
bool __KernelWaitTimesOutAtOnce(u32 timeoutPtr, int basePercent = 85, int stepPercent = 35);
|
||||
s64 __KernelWaitTimeoutUs(u32 micro);
|
||||
// The one CoreTiming event every kernel object wait's timeout runs on, keyed by thread.
|
||||
int __KernelWaitTimeoutEvent();
|
||||
// Schedules the timeout for a wait about to start, if timeoutPtr (0 or valid) gives one.
|
||||
void __KernelScheduleWaitTimeout(SceUID threadID, u32 timeoutPtr);
|
||||
// Starts a wait on a kernel object, with the timeout the hardware would use.
|
||||
void __KernelWaitCurThreadWithTimeout(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason);
|
||||
// Old savestates had an event per kind of object. Points one at the shared handler.
|
||||
void __KernelRestoreOldWaitTimeoutEvent(int &eventType, const char *name);
|
||||
// How long after its deadline a wait's timeout goes off. Not part of the time left written back.
|
||||
const int WAIT_TIMEOUT_LATENCY_US = 18;
|
||||
// The deadline is taken this far into the call, after what we already charge before scheduling.
|
||||
|
||||
Reference in new issue
Block a user