Windows: make sure that shutdown_cb is always called
This patch changes how uv-win uses the UV_SHUTTING and UV_SHUT flags. UV_SHUT is now only used for tcp handles to track whether shutdown() has actually been called. UV_SHUTTING has the more generic meaning of "no longer readable". It would be good to replace it by an actual UV_READABLE flag in the future. This makes the shutdown_close_tcp and shutdown_close_pipe tests pass on windows.
This commit is contained in:
parent
95296dfa3c
commit
5d21056277
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user