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:
Bert Belder 2012-03-09 04:58:49 +01:00
parent 95296dfa3c
commit 5d21056277
6 changed files with 43 additions and 19 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;