diff --git a/src/win/pipe.c b/src/win/pipe.c index 8cdbeebd..158be9c1 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -173,15 +173,48 @@ void uv_pipe_endgame(uv_pipe_t* handle) { int status; unsigned int uv_alloced; DWORD result; + uv_shutdown_t* req; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_PIPE_LOCAL_INFORMATION pipe_info; + if (handle->flags & UV_HANDLE_SHUTTING && !(handle->flags & UV_HANDLE_SHUT) && handle->write_reqs_pending == 0) { + req = handle->shutdown_req; - /* TODO: Try to avoid using the thread pool. Maybe we can somehow figure */ - /* out how much data is left in the kernel buffer? */ + /* Try to avoid flushing the pipe buffer in the thread pool. */ + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &pipe_info, + sizeof pipe_info, + FilePipeLocalInformation); + + if (nt_status != STATUS_SUCCESS) { + /* Failure */ + handle->flags &= ~UV_HANDLE_SHUTTING; + if (req->cb) { + uv_set_sys_error(pRtlNtStatusToDosError(nt_status)); + req->cb(req, -1); + } + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { + /* Short-circuit, no need to call FlushFileBuffers. */ + handle->flags |= UV_HANDLE_SHUT; + if (req->cb) { + req->cb(req, 0); + } + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + /* Run FlushFileBuffers in the thhead pool. */ result = QueueUserWorkItem(pipe_shutdown_thread_proc, - handle->shutdown_req, + req, WT_EXECUTELONGFUNCTION); if (result) { /* Mark the handle as shut now to avoid going through this again. */ @@ -189,13 +222,14 @@ void uv_pipe_endgame(uv_pipe_t* handle) { } else { /* Failure. */ - uv_set_sys_error(GetLastError()); - handle->shutdown_req->cb(handle->shutdown_req, -1); handle->flags &= ~UV_HANDLE_SHUTTING; + if (req->cb) { + uv_set_sys_error(GetLastError()); + req->cb(req, -1); + } DECREASE_PENDING_REQ_COUNT(handle); + return; } - - return; } if (handle->flags & UV_HANDLE_CLOSING &&