Save&Restore PSP Thread IDs to prevent using the wrong Thread ID after loading from save state, also making sure DoState have default value

This commit is contained in:
ANR2ME 2020-08-02 12:57:27 +07:00
parent 5f550fdf73
commit 8886291434
4 changed files with 88 additions and 96 deletions

View file

@ -479,8 +479,8 @@ typedef struct SceNetAdhocMatchingContext {
u64_le timeout;
// Helper Thread (fake PSP Thread) needed to execute callback
HLEHelperThread *matchingThread;
SceUID matching_thid;
//HLEHelperThread *matchingThread;
int matching_thid;
// Event Caller Thread
std::thread eventThread;
@ -801,6 +801,11 @@ public:
p.Do(EventID);
p.Do(argsAddr);
}
else {
HandlerID = -1;
EventID = -1;
argsAddr = 0;
}
}
void run(MipsCall& call) override;
void SetData(int handlerID, int eventId, u32_le argsAddr);
@ -822,10 +827,17 @@ public:
if (s >= 1) {
p.Do(EventID);
}
else {
EventID = -1;
}
if (s >= 4) {
p.Do(contextID);
p.Do(bufAddr);
}
else {
contextID = -1;
bufAddr = 0;
}
}
void run(MipsCall &call) override;
void SetData(int ContextID, int eventId, u32_le BufAddr);

View file

@ -248,6 +248,12 @@ void __NetDoState(PointerWrap &p) {
p.Do(actionAfterApctlMipsCall);
__KernelRestoreActionType(actionAfterApctlMipsCall, AfterApctlMipsCall::Create);
p.Do(apctlThreadHackAddr);
p.Do(apctlThreadID);
}
else {
actionAfterApctlMipsCall = 0;
apctlThreadHackAddr = 0;
apctlThreadID = 0;
}
// Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks
if (p.mode == p.MODE_READ) {
@ -256,7 +262,7 @@ void __NetDoState(PointerWrap &p) {
netInited = cur_netInited;
// Previously, this wasn't being saved. It needs its own space.
if (apctlThreadHackAddr && strcmp("apctlThreadHack", kernelMemory.GetBlockTag(apctlThreadHackAddr)) != 0) {
if (!apctlThreadHackAddr || (apctlThreadHackAddr && strcmp("apctlThreadHack", kernelMemory.GetBlockTag(apctlThreadHackAddr)) != 0)) {
u32 blockSize = sizeof(apctlThreadCode);
apctlThreadHackAddr = kernelMemory.Alloc(blockSize, false, "apctlThreadHack");
}

View file

@ -208,6 +208,7 @@ public:
auto s = p.Section("AfterApctlMipsCall", 1, 1);
if (!s)
return;
// Just in case there are "s" corruption in the future where s.ver is a negative number
if (s >= 1) {
p.Do(handlerID);
p.Do(oldState);
@ -216,6 +217,14 @@ public:
p.Do(error);
p.Do(argsAddr);
}
else {
handlerID = -1;
oldState = 0;
newState = 0;
event = 0;
error = 0;
argsAddr = 0;
}
}
void run(MipsCall& call) override;
void SetData(int HandlerID, int OldState, int NewState, int Event, int Error, u32_le ArgsAddr);

View file

@ -65,6 +65,7 @@ std::recursive_mutex adhocEvtMtx;
std::deque<std::pair<u32, u32>> adhocctlEvents;
std::deque<MatchingArgs> matchingEvents;
std::map<int, AdhocctlHandler> adhocctlHandlers;
std::vector<SceUID> matchingThreads;
int IsAdhocctlInCB = 0;
u32 dummyThreadHackAddr = 0;
@ -110,7 +111,7 @@ void __NetAdhocShutdown() {
}
void __NetAdhocDoState(PointerWrap &p) {
auto s = p.Section("sceNetAdhoc", 1, 3);
auto s = p.Section("sceNetAdhoc", 1, 4);
if (!s)
return;
@ -129,21 +130,38 @@ void __NetAdhocDoState(PointerWrap &p) {
p.Do(dummyThreadHackAddr);
}
else {
actionAfterMatchingMipsCall = 0;
dummyThreadHackAddr = 0;
}
if (s >= 3) {
//p.Do(IsAdhocctlInCB); // This will cause a crash if adhocEvtMtx was locked
p.Do(actionAfterAdhocMipsCall);
__KernelRestoreActionType(actionAfterAdhocMipsCall, AfterAdhocMipsCall::Create);
p.Do(matchingThreadHackAddr);
}
else {
actionAfterAdhocMipsCall = 0;
matchingThreadHackAddr = 0;
}
if (s >= 4) {
p.Do(threadAdhocID);
p.Do(matchingThreads);
}
else {
threadAdhocID = 0;
for (auto& it : matchingThreads) {
it = 0;
}
}
if (p.mode == p.MODE_READ) {
// Previously, this wasn't being saved. It needs its own space.
if (dummyThreadHackAddr && strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0) {
if (!dummyThreadHackAddr || (dummyThreadHackAddr && strcmp("dummythreadhack", kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0)) {
u32 blockSize = sizeof(dummyThreadCode);
dummyThreadHackAddr = kernelMemory.Alloc(blockSize, false, "dummythreadhack");
}
if (matchingThreadHackAddr && strcmp("matchingThreadHack", kernelMemory.GetBlockTag(matchingThreadHackAddr)) != 0) {
if (!matchingThreadHackAddr || (matchingThreadHackAddr && strcmp("matchingThreadHack", kernelMemory.GetBlockTag(matchingThreadHackAddr)) != 0)) {
u32 blockSize = sizeof(matchingThreadCode);
matchingThreadHackAddr = kernelMemory.Alloc(blockSize, false, "matchingThreadHack");
}
@ -2860,16 +2878,16 @@ int NetAdhocMatching_Stop(int matchingId) {
}
// Stop fake PSP Thread
if (item->matching_thid > 0) {
__KernelStopThread(item->matching_thid, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped");
__KernelDeleteThread(item->matching_thid, SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted");
if (matchingThreads[item->matching_thid] > 0) {
__KernelStopThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped");
__KernelDeleteThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted");
/*item->matchingThread->Terminate();
if (item->matchingThread && item->matchingThread->Stopped()) {
delete item->matchingThread;
item->matchingThread = nullptr;
}*/
}
item->matching_thid = 0;
matchingThreads[item->matching_thid] = 0;
// Multithreading Lock
peerlock.lock();
@ -2999,6 +3017,7 @@ int NetAdhocMatching_Term() {
context = next;
}
contexts = NULL;
matchingThreads.clear();
}
return 0;
@ -3099,6 +3118,8 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle
// Add Callback Handler
context->handler.entryPoint = callbackAddr;
context->matching_thid = static_cast<int>(matchingThreads.size());
matchingThreads.push_back(0);
// Link Context
//context->connected = true;
@ -3145,84 +3166,7 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle
return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED;
}
// This should be similar with sceNetAdhocMatchingStart2 but using USER_PARTITION_ID (2) for PartitionId params
static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) {
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
// Multithreading Lock
peerlock.lock();
SceNetAdhocMatchingContext * item = findMatchingContext(matchingId);
if (item != NULL) {
//sceNetAdhocMatchingSetHelloOpt(matchingId, optLen, optDataAddr); //SetHelloOpt only works when context is running
if ((optLen > 0) && Memory::IsValidAddress(optDataAddr)) {
// Allocate the memory and copy the content
if (item->hello != NULL) free(item->hello);
item->hello = (uint8_t *)malloc(optLen);
if (item->hello != NULL) {
Memory::Memcpy(item->hello, optDataAddr, optLen);
item->hellolen = optLen;
item->helloAddr = optDataAddr;
}
//else return ERROR_NET_ADHOC_MATCHING_NO_SPACE; //Faking success to prevent GTA:VCS from stuck unable to choose host/join menu
}
//else return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; // ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN; // Returning Not Success will cause GTA:VC stuck unable to choose host/join menu
//Add your own MAC as a member (only if it's empty?)
/*SceNetAdhocMatchingMemberInternal * peer = addMember(item, &item->mac);
switch (item->mode) {
case PSP_ADHOC_MATCHING_MODE_PARENT:
peer->state = PSP_ADHOC_MATCHING_PEER_OFFER;
break;
case PSP_ADHOC_MATCHING_MODE_CHILD:
peer->state = PSP_ADHOC_MATCHING_PEER_CHILD;
break;
case PSP_ADHOC_MATCHING_MODE_P2P:
peer->state = PSP_ADHOC_MATCHING_PEER_P2P;
}*/
// Create & Start the Fake PSP Thread ("matching_ev%d" and "matching_io%d")
std::string thrname = std::string("MatchingThr") + std::to_string(matchingId);
item->matching_thid = sceKernelCreateThread(thrname.c_str(), matchingThreadHackAddr, evthPri, evthStack, 0, 0);
//item->matchingThread = new HLEHelperThread(thrname.c_str(), "sceNetAdhocMatching", "__NetMatchingCallbacks", inthPri, inthStack);
if (item->matching_thid > 0) {
sceKernelStartThread(item->matching_thid, 0, 0); //sceKernelStartThread(context->event_thid, sizeof(context), &context);
//item->matchingThread->Start(matchingId, 0);
}
//Create the threads
if (!item->eventRunning) {
item->eventRunning = true;
item->eventThread = std::thread(matchingEventThread, matchingId);
}
if (!item->inputRunning) {
item->inputRunning = true;
item->inputThread = std::thread(matchingInputThread, matchingId);
}
item->running = 1;
netAdhocMatchingStarted++;
}
//else return ERROR_NET_ADHOC_MATCHING_INVALID_ID; //Faking success to prevent GTA:VCS from stuck unable to choose host/join menu
// Multithreading Unlock
peerlock.unlock();
sleep_ms(adhocMatchingEventDelayMS);
//hleDelayResult(0, "give some time", adhocMatchingEventDelayMS * 1000); // Give a little time to make sure matching Threads are ready before the game use the next sceNet functions, should've checked for status instead of guessing the time?
return 0;
}
// With params for Partition ID for the event & input handler stack
static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) {
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart2(%i, %i, %i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) {
// Multithreading Lock
peerlock.lock();
@ -3256,13 +3200,13 @@ static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartit
peer->state = PSP_ADHOC_MATCHING_PEER_P2P;
}*/
// Create & Start the Fake PSP Thread
// Create & Start the Fake PSP Thread ("matching_ev%d" and "matching_io%d")
std::string thrname = std::string("MatchingThr") + std::to_string(matchingId);
item->matching_thid = __KernelCreateThread(thrname.c_str(), __KernelGetCurThreadModuleId(), matchingThreadHackAddr, evthPri, evthStack, PSP_THREAD_ATTR_USER, 0, false);
//item->matchingThread = new HLEHelperThread(thrname, "sceNetAdhocMatching", "AdhocMatchingFunc", inthPri, inthStack);
if (item->matching_thid > 0) {
__KernelStartThread(item->matching_thid, 0, 0);
//item->matchingThread->Start(0, 0);
matchingThreads[item->matching_thid] = sceKernelCreateThread(thrname.c_str(), matchingThreadHackAddr, evthPri, evthStack, 0, 0);
//item->matchingThread = new HLEHelperThread(thrname.c_str(), "sceNetAdhocMatching", "__NetMatchingCallbacks", inthPri, inthStack);
if (matchingThreads[item->matching_thid] > 0) {
sceKernelStartThread(matchingThreads[item->matching_thid], 0, 0); //sceKernelStartThread(context->event_thid, sizeof(context), &context);
//item->matchingThread->Start(matchingId, 0);
}
//Create the threads
@ -3284,11 +3228,32 @@ static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartit
peerlock.unlock();
sleep_ms(adhocMatchingEventDelayMS);
//hleDelayResult(0,"give some time",adhocMatchingEventDelayMS*1000); // Give a little time to make sure matching Threads are ready before the game use the next sceNet functions, should've checked for status instead of guessing the time?
//hleDelayResult(0, "give some time", adhocMatchingEventDelayMS * 1000); // Give a little time to make sure matching Threads are ready before the game use the next sceNet functions, should've checked for status instead of guessing the time?
return 0;
}
#define KERNEL_PARTITION_ID 1
#define USER_PARTITION_ID 2
#define VSHELL_PARTITION_ID 5
// This should be similar with sceNetAdhocMatchingStart2 but using USER_PARTITION_ID (2) for PartitionId params
static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) {
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
return NetAdhocMatching_Start(matchingId, evthPri, USER_PARTITION_ID, evthStack, inthPri, USER_PARTITION_ID, inthStack, optLen, optDataAddr);
}
// With params for Partition ID for the event & input handler stack
static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) {
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart2(%i, %i, %i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
return NetAdhocMatching_Start(matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr);
}
static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) {
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc);