streaming redux

Dmitry Olshansky dmitry.olsh at gmail.com
Thu Dec 30 15:51:59 PST 2010


On 31.12.2010 1:14, Steven Schveighoffer wrote:
> On Thu, 30 Dec 2010 16:49:15 -0500, Dmitry Olshansky 
> <dmitry.olsh at gmail.com> wrote:
>
>> [snip]
>>> -----
>>> Question: Should we allow read to return an empty slice even if 
>>> atEnd is false? If we do, we allow non-blocking streams with burst 
>>> transfer. However, naive client code on non-blocking streams will be 
>>> inefficient because it would essentially implement busy-waiting.
>>>
>>> Why not return an integer so different situations could be 
>>> designated?  It's how the system call read works so you can tell no 
>>> data was read but that's because it's a non-blocking stream.
>>>
>>> I realize it's sexy to return the data again so it can be used 
>>> immediately, but in practice it's more useful to return an integer. 
>>> For example, if you want to fill a buffer, you need a loop anyways 
>>> (there's no guarantee that the first read will fill the buffer), and 
>>> at that point, you are just going to use the length member of the 
>>> return value to advance your loop.
>>>
>>> I'd say, return -1 if a non-blocking stream returns no data, 0 on 
>>> EOF, positive on data read, and throw an exception on error.
>>>
>> Maybe it's only me but I would prefer non-blocking IO not mixed with 
>> blocking in such a way. Imagine function that takes an 
>> UnbufferedInputTransport, how should it indicate that it expects only 
>> a non-blocking IO capable transport? Or the other way around. 
>> Checking return codes hardly helps anything, and it means supporting 
>> both types everywhere, which is a source of all kind of  weird problems.
>>  From my (somewhat limited) experience, code paths for blocking and 
>> non-blocking IO are quite different, the latter are performed by 
>> *special* asynchronous calls which are supported by all modern OSes 
>> for things like files/sockets.
>>
>> Then my position would be:
>> 1) All read/write methods are *blocking*, returning empty slices on EOF.
>> 2) Transport that supports asynchronous IO should implement extended 
>> interfaces like
>> interface AsyncInputTransport: UnbufferedInputTransport{
>>      void asyncRead(ubyte[] buffer, void delegate(ubyte[] data) 
>> callback=null);
>> }
>> interface AsyncOutputTransport: UnbufferedOutputTransport{
>>      void asyncWrite(ubyte[] buffer, void delegate(ubyte[] data) 
>> callback=null);
>> }
>> Where callback (if not null) is called with a slice of buffer 
>> containing actual read/written bytes on IO completion.
>> Any calls to read/asyncRead while there is asynchronous IO operation 
>> going on should throw, of course.
>
> On Linux, you set the file descriptor to blocking or non-blocking, and 
> read(fd) returns errno=EWOULDBLOCK when no data is available.  How 
> does this fit into your scheme?  I.e. if you call read() on a 
> AsyncInputTransport, what does it do when it gets this error?
The only general thing I can think of would be to suspend thread 
(core.Thread.yield), then re-attempt. There may be better platform 
specific ways (there is for GetOverlappedResult with wait flag in Win32).
>
> It's quite possible that there is some API I'm unaware of for doing 
> non-blocking and blocking I/O interleaved, but this has been my 
> experience.
>
> -Steve
You are right, I was referring to Win32 API, but I should have revisited 
that part in API docs. Just checked - indeed you should specify the 
intent in CreateFile operation.  So if asynchronous IO is chosen, then 
blocking IO could only be emulated as suggested above.

-- 
Dmitry Olshansky



More information about the Digitalmars-d mailing list