mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
don't use Thread* to create thread
slightly less hacky, as in, a little bit closer to what the actual PSP does, although the timings are still complete guesses also * Protect the adhoc Events by a mutex lock * don't use emplace_back since symbian doesn't compile with it
This commit is contained in:
parent
d479fae481
commit
a7d9370a69
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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<std::pair<u32, u32>> adhocctlEvents;
|
||||
std::vector<u64> matchingEvents;
|
||||
u32 dummyThreadHackAddr;
|
||||
u32_le dummyThreadCode[3];
|
||||
|
||||
std::map<int, AdhocctlHandler> 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<int, AdhocctlHandler>::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<Thread>(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<int, AdhocctlHandler>::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>, "sceNetAdhocInit"},
|
||||
{0xA62C6F57, WrapI_V<sceNetAdhocTerm>, "sceNetAdhocTerm"},
|
||||
@ -3531,6 +3513,8 @@ const HLEFunction sceNetAdhoc[] = {
|
||||
{0x73bfd52d, WrapI_II<sceNetAdhocSetSocketAlert>, "sceNetAdhocSetSocketAlert"},
|
||||
{0x4d2ce199, WrapI_IU<sceNetAdhocGetSocketAlert>, "sceNetAdhocGetSocketAlert"},
|
||||
{0x7a662d6b, WrapI_UIII<sceNetAdhocPollSocket>, "sceNetAdhocPollSocket"},
|
||||
// Fake function for PPSSPP's use.
|
||||
{0x756E6E6F, WrapV_V<__NetTriggerCallbacks>, "__NetTriggerCallbacks"},
|
||||
};
|
||||
|
||||
const HLEFunction sceNetAdhocMatching[] = {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user