lep: request all the things
Some stuff that needs clarification:
- @piscisaureus: can we have a
uv_stream_pollthing easily on Windows while still having the other mechanism? - @bnoordhuis: I'm not sure we want to reduce everything to
uv_stream_poll+ reading or writing inline, we'd loose the ability to queue writes, which is nice. Now, we could however get rid ofuv_read_alloc, maybe that's what you meant? Also, maybe we could folduv_readanduv_try_readinto one. If you want to do it inline just pass NULL as the request and the callback. Thoughts?
A random note about edge triggering: if we ever plan to use edge triggered i/o, we need a good story for uv_read. When the user uses uv_stream_poll + uv_try_read she can just keep calling it until EAGAIN, but when uv_read is used should we somehow signal the user in case we didn't get EAGAIN when reading, and thus there is more data awaiting? Or maybe it doesn't matter, because we'll try to read inline when uv_read is called anyway...
@saghul
can we have a uv_stream_poll thing easily on Windows while still having the other mechanism
Depends - it's possible to poll for readable, for some types of streams, most notably TCP connected streams, UDP sockets, and (with some caveats) pipes.
Polling for writable is more problematic. Also note that there may be stream types (file streams) for which readable is not a meaningful event.
I'd like to get rid of reading with an alloc callback. Instead, I would suggest that we support the poll+try_read pattern for the streams that support it. There should be an API to test whether a particular stream can be polled. This enables the embedder to use that strategy when it's the most efficient, and fall back to uv_read() with a pre-allocated buffer when needed.
I'm not sure we want to reduce everything to uv_stream_poll + reading or writing inline, we'd loose the ability to queue writes, which is nice. Now, we could however get rid of uv_read_alloc, maybe that's what you meant?
That's not quite what I meant but I didn't phrase it very well. My thinking was that we should be able to implement uv_read() in terms of uv_stream_poll() + uv_alloc_cb() + uv_try_read(); ditto for uv_write().
Also, maybe we could fold uv_read and uv_try_read into one. If you want to do it inline just pass NULL as the request and the callback.
I like that.
I'd like to get rid of reading with an alloc callback. Instead, I would suggest that we support the poll+try_read pattern for the streams that support it. There should be an API to test whether a particular stream can be polled. This enables the embedder to use that strategy when it's the most efficient, and fall back to uv_read() with a pre-allocated buffer when needed.
Agreed. I guess that the return code from uv_stream_poll could be used for that: if it returns ENOTSUP, you would fallback.
Added another round of fixes, please take a look when you can. Thanks!
LGTM
Hi,
just a comment from someone who looked through here by acccident and curiosity:
This API looks quite a lot of how boost asio works (without the C++parts) which I used a lot in one of my projects.
I found there the ability to mix asynchronous reads with non-blocking immediate reads quite useful. But I think this is covered by this proposal too (by passing a null callback)?
E.g. I have a TCP protocol which transports messages which consist of a 4 byte header containing the payload length and then the payload. I found at the lowest latency way to deal with that in asio is to do an async read (with callback) for the header and if then know the length to do perform a non-blocking immediate read for the payload. In most situations this will directly return and avoid the latency of a whole iteration through the eventloop. If there's really no content I get EAGAIN and start the async read operation instead.
What you might want for the async read operation is to request it to either callback once any data is received or only when exactly the required amount of data is received.
Afaik polling for read readiness on windows can be done by starting asynchronous 0-byte read operations with IOCP.
I found there the ability to mix asynchronous reads with non-blocking immediate reads quite useful. But I think this is covered by this proposal too (by passing a null callback)?
@Matthias247 yes, it will be covered. Maybe not exactly using a NULL callback, put the possibility will be there. We are ironing out API details.
@trevnorris thanks for the feedback, pushed some fixes.
@saghul What's the status of this proposal? Is it dead?
It is still a goal of mine, but this plan was too ambitious and too many things will break. So we are taking smaller steps. Also, we found some bumps on the way and some of the devs (myself, for one) have less time these days to work on it.
@saghul I'm interested in pull based reads. I saw that was planned for 2.0 and this was the only thing I could find with details.
Just FYI, I work for Microsoft on the ASP.NET Core team and we own a web server with a libuv based transport (https://github.com/aspnet/KestrelHttpServer).
@davidfowl I did at one point experiment with wrapping existing libuv with a C layer that exposed it as pull based. I never could get it very efficient, but depending on your requirements and scope, something like that might work. I wanted pull based since luajit's FFI doesn't do well with C callbacks.