Even more robust graceful close - #620
Open
vdukhovni wants to merge 4 commits into
Open
Conversation
…possible. trying to fix haskell#618
The drain loop makes `gracefulClose` depend on its timeout firing while `recvBuf` is blocked. With the MIO manager on Windows, `recvBuf` blocks in a foreign recv() call, and the asynchronous exception that `System.Timeout.timeout` throws cannot interrupt a foreign call. This is an existing: the timeout in `gracefulClose` hasn't been able to fire mid-recv under MIO on Windows, since 3.1.1.0. The previous single `recvBuf` masked it, because any data from the peer (not only FIN) completed the call before the timeout was needed. The drain loop is the first code path that actually waits for the FIN. Enforce the deadline with a watchdog thread instead: `threadDelay` for the deadline, then shutdown(SHUT_RDWR) on the socket. Shutdown aborts a blocked recv while leaving the descriptor valid, so unlike close it cannot race with a `recvBuf` that has not yet entered the kernel: whichever side wins, `recvBuf` returns EOF or fails, and either ends the loop. The watchdog itself only ever blocks in `threadDelay`, which is always interruptible, so `killThread` reliably reaps it once EOF is reached. No asynchronous exception ever needs to reach the draining thread, on any platform, so the same implementation serves everywhere and `timeout` is no longer used. Verified on Linux (threaded and non-threaded RTS): the deadline now bounds a peer that keeps the connection open, and the fast path (peer's FIN already queued) is unaffected. Microsoft does not document the effect of shutdown on an already-blocked recv; this PR's Windows CI run is the experiment. Should it not hold, CancelIoEx on the socket handle is the fallback. Co-Authored-By: Claude Fable 5
The previous commit's Windows CI run answered the open question in its message: shutdown() does not wake a recv that is already blocked on Windows -- the jobs fail exactly as before, with the deadline never enforced. Keep the shutdown: it still guarantees that a recv issued after the deadline fails immediately (WSAESHUTDOWN), closing the race with a recv that has not yet entered the kernel. Add CancelIoEx(handle, NULL) after it to abort a recv that has. Sockets are created with WSA_FLAG_OVERLAPPED, so even a blocking recv is an overlapped operation internally and is cancellable; it fails with WSA_OPERATION_ABORTED, which ends the drain loop like any other error. The descriptor remains valid throughout, so as with shutdown there is no reuse hazard of the kind close would have. Under WinIO nothing changes: its overlapped recv already maps ERROR_OPERATION_ABORTED to EOF, and a cancellation from the watchdog is handled by the same path. POSIX platforms are unchanged: shutdown alone wakes the blocked recv there (verified on Linux, threaded and non-threaded RTS). Co-Authored-By: Claude Fable 5
Author
|
CI now passes! Please feel free to squash the added commits, and apply any other sensible polish. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a proposed fix for the MIO issue in #619
Let's see whether CI agrees.