remove empty dir
[ghc-hetmet.git] / ghc / docs / comm / rts-libs / non-blocking.html
1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2 <html>
3   <head>
4     <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
5     <title>The GHC Commentary - Non-blocking I/O on Win32</title>
6   </head>
7
8   <body BGCOLOR="FFFFFF">
9     <h1>The GHC Commentary - Non-blocking I/O on Win32</h1>
10     <p>
11
12 This note discusses the implementation of non-blocking I/O on
13 Win32 platforms.   It is not implemented yet (Apr 2002), but it seems worth
14 capturing the ideas.  Thanks to Sigbjorn for writing them.
15
16 <h2> Background</h2>
17
18 GHC has provided non-blocking I/O support for Concurrent Haskell
19 threads on platforms that provide 'UNIX-style' non-blocking I/O for
20 quite a while. That is, platforms that let you alter the property of a
21 file descriptor to instead of having a thread block performing an I/O
22 operation that cannot be immediately satisfied, the operation returns
23 back a special error code (EWOULDBLOCK.) When that happens, the CH
24 thread that made the blocking I/O request is put into a blocked-on-IO
25 state (see Foreign.C.Error.throwErrnoIfRetryMayBlock). The RTS will
26 in a timely fashion check to see whether I/O is again possible
27 (via a call to select()), and if it is, unblock the thread & have it
28 re-try the I/O operation. The result is that other Concurrent Haskell
29 threads won't be affected, but can continue operating while a thread
30 is blocked on I/O.
31 <p>
32 Non-blocking I/O hasn't been supported by GHC on Win32 platforms, for
33 the simple reason that it doesn't provide the OS facilities described
34 above. 
35
36 <h2>Win32 non-blocking I/O, attempt 1</h2>
37
38 Win32 does provide something select()-like, namely the
39 WaitForMultipleObjects() API. It takes an array of kernel object
40 handles plus a timeout interval, and waits for either one (or all) of
41 them to become 'signalled'. A handle representing an open file (for
42 reading) becomes signalled once there is input available.
43 <p>
44 So, it is possible to observe that I/O is possible using this
45 function, but not whether there's "enough" to satisfy the I/O request.
46 So, if we were to mimic select() usage with WaitForMultipleObjects(),
47 we'd correctly avoid blocking initially, but a thread may very well 
48 block waiting for their I/O requests to be satisified once the file
49 handle has become signalled. [There is a fix for this -- only read
50 and write one byte at a the time -- but I'm not advocating that.]
51
52
53 <h2>Win32 non-blocking I/O, attempt 2</h2>
54
55 Asynchronous I/O on Win32 is supported via 'overlapped I/O'; that is,
56 asynchronous read and write requests can be made via the ReadFile() /
57 WriteFile () APIs, specifying position and length of the operation.
58 If the I/O requests cannot be handled right away, the APIs won't
59 block, but return immediately (and report ERROR_IO_PENDING as their
60 status code.)
61 <p>
62 The completion of the request can be reported in a number of ways:
63 <ul>
64   <li> synchronously, by blocking inside Read/WriteFile().  (this is the
65     non-overlapped case, really.)
66 <p>
67
68   <li> as part of the overlapped I/O request, pass a HANDLE to an event
69     object. The I/O system will signal this event once the request
70     completed, which a waiting thread will then be able to see.
71 <p>
72
73   <li> by supplying a pointer to a completion routine, which will be
74     called as an Asynchronous Procedure Call (APC) whenever a thread
75     calls a select bunch of 'alertable' APIs.
76 <p>
77
78   <li> by associating the file handle with an I/O completion port.  Once
79     the request completes, the thread servicing the I/O completion
80     port will be notified.
81 </ul>
82 The use of I/O completion port looks the most interesting to GHC,
83 as it provides a central point where all I/O requests are reported.
84 <p>
85 Note: asynchronous I/O is only fully supported by OSes based on
86 the NT codebase, i.e., Win9x don't permit async I/O on files and
87 pipes. However, Win9x does support async socket operations, and
88 I'm currently guessing here, console I/O. In my view, it would
89 be acceptable to provide non-blocking I/O support for NT-based
90 OSes only.
91 <p>
92 Here's the design I currently have in mind:
93 <ul>
94 <li> Upon startup, an RTS helper thread whose only purpose is to service
95   an I/O completion port, is created.
96 <p>
97 <li> All files are opened in 'overlapping' mode, and associated
98   with an I/O completion port.
99 <p>
100 <li> Overlapped I/O requests are used to implement read() and write().
101 <p>
102 <li> If the request cannot be satisified without blocking, the Haskell
103   thread is put on the blocked-on-I/O thread list & a re-schedule
104   is made.
105 <p>
106 <li> When the completion of a request is signalled via the I/O completion
107   port, the RTS helper thread will move the associated Haskell thread
108   from the blocked list onto the runnable list. (Clearly, care
109   is required here to have another OS thread mutate internal Scheduler
110   data structures.)
111   
112 <p>
113 <li> In the event all Concurrent Haskell threads are blocked waiting on
114   I/O, the main RTS thread blocks waiting on an event synchronisation
115   object, which the helper thread will signal whenever it makes
116   a Haskell thread runnable.
117
118 </ul>
119
120 I might do the communication between the RTS helper thread and the 
121 main RTS thread differently though: rather than have the RTS helper 
122 thread manipluate thread queues itself, thus requiring careful 
123 locking, just have it change a bit on the relevant TSO, which the main 
124 RTS thread can check at regular intervals (in some analog of 
125 awaitEvent(), for example).
126
127     <p><small>
128 <!-- hhmts start -->
129 Last modified: Wed Aug  8 19:30:18 EST 2001
130 <!-- hhmts end -->
131     </small>
132   </body>
133 </html>