#2189: hSetBuffering stdin NoBuffering doesn't work on Windows
--------------------------------------------+-------------------------------
 Reporter:  FalconNL                        |          Owner:         
     Type:  bug                             |         Status:  new    
 Priority:  high                            |      Milestone:  6.10.2 
Component:  libraries/base                  |        Version:  6.8.2  
 Severity:  normal                          |     Resolution:         
 Keywords:  hsetbuffering buffering buffer  |     Difficulty:  Unknown
 Testcase:                                  |   Architecture:  x86    
       Os:  Windows                         |  
--------------------------------------------+-------------------------------
Changes (by Deewiant):

 * cc: Deewiant (added)
  * summary:  hSetBuffer stdin NoBuffering doesn't seem to work in ghc
              6.8.2 on Windows XP => hSetBuffering stdin
              NoBuffering doesn't work on Windows

Comment:

 Unfortunately conio doesn't mix with ordinary IO, as I demonstrated in a
 response to that thread on glasgow-haskell-users.

 As for the original problem, I think this'd take some work to solve: GHC
 would have to convert to the Win32 API for all of its IO on Windows.
 (That'd also help with #806.)

 What currently happens is the following call chain, starting from
 `hGetChar` (a bit of documentation for any would-be fixers):
 {{{
 System.IO.hGetChar stdin

 -- meanings of numbers: stdin FD, not a socket, offset 0, length 1
 GHC.Handle.readRawBuffer "hGetChar" 0 0 <buffer> 0 1

 GHC.Handle.asyncReadRawBuffer 0 0 <buffer> 0 1

 GHC.Conc.asyncReadBA 0 0 1 0 <buffer>

 -- offset got applied
 GHC.Conc.asyncRead 0 0 1 <buffer>

 -- asyncReadzh_fast in rts/PrimOps.cmm
 asyncRead# 0 0 1 <buffer>

 -- in rts/win32/AsyncIO.c
 -- the new 0 signifies that this is a read and not a write
 addIORequest(0, 0, 0, 1, <buffer>)
 }}}
 From there it ends up into the asynchronous IO work queue, whence it
 eventually gets picked up by `IOWorkerProc` (in rts/win32/IOManager.c). It
 notices that the `workKind` is `WORKER_READ` but not `WORKER_FOR_SOCKET`,
 so it does a plain `read()` call.

 In the current situation that's basically fine, since the `hSetBuffering`
 never did anything and we're still in line buffered mode. In unbuffered
 mode, that'd be a problem, as the comment from System.Posix.Internals
 (which judah posted above) asserts: enter needs to be pressed twice. The
 fact that it gives '\r' instead of '\n' isn't such a big problem since it
 can be easily modified.

 I'm attaching a C program which shows how the problem is avoided by using
 the Win32 API directly (in this case, `ReadFile` is fine) instead of the
 POSIX `read`: the latter requires two presses of enter, the former only
 one.

 Since there seems to be no way of getting a Win32 `HANDLE` object from a C
 `FILE*` let alone a POSIX file descriptor, I believe that the only
 reasonable way of getting this and #806 to work reliably is to convert the
 whole IO subsystem to use the Windows API directly—starting from changing
 `GHC.IOBase.Handle__.haFD` from an `FD` to a `HANDLE` on Windows.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2189#comment:12>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to