+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
- <head>
- <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
- <title>The GHC Commentary - Non-blocking I/O on Win32</title>
- </head>
-
- <body BGCOLOR="FFFFFF">
- <h1>The GHC Commentary - Non-blocking I/O on Win32</h1>
- <p>
-
-This note discusses the implementation of non-blocking I/O on
-Win32 platforms. It is not implemented yet (Apr 2002), but it seems worth
-capturing the ideas. Thanks to Sigbjorn for writing them.
-
-<h2> Background</h2>
-
-GHC has provided non-blocking I/O support for Concurrent Haskell
-threads on platforms that provide 'UNIX-style' non-blocking I/O for
-quite a while. That is, platforms that let you alter the property of a
-file descriptor to instead of having a thread block performing an I/O
-operation that cannot be immediately satisfied, the operation returns
-back a special error code (EWOULDBLOCK.) When that happens, the CH
-thread that made the blocking I/O request is put into a blocked-on-IO
-state (see Foreign.C.Error.throwErrnoIfRetryMayBlock). The RTS will
-in a timely fashion check to see whether I/O is again possible
-(via a call to select()), and if it is, unblock the thread & have it
-re-try the I/O operation. The result is that other Concurrent Haskell
-threads won't be affected, but can continue operating while a thread
-is blocked on I/O.
-<p>
-Non-blocking I/O hasn't been supported by GHC on Win32 platforms, for
-the simple reason that it doesn't provide the OS facilities described
-above.
-
-<h2>Win32 non-blocking I/O, attempt 1</h2>
-
-Win32 does provide something select()-like, namely the
-WaitForMultipleObjects() API. It takes an array of kernel object
-handles plus a timeout interval, and waits for either one (or all) of
-them to become 'signalled'. A handle representing an open file (for
-reading) becomes signalled once there is input available.
-<p>
-So, it is possible to observe that I/O is possible using this
-function, but not whether there's "enough" to satisfy the I/O request.
-So, if we were to mimic select() usage with WaitForMultipleObjects(),
-we'd correctly avoid blocking initially, but a thread may very well
-block waiting for their I/O requests to be satisified once the file
-handle has become signalled. [There is a fix for this -- only read
-and write one byte at a the time -- but I'm not advocating that.]
-
-
-<h2>Win32 non-blocking I/O, attempt 2</h2>
-
-Asynchronous I/O on Win32 is supported via 'overlapped I/O'; that is,
-asynchronous read and write requests can be made via the ReadFile() /
-WriteFile () APIs, specifying position and length of the operation.
-If the I/O requests cannot be handled right away, the APIs won't
-block, but return immediately (and report ERROR_IO_PENDING as their
-status code.)
-<p>
-The completion of the request can be reported in a number of ways:
-<ul>
- <li> synchronously, by blocking inside Read/WriteFile(). (this is the
- non-overlapped case, really.)
-<p>
-
- <li> as part of the overlapped I/O request, pass a HANDLE to an event
- object. The I/O system will signal this event once the request
- completed, which a waiting thread will then be able to see.
-<p>
-
- <li> by supplying a pointer to a completion routine, which will be
- called as an Asynchronous Procedure Call (APC) whenever a thread
- calls a select bunch of 'alertable' APIs.
-<p>
-
- <li> by associating the file handle with an I/O completion port. Once
- the request completes, the thread servicing the I/O completion
- port will be notified.
-</ul>
-The use of I/O completion port looks the most interesting to GHC,
-as it provides a central point where all I/O requests are reported.
-<p>
-Note: asynchronous I/O is only fully supported by OSes based on
-the NT codebase, i.e., Win9x don't permit async I/O on files and
-pipes. However, Win9x does support async socket operations, and
-I'm currently guessing here, console I/O. In my view, it would
-be acceptable to provide non-blocking I/O support for NT-based
-OSes only.
-<p>
-Here's the design I currently have in mind:
-<ul>
-<li> Upon startup, an RTS helper thread whose only purpose is to service
- an I/O completion port, is created.
-<p>
-<li> All files are opened in 'overlapping' mode, and associated
- with an I/O completion port.
-<p>
-<li> Overlapped I/O requests are used to implement read() and write().
-<p>
-<li> If the request cannot be satisified without blocking, the Haskell
- thread is put on the blocked-on-I/O thread list & a re-schedule
- is made.
-<p>
-<li> When the completion of a request is signalled via the I/O completion
- port, the RTS helper thread will move the associated Haskell thread
- from the blocked list onto the runnable list. (Clearly, care
- is required here to have another OS thread mutate internal Scheduler
- data structures.)
-
-<p>
-<li> In the event all Concurrent Haskell threads are blocked waiting on
- I/O, the main RTS thread blocks waiting on an event synchronisation
- object, which the helper thread will signal whenever it makes
- a Haskell thread runnable.
-
-</ul>
-
-I might do the communication between the RTS helper thread and the
-main RTS thread differently though: rather than have the RTS helper
-thread manipluate thread queues itself, thus requiring careful
-locking, just have it change a bit on the relevant TSO, which the main
-RTS thread can check at regular intervals (in some analog of
-awaitEvent(), for example).
-
- <p><small>
-<!-- hhmts start -->
-Last modified: Wed Aug 8 19:30:18 EST 2001
-<!-- hhmts end -->
- </small>
- </body>
-</html>