Reorganisation of the source tree
[ghc-hetmet.git] / docs / comm / rts-libs / non-blocking.html
diff --git a/docs/comm/rts-libs/non-blocking.html b/docs/comm/rts-libs/non-blocking.html
new file mode 100644 (file)
index 0000000..627bde8
--- /dev/null
@@ -0,0 +1,133 @@
+<!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>