uv: upgrade 8c78cb4
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 9 Mar 2012 17:20:29 +0000 (09:20 -0800)
committerBen Noordhuis <info@bnoordhuis.nl>
Fri, 9 Mar 2012 17:42:12 +0000 (09:42 -0800)
31 files changed:
deps/uv/config-mingw.mk
deps/uv/include/uv.h
deps/uv/src/unix/cygwin.c
deps/uv/src/unix/stream.c
deps/uv/src/win/core.c
deps/uv/src/win/error.c
deps/uv/src/win/fs.c
deps/uv/src/win/handle.c
deps/uv/src/win/pipe.c
deps/uv/src/win/process.c
deps/uv/src/win/stream.c
deps/uv/src/win/tcp.c
deps/uv/src/win/tty.c
deps/uv/src/win/udp.c
deps/uv/src/win/util.c
deps/uv/src/win/winapi.h
deps/uv/test/benchmark-pound.c
deps/uv/test/benchmark-thread.c
deps/uv/test/run-tests.c
deps/uv/test/runner-win.c
deps/uv/test/runner.c
deps/uv/test/test-counters-init.c
deps/uv/test/test-cwd-and-chdir.c
deps/uv/test/test-fs.c
deps/uv/test/test-ipc-send-recv.c [new file with mode: 0644]
deps/uv/test/test-ipc.c
deps/uv/test/test-list.h
deps/uv/test/test-ref.c
deps/uv/test/test-shutdown-close.c [new file with mode: 0644]
deps/uv/test/test-tty.c
deps/uv/uv.gyp

index 12e9578..48c6325 100644 (file)
@@ -34,7 +34,7 @@ WIN_OBJS=$(WIN_SRCS:.c=.o)
 
 RUNNER_CFLAGS=$(CFLAGS) -D_GNU_SOURCE # Need _GNU_SOURCE for strdup?
 RUNNER_LINKFLAGS=$(LINKFLAGS)
-RUNNER_LIBS=-lws2_32
+RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi
 RUNNER_SRC=test/runner-win.c
 
 uv.a: $(WIN_OBJS) src/uv-common.o $(CARES_OBJS)
index 6c90a87..e3a8b70 100644 (file)
@@ -1388,7 +1388,7 @@ UV_EXTERN extern uint64_t uv_hrtime(void);
 
 
 /*
- * Opens a shared library. The filename is in utf-8. On success, -1 is
+ * Opens a shared library. The filename is in utf-8. On success, -1 is returned
  * and the variable pointed by library receives a handle to the library.
  */
 UV_EXTERN uv_err_t uv_dlopen(const char* filename, uv_lib_t* library);
index a3d1736..aef8d76 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include "uv.h"
+#include "../uv-common.h"
 
 #include <assert.h>
 #include <stdint.h>
index 111bbc2..b5ade16 100644 (file)
 #include "uv.h"
 #include "internal.h"
 
-#include <assert.h>
-#include <errno.h>
-#include <unistd.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/uio.h>
+#include <assert.h>
+#include <errno.h>
 
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
 
 
 static void uv__stream_connect(uv_stream_t*);
@@ -513,6 +516,28 @@ static void uv__write_callbacks(uv_stream_t* stream) {
 }
 
 
+static uv_handle_type uv__handle_type(int fd) {
+  struct sockaddr_storage ss;
+  socklen_t len;
+
+  memset(&ss, 0, sizeof(ss));
+  len = sizeof(ss);
+
+  if (getsockname(fd, (struct sockaddr*)&ss, &len))
+    return UV_UNKNOWN_HANDLE;
+
+  switch (ss.ss_family) {
+  case AF_UNIX:
+    return UV_NAMED_PIPE;
+  case AF_INET:
+  case AF_INET6:
+    return UV_TCP;
+  }
+
+  return UV_UNKNOWN_HANDLE;
+}
+
+
 static void uv__read(uv_stream_t* stream) {
   uv_buf_t buf;
   ssize_t nread;
@@ -633,7 +658,8 @@ static void uv__read(uv_stream_t* stream) {
 
 
         if (stream->accepted_fd >= 0) {
-          stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_TCP);
+          stream->read2_cb((uv_pipe_t*)stream, nread, buf,
+              uv__handle_type(stream->accepted_fd));
         } else {
           stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_UNKNOWN_HANDLE);
         }
index 8b44540..accacc5 100644 (file)
@@ -59,6 +59,7 @@ static void uv_init(void) {
 
 
 static void uv_loop_init(uv_loop_t* loop) {
+  loop->uv_ares_handles_ = NULL;
   /* Create an I/O completion port */
   loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
   if (loop->iocp == NULL) {
index 4fc8734..1951fc3 100644 (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;
index 9c112b8..507336e 100644 (file)
@@ -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;
index ba0af75..a1ff727 100644 (file)
 
 
 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;
 
index 54d90e0..83220a2 100644 (file)
@@ -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,13 +210,18 @@ 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;
   DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
 
   if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+    /* If this returns ERROR_INVALID_PARAMETER we probably opened something */
+    /* that is not a pipe. */
+    if (GetLastError() == ERROR_INVALID_PARAMETER) {
+      SetLastError(WSAENOTSOCK);
+    }
     return -1;
   }
 
@@ -242,6 +249,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 +286,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 +319,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 +335,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 +344,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 +360,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 +471,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 +498,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 +516,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 +525,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 +542,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 +562,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 +573,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
         goto error;
       }
 
+      uv_ref(loop);
       handle->reqs_pending++;
 
       return;
@@ -558,15 +583,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);
 
-  /* Ensure that what we just opened is actually a pipe */
-  if (!GetNamedPipeInfo(handle->handle, NULL, NULL, NULL, NULL)) {
-    errno = WSAENOTSOCK;
-    goto error;
-  }
-
-  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;
   }
@@ -574,6 +596,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:
@@ -582,15 +605,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;
 }
 
@@ -617,6 +640,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);
   }
 
@@ -625,8 +649,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;
 }
 
 
@@ -649,7 +671,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());
@@ -872,7 +894,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) {
@@ -1077,7 +1099,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.
@@ -1085,7 +1107,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.
        */
@@ -1129,10 +1151,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++;
 
@@ -1187,10 +1206,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++;
 
@@ -1365,7 +1381,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,
@@ -1446,15 +1462,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);
 }
 
@@ -1501,6 +1514,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
     }
   }
 
+  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
@@ -1525,6 +1539,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);
 }
 
@@ -1540,6 +1555,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);
 }
 
 
@@ -1602,6 +1618,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;
   }
@@ -1618,7 +1635,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;
   }
 
index 84781d6..7474486 100644 (file)
@@ -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) {
index ea7363e..d36bc68 100644 (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;
 }
 
 
@@ -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);
 }
index 956053c..ab656a1 100644 (file)
@@ -167,11 +167,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 {
@@ -185,6 +187,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;
   }
@@ -548,7 +553,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.
          */
@@ -639,10 +644,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;
@@ -698,9 +705,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;
@@ -795,12 +804,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());
@@ -831,7 +842,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);
@@ -900,7 +911,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);
@@ -946,6 +957,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
+  uv_unref(loop);
 }
 
 
@@ -1020,6 +1032,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
+  uv_unref(loop);
 }
 
 
@@ -1086,7 +1099,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
index dd2fdbc..5bf90be 100644 (file)
@@ -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;
   }
index ad05164..1964401 100644 (file)
@@ -400,11 +400,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());
@@ -569,6 +571,7 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     }
   }
 
+  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
index 15618e9..9f731ec 100644 (file)
@@ -490,11 +490,13 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
   unsigned long size = 0;
   IP_ADAPTER_ADDRESSES* adapter_addresses;
   IP_ADAPTER_ADDRESSES* adapter_address;
-  IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address;
   uv_interface_address_t* address;
   struct sockaddr* sock_addr;
   int length;
   char* name;
+  /* Use IP_ADAPTER_UNICAST_ADDRESS_XP to retain backwards compatibility */
+  /* with Windows XP */
+  IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address;
 
   if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size)
       != ERROR_BUFFER_OVERFLOW) {
@@ -517,7 +519,8 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
   for (adapter_address = adapter_addresses;
        adapter_address != NULL;
        adapter_address = adapter_address->Next) {
-    unicast_address = adapter_address->FirstUnicastAddress;
+    unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
+                      adapter_address->FirstUnicastAddress;
     while (unicast_address) {
       (*count)++;
       unicast_address = unicast_address->Next;
@@ -536,7 +539,8 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
        adapter_address != NULL;
        adapter_address = adapter_address->Next) {
     name = NULL;
-    unicast_address = adapter_address->FirstUnicastAddress;
+    unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
+                      adapter_address->FirstUnicastAddress;
 
     while (unicast_address) {
       sock_addr = unicast_address->Address.lpSockaddr;
@@ -610,6 +614,7 @@ void uv_filetime_to_time_t(FILETIME* file_time, time_t* stat_time) {
     time.tm_hour = system_time.wHour;
     time.tm_min = system_time.wMinute;
     time.tm_sec = system_time.wSecond;
+    time.tm_isdst = -1;
 
     *stat_time = mktime(&time);
   } else {
index c9552ed..b63c02d 100644 (file)
@@ -4323,10 +4323,17 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile)
 /*
  * Kernel32 headers
  */
-#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS    0x1
-#define FILE_SKIP_SET_EVENT_ON_HANDLE           0x2
+#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
+#endif
+
+#ifdef FILE_SKIP_SET_EVENT_ON_HANDLE
+# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#endif
 
-#define SYMBOLIC_LINK_FLAG_DIRECTORY            0x1
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
 
 #ifdef __MINGW32__
   typedef struct _OVERLAPPED_ENTRY {
index 64f404c..1693c31 100644 (file)
@@ -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++;
index cc7fd93..b37a7fd 100644 (file)
@@ -25,7 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#define NUM_THREADS (100 * 1000)
+#define NUM_THREADS (20 * 1000)
 
 static volatile int num_threads;
 
index 4bc5258..8f10023 100644 (file)
@@ -86,7 +86,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.
      */
@@ -121,7 +121,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;
@@ -131,8 +131,8 @@ static int ipc_helper(int listen_after_write) {
 
   uv_pipe_open(&channel, 0);
 
-  ASSERT(uv_is_readable((uv_stream_t*)&channel));
-  ASSERT(uv_is_writable((uv_stream_t*)&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);
@@ -208,7 +208,7 @@ static int stdio_over_pipes_helper() {
   uv_buf_t buf[ARRAY_SIZE(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));
 
@@ -271,6 +271,11 @@ static int maybe_run_test(int argc, char **argv) {
     return ipc_helper(1);
   }
 
+  if (strcmp(argv[1], "ipc_send_recv_helper") == 0) {
+    int ipc_send_recv_helper(void); /* See test-ipc-send-recv.c */
+    return ipc_send_recv_helper();
+  }
+
   if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
     return stdio_over_pipes_helper();
   }
index 6b6d500..d2a986a 100644 (file)
@@ -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;
 
index 8c7bd7f..be790f7 100644 (file)
@@ -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");
   }
 
@@ -194,6 +195,8 @@ out:
   if (status != 0 || task->show_output) {
     if (status != 0) {
       LOGF("\n`%s` failed: %s\n", test, errmsg);
+    } else {
+      LOGF("\n");
     }
 
     for (i = 0; i < process_count; i++) {
index 423d349..29e7acd 100644 (file)
@@ -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");
index deafdc9..d72c26a 100644 (file)
@@ -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);
index 619846d..a8fe0ab 100644 (file)
@@ -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);
 }
@@ -1218,7 +1224,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.
        */
@@ -1667,3 +1673,59 @@ TEST_IMPL(fs_rename_to_existing_file) {
 
   return 0;
 }
+
+
+TEST_IMPL(fs_read_file_eof) {
+  int r;
+
+  /* Setup. */
+  unlink("test_file");
+
+  loop = uv_default_loop();
+
+  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+      S_IWRITE | S_IREAD, NULL);
+  ASSERT(r != -1);
+  ASSERT(open_req1.result != -1);
+  uv_fs_req_cleanup(&open_req1);
+
+  r = uv_fs_write(loop, &write_req, open_req1.result, test_buf,
+      sizeof(test_buf), -1, NULL);
+  ASSERT(r != -1);
+  ASSERT(write_req.result != -1);
+  uv_fs_req_cleanup(&write_req);
+
+  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  ASSERT(r != -1);
+  ASSERT(close_req.result != -1);
+  uv_fs_req_cleanup(&close_req);
+
+  r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL);
+  ASSERT(r != -1);
+  ASSERT(open_req1.result != -1);
+  uv_fs_req_cleanup(&open_req1);
+
+  memset(buf, 0, sizeof(buf));
+  r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1,
+      NULL);
+  ASSERT(r != -1);
+  ASSERT(read_req.result != -1);
+  ASSERT(strcmp(buf, test_buf) == 0);
+  uv_fs_req_cleanup(&read_req);
+
+  r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf),
+      read_req.result, NULL);
+  ASSERT(r == 0);
+  ASSERT(read_req.result == 0);
+  uv_fs_req_cleanup(&read_req);
+
+  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  ASSERT(r != -1);
+  ASSERT(close_req.result != -1);
+  uv_fs_req_cleanup(&close_req);
+
+  /* Cleanup */
+  unlink("test_file");
+
+  return 0;
+}
diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c
new file mode 100644 (file)
index 0000000..96b47f0
--- /dev/null
@@ -0,0 +1,208 @@
+/* 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.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* See test-ipc.ctx */
+void spawn_helper(uv_pipe_t* channel,
+                  uv_process_t* process,
+                  const char* helper);
+
+union handles {
+  uv_handle_t handle;
+  uv_stream_t stream;
+  uv_pipe_t pipe;
+  uv_tcp_t tcp;
+  uv_tty_t tty;
+};
+
+struct echo_ctx {
+  uv_pipe_t channel;
+  uv_write_t write_req;
+  uv_handle_type expected_type;
+  union handles send;
+  union handles recv;
+};
+
+static struct echo_ctx ctx;
+static int num_recv_handles;
+
+
+static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
+  /* we're not actually reading anything so a small buffer is okay */
+  static char buf[8];
+  return uv_buf_init(buf, sizeof(buf));
+}
+
+
+static void recv_cb(uv_pipe_t* handle,
+                    ssize_t nread,
+                    uv_buf_t buf,
+                    uv_handle_type pending) {
+  int r;
+
+  ASSERT(pending == ctx.expected_type);
+  ASSERT(handle == &ctx.channel);
+  ASSERT(nread >= 0);
+
+  if (pending == UV_NAMED_PIPE)
+    r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
+  else if (pending == UV_TCP)
+    r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
+  else
+    abort();
+  ASSERT(r == 0);
+
+  r = uv_accept((uv_stream_t*)&ctx.channel, &ctx.recv.stream);
+  ASSERT(r == 0);
+
+  uv_close((uv_handle_t*)&ctx.channel, NULL);
+  uv_close(&ctx.send.handle, NULL);
+  uv_close(&ctx.recv.handle, NULL);
+  num_recv_handles++;
+}
+
+
+static int run_test(void) {
+  uv_process_t process;
+  uv_buf_t buf;
+  int r;
+
+  spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
+
+  buf = uv_buf_init(".", 1);
+  r = uv_write2(&ctx.write_req,
+                (uv_stream_t*)&ctx.channel,
+                &buf, 1,
+                &ctx.send.stream,
+                NULL);
+  ASSERT(r == 0);
+
+  r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
+  ASSERT(r == 0);
+
+  r = uv_run(uv_default_loop());
+  ASSERT(r == 0);
+
+  ASSERT(num_recv_handles == 1);
+
+  return 0;
+}
+
+
+TEST_IMPL(ipc_send_recv_pipe) {
+  int r;
+
+  ctx.expected_type = UV_NAMED_PIPE;
+
+  r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1);
+  ASSERT(r == 0);
+
+  r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME);
+  ASSERT(r == 0);
+
+  return run_test();
+}
+
+
+TEST_IMPL(ipc_send_recv_tcp) {
+  int r;
+
+  ctx.expected_type = UV_TCP;
+
+  r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
+  ASSERT(r == 0);
+
+  r = uv_tcp_bind(&ctx.send.tcp, uv_ip4_addr("127.0.0.1", TEST_PORT));
+  ASSERT(r == 0);
+
+  return run_test();
+}
+
+
+/* Everything here runs in a child process. */
+
+static void write2_cb(uv_write_t* req, int status) {
+  ASSERT(status == 0);
+  uv_close(&ctx.recv.handle, NULL);
+  uv_close((uv_handle_t*)&ctx.channel, NULL);
+}
+
+
+static void read2_cb(uv_pipe_t* handle,
+                     ssize_t nread,
+                     uv_buf_t buf,
+                     uv_handle_type pending) {
+  int r;
+
+  ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
+  ASSERT(handle == &ctx.channel);
+  ASSERT(nread >= 0);
+
+  buf = uv_buf_init(".", 1);
+
+  if (pending == UV_NAMED_PIPE)
+    r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
+  else if (pending == UV_TCP)
+    r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
+  else
+    abort();
+  ASSERT(r == 0);
+
+  r = uv_accept((uv_stream_t*)handle, &ctx.recv.stream);
+  ASSERT(r == 0);
+
+  r = uv_write2(&ctx.write_req,
+                (uv_stream_t*)&ctx.channel,
+                &buf, 1,
+                &ctx.recv.stream,
+                write2_cb);
+  ASSERT(r == 0);
+}
+
+
+/* stdin is a duplex channel over which a handle is sent.
+ * We receive it and send it back where it came from.
+ */
+int ipc_send_recv_helper(void) {
+  int r;
+
+  memset(&ctx, 0, sizeof(ctx));
+
+  r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
+  ASSERT(r == 0);
+
+  uv_pipe_open(&ctx.channel, 0);
+  ASSERT(uv_is_readable((uv_stream_t*)&ctx.channel));
+  ASSERT(uv_is_writable((uv_stream_t*)&ctx.channel));
+
+  r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, read2_cb);
+  ASSERT(r == 0);
+
+  r = uv_run(uv_default_loop());
+  ASSERT(r == 0);
+
+  return 0;
+}
index 0908879..ba122af 100644 (file)
@@ -25,9 +25,6 @@
 #include <stdio.h>
 #include <string.h>
 
-static char exepath[1024];
-static size_t exepath_size = 1024;
-static char* args[3];
 static uv_pipe_t channel;
 static uv_tcp_t tcp_server;
 
@@ -184,31 +181,44 @@ static void on_read(uv_pipe_t* pipe, ssize_t nread, uv_buf_t buf,
 }
 
 
-int run_ipc_test(const char* helper) {
-  int r;
+void spawn_helper(uv_pipe_t* channel,
+                  uv_process_t* process,
+                  const char* helper) {
   uv_process_options_t options;
-  uv_process_t process;
+  size_t exepath_size;
+  char exepath[1024];
+  char* args[3];
+  int r;
 
-  r = uv_pipe_init(uv_default_loop(), &channel, 1);
+  r = uv_pipe_init(uv_default_loop(), channel, 1);
   ASSERT(r == 0);
-  ASSERT(channel.ipc);
-
-  memset(&options, 0, sizeof(uv_process_options_t));
+  ASSERT(channel->ipc);
 
+  exepath_size = sizeof(exepath);
   r = uv_exepath(exepath, &exepath_size);
   ASSERT(r == 0);
+
   exepath[exepath_size] = '\0';
   args[0] = exepath;
   args[1] = (char*)helper;
   args[2] = NULL;
+
+  memset(&options, 0, sizeof(options));
   options.file = exepath;
   options.args = args;
   options.exit_cb = exit_cb;
-  options.stdin_stream = &channel;
+  options.stdin_stream = channel;
 
-  r = uv_spawn(uv_default_loop(), &process, options);
+  r = uv_spawn(uv_default_loop(), process, options);
   ASSERT(r == 0);
+}
+
+
+static int run_ipc_test(const char* helper) {
+  uv_process_t process;
+  int r;
 
+  spawn_helper(&channel, &process, helper);
   uv_read2_start((uv_stream_t*)&channel, on_alloc, on_read);
 
   r = uv_run(uv_default_loop());
@@ -218,6 +228,7 @@ int run_ipc_test(const char* helper) {
   ASSERT(remote_conn_accepted == 1);
   ASSERT(read2_cb_called == 1);
   ASSERT(exit_cb_called == 1);
+
   return 0;
 }
 
index 38d3925..ed27cf1 100644 (file)
@@ -24,6 +24,8 @@ TEST_DECLARE   (tty)
 TEST_DECLARE   (stdio_over_pipes)
 TEST_DECLARE   (ipc_listen_before_write)
 TEST_DECLARE   (ipc_listen_after_write)
+TEST_DECLARE   (ipc_send_recv_pipe)
+TEST_DECLARE   (ipc_send_recv_tcp)
 TEST_DECLARE   (tcp_ping_pong)
 TEST_DECLARE   (tcp_ping_pong_v6)
 TEST_DECLARE   (pipe_ping_pong)
@@ -61,6 +63,8 @@ TEST_DECLARE   (pipe_connect_bad_name)
 TEST_DECLARE   (pipe_connect_to_file)
 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)
@@ -81,12 +85,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)
@@ -124,6 +132,7 @@ TEST_DECLARE   (fs_utime)
 TEST_DECLARE   (fs_futime)
 TEST_DECLARE   (fs_file_open_append)
 TEST_DECLARE   (fs_stat_missing_path)
+TEST_DECLARE   (fs_read_file_eof)
 TEST_DECLARE   (fs_event_watch_dir)
 TEST_DECLARE   (fs_event_watch_file)
 TEST_DECLARE   (fs_event_watch_file_current_dir)
@@ -167,6 +176,8 @@ TASK_LIST_START
   TEST_ENTRY  (stdio_over_pipes)
   TEST_ENTRY  (ipc_listen_before_write)
   TEST_ENTRY  (ipc_listen_after_write)
+  TEST_ENTRY  (ipc_send_recv_pipe)
+  TEST_ENTRY  (ipc_send_recv_tcp)
 
   TEST_ENTRY  (tcp_ping_pong)
   TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
@@ -217,6 +228,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)
 
@@ -243,6 +259,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)
@@ -251,6 +271,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)
@@ -308,6 +332,7 @@ TASK_LIST_START
   TEST_ENTRY  (fs_futime)
   TEST_ENTRY  (fs_symlink)
   TEST_ENTRY  (fs_stat_missing_path)
+  TEST_ENTRY  (fs_read_file_eof)
   TEST_ENTRY  (fs_file_open_append)
   TEST_ENTRY  (fs_event_watch_dir)
   TEST_ENTRY  (fs_event_watch_file)
index 2b8aabb..cab3a70 100644 (file)
 #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 (file)
index 0000000..864f7ce
--- /dev/null
@@ -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;
+}
index 1e3e1f2..ded59c9 100644 (file)
 #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);
 
index 9a82830..6b46b38 100644 (file)
         'test/test-hrtime.c',
         'test/test-idle.c',
         'test/test-ipc.c',
+        'test/test-ipc-send-recv.c',
         'test/test-list.h',
         'test/test-loop-handles.c',
         'test/test-multiple-listen.c',
         'test/test-platform-output.c',
         'test/test-process-title.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',