diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index b314061cd6..e564128689 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -37,8 +37,6 @@ bool friendFinderRunning = false; SceNetAdhocctlPeerInfo * friends = NULL; SceNetAdhocctlScanInfo * networks = NULL; SceNetAdhocctlScanInfo * newnetworks = NULL; -int eventAdhocctlHandlerUpdate = -1; -int eventMatchingHandlerUpdate = -1; int threadStatus = ADHOCCTL_STATE_DISCONNECTED; bool IsAdhocctlInCB = false; @@ -930,11 +928,8 @@ void AfterMatchingMipsCall::SetContextID(u32 ContextID, u32 eventId) { } // Make sure MIPS calls have been fully executed before the next notifyAdhocctlHandlers -void notifyAdhocctlHandlers(int flag, int error) { - CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventAdhocctlHandlerUpdate, join32(flag, error)); - //CoreTiming::ScheduleEvent_Threadsafe(usToCycles(1), eventAdhocctlHandlerUpdate, join32(flag, error)); - //__KernelCheckCallbacks(); - //while (__KernelCurHasReadyCallbacks() || __KernelInCallback()) sleep_ms(1); +void notifyAdhocctlHandlers(u32 flag, u32 error) { + __UpdateAdhocctlHandlers(flag, error); // TODO: We should use after action instead of guessing the time like this sleep_ms(20); // Ugly workaround to give time for the mips callback to fully executed, usually only need <16ms } @@ -962,13 +957,8 @@ void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * context->IsMatchingInCB = true; // ScheduleEvent_Threadsafe_Immediate seems to get mixed up with interrupt (returning from mipscall inside an interrupt) and getting invalid address before returning from interrupt - CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventMatchingHandlerUpdate, (u64)args); - //CoreTiming::ScheduleEvent_Threadsafe(usToCycles(1), eventMatchingHandlerUpdate, (u64)args); // I don't like guessing the time like this, if only there is a way to prevent callback from returning inside an interrupt + __UpdateMatchingHandler((u64) args); - /*AfterMatchingMipsCall *after = (AfterMatchingMipsCall *)__KernelCreateAction(actionAfterMatchingMipsCall); // Does Action need to resides in the same address space with the thread that runs callback handlers? - after->SetID(context->id); - __KernelDirectMipsCall(context->handler.entryPoint, after, args, 5, true);*/ - //__KernelCheckCallbacks(); // Make sure MIPS call have been fully executed before the next notifyMatchingHandler int count = 0; while (/*(after != NULL) &&*/ IsMatchingInCallback(context) && (count < 250)) { diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index aac8628260..026715e3ec 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -801,8 +801,6 @@ extern int one; extern bool friendFinderRunning; extern SceNetAdhocctlPeerInfo * friends; extern SceNetAdhocctlScanInfo * networks; -extern int eventAdhocctlHandlerUpdate; -extern int eventMatchingHandlerUpdate; extern int threadStatus; // End of Aux vars @@ -921,7 +919,7 @@ SceNetAdhocMatchingContext * findMatchingContext(int id); */ void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32 &bufAddr, u32 &bufLen, u32_le * args); // Notifiy Adhocctl Handlers -void notifyAdhocctlHandlers(int flag, int error); +void notifyAdhocctlHandlers(u32 flag, u32 error); /* * Packet Handler diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index acb5eeeb96..a9e688a1e3 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -31,7 +31,6 @@ class Thread; int sceKernelChangeThreadPriority(SceUID threadID, int priority); SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr); int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr); -Thread* __KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr); int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr); int sceKernelDelayThread(u32 usec); int sceKernelDelayThreadCB(u32 usec); @@ -214,7 +213,6 @@ class Action; // Not an official Callback object, just calls a mips function on the current thread. void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, u32 args[], int numargs, bool reschedAfter); -void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId); void __KernelReturnFromMipsCall(); // Called as HLE function bool __KernelInCallback(); diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 2d1ae79167..d2f056e7ee 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -37,6 +37,8 @@ #include "Core/HLE/sceNet.h" #include "Core/HLE/proAdhocServer.h" +#include "base/mutex.h" + // shared in sceNetAdhoc.h since it need to be used from sceNet.cpp also // TODO: Make accessor functions instead, and throw all this state in a struct. bool netAdhocInited; @@ -47,8 +49,12 @@ static bool netAdhocMatchingInited; int netAdhocMatchingStarted = 0; SceUID threadAdhocID; -Thread *threadAdhoc; + +recursive_mutex adhocEvtMtx; +std::vector> adhocctlEvents; +std::vector matchingEvents; u32 dummyThreadHackAddr; +u32_le dummyThreadCode[3]; std::map adhocctlHandlers; @@ -60,14 +66,6 @@ int sceNetAdhocctlTerm(); int sceNetAdhocMatchingTerm(); int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr); -static u32_le dummyThreadCode[4]; /* = { - MIPS_MAKE_ADDIU(MIPS_REG_A0, MIPS_REG_ZERO, 1000), - MIPS_MAKE_SYSCALL("ThreadManForUser", "sceKernelDelayThread"), - MIPS_MAKE_B(-3), - MIPS_MAKE_NOP(), - //MIPS_MAKE_BREAK(0), -};*/ - void __NetAdhocShutdown() { //Kill AdhocServer Thread if (adhocServerRunning) { @@ -107,31 +105,15 @@ void __NetAdhocDoState(PointerWrap &p) { Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode)); } -static void __UpdateAdhocctlHandlers(int flag, int error) { - u32_le args[3] = { 0, 0, 0 }; - args[0] = flag; - args[1] = error; - - //__KernelSwitchToThread(threadIdleID[1], "switch to Adhocctl"); - for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) { - args[2] = it->second.argument; - //__KernelDirectMipsCall(it->second.entryPoint, NULL, args, 3, true); - __KernelCallAddress(threadAdhoc, it->second.entryPoint, NULL, args, 3, true, 0); - } +void __UpdateAdhocctlHandlers(u32 flag, u32 error) { + lock_guard adhocGuard(adhocEvtMtx); + adhocctlEvents.push_back({ flag, error }); } // TODO: MipsCall needs to be called from it's own PSP Thread instead of from any random PSP Thread void __UpdateMatchingHandler(u64 ArgsPtr) { - u32_le *args = (u32_le *)ArgsPtr; - AfterMatchingMipsCall *after = (AfterMatchingMipsCall *)__KernelCreateAction(actionAfterMatchingMipsCall); - after->SetContextID(args[0], args[1]); - //u32 error; - //Thread *t = kernelObjects.Get(threadAdhocID, error); - //__KernelSwitchToThread(threadIdleID[1], "switch to AdhocMatching"); // __KernelSwitchContext(threadIdleID[1], "switch to AdhocMatching"); - __KernelCallAddress(threadAdhoc, args[5], after, args, 5, true, 0); - //__KernelDirectMipsCall(args[5], after, args, 5, true); - // Make sure MIPS call have been fully executed before the next callback invoked - //while (/*(after != NULL) &&*/ IsMatchingInCallback(context)) sleep_ms(1); //Must not sleep inside callback handler otherwise Metal Slug XX will gets ThreadQueueList Empty popup + lock_guard adhocGuard(adhocEvtMtx); + matchingEvents.push_back(ArgsPtr); } static int getBlockingFlag(int id) { @@ -143,36 +125,6 @@ static int getBlockingFlag(int id) { #endif } -static void __handlerAdhocctlUpdateCallback(u64 userdata, int cycleslate) { - //SceUID cur = __KernelGetCurThread(); - // TODO: Since we only have access to __KernelDirectMipsCall we need to switch the thread context first to make sure the mipscall executed on the right thread - // Since __KernelSwitchToThread will flood the log with errors when current thread is already non-idle thread so we'll try to use any "fake" psp thread, BUT we need to backup ALL registers before the mipscall to prevent registers corruption after returning from mipscall - if ((__IsInInterrupt() || !__KernelIsDispatchEnabled() || __KernelInCallback()) /*||*/) - // ((cur != threadAdhocID && cur != threadIdleID[0] && cur != threadIdleID[1]) /*&& !__KernelSwitchToThread(threadAdhocID, "switch to AdhocThread")*/)) - { - // // Can't do anything now, inside an interrupt. Let's wait until later. - CoreTiming::ScheduleEvent(100, eventAdhocctlHandlerUpdate, userdata); - return; - } - int buff[2]; - split64(userdata,buff); - __UpdateAdhocctlHandlers(buff[0], buff[1]); -} - -static void __handlerMatchingUpdateCallback(u64 userdata, int cycleslate) { - //SceUID cur = __KernelGetCurThread(); - // TODO: Since we only have access to __KernelDirectMipsCall we need to switch the thread context first to make sure the mipscall executed on the right thread - // Since __KernelSwitchToThread will flood the log with errors when current thread is already non-idle thread so we'll try to use any "fake" psp thread, BUT we need to backup ALL registers before the mipscall to prevent registers corruption after returning from mipscall - if ((__IsInInterrupt() || !__KernelIsDispatchEnabled() || __KernelInCallback()) /*||*/) - // ((cur != threadAdhocID && cur != threadIdleID[0] && cur != threadIdleID[1]) /*&& !__KernelSwitchToThread(threadAdhocID, "switch to AdhocThread")*/)) - { - // Can't do anything now, inside an interrupt. Let's wait until later. - CoreTiming::ScheduleEvent(100, eventMatchingHandlerUpdate, userdata); - return; - } - __UpdateMatchingHandler(userdata); -} - void __NetAdhocInit() { friendFinderRunning = false; netAdhocInited = false; @@ -180,17 +132,13 @@ void __NetAdhocInit() { netAdhocMatchingInited = false; adhocctlHandlers.clear(); __AdhocServerInit(); - dummyThreadCode[0] = MIPS_MAKE_ADDIU(MIPS_REG_A0, MIPS_REG_ZERO, 1000); - dummyThreadCode[1] = MIPS_MAKE_SYSCALL("ThreadManForUser", "sceKernelDelayThread"); - dummyThreadCode[2] = MIPS_MAKE_B(-3); - dummyThreadCode[3] = MIPS_MAKE_NOP(); - //dummyThreadCode[4] = MIPS_MAKE_BREAK(0); + dummyThreadCode[0] = MIPS_MAKE_SYSCALL("sceNetAdhoc", "__NetTriggerCallbacks"); + dummyThreadCode[1] = MIPS_MAKE_B(-2); + dummyThreadCode[2] = MIPS_MAKE_NOP(); u32 blockSize = sizeof(dummyThreadCode); dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack"); Memory::Memcpy(dummyThreadHackAddr, dummyThreadCode, sizeof(dummyThreadCode)); // This area will be cleared again after loading an old savestate :( actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); - eventAdhocctlHandlerUpdate = CoreTiming::RegisterEvent("AdhocctlHandlerUpdateEvent", __handlerAdhocctlUpdateCallback); - eventMatchingHandlerUpdate = CoreTiming::RegisterEvent("MatchingHandlerUpdateEvent", __handlerMatchingUpdateCallback); // Create built-in AdhocServer Thread if (g_Config.bEnableWlan && g_Config.bEnableAdhocServer) { adhocServerRunning = true; @@ -213,7 +161,7 @@ u32 sceNetAdhocInit() { // TODO: Should use a separated threads for friendFinder, matchingEvent, and matchingInput and created on AdhocctlInit & AdhocMatchingStart instead of here #define PSP_THREAD_ATTR_KERNEL 0x00001000 // PSP_THREAD_ATTR_KERNEL is located in sceKernelThread.cpp instead of sceKernelThread.h :( //threadAdhocID = __KernelCreateThreadInternal("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x30, 4096, PSP_THREAD_ATTR_KERNEL); - threadAdhoc = __KernelCreateThread(threadAdhocID, __KernelGetCurThreadModuleId(), "AdhocThread", dummyThreadHackAddr, 0x10, 8192, PSP_THREAD_ATTR_KERNEL); // We don't have access to __KernelCreateThread function that use Thread class from sceKernelThread.h :( + threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, 0, PSP_THREAD_ATTR_KERNEL); if (threadAdhocID > 0) { __KernelStartThread(threadAdhocID, 0, 0); } @@ -1136,9 +1084,10 @@ static u32 sceNetAdhocctlDisconnect() { } // Notify Event Handlers (even if we weren't connected, not doing this will freeze games like God Eater, which expect this behaviour) - //__UpdateAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT,0); - CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventAdhocctlHandlerUpdate, join32(ADHOCCTL_EVENT_DISCONNECT, 0)); - + { + lock_guard adhocGuard(adhocEvtMtx); + adhocctlEvents.push_back({ ADHOCCTL_EVENT_DISCONNECT, 0 }); + } // Return Success, some games might ignore returned value and always treat it as success, otherwise repeatedly calling this function return 0; } @@ -3504,6 +3453,39 @@ int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; } +void __NetTriggerCallbacks() +{ + { + lock_guard adhocGuard(adhocEvtMtx); + + for (auto ¶ms : adhocctlEvents) + { + int flags = params.first; + int error = params.second; + u32_le args[3] = { 0, 0, 0 }; + args[0] = flags; + args[1] = error; + + for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) { + args[2] = it->second.argument; + __KernelDirectMipsCall(it->second.entryPoint, NULL, args, 3, true); + } + } + adhocctlEvents.clear(); + + for (auto ¶m : matchingEvents) + { + u32_le *args = (u32_le *) param; + AfterMatchingMipsCall *after = (AfterMatchingMipsCall *) __KernelCreateAction(actionAfterMatchingMipsCall); + after->SetContextID(args[0], args[1]); + __KernelDirectMipsCall(args[5], after, args, 5, true); + } + matchingEvents.clear(); + } + //magically make this work + hleDelayResult(0, "Prevent Adhoc thread from blocking", 1000); +} + const HLEFunction sceNetAdhoc[] = { {0xE1D621D7, WrapU_V, "sceNetAdhocInit"}, {0xA62C6F57, WrapI_V, "sceNetAdhocTerm"}, @@ -3531,6 +3513,8 @@ const HLEFunction sceNetAdhoc[] = { {0x73bfd52d, WrapI_II, "sceNetAdhocSetSocketAlert"}, {0x4d2ce199, WrapI_IU, "sceNetAdhocGetSocketAlert"}, {0x7a662d6b, WrapI_UIII, "sceNetAdhocPollSocket"}, + // Fake function for PPSSPP's use. + {0x756E6E6F, WrapV_V<__NetTriggerCallbacks>, "__NetTriggerCallbacks"}, }; const HLEFunction sceNetAdhocMatching[] = { diff --git a/Core/HLE/sceNetAdhoc.h b/Core/HLE/sceNetAdhoc.h index 0acacdfc48..829c973ebd 100644 --- a/Core/HLE/sceNetAdhoc.h +++ b/Core/HLE/sceNetAdhoc.h @@ -24,6 +24,8 @@ void Register_sceNetAdhoc(); void __NetAdhocInit(); void __NetAdhocShutdown(); void __NetAdhocDoState(PointerWrap &p); +void __UpdateAdhocctlHandlers(u32 flags, u32 error); +void __UpdateMatchingHandler(u64 params); // I have to call this from netdialog int sceNetAdhocctlCreate(const char * groupName);