streaming redux

Johannes Pfau spam at example.com
Fri Dec 31 03:06:55 PST 2010


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?
>
>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

I think it's possible (libev: "If you cannot use non-blocking mode,
then force the use of a known-to-be-good backend (at the time of this
writing, this includes only EVBACKEND_SELECT and EVBACKEND_POLL)") but
it's usually not a good idea.
I wonder if the Async*Transport should inherit
Unbuffered*Transport or maybe just TransportBase. A transport which
supports asynchronous and synchronous IO could then inherit both
interfaces. If Async*Transport always inherits Unbuffered*Transport
we'll need some other way to check whether the transport really
supports synchronous reading.

-- 
Johannes Pfau
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20101231/15c7b92c/attachment-0001.pgp>


More information about the Digitalmars-d mailing list