diff --git a/src/win/error.c b/src/win/error.c index 3f6615f5..5d695696 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -91,6 +91,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case WSAEFAULT: return UV_EFAULT; case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; + case ERROR_OPERATION_ABORTED: return UV_EINTR; + case WSAEINTR: return UV_EINTR; case ERROR_INVALID_DATA: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; diff --git a/src/win/handle.c b/src/win/handle.c index a4eadbdd..a1ff7275 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -91,9 +91,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { tcp = (uv_tcp_t*)handle; /* If we don't shutdown before calling closesocket, windows will */ /* silently discard the kernel send buffer and reset the connection. */ - if (!(tcp->flags & UV_HANDLE_SHUT)) { + if ((tcp->flags & UV_HANDLE_CONNECTION) && + !(tcp->flags & UV_HANDLE_SHUT)) { shutdown(tcp->socket, SD_SEND); - tcp->flags |= UV_HANDLE_SHUT; + tcp->flags |= UV_HANDLE_SHUTTING | UV_HANDLE_SHUT; } tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); closesocket(tcp->socket); diff --git a/src/win/pipe.c b/src/win/pipe.c index ab86018d..f99a32a9 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -281,11 +281,25 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; - if (handle->flags & UV_HANDLE_SHUTTING && - !(handle->flags & UV_HANDLE_SHUT) && + if ((handle->flags & UV_HANDLE_CONNECTION) && + handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { req = handle->shutdown_req; + /* Clear the shutdown_req field so we don't go here again. */ + handle->shutdown_req = NULL; + + if (handle->flags & UV_HANDLE_CLOSING) { + /* Already closing. Cancel the shutdown. */ + if (req->cb) { + uv__set_sys_error(loop, WSAEINTR); + req->cb(req, -1); + } + uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + /* Try to avoid flushing the pipe buffer in the thread pool. */ nt_status = pNtQueryInformationFile(handle->handle, &io_status, @@ -306,8 +320,6 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { - handle->flags |= UV_HANDLE_SHUT; - /* Short-circuit, no need to call FlushFileBuffers. */ uv_insert_pending_req(loop, (uv_req_t*) req); return; @@ -318,8 +330,6 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { req, WT_EXECUTELONGFUNCTION); if (result) { - /* Mark the handle as shut now to avoid going through this again. */ - handle->flags |= UV_HANDLE_SHUT; return; } else { @@ -625,6 +635,7 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { } if (handle->flags & UV_HANDLE_CONNECTION) { + handle->flags |= UV_HANDLE_SHUTTING; eof_timer_destroy(handle); } @@ -633,8 +644,6 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { CloseHandle(handle->handle); handle->handle = INVALID_HANDLE_VALUE; } - - handle->flags |= UV_HANDLE_SHUT; } diff --git a/src/win/stream.c b/src/win/stream.c index 53c4d9ec..d36bc682 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -47,6 +47,8 @@ void uv_connection_init(uv_stream_t* handle) { handle->read_req.wait_handle = INVALID_HANDLE_VALUE; handle->read_req.type = UV_READ; handle->read_req.data = handle; + + handle->shutdown_req = NULL; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 31de8448..25ca26bd 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -171,11 +171,13 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { uv_tcp_accept_t* req; if (handle->flags & UV_HANDLE_CONNECTION && - handle->flags & UV_HANDLE_SHUTTING && - !(handle->flags & UV_HANDLE_SHUT) && + handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { - if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) { + if (handle->flags & UV_HANDLE_CLOSING) { + status = -1; + sys_error = WSAEINTR; + } else if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) { status = 0; handle->flags |= UV_HANDLE_SHUT; } else { @@ -189,6 +191,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->shutdown_req->cb(handle->shutdown_req, status); } + handle->shutdown_req = NULL; + uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; diff --git a/src/win/tty.c b/src/win/tty.c index 2a696c89..601bf5ed 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1721,6 +1721,8 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv_tty_close(uv_tty_t* handle) { + handle->flags |= UV_HANDLE_SHUTTING; + uv_tty_read_stop(handle); CloseHandle(handle->handle); @@ -1731,17 +1733,21 @@ void uv_tty_close(uv_tty_t* handle) { void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { - if (handle->flags & UV_HANDLE_CONNECTION && - handle->flags & UV_HANDLE_SHUTTING && - !(handle->flags & UV_HANDLE_SHUT) && + if ((handle->flags && UV_HANDLE_CONNECTION) && + handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { - handle->flags |= UV_HANDLE_SHUT; - /* TTY shutdown is really just a no-op */ if (handle->shutdown_req->cb) { - handle->shutdown_req->cb(handle->shutdown_req, 0); + if (handle->flags & UV_HANDLE_CLOSING) { + uv__set_sys_error(loop, WSAEINTR); + handle->shutdown_req->cb(handle->shutdown_req, -1); + } else { + handle->shutdown_req->cb(handle->shutdown_req, 0); + } } + handle->shutdown_req = NULL; + uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return;