[Haskell-cafe] Re: Hugs vs GHC (again)was: Re: Somerandomnewbiequestions

Glynn Clements glynn at gclements.plus.com
Wed Jan 19 15:26:38 EST 2005


Ben Rudiak-Gould wrote:

>  >>GHC really needs non-blocking
>  >>I/O to support its thread model, and memory-mapped I/O always blocks.
>  >
>  >If, by "blocks", you mean that execution will be suspended until the
>  >data has been read from the device into the buffer cache, then Unix
>  >non-blocking I/O (i.e. O_NONBLOCK) also blocks.
> 
> Okay, my ignorance of Posix is showing again. Is it currently the case, 
> then, that every GHC thread will stop running while a disk read is in 
> progress in any thread?

The kernel thread which called read() will be blocked. If GHC threads
are userspace threads running within a single kernel thread, then they
will all block. If GHC uses multiple kernel threads, the other kernel
threads will continue to run.

> Is this true on all platforms?

Some platforms (but, AFAIK, not linux) allow asynchronous I/O on
regular files. NT has overlapped I/O, which is essentially the same
thing.

> There are two ways of reading from a file/stream in Win32 on NT. One is 
> asynchronous: the call returns immediately and you receive a 
> notification later that the read has completed. The other is synchronous 
> but almost-nonblocking: it returns as much data as is "available", and 
> the entire contents of a file is considered always available. But it 
> always returns at least one byte, and may spend an arbitrary amount of 
> time waiting for that first byte. You can avoid this by waiting for the 
> handle to become signalled; if it's signalled then a subsequent ReadFile 
> will not block indefinitely.
> 
> Win32's synchronous ReadFile is basically the same as Posix's (blocking) 
> read. For some reason I thought that Win32's asynchronous ReadFile was 
> similar to Posix's non-blocking read, but I gather from [1] that they're 
> completely different.

They're similar, but not identical. Traditionally, Unix non-blocking
I/O (along with asynchronous I/O, select() and poll()) were designed
for "slow" streams such as pipes, terminals, sockets etc. Regular
files and block devices are assumed to return the data "immediately".

Essentially, for slow streams, you have to wait for the data to arrive
before it can be read, so waiting may take an indefinite amount of
time. For "fast" streams, the data is always "available", you just
have to wait for the system call to give it to you.

IOW, the time taken to read from a block device is amortised into the
execution time of the system call, rather than being treated as a
delay.

Also, even with blocking I/O, slow streams only block if no data is
available. If less data is available than was requested, they will
usually return whatever is available rather than waiting until they
have the requested amount. Non-blocking I/O only affects the case
where no data is available.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the Haskell-Cafe mailing list