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:
Peter Tissen 2015-01-04 14:07:44 +01:00
parent d479fae481
commit a7d9370a69
5 changed files with 61 additions and 89 deletions

View File

@ -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)) {

View File

@ -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

View File

@ -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();

View File

@ -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 &params : 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 &param : 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[] = {

View File

@ -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);