Merge pull request #22386 from hrydgard/adhoc-shutdown-race

Adhoc: Fix shutdown hanging when it comes right after adhoc init
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-09-29 13:29:20 -06:00
commit b9c5b28b8f
6 files changed
+37 -7

No files matched your search

+1
View File
@@ -45,3 +45,4 @@ u32 matchingThreadHackAddr = 0;
u32_le matchingThreadCode[3];
bool g_adhocServerConnected = false;
std::atomic<bool> g_adhocServerLoginFailed(false);
+4
View File
@@ -20,6 +20,7 @@
#include "CommonTypes.h"
#include "Swap.h"
#include <atomic>
#include <mutex>
extern u32 dummyThreadHackAddr;
@@ -52,5 +53,8 @@ extern u32 matchingThreadHackAddr;
extern u32_le matchingThreadCode[3];
extern bool g_adhocServerConnected;
// Set by the friend finder when its attempt to connect and log in for the latest login request
// failed, so a caller waiting on that login can stop waiting.
extern std::atomic<bool> g_adhocServerLoginFailed;
constexpr u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable)
+12 -2
View File
@@ -1401,8 +1401,7 @@ int friendFinder() {
}
g_adhocServerIP.in.sin_port = htons(SERVER_PORT);
// Finder Loop
friendFinderRunning = true;
// Finder Loop. The flag was set by whoever started us, and cleared to stop us.
while (friendFinderRunning) {
// Acquire Network Lock
//_acquireNetworkLock();
@@ -1421,6 +1420,7 @@ int friendFinder() {
}
else {
g_adhocServerConnected = false;
g_adhocServerLoginFailed = true;
shutdown((int)metasocket, SD_BOTH);
closesocket((int)metasocket);
metasocket = (int)INVALID_SOCKET;
@@ -2252,6 +2252,16 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
return iResult;
done = (IsSocketReady((int)metasocket, false, true) > 0);
if (done) {
// Writable can also mean the attempt failed (refused, say). Then there's no point
// waiting out the timeout.
int soError = 0;
socklen_t soErrorLen = sizeof(soError);
if (getsockopt((int)metasocket, SOL_SOCKET, SO_ERROR, (char *)&soError, &soErrorLen) == 0 && soError != 0) {
errorcode = soError;
break;
}
}
struct sockaddr_in sin;
socklen_t sinlen = sizeof(sin);
memset(&sin, 0, sinlen);
+1 -3
View File
@@ -1865,9 +1865,7 @@ int create_listen_socket(uint16_t port)
*/
int server_loop(int server)
{
// Set Running Status
//_status = 1;
adhocServerRunning = true;
// adhocServerRunning was set by whoever started the thread, and is cleared to stop it.
// Create Empty Status Logfile
update_status();
+17 -2
View File
@@ -560,7 +560,8 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
}
// Retry until successfully sent. Login packet sent after successfully connected to Adhoc Server (indicated by networkInited), so we're not sending Login again here
if ((req.opcode == OPCODE_LOGIN && !g_adhocServerConnected) || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK))) {
// A login stops waiting early once the friend finder has tried and failed to connect.
if ((req.opcode == OPCODE_LOGIN && !g_adhocServerConnected && !g_adhocServerLoginFailed) || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK))) {
u64 now = (u64)(time_now_d() * 1000000.0);
if (now - adhocctlStartTime <= static_cast<u64>(adhocDefaultTimeout) + 500) {
// Try again in another 0.5ms until timedout.
@@ -1921,9 +1922,14 @@ void __NetAdhocInit() {
__AdhocNotifInit();
__AdhocServerInit();
// Create built-in AdhocServer Thread
// Create built-in AdhocServer Thread. The flag is set here rather than by the thread, so that a
// shutdown that clears it before the thread gets going can't be undone (see friendFinder).
adhocServerRunning = false;
if (adhocServerThread.joinable()) {
adhocServerThread.join();
}
if (g_Config.bEnableWlan && g_Config.bEnableAdhocServer) {
adhocServerRunning = true;
adhocServerThread = std::thread(proAdhocServerThread, SERVER_PORT);
}
}
@@ -1996,6 +2002,7 @@ int sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
adhocctlEvents.clear();
netAdhocctlInited = true; //needed for cleanup during AdhocctlTerm even when it failed to connect to Adhoc Server (since it's being faked as success)
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
// Create fake PSP Thread for callback
@@ -2008,6 +2015,12 @@ int sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
// TODO: Merging friendFinder (real) thread to AdhocThread (fake) thread on PSP side
if (!friendFinderRunning) {
// Set before the thread starts, not by it: shutting down before it got going used to clear
// the flag first, and then the thread set it again and never stopped, hanging the join.
if (friendFinderThread.joinable()) {
friendFinderThread.join();
}
friendFinderRunning = true;
friendFinderThread = std::thread(friendFinder);
}
@@ -3180,6 +3193,7 @@ int sceNetAdhocctlScan() {
// Only scan when in Disconnected state, otherwise AdhocServer will kick you out
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED && !isAdhocctlBusy) {
isAdhocctlBusy = true;
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
adhocctlState = ADHOCCTL_STATE_SCANNING;
adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL;
@@ -3673,6 +3687,7 @@ int NetAdhocctl_Create(const char *groupName) {
// Disconnected State
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED && !isAdhocctlBusy) {
isAdhocctlBusy = true;
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
// Set Network Name
+2
View File
@@ -903,6 +903,8 @@ int main(int argc, const char* argv[]) {
g_Config.bMemStickInserted = true;
g_Config.iMemStickSizeGB = 16;
g_Config.bEnableWlan = true;
// The net tests want WLAN on, but a test run shouldn't depend on reaching a real adhoc server.
g_Config.sProAdhocServer = "localhost";
g_Config.sMACAddress = "12:34:56:78:9A:BC";
g_Config.iFirmwareVersion = PSP_DEFAULT_FIRMWARE;
g_Config.iPSPModel = PSP_MODEL_SLIM;