Skip to content

Commit 7e482c5

Browse files
committed
fix(client): wake a blocked Windows recv on closeTraffic
On POSIX, shutdown(SHUT_RDWR) unblocks a recv() already in progress on another thread, which is how closeTraffic() wakes a worker parked in recv without releasing the fd. Winsock's shutdown(SD_BOTH) does not do this: an already-blocked recv() stays parked until data arrives, the peer resets, or the socket is closed. That left the QWP I/O worker stuck and failed SocketTrafficShutdownTest.testPlainSocketShutdownWakesWindowsRecvAndRetainsFd on the windows-msvc-2022-x64 job. Cancel outstanding I/O on the socket handle with CancelIoEx before the shutdown(). This wakes the blocked recv() while leaving the descriptor allocated, so the fd is retained (no reuse race) until close() releases it, matching the POSIX/macOS behaviour the sibling tests already rely on. Net.shutdown() is only reached via PlainSocket.closeTraffic(), so no other caller is affected.
1 parent ca7a2da commit 7e482c5

1 file changed

Lines changed: 8 additions & 0 deletions

File tree

  • core/src/main/c/windows

core/src/main/c/windows/net.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_configureNonBlocking
232232

233233
JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_shutdown
234234
(JNIEnv *e, jclass cl, jint fd) {
235+
// Unlike POSIX, a Winsock shutdown() does not unblock a recv() that is
236+
// already in progress on another thread. Cancel any outstanding I/O on the
237+
// handle first so a worker parked in a blocking recv() wakes up. CancelIoEx
238+
// does not close the socket, so the descriptor stays allocated and the fd
239+
// cannot be reused underneath the worker before close() releases it. A
240+
// FALSE return with ERROR_NOT_FOUND (nothing was pending) is expected here
241+
// and deliberately ignored.
242+
CancelIoEx((HANDLE) (SOCKET) fd, NULL);
235243
const int result = shutdown((SOCKET) fd, SD_BOTH);
236244
if (result == SOCKET_ERROR) {
237245
const int error = WSAGetLastError();

0 commit comments

Comments
 (0)