mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 21:39:52 +00:00
ThreadEvent: Initial support for create/delete.
This commit is contained in:
parent
e9916bdf0b
commit
be1cde15ba
@ -91,7 +91,17 @@ const char *getWaitTypeName(WaitType type)
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum ThreadEventType {
|
||||||
|
THREADEVENT_CREATE = 1,
|
||||||
|
THREADEVENT_START = 2,
|
||||||
|
THREADEVENT_EXIT = 4,
|
||||||
|
THREADEVENT_DELETE = 8,
|
||||||
|
THREADEVENT_SUPPORTED = THREADEVENT_CREATE | THREADEVENT_START | THREADEVENT_EXIT | THREADEVENT_DELETE,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type);
|
||||||
|
|
||||||
|
enum {
|
||||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
||||||
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
||||||
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
||||||
@ -632,6 +642,9 @@ u32 extendReturnHackAddr;
|
|||||||
u32 moduleReturnHackAddr;
|
u32 moduleReturnHackAddr;
|
||||||
std::vector<ThreadCallback> threadEndListeners;
|
std::vector<ThreadCallback> threadEndListeners;
|
||||||
|
|
||||||
|
typedef std::vector<SceUID> ThreadEventHandlerList;
|
||||||
|
static std::map<SceUID, ThreadEventHandlerList> threadEventHandlers;
|
||||||
|
|
||||||
// Lists all thread ids that aren't deleted/etc.
|
// Lists all thread ids that aren't deleted/etc.
|
||||||
std::vector<SceUID> threadqueue;
|
std::vector<SceUID> threadqueue;
|
||||||
|
|
||||||
@ -943,7 +956,7 @@ void __KernelThreadingInit()
|
|||||||
|
|
||||||
void __KernelThreadingDoState(PointerWrap &p)
|
void __KernelThreadingDoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
auto s = p.Section("sceKernelThread", 1);
|
auto s = p.Section("sceKernelThread", 1, 2);
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -978,6 +991,9 @@ void __KernelThreadingDoState(PointerWrap &p)
|
|||||||
|
|
||||||
__SetCurrentThread(kernelObjects.GetFast<Thread>(currentThread), currentThread, __KernelGetThreadName(currentThread));
|
__SetCurrentThread(kernelObjects.GetFast<Thread>(currentThread), currentThread, __KernelGetThreadName(currentThread));
|
||||||
lastSwitchCycles = CoreTiming::GetTicks();
|
lastSwitchCycles = CoreTiming::GetTicks();
|
||||||
|
|
||||||
|
if (s >= 2)
|
||||||
|
p.Do(threadEventHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __KernelThreadingDoStateLate(PointerWrap &p)
|
void __KernelThreadingDoStateLate(PointerWrap &p)
|
||||||
@ -1146,6 +1162,7 @@ void __KernelThreadingShutdown()
|
|||||||
__SetCurrentThread(NULL, 0, NULL);
|
__SetCurrentThread(NULL, 0, NULL);
|
||||||
intReturnHackAddr = 0;
|
intReturnHackAddr = 0;
|
||||||
pausedDelays.clear();
|
pausedDelays.clear();
|
||||||
|
threadEventHandlers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *__KernelGetThreadName(SceUID threadID)
|
const char *__KernelGetThreadName(SceUID threadID)
|
||||||
@ -1633,6 +1650,9 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason)
|
|||||||
t->Cleanup();
|
t->Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Thread should not be deleted yet...
|
||||||
|
__KernelThreadTriggerEvent((t->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0, threadID, THREADEVENT_DELETE);
|
||||||
|
|
||||||
return kernelObjects.Destroy<Thread>(threadID);
|
return kernelObjects.Destroy<Thread>(threadID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1940,6 +1960,8 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32
|
|||||||
// This won't schedule to the new thread, but it may to one woken from eating cycles.
|
// This won't schedule to the new thread, but it may to one woken from eating cycles.
|
||||||
// Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
|
// Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
|
||||||
hleReSchedule("thread created");
|
hleReSchedule("thread created");
|
||||||
|
|
||||||
|
__KernelThreadTriggerEvent((attr & PSP_THREAD_ATTR_KERNEL) != 0, id, THREADEVENT_CREATE);
|
||||||
return hleLogSuccessInfoI(SCEKERNEL, id);
|
return hleLogSuccessInfoI(SCEKERNEL, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3472,13 +3494,6 @@ int LoadExecForUser_362A956B()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const SceUID SCE_TE_THREADID_ALL_USER = 0xFFFFFFF0;
|
static const SceUID SCE_TE_THREADID_ALL_USER = 0xFFFFFFF0;
|
||||||
enum {
|
|
||||||
THREADEVENT_CREATE = 1,
|
|
||||||
THREADEVENT_START = 2,
|
|
||||||
THREADEVENT_EXIT = 4,
|
|
||||||
THREADEVENT_DELETE = 8,
|
|
||||||
THREADEVENT_KNOWN = THREADEVENT_CREATE | THREADEVENT_START | THREADEVENT_EXIT | THREADEVENT_DELETE,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NativeThreadEventHandler {
|
struct NativeThreadEventHandler {
|
||||||
u32 size;
|
u32 size;
|
||||||
@ -3512,6 +3527,37 @@ KernelObject *__KernelThreadEventHandlerObject() {
|
|||||||
return new ThreadEventHandler;
|
return new ThreadEventHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID threadID, ThreadEventType type) {
|
||||||
|
for (auto it = handlers.begin(), end = handlers.end(); it != end; ++it) {
|
||||||
|
u32 error;
|
||||||
|
const auto teh = kernelObjects.Get<ThreadEventHandler>(*it, error);
|
||||||
|
if (!teh || (teh->nteh.mask & type) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 args[] = {(u32)type, (u32)threadID, teh->nteh.commonArg};
|
||||||
|
__KernelCallAddress(__GetCurrentThread(), teh->nteh.handlerPtr, nullptr, args, ARRAY_SIZE(args), true, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type) {
|
||||||
|
auto exactHandlers = threadEventHandlers.find(threadID);
|
||||||
|
if (exactHandlers != threadEventHandlers.end()) {
|
||||||
|
__KernelThreadTriggerEvent(exactHandlers->second, threadID, type);
|
||||||
|
}
|
||||||
|
if (isKernel) {
|
||||||
|
auto kernelHandlers = threadEventHandlers.find(SCE_TE_THREADID_ALL_USER);
|
||||||
|
if (kernelHandlers != threadEventHandlers.end()) {
|
||||||
|
__KernelThreadTriggerEvent(kernelHandlers->second, threadID, type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto userHandlers = threadEventHandlers.find(SCE_TE_THREADID_ALL_USER);
|
||||||
|
if (userHandlers != threadEventHandlers.end()) {
|
||||||
|
__KernelThreadTriggerEvent(userHandlers->second, threadID, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg) {
|
SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name");
|
return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name");
|
||||||
@ -3523,7 +3569,7 @@ SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u3
|
|||||||
if (kernelObjects.Get<Thread>(threadID, error) == NULL && threadID != SCE_TE_THREADID_ALL_USER) {
|
if (kernelObjects.Get<Thread>(threadID, error) == NULL && threadID != SCE_TE_THREADID_ALL_USER) {
|
||||||
return hleReportError(SCEKERNEL, error, "bad thread id");
|
return hleReportError(SCEKERNEL, error, "bad thread id");
|
||||||
}
|
}
|
||||||
if ((mask & ~THREADEVENT_KNOWN) != 0) {
|
if ((mask & ~THREADEVENT_SUPPORTED) != 0) {
|
||||||
return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MASK, "invalid event mask");
|
return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MASK, "invalid event mask");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3537,11 +3583,20 @@ SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u3
|
|||||||
teh->nteh.commonArg = commonArg;
|
teh->nteh.commonArg = commonArg;
|
||||||
|
|
||||||
SceUID uid = kernelObjects.Create(teh);
|
SceUID uid = kernelObjects.Create(teh);
|
||||||
|
threadEventHandlers[threadID].push_back(uid);
|
||||||
|
|
||||||
return hleLogSuccessI(SCEKERNEL, uid);
|
return hleLogSuccessI(SCEKERNEL, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sceKernelReleaseThreadEventHandler(SceUID uid) {
|
int sceKernelReleaseThreadEventHandler(SceUID uid) {
|
||||||
|
u32 error;
|
||||||
|
auto teh = kernelObjects.Get<ThreadEventHandler>(uid, error);
|
||||||
|
if (!teh) {
|
||||||
|
return hleReportError(SCEKERNEL, error, "bad handler id");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &handlers = threadEventHandlers[teh->nteh.threadID];
|
||||||
|
handlers.erase(std::remove(handlers.begin(), handlers.end(), uid), handlers.end());
|
||||||
return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy<ThreadEventHandler>(uid));
|
return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy<ThreadEventHandler>(uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user