From fce90652ed38ab0925131ed141972354a494933b Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 28 Nov 2011 19:36:41 +0100 Subject: [PATCH 01/11] Windows: avoid the loop starvation bug. Closes GH-154 --- src/win/core.c | 14 ++++++-------- src/win/req.c | 36 ++++++++++++++---------------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/win/core.c b/src/win/core.c index 4914fb41..e6bcc5fe 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -204,13 +204,8 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { uv_idle_invoke((loop)); \ } \ \ - /* Completely flush all pending reqs and endgames. */ \ - /* We do even when we just called the idle callbacks because those may */ \ - /* have closed handles or started requests that short-circuited. */ \ - while ((loop)->pending_reqs_tail || (loop)->endgame_handles) { \ - uv_process_endgames((loop)); \ - uv_process_reqs((loop)); \ - } \ + uv_process_reqs((loop)); \ + uv_process_endgames((loop)); \ \ if ((loop)->refs <= 0) { \ break; \ @@ -218,7 +213,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { \ uv_prepare_invoke((loop)); \ \ - poll((loop), (loop)->idle_handles == NULL && (loop)->refs > 0); \ + poll((loop), (loop)->idle_handles == NULL && \ + (loop)->pending_reqs_tail == NULL && \ + (loop)->endgame_handles == NULL && \ + (loop)->refs > 0); \ \ uv_check_invoke((loop)); \ } diff --git a/src/win/req.c b/src/win/req.c index dd2b3880..65aa6c15 100644 --- a/src/win/req.c +++ b/src/win/req.c @@ -51,27 +51,6 @@ void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { } -static uv_req_t* uv_remove_pending_req(uv_loop_t* loop) { - uv_req_t* req; - - if (loop->pending_reqs_tail) { - req = loop->pending_reqs_tail->next_req; - - if (req == loop->pending_reqs_tail) { - loop->pending_reqs_tail = NULL; - } else { - loop->pending_reqs_tail->next_req = req->next_req; - } - - return req; - - } else { - /* queue empty */ - return NULL; - } -} - - #define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ do { \ switch (((uv_handle_t*) (req)->handle_at)->type) { \ @@ -101,8 +80,21 @@ static uv_req_t* uv_remove_pending_req(uv_loop_t* loop) { void uv_process_reqs(uv_loop_t* loop) { uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) { + return; + } + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; - while (req = uv_remove_pending_req(loop)) { switch (req->type) { case UV_READ: DELEGATE_STREAM_REQ(loop, req, read, data); From d513d9bb4178d284be70c43eaa51d982ca86071f Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 30 Nov 2011 11:26:52 +0700 Subject: [PATCH 02/11] Fix typos. --- README.md | 2 +- include/uv.h | 18 +++++++++--------- src/win/cares.c | 6 +++--- src/win/core.c | 2 +- src/win/pipe.c | 2 +- src/win/process.c | 8 ++++---- src/win/tcp.c | 4 ++-- src/win/timer.c | 2 +- src/win/tty.c | 2 +- src/win/udp.c | 2 +- test/benchmark-ping-pongs.c | 2 +- test/runner-win.c | 2 +- test/runner-win.h | 4 ++-- test/runner.c | 2 +- test/test-callback-stack.c | 2 +- test/test-connection-fail.c | 2 +- test/test-delayed-accept.c | 2 +- test/test-fs.c | 2 +- test/test-getsockname.c | 2 +- test/test-loop-handles.c | 2 +- test/test-ping-pong.c | 6 +++--- test/test-tty.c | 2 +- 22 files changed, 39 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 8e569bbf..bd4945a9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # libuv libuv is a new platform layer for Node. Its purpose is to abstract IOCP on -windows and libev on Unix systems. We intend to eventually contain all +Windows and libev on Unix systems. We intend to eventually contain all platform differences in this library. http://nodejs.org/ diff --git a/include/uv.h b/include/uv.h index 6eaf6355..bed0276c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -106,7 +106,7 @@ typedef intptr_t ssize_t; XX( 35, ENOSYS, "function not implemented") \ XX( 36, EPIPE, "broken pipe") \ XX( 37, EPROTO, "protocol error") \ - XX( 38, EPROTONOSUPPORT, "protocol not suppored") \ + XX( 38, EPROTONOSUPPORT, "protocol not supported") \ XX( 39, EPROTOTYPE, "protocol wrong type for socket") \ XX( 40, ETIMEDOUT, "connection timed out") \ XX( 41, ECHARSET, "") \ @@ -263,7 +263,7 @@ typedef void (*uv_after_work_cb)(uv_work_t* req); * This will be called repeatedly after the uv_fs_event_t is initialized. * If uv_fs_event_t was initialized with a directory the filename parameter * will be a relative path to a file contained in the directory. -* The events paramenter is an ORed mask of enum uv_fs_event elements. +* The events parameter is an ORed mask of enum uv_fs_event elements. */ typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status); @@ -315,8 +315,8 @@ UV_PRIVATE_REQ_TYPES * * Shutdown the outgoing (write) side of a duplex stream. It waits for * pending write requests to complete. The handle should refer to a - * initialized stream. req should be an uninitalized shutdown request - * struct. The cb is a called after shutdown is complete. + * initialized stream. req should be an uninitialized shutdown request + * struct. The cb is called after shutdown is complete. */ UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb); @@ -509,7 +509,7 @@ UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, * uv_tcp_connect, uv_tcp_connect6 * These functions establish IPv4 and IPv6 TCP connections. Provide an * initialized TCP handle and an uninitialized uv_connect_t*. The callback - * will be made when the connection is estabished. + * will be made when the connection is established. */ UV_EXTERN int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in address, uv_connect_cb cb); @@ -884,7 +884,7 @@ UV_EXTERN int uv_timer_again(uv_timer_t* timer); /* * Set the repeat value. Note that if the repeat value is set from a timer - * callback it does not immediately take effect. If the timer was nonrepeating + * callback it does not immediately take effect. If the timer was non-repeating * before, it will have been stopped. If it was repeating, then the old repeat * value will have been used to schedule the next timeout. */ @@ -938,7 +938,7 @@ typedef struct uv_process_options_s { const char* file; /* Path to program to execute. */ /* * Command line arguments. args[0] should be the path to the program. On - * Windows this uses CreateProcess which concatinates the arguments into a + * Windows this uses CreateProcess which concatenates the arguments into a * string this can cause some strange errors. See the note at * windows_verbatim_arguments. */ @@ -962,7 +962,7 @@ typedef struct uv_process_options_s { /* * The user should supply pointers to initialized uv_pipe_t structs for * stdio. This is used to to send or receive input from the subprocess. - * The user is reponsible for calling uv_close on them. + * The user is responsible for calling uv_close on them. */ uv_pipe_t* stdin_stream; uv_pipe_t* stdout_stream; @@ -1022,7 +1022,7 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req, * uninitialized uv_fs_t object. * * uv_fs_req_cleanup() must be called after completion of the uv_fs_ - * function to free any internal memory allocations associted with the + * function to free any internal memory allocations associated with the * request. */ diff --git a/src/win/cares.c b/src/win/cares.c index f146c31a..f504bf96 100644 --- a/src/win/cares.c +++ b/src/win/cares.c @@ -62,7 +62,7 @@ static void CALLBACK uv_ares_socksignal_tp(void* parameter, /* do not fail if error, thread may run after socket close */ /* The code assumes that c-ares will write all pending data in the */ /* callback, unless the socket would block. We can clear the state here */ - /* to avoid unecessary signals. */ + /* to avoid unnecessary signals. */ WSAEnumNetworkEvents(sockhandle->sock, sockhandle->h_event, &network_events); @@ -113,7 +113,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, if (read == 0 && write == 0) { /* if read and write are 0, cleanup existing data */ /* The code assumes that c-ares does a callback with read = 0 and */ - /* write = 0 when the socket is closed. After we recieve this we stop */ + /* write = 0 when the socket is closed. After we receive this we stop */ /* monitoring the socket. */ if (uv_handle_ares != NULL) { uv_req_t* uv_ares_req; @@ -244,7 +244,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, } } } else { - /* stil busy - repost and try again */ + /* still busy - repost and try again */ POST_COMPLETION_FOR_REQ(loop, req); } } diff --git a/src/win/core.c b/src/win/core.c index e6bcc5fe..72fee1c8 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -91,7 +91,7 @@ static void uv_loop_init(uv_loop_t* loop) { static void uv_default_loop_init(void) { - /* Intialize libuv itself first */ + /* Initialize libuv itself first */ uv_once(&uv_init_guard_, uv_init); /* Initialize the main loop */ diff --git a/src/win/pipe.c b/src/win/pipe.c index bd187da5..5dada4f9 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -249,7 +249,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { return; } - /* Run FlushFileBuffers in the thhead pool. */ + /* Run FlushFileBuffers in the thread pool. */ result = QueueUserWorkItem(pipe_shutdown_thread_proc, req, WT_EXECUTELONGFUNCTION); diff --git a/src/win/process.c b/src/win/process.c index 61abb6f9..3d649835 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -254,7 +254,7 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * - CMD does not trim leading/trailing whitespace from path/pathex entries * nor from the environment variables as a whole. * - * - When cmd.exe cannot read a directory, it wil just skip it and go on + * - When cmd.exe cannot read a directory, it will just skip it and go on * searching. However, unlike posix-y systems, it will happily try to run a * file that is not readable/executable; if the spawn fails it will not * continue searching. @@ -400,7 +400,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { } /* - * Expected intput/output: + * Expected input/output: * input : hello"world * output: "hello\"world" * input : hello""world @@ -1018,7 +1018,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, } else { /* CreateProcessW failed, but this failure should be delivered */ - /* asynchronously to retain unix compatibility. So pretent spawn */ + /* asynchronously to retain unix compatibility. So pretend spawn */ /* succeeded, and start a thread instead that prints an error */ /* to the child's intended stderr. */ process->spawn_errno = GetLastError(); @@ -1046,7 +1046,7 @@ done: close_child_stdio(process); } else { /* We're keeping the handles open, the thread pool is going to have */ - /* it's way with them. But at least make them noninheritable. */ + /* it's way with them. But at least make them non-inheritable. */ int i; for (i = 0; i < COUNTOF(process->child_stdio); i++) { SetHandleInformation(child_stdio[i], HANDLE_FLAG_INHERIT, 0); diff --git a/src/win/tcp.c b/src/win/tcp.c index 5506ede0..dee77875 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1084,7 +1084,7 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, /* * 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 conections on it. So, before sharing the socket + * be accepting connections on it. So, before sharing the socket * with another process, we call listen here in the parent process. * This needs to be modified if the socket is shared with * another process for anything other than accepting connections. @@ -1137,7 +1137,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; - /* Flip the changing flag if we have already queueed multiple accepts. */ + /* Flip the changing flag if we have already queued multiple accepts. */ if (handle->flags & UV_HANDLE_LISTENING) { handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; } diff --git a/src/win/timer.c b/src/win/timer.c index 58f2eef0..555d71ea 100644 --- a/src/win/timer.c +++ b/src/win/timer.c @@ -86,7 +86,7 @@ uint64_t uv_hrtime(void) { return 0; } - /* Because we have no guarantee about the order of magniture of the */ + /* Because we have no guarantee about the order of magnitude of the */ /* performance counter frequency, and there may not be much headroom to */ /* multiply by NANOSEC without overflowing, we use 128-bit math instead. */ return ((uint64_t) counter.LowPart * NANOSEC / uv_hrtime_frequency_) + diff --git a/src/win/tty.c b/src/win/tty.c index a7285127..b90d2cfe 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -739,7 +739,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could stell be a */ + /* If reading was stopped and then started again, there could still be a */ /* read request pending. */ if (handle->flags & UV_HANDLE_READ_PENDING) { return 0; diff --git a/src/win/udp.c b/src/win/udp.c index 3beb8ab9..0299e775 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -362,7 +362,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, handle->recv_cb = recv_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could stell be a */ + /* If reading was stopped and then started again, there could still be a */ /* recv request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_udp_queue_recv(loop, handle); diff --git a/test/benchmark-ping-pongs.c b/test/benchmark-ping-pongs.c index c36215c1..d42e7063 100644 --- a/test/benchmark-ping-pongs.c +++ b/test/benchmark-ping-pongs.c @@ -186,7 +186,7 @@ static void pinger_new() { pinger->state = 0; pinger->pongs = 0; - /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(loop, &pinger->tcp); ASSERT(!r); diff --git a/test/runner-win.c b/test/runner-win.c index fc08839e..6b6d500c 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -156,7 +156,7 @@ int process_wait(process_info_t *vec, int n, int timeout) { HANDLE handles[MAXIMUM_WAIT_OBJECTS]; DWORD timeout_api, result; - /* If there's nothing to wait for, return immedately. */ + /* If there's nothing to wait for, return immediately. */ if (n == 0) return 0; diff --git a/test/runner-win.h b/test/runner-win.h index a2c8b6f3..f69976e9 100644 --- a/test/runner-win.h +++ b/test/runner-win.h @@ -19,10 +19,10 @@ * IN THE SOFTWARE. */ -/* Don't complain about _snprintf being unsecure. */ +/* Don't complain about _snprintf being insecure. */ #define _CRT_SECURE_NO_WARNINGS -/* Dont complain about write(), fileno() etc. being deprecated. */ +/* Don't complain about write(), fileno() etc. being deprecated. */ #pragma warning(disable : 4996) diff --git a/test/runner.c b/test/runner.c index 73a3864e..daa8a2e4 100644 --- a/test/runner.c +++ b/test/runner.c @@ -218,7 +218,7 @@ out: } else if (benchmark_output) { switch (process_output_size(main_proc)) { case -1: - LOGF("%s: (unavailabe)\n", test); + LOGF("%s: (unavailable)\n", test); break; case 0: diff --git a/test/test-callback-stack.c b/test/test-callback-stack.c index 4af63648..4983b651 100644 --- a/test/test-callback-stack.c +++ b/test/test-callback-stack.c @@ -138,7 +138,7 @@ static void write_cb(uv_write_t* req, int status) { /* After the data has been sent, we're going to wait for a while, then */ /* start reading. This makes us certain that the message has been echoed */ /* back to our receive buffer when we start reading. This maximizes the */ - /* tempation for the backend to use dirty stack for calling read_cb. */ + /* temptation for the backend to use dirty stack for calling read_cb. */ nested++; r = uv_timer_init(uv_default_loop(), &timer); ASSERT(r == 0); diff --git a/test/test-connection-fail.c b/test/test-connection-fail.c index 2762aa28..1c5a31d1 100644 --- a/test/test-connection-fail.c +++ b/test/test-connection-fail.c @@ -97,7 +97,7 @@ void connection_fail(uv_connect_cb connect_cb) { /* There should be no servers listening on this port. */ server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT); - /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &tcp); ASSERT(!r); diff --git a/test/test-delayed-accept.c b/test/test-delayed-accept.c index 78531f68..990444ef 100644 --- a/test/test-delayed-accept.c +++ b/test/test-delayed-accept.c @@ -152,7 +152,7 @@ static void connect_cb(uv_connect_t* req, int status) { ASSERT(status == 0); /* Not that the server will send anything, but otherwise we'll never know */ - /* when te server closes the connection. */ + /* when the server closes the connection. */ r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb); ASSERT(r == 0); diff --git a/test/test-fs.c b/test/test-fs.c index 28b914a7..34f891c1 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -19,7 +19,7 @@ * IN THE SOFTWARE. */ -/* FIXME we shouldnt need to branch in this file */ +/* FIXME we shouldn't need to branch in this file */ #define UNIX (defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)) #include "uv.h" diff --git a/test/test-getsockname.c b/test/test-getsockname.c index 5dac88b7..ff28beb9 100644 --- a/test/test-getsockname.c +++ b/test/test-getsockname.c @@ -83,7 +83,7 @@ static void check_sockname(struct sockaddr* addr, const char* compare_ip, char check_ip[17]; int r; - /* Both adresses should be ipv4 */ + /* Both addresses should be ipv4 */ ASSERT(check_addr.sin_family == AF_INET); ASSERT(compare_addr.sin_family == AF_INET); diff --git a/test/test-loop-handles.c b/test/test-loop-handles.c index 9a76cc53..425dcf63 100644 --- a/test/test-loop-handles.c +++ b/test/test-loop-handles.c @@ -58,7 +58,7 @@ * being started by a check_1 watcher. It verifies that a watcher is * implicitly stopped when closed, and that a watcher can close itself * safely. - * - There is a repeating timer. It does not keep te event loop alive + * - There is a repeating timer. It does not keep the event loop alive * (ev_unref) but makes sure that the loop keeps polling the system for * events. */ diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index b73b4ce4..5c3de3b4 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -154,7 +154,7 @@ static void tcp_pinger_v6_new() { pinger->state = 0; pinger->pongs = 0; - /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); pinger->stream.tcp.data = pinger; ASSERT(!r); @@ -179,7 +179,7 @@ static void tcp_pinger_new() { pinger->state = 0; pinger->pongs = 0; - /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); pinger->stream.tcp.data = pinger; ASSERT(!r); @@ -203,7 +203,7 @@ static void pipe_pinger_new() { pinger->state = 0; pinger->pongs = 0; - /* Try to connec to the server and do NUM_PINGS ping-pongs. */ + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0); pinger->stream.pipe.data = pinger; ASSERT(!r); diff --git a/test/test-tty.c b/test/test-tty.c index 60aedf39..d1f6ae6f 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,7 +28,7 @@ TEST_IMPL(tty) { uv_loop_t* loop = uv_default_loop(); /* - * Not necessarally a problem if this assert goes off. E.G you are piping + * 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)); From b684deb4f4d1e939813fc8195be219ab70e67c95 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 25 Nov 2011 16:32:32 +0700 Subject: [PATCH 03/11] Note that uv_is_active works on timers. --- include/uv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uv.h b/include/uv.h index bed0276c..27105184 100644 --- a/include/uv.h +++ b/include/uv.h @@ -345,8 +345,8 @@ struct uv_handle_s { }; /* - * Returns 1 if the prepare/check/idle handle has been started, 0 otherwise. - * For other handle types this always returns 1. + * Returns 1 if the prepare/check/idle/timer handle has been started, 0 + * otherwise. For other handle types this always returns 1. */ UV_EXTERN int uv_is_active(uv_handle_t* handle); From c69ccfabc21a2032c40e97f08412f78bd03bbb53 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Thu, 1 Dec 2011 20:15:18 +0700 Subject: [PATCH 04/11] Remove incorrect documentation comment. The callback for uv_close does not have a status parameter. --- include/uv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 27105184..5fde249e 100644 --- a/include/uv.h +++ b/include/uv.h @@ -226,7 +226,6 @@ UV_EXTERN int64_t uv_now(uv_loop_t*); /* * The status parameter is 0 if the request completed successfully, * and should be -1 if the request was cancelled or failed. - * For uv_close_cb, -1 means that the handle was closed due to an error. * Error details can be obtained by calling uv_last_error(). * * In the case of uv_read_cb the uv_buf_t returned should be freed by the From fadfd0f5b2889fc097ea6b3bc3f008d7cd7ce048 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 1 Dec 2011 14:24:25 +0100 Subject: [PATCH 05/11] Update AUTHORS and .mailmap --- .mailmap | 1 + AUTHORS | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.mailmap b/.mailmap index accc9621..9af6eb6a 100644 --- a/.mailmap +++ b/.mailmap @@ -9,3 +9,4 @@ Isaac Z. Schlueter Saúl Ibarra Corretgé Yuki OKUMURA Frank Denis +Ryan Emery diff --git a/AUTHORS b/AUTHORS index 16f88934..40286bcf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,3 +33,6 @@ Roman Shtylman Frank Denis Carter Allen Tj Holowaychuk +Shimon Doodkin +Ryan Emery +Bruce Mitchener From ec37d05d6669039a6e756d303638de3fba7461d5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 1 Dec 2011 21:02:29 +0100 Subject: [PATCH 06/11] Revert "build: compile with -D__DARWIN_64_BIT_INO_T on OS X" This reverts commit 01fbe7bf37909736b4ba99d30c34378f561d6761. __DARWIN_64_BIT_INO_T is a no-op in most cases and might be actively harmful in some others. --- config-unix.mk | 1 - uv.gyp | 3 --- 2 files changed, 4 deletions(-) diff --git a/config-unix.mk b/config-unix.mk index 759be4e0..8fe7254c 100644 --- a/config-unix.mk +++ b/config-unix.mk @@ -50,7 +50,6 @@ endif ifeq (Darwin,$(uname_S)) EV_CONFIG=config_darwin.h EIO_CONFIG=config_darwin.h -CPPFLAGS += -D__DARWIN_64_BIT_INO_T=1 CPPFLAGS += -Isrc/ares/config_darwin LINKFLAGS+=-framework CoreServices OBJS += src/unix/darwin.o diff --git a/uv.gyp b/uv.gyp index 88cee32b..83129b5c 100644 --- a/uv.gyp +++ b/uv.gyp @@ -9,9 +9,6 @@ 'EIO_STACKSIZE=262144' ], 'conditions': [ - ['OS=="mac"', { - 'defines': ['__DARWIN_64_BIT_INO_T=1'], - }], ['OS=="solaris"', { 'cflags': ['-pthreads'], 'ldlags': ['-pthreads'], From dceb3e65cafdfce9cc931c285d6e742e74ac7cc9 Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Wed, 30 Nov 2011 15:31:39 -0800 Subject: [PATCH 07/11] uv_cwd + uv_chdir --- include/uv.h | 6 +++ src/unix/core.c | 22 ++++++++++ src/win/util.c | 86 +++++++++++++++++++++++++++++++++++++++ test/test-cwd-and-chdir.c | 61 +++++++++++++++++++++++++++ test/test-list.h | 3 ++ uv.gyp | 1 + 6 files changed, 179 insertions(+) create mode 100644 test/test-cwd-and-chdir.c diff --git a/include/uv.h b/include/uv.h index 5fde249e..ea845e3a 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1213,6 +1213,12 @@ UV_EXTERN int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size); /* Gets the executable path */ UV_EXTERN int uv_exepath(char* buffer, size_t* size); +/* Gets the current working directory */ +UV_EXTERN uv_err_t uv_cwd(char* buffer, size_t size); + +/* Changes the current working directory */ +UV_EXTERN uv_err_t uv_chdir(const char* dir); + /* Gets memory info in bytes */ UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); diff --git a/src/unix/core.c b/src/unix/core.c index 4d832413..7978e1bb 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -845,3 +845,25 @@ size_t uv__strlcpy(char* dst, const char* src, size_t size) { return src - org; } + + +uv_err_t uv_cwd(char* buffer, size_t size) { + if (!buffer || !size) { + return uv__new_artificial_error(UV_EINVAL); + } + + if (getcwd(buffer, size)) { + return uv_ok_; + } else { + return uv__new_sys_error(errno); + } +} + + +uv_err_t uv_chdir(const char* dir) { + if (chdir(dir) == 0) { + return uv_ok_; + } else { + return uv__new_sys_error(errno); + } +} diff --git a/src/win/util.c b/src/win/util.c index 3bc3e1db..ece56611 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -97,6 +98,91 @@ done: } +uv_err_t uv_cwd(char* buffer, size_t size) { + uv_err_t err; + size_t utf8Size; + wchar_t* utf16Buffer = NULL; + + if (!buffer || !size) { + err.code = UV_EINVAL; + goto done; + } + + utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * size); + if (!utf16Buffer) { + err.code = UV_ENOMEM; + goto done; + } + + if (!_wgetcwd(utf16Buffer, size - 1)) { + err = uv__new_sys_error(_doserrno); + goto done; + } + + utf16Buffer[size - 1] = L'\0'; + + /* Convert to UTF-8 */ + utf8Size = uv_utf16_to_utf8(utf16Buffer, -1, buffer, size); + if (utf8Size == 0) { + err = uv__new_sys_error(GetLastError()); + goto done; + } + + buffer[utf8Size] = '\0'; + err = uv_ok_; + +done: + if (utf16Buffer) { + free(utf16Buffer); + } + + return err; +} + + +uv_err_t uv_chdir(const char* dir) { + uv_err_t err; + wchar_t* utf16Buffer = NULL; + size_t utf16Size; + + if (!dir) { + err.code = UV_EINVAL; + goto done; + } + + utf16Size = uv_utf8_to_utf16(dir, NULL, 0); + if (!utf16Size) { + err = uv__new_sys_error(GetLastError()); + goto done; + } + + utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * utf16Size); + if (!utf16Buffer) { + err.code = UV_ENOMEM; + goto done; + } + + if (!uv_utf8_to_utf16(dir, utf16Buffer, utf16Size)) { + err = uv__new_sys_error(GetLastError()); + goto done; + } + + if (_wchdir(utf16Buffer) == -1) { + err = uv__new_sys_error(_doserrno); + goto done; + } + + err = uv_ok_; + +done: + if (utf16Buffer) { + free(utf16Buffer); + } + + return err; +} + + void uv_loadavg(double avg[3]) { /* Can't be implemented */ avg[0] = avg[1] = avg[2] = 0; diff --git a/test/test-cwd-and-chdir.c b/test/test-cwd-and-chdir.c new file mode 100644 index 00000000..deafdc94 --- /dev/null +++ b/test/test-cwd-and-chdir.c @@ -0,0 +1,61 @@ +/* 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 + +#define PATHMAX 1024 +extern char executable_path[]; + +TEST_IMPL(cwd_and_chdir) { + char buffer_orig[PATHMAX]; + char buffer_new[PATHMAX]; + size_t size; + char* last_slash; + uv_err_t err; + + size = sizeof(buffer_orig) / sizeof(buffer_orig[0]); + err = uv_cwd(buffer_orig, size); + ASSERT(err.code == UV_OK); + + last_slash = strrchr(buffer_orig, +#ifdef _WIN32 + '\\' +#else + '/' +#endif + ); + + ASSERT(last_slash); + + *last_slash = '\0'; + + err = uv_chdir(buffer_orig); + ASSERT(err.code == UV_OK); + + err = uv_cwd(buffer_new, size); + ASSERT(err.code == UV_OK); + + ASSERT(strcmp(buffer_orig, buffer_new) == 0); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index d6639df0..fbd23d6c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -77,6 +77,7 @@ TEST_DECLARE (check_ref) TEST_DECLARE (unref_in_prepare_cb) TEST_DECLARE (async) TEST_DECLARE (get_currentexe) +TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_basic) @@ -216,6 +217,8 @@ TASK_LIST_START TEST_ENTRY (get_currentexe) + TEST_ENTRY (cwd_and_chdir) + TEST_ENTRY (get_memory) TEST_ENTRY (get_loadavg) diff --git a/uv.gyp b/uv.gyp index 83129b5c..fae7263a 100644 --- a/uv.gyp +++ b/uv.gyp @@ -278,6 +278,7 @@ 'test/test-error.c', 'test/test-callback-stack.c', 'test/test-connection-fail.c', + 'test/test-cwd-and-chdir.c', 'test/test-delayed-accept.c', 'test/test-fail-always.c', 'test/test-fs.c', From f71f5a02e6c3bff5249b1c13cd94fbd21070ed9c Mon Sep 17 00:00:00 2001 From: Yuki Okumura Date: Fri, 21 Oct 2011 00:42:40 +0900 Subject: [PATCH 08/11] Win: lower case tlhelp32.h to support cross compilation --- src/win/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index ece56611..fcdeafc7 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -26,7 +26,7 @@ #include "uv.h" #include "internal.h" -#include "Tlhelp32.h" +#include "tlhelp32.h" int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, From 2a6a4a08646ba36d436ea9bfa7af796c1cdc6230 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 1 Dec 2011 22:44:13 +0100 Subject: [PATCH 09/11] Fix MinGW and MinGW-w64 builds --- src/win/winapi.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/win/winapi.h b/src/win/winapi.h index e0038f14..b65ef0d0 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4080,7 +4080,7 @@ /* from ntifs.h */ /* MinGW already has it */ -#ifndef __MINGW32__ +#if defined(_MSC_VER) || defined(__MINGW64__) typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; @@ -4281,6 +4281,10 @@ typedef enum _FILE_INFORMATION_CLASS { FILE_SPECIAL_ACCESS) #endif +#ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif + typedef VOID (NTAPI *PIO_APC_ROUTINE) (PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, @@ -4333,6 +4337,19 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile) } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; #endif +/* from wincon.h */ +#ifndef ENABLE_INSERT_MODE +# define ENABLE_INSERT_MODE 0x20 +#endif + +#ifndef ENABLE_QUICK_EDIT_MODE +# define ENABLE_QUICK_EDIT_MODE 0x40 +#endif + +#ifndef ENABLE_EXTENDED_FLAGS +# define ENABLE_EXTENDED_FLAGS 0x80 +#endif + typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) (HANDLE CompletionPort, LPOVERLAPPED_ENTRY lpCompletionPortEntries, @@ -4351,6 +4368,7 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) DWORD dwFlags); + /* Ntapi function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; From 9c064fbbd20cff5e985d9856930769031809a368 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 1 Dec 2011 19:38:58 +0100 Subject: [PATCH 10/11] Win: utf-8 decoder bug when compiling with gcc --- src/win/tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/tty.c b/src/win/tty.c index b90d2cfe..6d8f6bca 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1258,7 +1258,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t bufs[], int bufcnt, #ifdef _MSC_VER /* msvc */ if (_BitScanReverse(&first_zero_bit, not_c)) { #else /* assume gcc */ - if (first_zero_bit = __builtin_clzl(not_c), c != 0) { + if (c != 0) { + first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c); #endif if (first_zero_bit == 7) { /* Ascii - pass right through */ From 60630dab0f336f5c611b9c76ddd37734a3a72270 Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Thu, 1 Dec 2011 00:38:08 -0800 Subject: [PATCH 11/11] windows: enable pending pipe instances knob --- include/uv-private/uv-win.h | 3 ++- include/uv.h | 7 +++++++ src/unix/pipe.c | 5 +++++ src/win/pipe.c | 31 +++++++++++++++++++++++++++---- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index 5d461090..7c1818cb 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -276,7 +276,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); LPFN_WSARECVFROM func_wsarecvfrom; #define uv_pipe_server_fields \ - uv_pipe_accept_t accept_reqs[4]; \ + int pending_instances; \ + uv_pipe_accept_t* accept_reqs; \ uv_pipe_accept_t* pending_accepts; #define uv_pipe_connection_fields \ diff --git a/include/uv.h b/include/uv.h index ea845e3a..e8b70b18 100644 --- a/include/uv.h +++ b/include/uv.h @@ -772,6 +772,13 @@ UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb); +/* + * This setting applies to Windows only. + * Set the number of pending pipe instance handles when the pipe server + * is waiting for connections. + */ +UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); + /* * uv_prepare_t is a subclass of uv_handle_t. diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 87959a6e..43869b63 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -271,3 +271,8 @@ void uv__pipe_accept(EV_P_ ev_io* watcher, int revents) { errno = saved_errno; } + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { + return 0; +} diff --git a/src/win/pipe.c b/src/win/pipe.c index 5dada4f9..3bbfa833 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -39,6 +39,8 @@ static const uv_buf_t uv_null_buf_ = { 0, NULL }; /* when the local ends wants to shut it down. */ static const int64_t eof_timeout = 50; /* ms */ +static const int default_pending_pipe_instances = 4; + /* IPC protocol flags. */ #define UV_IPC_RAW_DATA 0x0001 #define UV_IPC_UV_STREAM 0x0002 @@ -293,6 +295,12 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } } + if (handle->flags & UV_HANDLE_PIPESERVER) { + assert(handle->accept_reqs); + free(handle->accept_reqs); + handle->accept_reqs = NULL; + } + /* Remember the state of this flag because the close callback is */ /* allowed to clobber or free the handle's memory */ uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED; @@ -310,6 +318,12 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { + handle->pending_instances = count; + handle->flags |= UV_HANDLE_PIPESERVER; +} + + /* Creates a pipe server. */ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { uv_loop_t* loop = handle->loop; @@ -326,7 +340,17 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { return -1; } - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + handle->pending_instances = default_pending_pipe_instances; + } + + handle->accept_reqs = (uv_pipe_accept_t*) + malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances); + if (!handle->accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + for (i = 0; i < handle->pending_instances; i++) { req = &handle->accept_reqs[i]; uv_req_init(loop, (uv_req_t*) req); req->type = UV_ACCEPT; @@ -537,14 +561,13 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { } if (handle->flags & UV_HANDLE_PIPESERVER) { - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { + for (i = 0; i < handle->pending_instances; i++) { pipeHandle = handle->accept_reqs[i].pipeHandle; if (pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(pipeHandle); handle->accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE; } } - } if (handle->flags & UV_HANDLE_CONNECTION) { @@ -686,7 +709,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { /* First pipe handle should have already been created in uv_pipe_bind */ assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { + for (i = 0; i < handle->pending_instances; i++) { uv_pipe_queue_accept(loop, handle, &handle->accept_reqs[i], i == 0); }