summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2012-03-14 16:30:35 -0700
committerisaacs <i@izs.me>2012-03-14 16:44:36 -0700
commitad5a108dfd5bb0a0b46c0f328adda28fa4edcd8e (patch)
tree691e8d2f399f8bcdeaf1002f2944547111763861 /deps
parentc834ef409e85eaa43782bb3edd844af8923f3056 (diff)
downloadnode-new-ad5a108dfd5bb0a0b46c0f328adda28fa4edcd8e.tar.gz
Update uv to 5d21056
Diffstat (limited to 'deps')
-rw-r--r--deps/uv/src/win/error.c2
-rw-r--r--deps/uv/src/win/fs.c3
-rw-r--r--deps/uv/src/win/handle.c15
-rw-r--r--deps/uv/src/win/pipe.c176
-rw-r--r--deps/uv/src/win/process.c2
-rw-r--r--deps/uv/src/win/stream.c5
-rw-r--r--deps/uv/src/win/tcp.c27
-rw-r--r--deps/uv/src/win/tty.c21
-rw-r--r--deps/uv/src/win/udp.c3
-rw-r--r--deps/uv/test/benchmark-pound.c4
-rw-r--r--deps/uv/test/run-tests.c10
-rw-r--r--deps/uv/test/runner-win.c2
-rw-r--r--deps/uv/test/runner.c3
-rw-r--r--deps/uv/test/test-counters-init.c30
-rw-r--r--deps/uv/test/test-cwd-and-chdir.c21
-rw-r--r--deps/uv/test/test-fs.c10
-rw-r--r--deps/uv/test/test-list.h19
-rw-r--r--deps/uv/test/test-ref.c76
-rw-r--r--deps/uv/test/test-shutdown-close.c101
-rw-r--r--deps/uv/test/test-tty.c64
-rw-r--r--deps/uv/uv.gyp1
21 files changed, 447 insertions, 148 deletions
diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c
index 3f6615f5a5..5d695696ff 100644
--- a/deps/uv/src/win/error.c
+++ b/deps/uv/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/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 9c112b80d2..507336eed4 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -547,7 +547,8 @@ static void fs__stat(uv_fs_t* req, const wchar_t* path) {
req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) +
(int64_t) info.nFileSizeLow;
- req->stat.st_nlink = info.nNumberOfLinks;
+ req->stat.st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ?
+ (short) info.nNumberOfLinks : SHRT_MAX;
req->ptr = &req->stat;
req->result = 0;
diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c
index ba0af755fe..a1ff7275c1 100644
--- a/deps/uv/src/win/handle.c
+++ b/deps/uv/src/win/handle.c
@@ -27,9 +27,15 @@
uv_handle_type uv_guess_handle(uv_file file) {
- HANDLE handle = (HANDLE) _get_osfhandle(file);
+ HANDLE handle;
DWORD mode;
+ if (file < 0) {
+ return UV_UNKNOWN_HANDLE;
+ }
+
+ handle = (HANDLE) _get_osfhandle(file);
+
switch (GetFileType(handle)) {
case FILE_TYPE_CHAR:
if (GetConsoleMode(handle, &mode)) {
@@ -85,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);
@@ -173,7 +180,7 @@ void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
void uv_process_endgames(uv_loop_t* loop) {
uv_handle_t* handle;
- while (loop->endgame_handles) {
+ while (loop->endgame_handles && loop->refs > 0) {
handle = loop->endgame_handles;
loop->endgame_handles = handle->endgame_next;
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index ae769c1d1e..f99a32a9bc 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -98,59 +98,61 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) {
}
-static int open_named_pipe(uv_pipe_t* handle) {
- /*
- * Assume that we have a duplex pipe first, so attempt to
+static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
+ HANDLE pipeHandle;
+
+ /*
+ * Assume that we have a duplex pipe first, so attempt to
* connect with GENERIC_READ | GENERIC_WRITE.
*/
- handle->handle = CreateFileW(handle->name,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (handle->handle != INVALID_HANDLE_VALUE) {
- return 0;
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = 0;
+ return pipeHandle;
}
- /*
- * If the pipe is not duplex CreateFileW fails with
+ /*
+ * If the pipe is not duplex CreateFileW fails with
* ERROR_ACCESS_DENIED. In that case try to connect
* as a read-only or write-only.
*/
if (GetLastError() == ERROR_ACCESS_DENIED) {
- handle->handle = CreateFileW(handle->name,
- GENERIC_READ | FILE_WRITE_ATTRIBUTES,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (handle->handle != INVALID_HANDLE_VALUE) {
- handle->flags |= UV_HANDLE_SHUT;
- return 0;
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_SHUTTING;
+ return pipeHandle;
}
}
if (GetLastError() == ERROR_ACCESS_DENIED) {
- handle->handle = CreateFileW(handle->name,
- GENERIC_WRITE | FILE_READ_ATTRIBUTES,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (handle->handle != INVALID_HANDLE_VALUE) {
- handle->flags |= UV_HANDLE_EOF;
- return 0;
+ pipeHandle = CreateFileW(name,
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_EOF;
+ return pipeHandle;
}
}
- return -1;
+ return INVALID_HANDLE_VALUE;
}
@@ -208,7 +210,7 @@ done:
static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle,
- HANDLE pipeHandle) {
+ HANDLE pipeHandle, DWORD duplex_flags) {
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_MODE_INFORMATION mode_info;
@@ -242,6 +244,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle,
}
}
+ handle->handle = pipeHandle;
+ handle->flags |= duplex_flags;
+
return 0;
}
@@ -276,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,
@@ -295,13 +314,12 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status));
req->cb(req, -1);
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
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;
@@ -312,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 {
@@ -323,6 +339,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
uv__set_sys_error(loop, GetLastError());
req->cb(req, -1);
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
@@ -338,7 +355,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
free(handle->pending_socket_info);
handle->pending_socket_info = NULL;
}
-
+
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(handle->read_req.wait_handle);
@@ -449,7 +466,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
goto error;
}
- if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle)) {
+ if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle, 0)) {
uv__set_sys_error(loop, GetLastError());
goto error;
}
@@ -476,11 +493,12 @@ error:
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
- HANDLE pipeHandle = INVALID_HANDLE_VALUE;
int errno;
uv_loop_t* loop;
uv_pipe_t* handle;
uv_connect_t* req;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
req = (uv_connect_t*) parameter;
assert(req);
@@ -493,7 +511,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
/* We wait for the pipe to become available with WaitNamedPipe. */
while (WaitNamedPipeW(handle->name, 30000)) {
/* The pipe is now available, try to connect. */
- if (open_named_pipe(handle) == 0) {
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
break;
}
@@ -501,8 +520,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
}
if (pipeHandle != INVALID_HANDLE_VALUE &&
- !uv_set_pipe_handle(loop, handle, pipeHandle)) {
- handle->handle = pipeHandle;
+ !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) {
SET_REQ_SUCCESS(req);
} else {
SET_REQ_ERROR(req, GetLastError());
@@ -519,8 +537,8 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
const char* name, uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
int errno, nameSize;
-
- handle->handle = INVALID_HANDLE_VALUE;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_CONNECT;
@@ -539,7 +557,8 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
goto error;
}
- if (open_named_pipe(handle) != 0) {
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_PIPE_BUSY) {
/* Wait for the server to make a pipe instance available. */
if (!QueueUserWorkItem(&pipe_connect_thread_proc,
@@ -549,6 +568,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
goto error;
}
+ uv_ref(loop);
handle->reqs_pending++;
return;
@@ -558,9 +578,12 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
goto error;
}
- assert(handle->handle != INVALID_HANDLE_VALUE);
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
- if (uv_set_pipe_handle(loop, (uv_pipe_t*)req->handle, handle->handle)) {
+ if (uv_set_pipe_handle(loop,
+ (uv_pipe_t*) req->handle,
+ pipeHandle,
+ duplex_flags)) {
errno = GetLastError();
goto error;
}
@@ -568,6 +591,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
SET_REQ_SUCCESS(req);
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
+ uv_ref(loop);
return;
error:
@@ -576,15 +600,15 @@ error:
handle->name = NULL;
}
- if (handle->handle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle->handle);
- handle->handle = INVALID_HANDLE_VALUE;
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
}
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, errno);
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
+ uv_ref(loop);
return;
}
@@ -611,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);
}
@@ -619,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;
}
@@ -643,7 +666,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
return;
}
- if (uv_set_pipe_handle(loop, handle, req->pipeHandle)) {
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, 0)) {
CloseHandle(req->pipeHandle);
req->pipeHandle = INVALID_HANDLE_VALUE;
SET_REQ_ERROR(req, GetLastError());
@@ -866,7 +889,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, GetLastError());
goto error;
- }
+ }
} else {
memset(&req->overlapped, 0, sizeof(req->overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
@@ -1071,7 +1094,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
ipc_frame.header.raw_data_length = bufs[0].len;
}
- /*
+ /*
* Use the provided req if we're only doing a single write.
* If we're doing multiple writes, use ipc_header_write_req to do
* the first write, and then use the provided req for the second write.
@@ -1079,7 +1102,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
ipc_header_req = req;
} else {
- /*
+ /*
* Try to use the preallocated write req if it's available.
* Otherwise allocate a new one.
*/
@@ -1123,10 +1146,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
handle->write_queue_size += req->queued_bytes;
}
- if (handle->write_reqs_pending == 0) {
- uv_ref(loop);
- }
-
+ uv_ref(loop);
handle->reqs_pending++;
handle->write_reqs_pending++;
@@ -1181,10 +1201,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
}
}
- if (handle->write_reqs_pending == 0) {
- uv_ref(loop);
- }
-
+ uv_ref(loop);
handle->reqs_pending++;
handle->write_reqs_pending++;
@@ -1359,7 +1376,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
/* Successful read */
if (handle->ipc) {
assert(handle->remaining_ipc_rawdata_bytes >= bytes);
- handle->remaining_ipc_rawdata_bytes =
+ handle->remaining_ipc_rawdata_bytes =
handle->remaining_ipc_rawdata_bytes - bytes;
if (handle->read2_cb) {
handle->read2_cb(handle, bytes, buf,
@@ -1440,15 +1457,12 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_queue_non_overlapped_write(handle);
}
- if (handle->write_reqs_pending == 0) {
- uv_unref(loop);
- }
-
if (handle->write_reqs_pending == 0 &&
handle->flags & UV_HANDLE_SHUTTING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
}
@@ -1495,6 +1509,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
}
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
}
@@ -1519,6 +1534,7 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
req->cb(req, 0);
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
}
@@ -1534,6 +1550,7 @@ static void eof_timer_init(uv_pipe_t* pipe) {
r = uv_timer_init(pipe->loop, pipe->eof_timer);
assert(r == 0); /* timers can't fail */
pipe->eof_timer->data = pipe;
+ uv_unref(pipe->loop);
}
@@ -1596,6 +1613,7 @@ static void eof_timer_destroy(uv_pipe_t* pipe) {
assert(pipe->flags && UV_HANDLE_CONNECTION);
if (pipe->eof_timer) {
+ uv_ref(pipe->loop);
uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
pipe->eof_timer = NULL;
}
@@ -1612,7 +1630,7 @@ void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
HANDLE os_handle = (HANDLE)_get_osfhandle(file);
if (os_handle == INVALID_HANDLE_VALUE ||
- uv_set_pipe_handle(pipe->loop, pipe, os_handle) == -1) {
+ uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) {
return;
}
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 3d64983545..a23ba0b14f 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -832,7 +832,7 @@ done:
static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
HANDLE handle;
HANDLE current_process = GetCurrentProcess();
-
+
handle = GetStdHandle(id);
if (handle == NULL) {
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
index ea7363ef03..d36bc682a8 100644
--- a/deps/uv/src/win/stream.c
+++ b/deps/uv/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;
}
@@ -169,6 +171,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
handle->flags |= UV_HANDLE_SHUTTING;
handle->shutdown_req = req;
handle->reqs_pending++;
+ uv_ref(loop);
uv_want_endgame(loop, (uv_handle_t*)handle);
@@ -194,5 +197,5 @@ int uv_is_readable(uv_stream_t* handle) {
int uv_is_writable(uv_stream_t* handle) {
- return !(handle->flags & UV_HANDLE_SHUT);
+ return !(handle->flags & UV_HANDLE_SHUTTING);
}
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index 628d294dfd..25ca26bdd2 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/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,9 @@ 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;
}
@@ -552,7 +557,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
if (server->processed_accepts >= uv_simultaneous_server_accepts) {
server->processed_accepts = 0;
- /*
+ /*
* All previously queued accept requests are now processed.
* We now switch to queueing just a single accept.
*/
@@ -643,10 +648,12 @@ int uv__tcp_connect(uv_connect_t* req,
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
/* Process the req without IOCP. */
handle->reqs_pending++;
+ uv_ref(loop);
uv_insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
/* The req will be processed with IOCP. */
handle->reqs_pending++;
+ uv_ref(loop);
} else {
uv__set_sys_error(loop, WSAGetLastError());
return -1;
@@ -702,9 +709,11 @@ int uv__tcp_connect6(uv_connect_t* req,
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
handle->reqs_pending++;
+ uv_ref(loop);
uv_insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
handle->reqs_pending++;
+ uv_ref(loop);
} else {
uv__set_sys_error(loop, WSAGetLastError());
return -1;
@@ -799,12 +808,14 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
handle->reqs_pending++;
handle->write_reqs_pending++;
uv_insert_pending_req(loop, (uv_req_t*) req);
+ uv_ref(loop);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
handle->reqs_pending++;
handle->write_reqs_pending++;
handle->write_queue_size += req->queued_bytes;
+ uv_ref(loop);
} else {
/* Send failed due to an error. */
uv__set_sys_error(loop, WSAGetLastError());
@@ -835,7 +846,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
err = GET_REQ_SOCK_ERROR(req);
if (err == WSAECONNABORTED) {
- /*
+ /*
* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
*/
uv__set_error(loop, UV_ECONNRESET, err);
@@ -904,7 +915,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
handle->read_cb((uv_stream_t*)handle, 0, buf);
} else {
if (err == WSAECONNABORTED) {
- /*
+ /*
* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
*/
uv__set_error(loop, UV_ECONNRESET, err);
@@ -950,6 +961,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
}
DECREASE_PENDING_REQ_COUNT(handle);
+ uv_unref(loop);
}
@@ -1024,6 +1036,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
}
DECREASE_PENDING_REQ_COUNT(handle);
+ uv_unref(loop);
}
@@ -1090,7 +1103,7 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
LPWSAPROTOCOL_INFOW protocol_info) {
assert(!(handle->flags & UV_HANDLE_CONNECTION));
- /*
+ /*
* We're about to share the socket with another process. Because
* this is a listening socket, we assume that the other process will
* be accepting connections on it. So, before sharing the socket
diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
index 556875d433..601bf5ed16 100644
--- a/deps/uv/src/win/tty.c
+++ b/deps/uv/src/win/tty.c
@@ -1683,6 +1683,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
handle->reqs_pending++;
handle->write_reqs_pending++;
+ uv_ref(loop);
req->queued_bytes = 0;
@@ -1715,10 +1716,13 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
}
DECREASE_PENDING_REQ_COUNT(handle);
+ uv_unref(loop);
}
void uv_tty_close(uv_tty_t* handle) {
+ handle->flags |= UV_HANDLE_SHUTTING;
+
uv_tty_read_stop(handle);
CloseHandle(handle->handle);
@@ -1729,17 +1733,22 @@ 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;
}
diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c
index 39221de6f7..18ae4a2c13 100644
--- a/deps/uv/src/win/udp.c
+++ b/deps/uv/src/win/udp.c
@@ -404,11 +404,13 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
/* Request completed immediately. */
req->queued_bytes = 0;
handle->reqs_pending++;
+ uv_ref(loop);
uv_insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
handle->reqs_pending++;
+ uv_ref(loop);
} else {
/* Send failed due to an error. */
uv__set_sys_error(loop, WSAGetLastError());
@@ -573,6 +575,7 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
}
}
+ uv_unref(loop);
DECREASE_PENDING_REQ_COUNT(handle);
}
diff --git a/deps/uv/test/benchmark-pound.c b/deps/uv/test/benchmark-pound.c
index 64f404ca94..1693c31c8b 100644
--- a/deps/uv/test/benchmark-pound.c
+++ b/deps/uv/test/benchmark-pound.c
@@ -107,7 +107,9 @@ static void connect_cb(uv_connect_t* req, int status) {
if (status != 0) {
#if DEBUG
- fprintf(stderr, "connect error %s\n", uv_err_name(uv_last_error()));
+ fprintf(stderr,
+ "connect error %s\n",
+ uv_err_name(uv_last_error(uv_default_loop())));
#endif
uv_close((uv_handle_t*)req->handle, close_cb);
conns_failed++;
diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c
index a3e08fc096..a8c886527e 100644
--- a/deps/uv/test/run-tests.c
+++ b/deps/uv/test/run-tests.c
@@ -84,7 +84,7 @@ static void ipc_on_connection(uv_stream_t* server, int status) {
uv_tcp_t* conn;
if (!connection_accepted) {
- /*
+ /*
* Accept the connection and close it. Also let the other
* side know.
*/
@@ -119,7 +119,7 @@ static int ipc_helper(int listen_after_write) {
* data is transfered over the channel. XXX edit this comment after handle
* transfer is added.
*/
-
+
uv_write_t write_req;
int r;
uv_buf_t buf;
@@ -129,8 +129,8 @@ static int ipc_helper(int listen_after_write) {
uv_pipe_open(&channel, 0);
- ASSERT(uv_is_readable(&channel));
- ASSERT(uv_is_writable(&channel));
+ ASSERT(uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(uv_is_writable((uv_stream_t*) &channel));
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
@@ -206,7 +206,7 @@ static int stdio_over_pipes_helper() {
uv_buf_t buf[COUNTOF(buffers)];
int r, i;
uv_loop_t* loop = uv_default_loop();
-
+
ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c
index 6b6d500c44..d2a986a714 100644
--- a/deps/uv/test/runner-win.c
+++ b/deps/uv/test/runner-win.c
@@ -135,7 +135,7 @@ int process_start(char *name, char *part, process_info_t *p) {
p->stdio_in = nul;
p->stdio_out = file;
p->process = pi.hProcess;
- p->name = name;
+ p->name = part;
return 0;
diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c
index fdd8168411..73570fc332 100644
--- a/deps/uv/test/runner.c
+++ b/deps/uv/test/runner.c
@@ -186,7 +186,8 @@ out:
process_terminate(&processes[i]);
}
- if (process_wait(processes, process_count - 1, -1) < 0) {
+ if (process_count > 0 &&
+ process_wait(processes, process_count - 1, -1) < 0) {
FATAL("process_wait failed");
}
diff --git a/deps/uv/test/test-counters-init.c b/deps/uv/test/test-counters-init.c
index 423d349c3b..29e7acdf9f 100644
--- a/deps/uv/test/test-counters-init.c
+++ b/deps/uv/test/test-counters-init.c
@@ -92,21 +92,21 @@ static void create_cb(uv_fs_t* req) {
TEST_IMPL(counters_init) {
int r;
- int eio_init_prev;
- int req_init_prev;
- int handle_init_prev;
- int stream_init_prev;
- int tcp_init_prev;
- int udp_init_prev;
- int pipe_init_prev;
- int tty_init_prev;
- int prepare_init_prev;
- int check_init_prev;
- int idle_init_prev;
- int async_init_prev;
- int timer_init_prev;
- int process_init_prev;
- int fs_event_init_prev;
+ uint64_t eio_init_prev;
+ uint64_t req_init_prev;
+ uint64_t handle_init_prev;
+ uint64_t stream_init_prev;
+ uint64_t tcp_init_prev;
+ uint64_t udp_init_prev;
+ uint64_t pipe_init_prev;
+ uint64_t tty_init_prev;
+ uint64_t prepare_init_prev;
+ uint64_t check_init_prev;
+ uint64_t idle_init_prev;
+ uint64_t async_init_prev;
+ uint64_t timer_init_prev;
+ uint64_t process_init_prev;
+ uint64_t fs_event_init_prev;
/* req_init and eio_init test by uv_fs_open() */
unlink("test_file");
diff --git a/deps/uv/test/test-cwd-and-chdir.c b/deps/uv/test/test-cwd-and-chdir.c
index deafdc9488..d72c26a80d 100644
--- a/deps/uv/test/test-cwd-and-chdir.c
+++ b/deps/uv/test/test-cwd-and-chdir.c
@@ -37,17 +37,20 @@ TEST_IMPL(cwd_and_chdir) {
err = uv_cwd(buffer_orig, size);
ASSERT(err.code == UV_OK);
- last_slash = strrchr(buffer_orig,
+ /* Remove trailing slash unless at a root directory. */
#ifdef _WIN32
- '\\'
-#else
- '/'
-#endif
- );
-
+ last_slash = strrchr(buffer_orig, '\\');
ASSERT(last_slash);
-
- *last_slash = '\0';
+ if (last_slash > buffer_orig && *(last_slash - 1) != ':') {
+ *last_slash = '\0';
+ }
+#else /* Unix */
+ last_slash = strrchr(buffer_orig, '/');
+ ASSERT(last_slash);
+ if (last_slash != buffer_orig) {
+ *last_slash = '\0';
+ }
+#endif
err = uv_chdir(buffer_orig);
ASSERT(err.code == UV_OK);
diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c
index af2ebbf5bc..8dc7147310 100644
--- a/deps/uv/test/test-fs.c
+++ b/deps/uv/test/test-fs.c
@@ -115,7 +115,7 @@ void check_permission(const char* filename, int mode) {
s = req.ptr;
#ifdef _WIN32
- /*
+ /*
* On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit,
* so only testing for the specified flags.
*/
@@ -186,8 +186,14 @@ static void chown_cb(uv_fs_t* req) {
static void chown_root_cb(uv_fs_t* req) {
ASSERT(req->fs_type == UV_FS_CHOWN);
+#ifdef _WIN32
+ /* On windows, chown is a no-op and always succeeds. */
+ ASSERT(req->result == 0);
+#else
+ /* On unix, chown'ing the root directory is not allowed. */
ASSERT(req->result == -1);
ASSERT(req->errorno == UV_EPERM);
+#endif
chown_cb_count++;
uv_fs_req_cleanup(req);
}
@@ -1210,7 +1216,7 @@ TEST_IMPL(fs_symlink) {
*/
return 0;
} else if (uv_last_error(loop).sys_errno_ == ERROR_PRIVILEGE_NOT_HELD) {
- /*
+ /*
* Creating a symlink is only allowed when running elevated.
* We pass the test and bail out early if we get ERROR_PRIVILEGE_NOT_HELD.
*/
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 1371371776..9e5309c170 100644
--- a/deps/uv/test/test-list.h
+++ b/deps/uv/test/test-list.h
@@ -59,6 +59,8 @@ TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (connection_fail)
TEST_DECLARE (connection_fail_doesnt_auto_close)
+TEST_DECLARE (shutdown_close_tcp)
+TEST_DECLARE (shutdown_close_pipe)
TEST_DECLARE (shutdown_eof)
TEST_DECLARE (callback_stack)
TEST_DECLARE (error_message)
@@ -79,12 +81,16 @@ TEST_DECLARE (fs_event_ref)
TEST_DECLARE (tcp_ref)
TEST_DECLARE (tcp_ref2)
TEST_DECLARE (tcp_ref3)
+TEST_DECLARE (tcp_ref4)
+TEST_DECLARE (tcp_ref5)
TEST_DECLARE (udp_ref)
TEST_DECLARE (udp_ref2)
TEST_DECLARE (udp_ref3)
TEST_DECLARE (pipe_ref)
TEST_DECLARE (pipe_ref2)
TEST_DECLARE (pipe_ref3)
+TEST_DECLARE (pipe_ref4)
+TEST_DECLARE (pipe_ref5)
TEST_DECLARE (process_ref)
TEST_DECLARE (async)
TEST_DECLARE (get_currentexe)
@@ -202,6 +208,11 @@ TASK_LIST_START
TEST_ENTRY (connection_fail)
TEST_ENTRY (connection_fail_doesnt_auto_close)
+ TEST_ENTRY (shutdown_close_tcp)
+ TEST_HELPER (shutdown_close_tcp, tcp4_echo_server)
+ TEST_ENTRY (shutdown_close_pipe)
+ TEST_HELPER (shutdown_close_pipe, pipe_echo_server)
+
TEST_ENTRY (shutdown_eof)
TEST_HELPER (shutdown_eof, tcp4_echo_server)
@@ -228,6 +239,10 @@ TASK_LIST_START
TEST_ENTRY (tcp_ref2)
TEST_ENTRY (tcp_ref3)
TEST_HELPER (tcp_ref3, tcp4_echo_server)
+ TEST_ENTRY (tcp_ref4)
+ TEST_HELPER (tcp_ref4, tcp4_echo_server)
+ TEST_ENTRY (tcp_ref5)
+ TEST_HELPER (tcp_ref5, tcp4_echo_server)
TEST_ENTRY (udp_ref)
TEST_ENTRY (udp_ref2)
TEST_ENTRY (udp_ref3)
@@ -236,6 +251,10 @@ TASK_LIST_START
TEST_ENTRY (pipe_ref2)
TEST_ENTRY (pipe_ref3)
TEST_HELPER (pipe_ref3, pipe_echo_server)
+ TEST_ENTRY (pipe_ref4)
+ TEST_HELPER (pipe_ref4, pipe_echo_server)
+ TEST_ENTRY (pipe_ref5)
+ TEST_HELPER (pipe_ref5, pipe_echo_server)
TEST_ENTRY (process_ref)
TEST_ENTRY (loop_handles)
diff --git a/deps/uv/test/test-ref.c b/deps/uv/test/test-ref.c
index 2b8aabbc6f..9a474b5636 100644
--- a/deps/uv/test/test-ref.c
+++ b/deps/uv/test/test-ref.c
@@ -26,11 +26,39 @@
#include <string.h>
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static char buffer[32767];
+
+
static void fail_cb(void) {
FATAL("fail_cb should not have been called");
}
+static void write_unref_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ uv_write(&write_req, req->handle, &buf, 1, (uv_write_cb) fail_cb);
+ uv_unref(uv_default_loop()); // uv_write refs the loop
+}
+
+
+
+static void shutdown_unref_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ uv_shutdown(&shutdown_req, req->handle, (uv_shutdown_cb) fail_cb);
+ uv_unref(uv_default_loop()); // uv_shutdown refs the loop
+}
+
+
TEST_IMPL(ref) {
uv_run(uv_default_loop());
return 0;
@@ -142,10 +170,9 @@ TEST_IMPL(tcp_ref2) {
TEST_IMPL(tcp_ref3) {
struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
- uv_connect_t req;
uv_tcp_t h;
uv_tcp_init(uv_default_loop(), &h);
- uv_tcp_connect(&req, &h, addr, (uv_connect_cb)fail_cb);
+ uv_tcp_connect(&connect_req, &h, addr, (uv_connect_cb)fail_cb);
uv_unref(uv_default_loop());
uv_unref(uv_default_loop()); /* connect req refs the loop */
uv_run(uv_default_loop());
@@ -153,6 +180,28 @@ TEST_IMPL(tcp_ref3) {
}
+TEST_IMPL(tcp_ref4) {
+ struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req, &h, addr, write_unref_cb);
+ uv_unref(uv_default_loop());
+ uv_run(uv_default_loop());
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref5) {
+ struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req, &h, addr, shutdown_unref_cb);
+ uv_unref(uv_default_loop());
+ uv_run(uv_default_loop());
+ return 0;
+}
+
+
TEST_IMPL(udp_ref) {
uv_udp_t h;
uv_udp_init(uv_default_loop(), &h);
@@ -210,10 +259,9 @@ TEST_IMPL(pipe_ref2) {
TEST_IMPL(pipe_ref3) {
- uv_connect_t req;
uv_pipe_t h;
uv_pipe_init(uv_default_loop(), &h, 0);
- uv_pipe_connect(&req, &h, TEST_PIPENAME, (uv_connect_cb)fail_cb);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, (uv_connect_cb)fail_cb);
uv_unref(uv_default_loop());
uv_unref(uv_default_loop()); /* connect req refs the loop */
uv_run(uv_default_loop());
@@ -221,6 +269,26 @@ TEST_IMPL(pipe_ref3) {
}
+TEST_IMPL(pipe_ref4) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, write_unref_cb);
+ uv_unref(uv_default_loop());
+ uv_run(uv_default_loop());
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref5) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, shutdown_unref_cb);
+ uv_unref(uv_default_loop());
+ uv_run(uv_default_loop());
+ return 0;
+}
+
+
TEST_IMPL(process_ref) {
/* spawn_helper4 blocks indefinitely. */
char *argv[] = { NULL, "spawn_helper4", NULL };
diff --git a/deps/uv/test/test-shutdown-close.c b/deps/uv/test/test-shutdown-close.c
new file mode 100644
index 0000000000..864f7cecae
--- /dev/null
+++ b/deps/uv/test/test-shutdown-close.c
@@ -0,0 +1,101 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * These tests verify that the uv_shutdown callback is always made, even when
+ * it is immediately followed by an uv_close call.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static int connect_cb_called = 0;
+static int shutdown_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0 ||
+ (status == -1 && uv_last_error(uv_default_loop()).code == UV_EINTR));
+ shutdown_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) req->handle, close_cb);
+
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(shutdown_close_tcp) {
+ struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+ uv_tcp_t h;
+ int r;
+
+ r = uv_tcp_init(uv_default_loop(), &h);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&connect_req, &h, addr, connect_cb);
+ ASSERT(r == 0);
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(shutdown_close_pipe) {
+ uv_pipe_t h;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &h, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb);
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c
index 1e3e1f280c..24f0def6a6 100644
--- a/deps/uv/test/test-tty.c
+++ b/deps/uv/test/test-tty.c
@@ -22,23 +22,64 @@
#include "uv.h"
#include "task.h"
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+#else // Unix
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+
TEST_IMPL(tty) {
int r, width, height;
- uv_tty_t tty;
+ int ttyin_fd, ttyout_fd;
+ uv_tty_t tty_in, tty_out;
uv_loop_t* loop = uv_default_loop();
+ // Make sure we have an FD that refers to a tty
+#ifdef _WIN32
+ HANDLE handle;
+ handle = CreateFileA("conin$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
+
+ handle = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
+
+#else /* unix */
+ ttyin_fd = open("/dev/tty", O_RDONLY, 0);
+ ttyout_fd = open("/dev/tty", O_WRONLY, 0);
+#endif
+
+ ASSERT(ttyin_fd >= 0);
+ ASSERT(ttyout_fd >= 0);
+
ASSERT(UV_UNKNOWN_HANDLE == uv_guess_handle(-1));
- /*
- * Not necessarily a problem if this assert goes off. E.G you are piping
- * this test to a file. 0 == stdin.
- */
- ASSERT(UV_TTY == uv_guess_handle(0));
+ ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
+ ASSERT(UV_TTY == uv_guess_handle(ttyout_fd));
+
+ r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1);
+ ASSERT(r == 0);
- r = uv_tty_init(uv_default_loop(), &tty, 0, 1);
+ r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 2);
ASSERT(r == 0);
- r = uv_tty_get_winsize(&tty, &width, &height);
+ r = uv_tty_get_winsize(&tty_out, &width, &height);
ASSERT(r == 0);
printf("width=%d height=%d\n", width, height);
@@ -51,16 +92,17 @@ TEST_IMPL(tty) {
ASSERT(height > 10);
/* Turn on raw mode. */
- r = uv_tty_set_mode(&tty, 1);
+ r = uv_tty_set_mode(&tty_in, 1);
ASSERT(r == 0);
/* Turn off raw mode. */
- r = uv_tty_set_mode(&tty, 0);
+ r = uv_tty_set_mode(&tty_in, 0);
ASSERT(r == 0);
/* TODO check the actual mode! */
- uv_close((uv_handle_t*)&tty, NULL);
+ uv_close((uv_handle_t*) &tty_in, NULL);
+ uv_close((uv_handle_t*) &tty_out, NULL);
uv_run(loop);
diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp
index 07ea07a817..8151878fa5 100644
--- a/deps/uv/uv.gyp
+++ b/deps/uv/uv.gyp
@@ -299,6 +299,7 @@
'test/test-pipe-bind-error.c',
'test/test-pipe-connect-error.c',
'test/test-ref.c',
+ 'test/test-shutdown-close.c',
'test/test-shutdown-eof.c',
'test/test-spawn.c',
'test/test-stdio-over-pipes.c',