Asynchronous I/O in Windows for UNIX Programmers

This document assumes you are familiar with how non-blocking socket I/O is done in UNIX.

Windows has very different notions for how asynchronous and non-blocking I/O are done. While Windows has select() it supports only 64 file descriptors. Obviously Microsoft does understand how to make high-concurrency servers, they've simply choosen a different paradigm for this called overlapped I/O. The mechanism in Windows by which multiple sockets are polled for compltion is called I/O completion ports. More or less equivlant to kqueue (Macintosh, FreeBSD, other BSDs), epoll (Linux), event completion ports (Solaris), poll (modern UNIXes), or select (all operating systems). The main difference is that in UNIX you ask the kernel to wait for file descriptors to change their readability or writablity while in windows you wait for asynchronous functions to complete. For example, instead of waiting for a socket to become writable and then write(2) to it, as you do in UNIX operating systems, you rather WSASend() a buffer and wait for it to have been sent. The result is that non-blocking write(2) read(2) are non-portable to Windows. This tends to throw the poor sap assigned with the job of porting your app to Windows into complusive nervous twitches.

Almost every socket operation that you're familar with has an overlapped counter-part (see table).

int fd;
HANDLE handle;
SOCKET socket;
(the two are the same type)
socket or pipe send(2), write(2) WSASend()
socket or pipe recv(2), read(2) WSARecv()
socket or pipe connect(2) ConnectEx()
file write(2) WriteFileEx()
file read(2) ReadFileEx()
socket and file sendfile() [1] TransmitFile()
tty tcsetattr(3) SetConsoleMode()
tty read(2) ReadConsole() and ReadConsoleInput() do not support overlapped I/O and there are no overlapped counter-parts. One strategy to get around this is
RegisterWaitForSingleObject(&tty_wait_handle, tty_handle,
        tty_want_poll, NULL, INFINITE, WT_EXECUTEINWAITTHREAD |
        WT_EXECUTEONLYONCE)
which will execute tty_want_poll() in a different thread. You can use this to notify the calling thread that ReadConsoleInput() will not block.
tty write(2) WriteConsole() is also blocking but this is probably acceptable.

[1] sendfile() on UNIX has not been agreed on yet. Each operating system has a slightly different API.

tips

IOCP:

APC:

Pipes: