Skip to content

Wait for readiness on Windows through IOCTL_AFD_POLL under WinIO - #641

Merged
kazu-yamamoto merged 2 commits into
haskell:masterfrom
kazu-yamamoto:afd-poll
Nov 14, 2026
Merged

kazu-yamamoto merged 2 commits into
haskell:masterfrom
kazu-yamamoto:afd-poll

Conversation

@kazu-yamamoto

@kazu-yamamoto kazu-yamamoto commented Nov 14, 2026 •

Copy link
Copy Markdown
Collaborator

waitReadSocketSTM, waitWriteSocketSTM and their waitAndCancel versions threw on Windows. Under WinIO they now work as on POSIX, through IOCTL_AFD_POLL: an undocumented but long-stable ioctl of the AFD driver beneath Winsock, which libuv (uv_poll), wepoll and mio use. Issued overlapped on the socket, it completes on the I/O manager's port like any other operation. This is one of the items of #557 (network 4.0, WinIO only on Windows).

  • cbits/afdpoll.c: hsnet_afd_poll issues the poll through NtDeviceIoControlFile, looked up in ntdll at run time. It sets the status block to STATUS_PENDING first, as DeviceIoControl does; otherwise getOverlappedResult reads a pending poll as finished.
  • Network/Socket/STM.hs: under WinIO, the wait runs Mgr.withOverlapped in a thread of its own and hands the result over through a TMVar; cancelling kills that thread, and withOverlapped cancels the poll. Read readiness is RECEIVE, DISCONNECT, ACCEPT, ABORT or LOCAL_CLOSE, and write readiness SEND, CONNECT_FAIL, ABORT or LOCAL_CLOSE. Under No IO Manager the functions still throw.
  • A poll that finds the socket ready already completes at once; this relies on FILE_SKIP_COMPLETION_PORT_ON_SUCCESS (WinIO: skip the completion port when a socket request finishes at once #639) so that no stray packet is left on the port.
  • The readiness functions had no tests. The new ones (read, read at once, write, cancel, listener, UDP, and many immediate and cancelled waits) run on POSIX and on Windows under WinIO, and are pending where readiness is not available.
  • Documentation: no longer "POSIX only"; sockets behind a non-IFS LSP, deprecated since Windows 8, are not supported.

Tested on Windows 11 with GHC 9.12.4.20260713: 123 examples, 0 failures under WinIO, with the seven new tests running; with No IO Manager and with GHC 9.8.2 they are pending. macOS: 127 examples, 0 failures. CI's Windows jobs use GHC 9.4 and 9.14.1, which compile WinIO out, so the new tests are pending there.

🤖 Generated with Claude Code

kazu-yamamoto and others added 2 commits November 15, 2026 08:28
waitAndCancelReadSocketSTM and waitAndCancelWriteSocketSTM issue an
AFD poll on the socket, which completes on the I/O manager's port like
any overlapped operation; cancelling kills the waiting thread.  MIO
still throws.  Relies on FILE_SKIP_COMPLETION_PORT_ON_SUCCESS (haskell#639).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They had no tests.  The new ones run on POSIX and on Windows under
WinIO, and are pending where readiness is not available.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kazu-yamamoto
kazu-yamamoto merged commit e58d432 into haskell:master Nov 14, 2026
11 checks passed
kazu-yamamoto added a commit that referenced this pull request Nov 14, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kazu-yamamoto
kazu-yamamoto deleted the afd-poll branch November 14, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant