Join wait: non-blocking dial -- the spinner no longer stutters
User-reported after the waiting-screen fix: "the animation keeps hanging." Cause: RelayDialTcp used a BLOCKING connect() -- against a down/unreachable operator each attempt froze the window thread for the OS SYN-retry window (seconds), so the spinner ran only during the 2s sleep between attempts. RelayDialTcp now connects NON-blocking and select()s in 100ms slices, pumping the message loop + repainting the waiting screen every slice (both in-flight and between retry attempts). The success path already returned a non-blocking socket (FIONBIO), so caller semantics are unchanged; the other dial sites (console dial, game-socket dial) inherit the smooth behavior. Verified: 4 window captures at 400ms intervals during a dead-host dial all differ in the spinner region (uniform diff energy == continuous animation) and IsHungAppWindow reads false on every sample. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f5e0ffcd14
commit
a1c9a71898
@@ -1663,6 +1663,16 @@ SOCKET L4NetworkManager::RelayDialTcp(
|
||||
const SOCKADDR_IN &endpoint,
|
||||
int timeout_seconds)
|
||||
{
|
||||
//
|
||||
// NON-BLOCKING dial (2026-07-22, the "spinner keeps hanging" fix): the
|
||||
// old blocking connect() froze the window thread for the OS SYN-retry
|
||||
// window (seconds) per attempt -- the waiting screen stuttered. Connect
|
||||
// non-blocking and select() in 100ms slices, pumping the message loop +
|
||||
// repainting the waiting screen each slice (RelayWaitTick). The success
|
||||
// path always returned a NON-blocking socket anyway (FIONBIO set below),
|
||||
// so callers see identical semantics.
|
||||
//
|
||||
extern void BTWaitScreenPaint(const char *, const char *);
|
||||
unsigned long deadline = GetTickCount() + (unsigned long)timeout_seconds * 1000UL;
|
||||
for (;;)
|
||||
{
|
||||
@@ -1671,16 +1681,58 @@ SOCKET L4NetworkManager::RelayDialTcp(
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if (connect(sock, (const sockaddr *)&endpoint, sizeof(endpoint)) == 0)
|
||||
unsigned long enable = 1;
|
||||
ioctlsocket(sock, FIONBIO, &enable);
|
||||
int rc = connect(sock, (const sockaddr *)&endpoint, sizeof(endpoint));
|
||||
int wsa_error = (rc == 0) ? 0 : WSAGetLastError();
|
||||
int connected = (rc == 0);
|
||||
if (!connected && wsa_error == WSAEWOULDBLOCK)
|
||||
{
|
||||
// in flight: watch writability (success) / except (refusal),
|
||||
// animating between slices
|
||||
for (;;)
|
||||
{
|
||||
fd_set write_set, except_set;
|
||||
FD_ZERO(&write_set); FD_SET(sock, &write_set);
|
||||
FD_ZERO(&except_set); FD_SET(sock, &except_set);
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100000;
|
||||
int ready = select(0, NULL, &write_set, &except_set, &tv);
|
||||
if (ready == 1 || ready == 2)
|
||||
{
|
||||
if (FD_ISSET(sock, &write_set))
|
||||
{
|
||||
connected = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
wsa_error = WSAECONNREFUSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (GetTickCount() >= deadline)
|
||||
{
|
||||
wsa_error = WSAETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
MSG msg;
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
BTWaitScreenPaint("WAITING FOR THE OPERATOR'S SESSION",
|
||||
"connecting...");
|
||||
}
|
||||
}
|
||||
if (connected)
|
||||
{
|
||||
unsigned long enable = 1;
|
||||
ioctlsocket(sock, FIONBIO, &enable);
|
||||
BOOL noDelay = TRUE;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&noDelay, sizeof(noDelay));
|
||||
return sock;
|
||||
return sock; // already non-blocking (FIONBIO above)
|
||||
}
|
||||
int wsa_error = WSAGetLastError();
|
||||
closesocket(sock);
|
||||
if (GetTickCount() >= deadline
|
||||
|| (wsa_error != WSAECONNREFUSED && wsa_error != WSAETIMEDOUT))
|
||||
@@ -1689,7 +1741,17 @@ SOCKET L4NetworkManager::RelayDialTcp(
|
||||
<< ")\n" << std::flush;
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
Sleep(250);
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
BTWaitScreenPaint("WAITING FOR THE OPERATOR'S SESSION",
|
||||
"connecting...");
|
||||
Sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user