mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Implement deferred rescheduling/callbacks.
This way most HLE functions can be wrapped normally. Hurray, sanity.
This commit is contained in:
parent
000884fadb
commit
5e8aa4c071
@ -25,10 +25,27 @@
|
||||
#include "sceIo.h"
|
||||
#include "sceAudio.h"
|
||||
#include "sceKernelMemory.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "../MIPS/MIPSCodeUtils.h"
|
||||
|
||||
static std::vector<HLEModule> moduleDB;
|
||||
static std::vector<Syscall> 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
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -269,7 +269,7 @@ void sceKernelDeleteMutex(SceUID id)
|
||||
RETURN(kernelObjects.Destroy<Mutex>(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
|
||||
|
@ -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<Semaphore>(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
|
||||
{
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user