| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Hmssql.Connection.Backend.Windows
Description
Overlapped I/O on a Windows handle: what a connection's bytes travel
on over Shared Memory and Named Pipes, and on Windows over TCP as well
(a socket is a handle that ReadFile and WriteFile accept).
Hmssql.Connection.Backend wraps it as a
Backend; on other platforms this module is
empty.
GHC's own handle and socket I/O is not used. With the threaded RTS and
the default I/O manager it blocks in a foreign call, which no
asynchronous exception can interrupt and no other thread can end.
Without -threaded an exception interrupts a read, but the read itself
stays pending on a worker thread and takes the next bytes to arrive. With
the native I/O manager (WinIO) it is interruptible, but that manager
crashed under a few dozen busy sockets and hung on an interrupted file
read (both upstream bugs, fixed on a GHC branch since), so nothing here
goes through it either: the same code runs under both managers, and
under the native one the low bit of each operation's event keeps its
completion off the manager's completion port. Where the native manager
is used at all (nativeIO), nothing
comes here (see the end of this header).
Here every operation is started overlapped, so it returns at once, and
a pending one is waited for on an MVar that a helper thread fills
when the operation's event is signaled (awaitEvent). So:
- An asynchronous exception (a
timeout, akillThread) interrupts a blocked operation. The operation is then canceled withCancelIoExand waited for, since its buffer and itsOVERLAPPEDmust not be freed while the kernel may still write to them. hioStopReceivingandhioShutdownare sticky. Each sets a flag and then cancels what is pending; an operation checks the flag before it starts and again once it is pending, so a cancel that arrives between two operations is not lost.- A read and a write can be pending at once (each has its own
OVERLAPPEDand event), which a handle opened withoutFILE_FLAG_OVERLAPPEDdoesn't allow: there the Attention would wait behind the reader thread's read. - Every operation is started on one bound thread that lives as long as
the process (
onIssuer), because Windows cancels a pending operation when the thread that started it exits, and the runtime's worker threads come and go.
That is the threaded runtime. Without -threaded a safe foreign call
stops every Haskell thread, so the waits happen elsewhere: on a worker
thread of GHC's default I/O manager, through asyncDoProc, which runs a
C function there while the scheduler goes on (cbits/windows.c). An
operation is started in place there, since every Haskell thread then
runs on the one operating-system thread that runs the scheduler. The
foreign calls that block for long (a name lookup, a connect, the open
of a pipe) are run on a worker the same way (onWorker). The native
I/O manager of a released GHC has no such workers, so without
-threaded this module needs the default one (requireRuntime).
Under the native I/O manager, with a network and a GHC that support it
(nativeIO), nothing comes here, with
or without -threaded: TCP goes through network's own calls, as on
Linux and macOS, and the pipes through the manager's completion port
(Hmssql.Connection.Backend.WinIO), which takes its foreign calls and
its errors from here.