From 5e8aa4c0719fc2767df568057dba21811845cee7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 8 Dec 2012 22:39:36 -0800 Subject: [PATCH] Implement deferred rescheduling/callbacks. This way most HLE functions can be wrapped normally. Hurray, sanity. --- Core/HLE/HLE.cpp | 55 +++++++++++++++++++++++++++++++++ Core/HLE/HLE.h | 8 +++++ Core/HLE/sceKernelMutex.cpp | 12 +++---- Core/HLE/sceKernelSemaphore.cpp | 10 +++--- Core/HLE/sceKernelThread.cpp | 25 +++++++-------- Core/HLE/sceUmd.cpp | 8 ++--- 6 files changed, 90 insertions(+), 28 deletions(-) diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 5313b5a1f2..eebc8bc888 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -25,10 +25,27 @@ #include "sceIo.h" #include "sceAudio.h" #include "sceKernelMemory.h" +#include "sceKernelThread.h" #include "../MIPS/MIPSCodeUtils.h" static std::vector moduleDB; static std::vector unresolvedSyscalls; +static int hleAfterSyscall; +static const char *hleAfterSyscallReschedReason; + +enum +{ + // Do nothing after the syscall. + HLE_AFTER_NOTHING = 0x00, + // Reschedule immediately after the syscall. + HLE_AFTER_RESCHED = 0x01, + // Call current thread's callbacks after the syscall. + HLE_AFTER_CURRENT_CALLBACKS = 0x02, + // Check all threads' callbacks after the syscall. + HLE_AFTER_ALL_CALLBACKS = 0x04, + // Reschedule and process current thread's callbacks after the syscall. + HLE_AFTER_RESCHED_CALLBACKS = 0x08, +}; void HLEInit() { @@ -177,6 +194,30 @@ const char *GetFuncName(int moduleIndex, int func) return "[unknown]"; } +void hleCheckAllCallbacks() +{ + hleAfterSyscall |= HLE_AFTER_ALL_CALLBACKS; +} + +void hleCheckCurrentCallbacks() +{ + hleAfterSyscall |= HLE_AFTER_CURRENT_CALLBACKS; +} + +void hleReSchedule(const char *reason) +{ + _dbg_assert_msg_(HLE, reason != 0, "hleReSchedule: Expecting a valid reason."); + + hleAfterSyscall |= HLE_AFTER_RESCHED; + hleAfterSyscallReschedReason = reason; +} + +void hleReSchedule(bool callbacks, const char *reason) +{ + hleReSchedule(reason); + hleAfterSyscall |= HLE_AFTER_RESCHED_CALLBACKS; +} + void CallSyscall(u32 op) { u32 callno = (op >> 6) & 0xFFFFF; //20 bits @@ -191,7 +232,21 @@ void CallSyscall(u32 op) HLEFunc func = moduleDB[modulenum].funcTable[funcnum].func; if (func) { + hleAfterSyscall = HLE_AFTER_NOTHING; + hleAfterSyscallReschedReason = 0; + func(); + + if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0) + __KernelForceCallbacks(); + + // Rescheduling will also do HLE_AFTER_ALL_CALLBACKS. + if ((hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) != 0) + __KernelReSchedule(true, hleAfterSyscallReschedReason); + else if ((hleAfterSyscall & HLE_AFTER_RESCHED) != 0) + __KernelReSchedule(hleAfterSyscallReschedReason); + else if ((hleAfterSyscall & HLE_AFTER_ALL_CALLBACKS) != 0) + __KernelCheckCallbacks(); } else { diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 9305057b61..83633b134f 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -73,6 +73,14 @@ int GetModuleIndex(const char *modulename); void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable); +// Run the current thread's callbacks after the syscall finishes. +void hleCheckCurrentCallbacks(); +// Check and potentially run all thread's callbacks after the syscall finishes. +void hleCheckAllCallbacks(); +// Reschedule after the syscall finishes. +void hleReSchedule(const char *reason); +// Reschedule and go into a callback processing state after the syscall finishes. +void hleReSchedule(bool callbacks, const char *reason); void HLEInit(); void HLEShutdown(); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index c9936f48a3..bae59ab945 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -269,7 +269,7 @@ void sceKernelDeleteMutex(SceUID id) RETURN(kernelObjects.Destroy(id)); if (wokeThreads) - __KernelReSchedule("mutex deleted"); + hleReSchedule("mutex deleted"); } else RETURN(error); @@ -430,7 +430,7 @@ void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) if (__KernelLockMutex(mutex, count, error)) { RETURN(0); - __KernelForceCallbacks(); + hleCheckCurrentCallbacks(); } else if (error) RETURN(error); @@ -490,7 +490,7 @@ void sceKernelUnlockMutex(SceUID id, int count) if (mutex->nm.lockLevel == 0) { if (__KernelUnlockMutex(mutex, error)) - __KernelReSchedule("mutex unlocked"); + hleReSchedule("mutex unlocked"); } } @@ -596,7 +596,7 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) Memory::WriteStruct(workareaPtr, &workarea); if (wokeThreads) - __KernelReSchedule("lwmutex deleted"); + hleReSchedule("lwmutex deleted"); } else RETURN(error); @@ -789,7 +789,7 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { Memory::WriteStruct(workareaPtr, &workarea); RETURN(0); - __KernelForceCallbacks(); + hleCheckCurrentCallbacks(); } else if (error) RETURN(error); @@ -838,7 +838,7 @@ void sceKernelUnlockLwMutex(u32 workareaPtr, int count) if (workarea.lockLevel == 0) { if (__KernelUnlockLwMutex(workarea, error)) - __KernelReSchedule("lwmutex unlocked"); + hleReSchedule("lwmutex unlocked"); Memory::WriteStruct(workareaPtr, &workarea); } else diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index fccd3d0c6c..1edaee93bf 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -168,7 +168,7 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) RETURN(0); if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) - __KernelReSchedule("semaphore canceled"); + hleReSchedule("semaphore canceled"); } else { @@ -224,7 +224,7 @@ void sceKernelDeleteSema(SceUID id) RETURN(kernelObjects.Destroy(id)); if (wokeThreads) - __KernelReSchedule("semaphore deleted"); + hleReSchedule("semaphore deleted"); } else { @@ -291,12 +291,12 @@ retry: } if (wokeThreads) - __KernelReSchedule("semaphore signaled"); + hleReSchedule("semaphore signaled"); } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - RETURN(error;) + RETURN(error); } } @@ -356,7 +356,7 @@ void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *ba { s->ns.currentCount -= wantedCount; if (processCallbacks) - __KernelForceCallbacks(); + hleCheckCurrentCallbacks(); } else { diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index acb46f66bf..7dc3683825 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -397,7 +397,7 @@ void __KernelIdle() // In Advance, we might trigger an interrupt such as vblank. // If we end up in an interrupt, we don't want to reschedule. // However, we have to reschedule... damn. - __KernelReSchedule("idle"); + hleReSchedule("idle"); } void __KernelThreadingShutdown() @@ -618,10 +618,9 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, int retval) } } -// DANGEROUS // Only run when you can safely accept a context switch // Triggers a waitable event, that is, it wakes up all threads that waits for it -// If any changes were made, it will context switch +// If any changes were made, it will context switch after the syscall bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool dontSwitch) { bool doneAnything = false; @@ -649,7 +648,7 @@ bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool // TODO: time waster char temp[256]; sprintf(temp, "resumed from wait %s", waitTypeStrings[(int)type]); - __KernelReSchedule(temp); + hleReSchedule(temp); } } return true; @@ -681,7 +680,7 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time char temp[256]; sprintf(temp, "started wait %s", waitTypeStrings[(int)type]); - __KernelReSchedule(processCallbacks, temp); + hleReSchedule(processCallbacks, temp); // TODO: Remove thread from Ready queue? } @@ -998,7 +997,7 @@ void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr) } RETURN(0); - __KernelReSchedule("thread started"); + hleReSchedule("thread started"); } else { @@ -1058,7 +1057,7 @@ void __KernelReturnFromThread() // Find threads that waited for me // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("return from thread"); + hleReSchedule("return from thread"); // The stack will be deallocated when the thread is deleted. } @@ -1073,7 +1072,7 @@ void sceKernelExitThread() //Find threads that waited for me // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("exited thread"); + hleReSchedule("exited thread"); // The stack will be deallocated when the thread is deleted. } @@ -1088,7 +1087,7 @@ void _sceKernelExitThread() //Find threads that waited for this one // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("exit-deleted thread"); + hleReSchedule("exit-deleted thread"); // The stack will be deallocated when the thread is deleted. } @@ -1140,7 +1139,7 @@ u32 sceKernelResumeDispatchThread(u32 suspended) void sceKernelRotateThreadReadyQueue() { DEBUG_LOG(HLE,"sceKernelRotateThreadReadyQueue : rescheduling"); - __KernelReSchedule("rotatethreadreadyqueue"); + hleReSchedule("rotatethreadreadyqueue"); } void sceKernelDeleteThread() @@ -1164,7 +1163,7 @@ void sceKernelDeleteThread() //TODO: should we really reschedule here? //if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle)) - // __KernelReSchedule("thread deleted"); + // hleReSchedule("thread deleted"); } } else @@ -1185,7 +1184,7 @@ void sceKernelTerminateDeleteThread() //TODO: should we really reschedule here? if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadno)) - __KernelReSchedule("termdeletethread"); + hleReSchedule("termdeletethread"); } else { @@ -1766,7 +1765,7 @@ void __KernelReturnFromMipsCall() { // Sometimes, we want to stay on the thread. if (call->reschedAfter) - __KernelReSchedule("return from callback"); + hleReSchedule("return from callback"); } } diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index f960edd72b..7868cb3fa1 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -132,7 +132,7 @@ void sceUmdActivate(u32 unknown, const char *name) RETURN(0); if (changed) - __KernelReSchedule("umd activated"); + hleReSchedule("umd activated"); } void sceUmdDeactivate(u32 unknown, const char *name) @@ -161,7 +161,7 @@ void sceUmdDeactivate(u32 unknown, const char *name) RETURN(0); if (changed) - __KernelReSchedule("umd deactivated"); + hleReSchedule("umd deactivated"); } u32 sceUmdRegisterUMDCallBack(u32 cbId) @@ -268,7 +268,7 @@ void sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); - __KernelForceCallbacks(); + hleCheckCurrentCallbacks(); } else { @@ -284,7 +284,7 @@ void sceUmdWaitDriveStatCB(u32 stat, u32 timeout) __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true); } else if (driveCBId != -1) - __KernelReSchedule("umd stat waited"); + hleReSchedule("umd stat waited"); } void sceUmdCancelWaitDriveStat()