diff --git a/src/unix/stream.c b/src/unix/stream.c index 93c6b934..9c0d6e70 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -66,6 +66,7 @@ static void uv__read(uv_stream_t* stream); static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); static void uv__write_callbacks(uv_stream_t* stream); static size_t uv__write_req_size(uv_write_t* req); +static void uv__drain(uv_stream_t* stream); void uv__stream_init(uv_loop_t* loop, @@ -453,17 +454,7 @@ void uv__stream_destroy(uv_stream_t* stream) { uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); - - if (stream->shutdown_req) { - /* The ECANCELED error code is a lie, the shutdown(2) syscall is a - * fait accompli at this point. Maybe we should revisit this in v0.11. - * A possible reason for leaving it unchanged is that it informs the - * callee that the handle has been destroyed. - */ - uv__req_unregister(stream->loop, stream->shutdown_req); - stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED); - stream->shutdown_req = NULL; - } + uv__drain(stream); assert(stream->write_queue_size == 0); } @@ -668,26 +659,31 @@ static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; int err; + if (!(stream->flags & UV_HANDLE_SHUTTING)) + return; + assert(QUEUE_EMPTY(&stream->write_queue)); - uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - uv__stream_osx_interrupt_select(stream); + req = stream->shutdown_req; + assert(req); - /* Shutdown? */ - if ((stream->flags & UV_HANDLE_SHUTTING) && - !(stream->flags & UV_HANDLE_CLOSING) && + if (!(stream->flags & UV_HANDLE_CLOSING)) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + if ((stream->flags & UV_HANDLE_CLOSING) || !(stream->flags & UV_HANDLE_SHUT)) { - assert(stream->shutdown_req); - - req = stream->shutdown_req; stream->shutdown_req = NULL; stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; - if (shutdown(uv__stream_fd(stream), SHUT_WR)) + if (stream->flags & UV_HANDLE_CLOSING) + /* The user destroyed the stream before we got to do the shutdown. */ + err = UV_ECANCELED; + else if (shutdown(uv__stream_fd(stream), SHUT_WR)) err = UV__ERR(errno); - - if (err == 0) + else /* Success. */ stream->flags |= UV_HANDLE_SHUT; if (req->cb != NULL)