joyent/libuv

How should I handle uv_read_cb's nread < 0

Closed this issue · 12 comments

I called uv_read_stop and it caused an assertion failure at the following assert on Linux. I thought I might called uv_read_stop at a wrong time. So please tell me calling it at what situations will cause the failure and when should I call it.

v0.11

int uv_read_stop(uv_stream_t* stream) {
  /* Sanity check. We're going to stop the handle unless it's primed for
   * writing but that means there should be some kind of write action in
   * progress.
   */
  assert(!uv__io_active(&stream->io_watcher, UV__POLLOUT) ||
         !QUEUE_EMPTY(&stream->write_completed_queue) ||
         !QUEUE_EMPTY(&stream->write_queue) ||
         stream->shutdown_req != NULL ||
         stream->connect_req != NULL);

When a stream's EOF reached, calling uv_read_stop will cause this assert failure. But if I uv_shutdown the stream then, calling uv_read_stop won't cause that assert. So if the read callback was called with nread < 0, it won't be called any more and I shouldn't use uv_read_stop in that situation, just uv_close is required. Am I right?

txdv commented

Yes, at least that is how I implemented it in my wrapper.

I'd need to look a bit deeper, we might need to handle it better.

If EOF is reached the stream automatically stops reading: https://github.com/joyent/libuv/blob/master/src/unix/stream.c#L947-L954, not so if there has been another type of error: https://github.com/joyent/libuv/blob/master/src/unix/stream.c#L1118-L1121 In the latter case, not stopping or closing the handle will trigger that other assert.

Also, uv_close ends up calling uv_read_stop. Can you paste a backtrace?

Which traceback, the assertion failure? The assertion failure is just inside uv_read_stop according to the gdb backtrace when assertion failure. That happened when I call uv_read_stop after the read callback got an EOF. I think uv_read_stop should return an error code instead of an assertion failure which breaks the program.

And if I didn't call uv_close, another assertion failure will be caused according to the another type of error @saghul mentioned, so I must make sure uv_close called when the read callback got an error. Am I right?

Yes, the backtrace. I wonder why this doesn't fail when you do uv_close: https://github.com/joyent/libuv/blob/master/src/unix/stream.c#L1549

so I must make sure uv_close called when the read callback got an error. Am I right?

YEah. IDeally uv_read_stop is enough... excpt when it isn't.

I think uv_read_stop should return an error code instead of an assertion failure which breaks the program.

I'd rather have it silently do nothing instead.

@imzyxwvu @txdv please take a look / test this: #1541

I think backtrace won't help a lot. I will add a printf to print the values later.

IDeally uv_read_stop is enough... excpt when it isn't.

I think it just should help the user close the handle if the user didn't do it instead causing an assertion failure.

Closing, libuv/libuv#47 landed, so now you won't need to do anything, the handle stops itself.