diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2012-06-05 15:45:46 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2012-06-05 16:48:17 +0200 |
commit | 0a2076b26ac0dee453d664e0d0d6a0cc934bd579 (patch) | |
tree | 3b47e7a48d5ab6e9994835be430a0d333218228e | |
parent | 27061cc9f45afbc4ddc1efa8bed1ea22df7cb0f4 (diff) | |
download | node-0a2076b26ac0dee453d664e0d0d6a0cc934bd579.tar.gz |
deps: upgrade libuv to c8c9fe1
45 files changed, 1564 insertions, 679 deletions
diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index ae9f5fb3d..3b9619c87 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/include/uv-private/uv-unix.h @@ -35,6 +35,8 @@ #include <netdb.h> #include <pwd.h> #include <termios.h> + +#include <semaphore.h> #include <pthread.h> #if __sun @@ -58,6 +60,7 @@ typedef pthread_once_t uv_once_t; typedef pthread_t uv_thread_t; typedef pthread_mutex_t uv_mutex_t; typedef pthread_rwlock_t uv_rwlock_t; +typedef sem_t uv_sem_t; /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 3b091b93d..259984944 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -169,6 +169,8 @@ typedef SOCKET uv_os_sock_t; typedef HANDLE uv_thread_t; +typedef HANDLE uv_sem_t; + typedef CRITICAL_SECTION uv_mutex_t; typedef union { diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 2ddcfa7ca..e52ae6431 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -432,7 +432,7 @@ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); * base and len members of the uv_buf_t struct. The user is responsible for * freeing base after the uv_buf_t is done. Return struct passed by value. */ -UV_EXTERN uv_buf_t uv_buf_init(char* base, size_t len); +UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); /* @@ -1624,6 +1624,15 @@ UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); +/* + * Same goes for the semaphore functions. + */ +UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); +UV_EXTERN void uv_sem_destroy(uv_sem_t* sem); +UV_EXTERN void uv_sem_post(uv_sem_t* sem); +UV_EXTERN void uv_sem_wait(uv_sem_t* sem); +UV_EXTERN int uv_sem_trywait(uv_sem_t* sem); + /* Runs a function once and only once. Concurrent calls to uv_once() with the * same guard will block all callers except one (it's unspecified which one). * The guard should be initialized statically with the UV_ONCE_INIT macro. diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 1802d2f1b..37d03d3eb 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -604,6 +604,13 @@ static void uv__io_rw(struct ev_loop* ev, ev_io* w, int events) { uv__io_t* handle = container_of(w, uv__io_t, io_watcher); u.data = handle->io_watcher.data; u.cb(loop, handle, events & (EV_READ|EV_WRITE|EV_ERROR)); + + /* The callback may have closed all active handles. Stop libev from entering + * the epoll_wait/kevent/port_getn/etc. syscall if that's the case, it would + * hang indefinitely. + */ + if (loop->active_handles == 0) + ev_break(loop->ev, EVBREAK_ONE); } diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 7584d9280..d3eb998c1 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -28,6 +28,7 @@ #include <poll.h> #include <unistd.h> #include <stdio.h> +#include <fcntl.h> #ifdef __APPLE__ # include <TargetConditionals.h> @@ -217,6 +218,68 @@ static void uv__process_close_stream(uv_stdio_container_t* container) { uv__stream_close((uv_stream_t*)container->data.stream); } + +static void uv__process_child_init(uv_process_options_t options, + int stdio_count, + int* pipes) { + int i; + + if (options.flags & UV_PROCESS_DETACHED) { + setsid(); + } + + /* Dup fds */ + for (i = 0; i < stdio_count; i++) { + /* + * stdin has swapped ends of pipe + * (it's the only one readable stream) + */ + int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2]; + int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1]; + + if (use_fd >= 0) { + close(close_fd); + } else if (i < 3) { + /* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */ + use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR); + + if (use_fd < 0) { + perror("failed to open stdio"); + _exit(127); + } + } else { + continue; + } + + if (i != use_fd) { + dup2(use_fd, i); + close(use_fd); + } + } + + if (options.cwd && chdir(options.cwd)) { + perror("chdir()"); + _exit(127); + } + + if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) { + perror("setgid()"); + _exit(127); + } + + if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) { + perror("setuid()"); + _exit(127); + } + + environ = options.env; + + execvp(options.file, options.args); + perror("execvp()"); + _exit(127); +} + + #ifndef SPAWN_WAIT_EXEC # define SPAWN_WAIT_EXEC 1 #endif @@ -229,7 +292,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, */ char** save_our_env = environ; - int* pipes = malloc(2 * options.stdio_count * sizeof(int)); + int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count; + int* pipes = malloc(2 * stdio_count * sizeof(int)); #if SPAWN_WAIT_EXEC int signal_pipe[2] = { -1, -1 }; @@ -258,7 +322,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, process->exit_cb = options.exit_cb; /* Init pipe pairs */ - for (i = 0; i < options.stdio_count; i++) { + for (i = 0; i < stdio_count; i++) { pipes[i * 2] = -1; pipes[i * 2 + 1] = -1; } @@ -308,49 +372,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, if (pid == 0) { /* Child */ - if (options.flags & UV_PROCESS_DETACHED) { - setsid(); - } - - /* Dup fds */ - for (i = 0; i < options.stdio_count; i++) { - /* - * stdin has swapped ends of pipe - * (it's the only one readable stream) - */ - int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2]; - int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1]; - - if (use_fd >= 0) { - close(close_fd); - dup2(use_fd, i); - } else { - /* Reset flags that might be set by Node */ - uv__cloexec(i, 0); - uv__nonblock(i, 0); - } - } + uv__process_child_init(options, stdio_count, pipes); - if (options.cwd && chdir(options.cwd)) { - perror("chdir()"); - _exit(127); - } - - if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) { - perror("setgid()"); - _exit(127); - } - - if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) { - perror("setuid()"); - _exit(127); - } - - environ = options.env; - - execvp(options.file, options.args); - perror("execvp()"); - _exit(127); /* Execution never reaches here. */ } @@ -399,7 +422,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, error: uv__set_sys_error(process->loop, errno); - for (i = 0; i < options.stdio_count; i++) { + for (i = 0; i < stdio_count; i++) { close(pipes[i * 2]); close(pipes[i * 2 + 1]); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9091b90fb..602e94889 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -561,12 +561,19 @@ static void uv__read(uv_stream_t* stream) { struct msghdr msg; struct cmsghdr* cmsg; char cmsg_space[64]; + int count; + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; /* XXX: Maybe instead of having UV_STREAM_READING we just test if * tcp->read_cb is NULL or not? */ - while ((stream->read_cb || stream->read2_cb) && - stream->flags & UV_STREAM_READING) { + while ((stream->read_cb || stream->read2_cb) + && (stream->flags & UV_STREAM_READING) + && (count-- > 0)) { assert(stream->alloc_cb); buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024); @@ -890,42 +897,36 @@ int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt, req->send_handle = send_handle; ngx_queue_init(&req->queue); - if (bufcnt <= UV_REQ_BUFSML_SIZE) { + if (bufcnt <= UV_REQ_BUFSML_SIZE) req->bufs = req->bufsml; - } - else { + else req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); - } memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; - - /* - * fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml); - */ - req->write_index = 0; stream->write_queue_size += uv__buf_count(bufs, bufcnt); /* Append the request to write_queue. */ ngx_queue_insert_tail(&stream->write_queue, &req->queue); - assert(!ngx_queue_empty(&stream->write_queue)); - /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait * for the fd to become writable. */ - if (empty_queue) { + if (stream->connect_req) { + /* Still connecting, do nothing. */ + } + else if (empty_queue) { uv__write(stream); - } else { + } + else { /* * blocking streams should never have anything in the queue. * if this assert fires then somehow the blocking stream isn't being - * sufficently flushed in uv__write. + * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); - uv__io_start(stream->loop, &stream->write_watcher); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 4a987a715..cd4e3333b 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -26,19 +26,6 @@ #include <assert.h> #include <errno.h> -#ifdef NDEBUG -# define CHECK(r) ((void) (r)) -#else -# include <stdio.h> -# include <stdlib.h> -# define CHECK(r) \ - do { \ - int __r = (r); \ - if (__r) errno = __r, perror(#r), abort(); \ - } \ - while (0) -#endif - int uv_thread_join(uv_thread_t *tid) { if (pthread_join(*tid, NULL)) @@ -49,20 +36,40 @@ int uv_thread_join(uv_thread_t *tid) { int uv_mutex_init(uv_mutex_t* mutex) { +#ifdef NDEBUG if (pthread_mutex_init(mutex, NULL)) return -1; else return 0; +#else + pthread_mutexattr_t attr; + int r; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) + abort(); + + r = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return r ? -1 : 0; +#endif } void uv_mutex_destroy(uv_mutex_t* mutex) { - CHECK(pthread_mutex_destroy(mutex)); + if (pthread_mutex_destroy(mutex)) + abort(); } void uv_mutex_lock(uv_mutex_t* mutex) { - CHECK(pthread_mutex_lock(mutex)); + if (pthread_mutex_lock(mutex)) + abort(); } @@ -72,7 +79,7 @@ int uv_mutex_trylock(uv_mutex_t* mutex) { r = pthread_mutex_trylock(mutex); if (r && r != EAGAIN) - CHECK(r); + abort(); if (r) return -1; @@ -82,7 +89,8 @@ int uv_mutex_trylock(uv_mutex_t* mutex) { void uv_mutex_unlock(uv_mutex_t* mutex) { - CHECK(pthread_mutex_unlock(mutex)); + if (pthread_mutex_unlock(mutex)) + abort(); } @@ -95,12 +103,14 @@ int uv_rwlock_init(uv_rwlock_t* rwlock) { void uv_rwlock_destroy(uv_rwlock_t* rwlock) { - CHECK(pthread_rwlock_destroy(rwlock)); + if (pthread_rwlock_destroy(rwlock)) + abort(); } void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { - CHECK(pthread_rwlock_rdlock(rwlock)); + if (pthread_rwlock_rdlock(rwlock)) + abort(); } @@ -110,7 +120,7 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { r = pthread_rwlock_tryrdlock(rwlock); if (r && r != EAGAIN) - CHECK(r); + abort(); if (r) return -1; @@ -120,12 +130,14 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { - CHECK(pthread_rwlock_unlock(rwlock)); + if (pthread_rwlock_unlock(rwlock)) + abort(); } void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { - CHECK(pthread_rwlock_wrlock(rwlock)); + if (pthread_rwlock_wrlock(rwlock)) + abort(); } @@ -135,7 +147,7 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { r = pthread_rwlock_trywrlock(rwlock); if (r && r != EAGAIN) - CHECK(r); + abort(); if (r) return -1; @@ -145,10 +157,55 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { - CHECK(pthread_rwlock_unlock(rwlock)); + if (pthread_rwlock_unlock(rwlock)) + abort(); } void uv_once(uv_once_t* guard, void (*callback)(void)) { - CHECK(pthread_once(guard, callback)); + if (pthread_once(guard, callback)) + abort(); +} + + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + return sem_init(sem, 0, value); +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (sem_destroy(sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (sem_post(sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = sem_wait(sem); + while (r == -1 && errno == EINTR); + + if (r) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + int r; + + do + r = sem_trywait(sem); + while (r == -1 && errno == EINTR); + + if (r && errno != EAGAIN) + abort(); + + return r; } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 523d2823d..9f87060ae 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -196,6 +196,7 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) { ssize_t nread; uv_buf_t buf; int flags; + int count; handle = container_of(w, uv_udp_t, read_watcher); assert(handle->type == UV_UDP); @@ -204,15 +205,20 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) { assert(handle->recv_cb != NULL); assert(handle->alloc_cb != NULL); + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + memset(&h, 0, sizeof(h)); + h.msg_name = &peer; + do { - /* FIXME: hoist alloc_cb out the loop but for now follow uv__read() */ buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024); assert(buf.len > 0); assert(buf.base != NULL); - memset(&h, 0, sizeof h); - h.msg_name = &peer; - h.msg_namelen = sizeof peer; + h.msg_namelen = sizeof(peer); h.msg_iov = (struct iovec*)&buf; h.msg_iovlen = 1; @@ -246,6 +252,7 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) { } /* recv_cb callback may decide to pause or close the handle */ while (nread != -1 + && count-- > 0 && handle->fd != -1 && handle->recv_cb != NULL); } diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 761133a63..48f850c73 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -87,7 +87,7 @@ size_t uv_strlcat(char* dst, const char* src, size_t size) { } -uv_buf_t uv_buf_init(char* base, size_t len) { +uv_buf_t uv_buf_init(char* base, unsigned int len) { uv_buf_t buf; buf.base = base; buf.len = len; diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 4a721ef97..c86cb7daa 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -42,8 +42,10 @@ #ifdef _MSC_VER # define UNUSED /* empty */ +# define INLINE __inline #else # define UNUSED __attribute__((unused)) +# define INLINE inline #endif diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index 87f55296e..184802370 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -23,6 +23,8 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" /* Atomic set operation on char */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 78c9fac54..7a3558038 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -28,6 +28,8 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" /* The only event loop we support right now */ @@ -43,17 +45,21 @@ static void uv_init(void) { SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); + /* Fetch winapi function pointers. This must be done first because other */ + /* intialization code might need these function pointers to be loaded. */ + uv_winapi_init(); + /* Initialize winsock */ uv_winsock_init(); - /* Fetch winapi function pointers */ - uv_winapi_init(); - /* Initialize FS */ uv_fs_init(); /* Initialize console */ uv_console_init(); + + /* Initialize utilities */ + uv__util_init(); } @@ -100,13 +106,18 @@ static void uv_loop_init(uv_loop_t* loop) { static void uv_default_loop_init(void) { /* Initialize libuv itself first */ - uv_once(&uv_init_guard_, uv_init); + uv__once_init(); /* Initialize the main loop */ uv_loop_init(&uv_default_loop_); } +void uv__once_init(void) { + uv_once(&uv_init_guard_, uv_init); +} + + uv_loop_t* uv_default_loop(void) { uv_once(&uv_default_loop_init_guard_, uv_default_loop_init); return &uv_default_loop_; @@ -117,7 +128,7 @@ uv_loop_t* uv_loop_new(void) { uv_loop_t* loop; /* Initialize libuv itself first */ - uv_once(&uv_init_guard_, uv_init); + uv__once_init(); loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 30a571a7c..ccf941d1b 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -19,15 +19,17 @@ * IN THE SOFTWARE. */ -#include "uv.h" -#include "internal.h" - #include <assert.h> #include <malloc.h> #include <errno.h> #include <stdio.h> #include <string.h> +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + const unsigned int uv_directory_watcher_buffer_size = 4096; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 5df4829d8..b6b973939 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -32,6 +32,8 @@ #include "uv.h" #include "internal.h" +#include "req-inl.h" + #define UV_FS_ASYNC_QUEUED 0x0001 #define UV_FS_FREE_PATH 0x0002 diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index bdfe1bb93..41e7a4aa2 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -24,6 +24,7 @@ #include "uv.h" #include "internal.h" +#include "req-inl.h" /* diff --git a/deps/uv/src/win/handle-inl.h b/deps/uv/src/win/handle-inl.h new file mode 100644 index 000000000..f069dd192 --- /dev/null +++ b/deps/uv/src/win/handle-inl.h @@ -0,0 +1,150 @@ +/* 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. + */ + +#ifndef UV_WIN_HANDLE_INL_H_ +#define UV_WIN_HANDLE_INL_H_ + +#include <assert.h> + +#include "uv.h" +#include "internal.h" + + +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + + +#define DECREASE_PENDING_REQ_COUNT(handle) \ + do { \ + assert(handle->reqs_pending > 0); \ + handle->reqs_pending--; \ + \ + if (handle->flags & UV_HANDLE_CLOSING && \ + handle->reqs_pending == 0) { \ + uv_want_endgame(loop, (uv_handle_t*)handle); \ + } \ + } while (0) + + +#define uv__handle_close(handle) \ + do { \ + ngx_queue_remove(&(handle)->handle_queue); \ + (handle)->flags |= UV_HANDLE_CLOSED; \ + if ((handle)->close_cb) { \ + (handle)->close_cb((uv_handle_t*)(handle)); \ + } \ + } while (0) + + +INLINE static void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) { + handle->loop = loop; + handle->flags = UV__HANDLE_REF; + ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue); + + loop->counters.handle_init++; +} + + +INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { + handle->flags |= UV_HANDLE_ENDGAME_QUEUED; + + handle->endgame_next = loop->endgame_handles; + loop->endgame_handles = handle; + } +} + + +INLINE static void uv_process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv_tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv_pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv_tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv_udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv_timer_endgame(loop, (uv_timer_t*) handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv_loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv_async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_PROCESS: + uv_process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + +#endif /* UV_WIN_HANDLE_INL_H_ */ diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index a3abb0ab8..9343d256e 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -24,6 +24,7 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" uv_handle_type uv_guess_handle(uv_file file) { @@ -62,15 +63,6 @@ int uv_is_active(const uv_handle_t* handle) { } -void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) { - handle->loop = loop; - handle->flags = UV__HANDLE_REF; - ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue); - - loop->counters.handle_init++; -} - - void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_loop_t* loop = handle->loop; @@ -150,73 +142,3 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { int uv_is_closing(const uv_handle_t* handle) { return handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED); } - - -void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { - if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { - handle->flags |= UV_HANDLE_ENDGAME_QUEUED; - - handle->endgame_next = loop->endgame_handles; - loop->endgame_handles = handle; - } -} - - -void uv_process_endgames(uv_loop_t* loop) { - uv_handle_t* handle; - - while (loop->endgame_handles) { - handle = loop->endgame_handles; - loop->endgame_handles = handle->endgame_next; - - handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; - - switch (handle->type) { - case UV_TCP: - uv_tcp_endgame(loop, (uv_tcp_t*) handle); - break; - - case UV_NAMED_PIPE: - uv_pipe_endgame(loop, (uv_pipe_t*) handle); - break; - - case UV_TTY: - uv_tty_endgame(loop, (uv_tty_t*) handle); - break; - - case UV_UDP: - uv_udp_endgame(loop, (uv_udp_t*) handle); - break; - - case UV_POLL: - uv_poll_endgame(loop, (uv_poll_t*) handle); - break; - - case UV_TIMER: - uv_timer_endgame(loop, (uv_timer_t*) handle); - break; - - case UV_PREPARE: - case UV_CHECK: - case UV_IDLE: - uv_loop_watcher_endgame(loop, handle); - break; - - case UV_ASYNC: - uv_async_endgame(loop, (uv_async_t*) handle); - break; - - case UV_PROCESS: - uv_process_endgame(loop, (uv_process_t*) handle); - break; - - case UV_FS_EVENT: - uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); - break; - - default: - assert(0); - break; - } - } -} diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 787622614..f5d0d1721 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -32,6 +32,7 @@ /* * Handles + * (also see handle-inl.h) */ /* Used by all handles. */ @@ -81,96 +82,14 @@ #define UV_HANDLE_POLL_SLOW 0x02000000 -void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); -void uv_process_endgames(uv_loop_t* loop); - -#define DECREASE_PENDING_REQ_COUNT(handle) \ - do { \ - assert(handle->reqs_pending > 0); \ - handle->reqs_pending--; \ - \ - if (handle->flags & UV_HANDLE_CLOSING && \ - handle->reqs_pending == 0) { \ - uv_want_endgame(loop, (uv_handle_t*)handle); \ - } \ - } while (0) - -#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ - ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) - -#define UV_SUCCEEDED_WITH_IOCP(result) \ - ((result) || (GetLastError() == ERROR_IO_PENDING)) - -#define DECREASE_ACTIVE_COUNT(loop, handle) \ - do { \ - if (--(handle)->activecnt == 0 && \ - !((handle)->flags & UV_HANDLE_CLOSING)) { \ - uv__handle_stop((handle)); \ - } \ - assert((handle)->activecnt >= 0); \ - } while (0) - -#define INCREASE_ACTIVE_COUNT(loop, handle) \ - do { \ - if ((handle)->activecnt++ == 0) { \ - uv__handle_start((handle)); \ - } \ - assert((handle)->activecnt > 0); \ - } while (0) - -#define REGISTER_HANDLE_REQ(loop, handle, req) \ - do { \ - INCREASE_ACTIVE_COUNT((loop), (handle)); \ - uv__req_register((loop), (req)); \ - } while (0) - -#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ - do { \ - DECREASE_ACTIVE_COUNT((loop), (handle)); \ - uv__req_unregister((loop), (req)); \ - } while (0) - -#define uv__handle_close(handle) \ - do { \ - ngx_queue_remove(&(handle)->handle_queue); \ - (handle)->flags |= UV_HANDLE_CLOSED; \ - if ((handle)->close_cb) { \ - (handle)->close_cb((uv_handle_t*)(handle)); \ - } \ - } while (0) - /* - * Handles + * Requests: see req-inl.h */ -void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle); /* - * Requests + * Streams: see stream-inl.h */ -void uv_req_init(uv_loop_t* loop, uv_req_t* req); - -uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped); - -void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req); -void uv_process_reqs(uv_loop_t* loop); - -#define POST_COMPLETION_FOR_REQ(loop, req) \ - if (!PostQueuedCompletionStatus((loop)->iocp, \ - 0, \ - 0, \ - &((req)->overlapped))) { \ - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ - } - - -/* - * Streams - */ -void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle); -void uv_connection_init(uv_stream_t* handle); - -size_t uv_count_bufs(uv_buf_t bufs[], int count); /* @@ -299,6 +218,8 @@ void uv_prepare_invoke(uv_loop_t* loop); void uv_check_invoke(uv_loop_t* loop); void uv_idle_invoke(uv_loop_t* loop); +void uv__once_init(); + /* * Async watcher @@ -347,33 +268,16 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); -/* Utils */ +/* + * Utilities. + */ +void uv__util_init(); + int uv_parent_pid(); void uv_filetime_to_time_t(FILETIME* file_time, time_t* stat_time); void uv_fatal_error(const int errorno, const char* syscall); uv_err_code uv_translate_sys_error(int sys_errno); -#define SET_REQ_STATUS(req, status) \ - (req)->overlapped.Internal = (ULONG_PTR) (status) - -#define SET_REQ_ERROR(req, error) \ - SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) - -#define SET_REQ_SUCCESS(req) \ - SET_REQ_STATUS((req), STATUS_SUCCESS) - -#define GET_REQ_STATUS(req) \ - ((req)->overlapped.Internal) - -#define REQ_SUCCESS(req) \ - (NT_SUCCESS(GET_REQ_STATUS((req)))) - -#define GET_REQ_ERROR(req) \ - (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) - -#define GET_REQ_SOCK_ERROR(req) \ - (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) - /* * Winapi and ntapi utility functions diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index c573cd7d6..a753a0632 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -23,6 +23,7 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 8a64f71bf..055104712 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -26,6 +26,9 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" /* A zero-size buffer for use by uv_pipe_read */ diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 55e0b27e8..ba31ae9ef 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -19,12 +19,13 @@ * IN THE SOFTWARE. */ +#include <assert.h> +#include <io.h> #include "uv.h" #include "internal.h" - -#include <assert.h> -#include <io.h> +#include "handle-inl.h" +#include "req-inl.h" static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { @@ -42,6 +43,28 @@ typedef struct uv_single_fd_set_s { } uv_single_fd_set_t; +static OVERLAPPED overlapped_dummy_; +static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_overlapped_dummy(void) { + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (event == NULL) + uv_fatal_error(GetLastError(), "CreateEvent"); + + memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_); + overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1); +} + + +static OVERLAPPED* uv__get_overlapped_dummy() { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { uv_req_t* req; AFD_POLL_INFO* afd_poll_info; @@ -97,43 +120,26 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { AFD_POLL_INFO afd_poll_info; DWORD result; - HANDLE event; - OVERLAPPED overlapped; - - event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (event == NULL) { - uv__set_sys_error(loop, GetLastError()); - return -1; - } - afd_poll_info.Exclusive = FALSE; + afd_poll_info.Exclusive = TRUE; afd_poll_info.NumberOfHandles = 1; - afd_poll_info.Timeout.QuadPart = 0; + afd_poll_info.Timeout.QuadPart = INT64_MAX; afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; afd_poll_info.Handles[0].Status = 0; afd_poll_info.Handles[0].Events = AFD_POLL_ALL; - memset(&overlapped, 0, sizeof overlapped); - overlapped.hEvent = (HANDLE) ((uintptr_t) event | 1); - result = uv_msafd_poll(handle->socket, &afd_poll_info, - &overlapped); + uv__get_overlapped_dummy()); if (result == SOCKET_ERROR) { DWORD error = WSAGetLastError(); if (error != WSA_IO_PENDING) { uv__set_sys_error(loop, WSAGetLastError()); - CloseHandle(event); return -1; } } - if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) { - uv_fatal_error(GetLastError(), "WaitForSingleObject"); - } - - CloseHandle(event); return 0; } @@ -181,6 +187,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { /* Stop polling. */ handle->events = 0; + uv__handle_stop(handle); } if (events != 0) { @@ -229,17 +236,9 @@ static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { handle->submitted_events_2 == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); } else { - /* Try to cancel outstanding poll requests. */ - if (pCancelIoEx) { - /* Use CancelIoEx to cancel poll requests if available. */ - if (handle->submitted_events_1) - pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_1.overlapped); - if (handle->submitted_events_2) - pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_2.overlapped); - } else if (handle->submitted_events_1 | handle->submitted_events_2) { - /* Execute another unique poll to force the others to return. */ - uv__fast_poll_cancel_poll_req(loop, handle); - } + /* Cancel outstanding poll requests by executing another, unique poll */ + /* request that forces the outstanding ones to return. */ + uv__fast_poll_cancel_poll_req(loop, handle); } } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 23a3012e1..332ef0f58 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -19,15 +19,16 @@ * IN THE SOFTWARE. */ -#include "uv.h" -#include "internal.h" - #include <assert.h> #include <io.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> -#include <windows.h> + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" #define SIGKILL 9 @@ -86,7 +87,7 @@ typedef struct env_var { ((LPBYTE) (buffer)) #define CHILD_STDIO_CBRESERVED2(buffer) \ - CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))) + ((WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)))) #define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ *((unsigned char*) (buffer) + sizeof(int) + fd) @@ -756,6 +757,32 @@ static int duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { } +static int create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr, + DWORD access) { + HANDLE handle; + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = CreateFileW(L"NUL", + access, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + 0, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + uv__set_sys_error(loop, GetLastError()); + return -1; + } + + *handle_ptr = handle; + return 0; +} + + static void set_child_stdio_noinherit(void* buffer) { int i, count; @@ -965,16 +992,34 @@ static int init_child_stdio(uv_loop_t* loop, uv_process_options_t* options, CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; } - for (i = 0; i < options->stdio_count; i++) { - uv_stdio_container_t fdopt = options->stdio[i]; + for (i = 0; i < count; i++) { + uv_stdio_container_t fdopt; + if (i < options->stdio_count) { + fdopt = options->stdio[i]; + } else { + fdopt.flags = UV_IGNORE; + } switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM)) { case UV_IGNORE: - /* The child is not supposed to inherit this handle. It has already */ - /* been initialized to INVALID_HANDLE_VALUE, so just keep it like */ - /* that. */ - continue; + /* Starting a process with no stdin/stout/stderr can confuse it. */ + /* So no matter what the user specified, we make sure the first */ + /* three FDs are always open in their typical modes, e.g. stdin */ + /* be readable and stdout/err should be writable. For FDs > 2, don't */ + /* do anything - all handles in the stdio buffer are initialized with */ + /* INVALID_HANDLE_VALUE, which should be okay. */ + if (i <= 2) { + DWORD access = (i == 0) ? FILE_GENERIC_READ : + FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; + if (create_nul_handle(loop, + &CHILD_STDIO_HANDLE(buffer, i), + access) < 0) { + goto error; + } + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + } + break; case UV_CREATE_PIPE: { /* Create a pair of two connected pipe ends; one end is turned into */ @@ -1077,6 +1122,7 @@ static int init_child_stdio(uv_loop_t* loop, uv_process_options_t* options, CHILD_STDIO_HANDLE(buffer, i) = child_handle; CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; + break; } default: diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h new file mode 100644 index 000000000..a0d91cb19 --- /dev/null +++ b/deps/uv/src/win/req-inl.h @@ -0,0 +1,225 @@ +/* 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. + */ + +#ifndef UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include <assert.h> + +#include "uv.h" +#include "internal.h" + + +#define SET_REQ_STATUS(req, status) \ + (req)->overlapped.Internal = (ULONG_PTR) (status) + +#define SET_REQ_ERROR(req, error) \ + SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) + +#define SET_REQ_SUCCESS(req) \ + SET_REQ_STATUS((req), STATUS_SUCCESS) + +#define GET_REQ_STATUS(req) \ + ((NTSTATUS) (req)->overlapped.Internal) + +#define REQ_SUCCESS(req) \ + (NT_SUCCESS(GET_REQ_STATUS((req)))) + +#define GET_REQ_ERROR(req) \ + (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) + +#define GET_REQ_SOCK_ERROR(req) \ + (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) + + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ + ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) + +#define UV_SUCCEEDED_WITH_IOCP(result) \ + ((result) || (GetLastError() == ERROR_IO_PENDING)) + + +#define POST_COMPLETION_FOR_REQ(loop, req) \ + if (!PostQueuedCompletionStatus((loop)->iocp, \ + 0, \ + 0, \ + &((req)->overlapped))) { \ + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ + } + + +INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) { + loop->counters.req_init++; + req->type = UV_UNKNOWN_REQ; + SET_REQ_SUCCESS(req); +} + + +INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { + return CONTAINING_RECORD(overlapped, uv_req_t, overlapped); +} + + +INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} + + +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv_process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv_process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv_process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +INLINE static 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; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + /* Tcp shutdown requests don't come here. */ + assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); + uv_process_pipe_shutdown_req( + loop, + (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, + (uv_shutdown_t*) req); + break; + + case UV_UDP_RECV: + uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv_process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_GETADDRINFO: + uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); + break; + + case UV_PROCESS_EXIT: + uv_process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_PROCESS_CLOSE: + uv_process_proc_close(loop, (uv_process_t*) req->data); + break; + + case UV_FS: + uv_process_fs_req(loop, (uv_fs_t*) req); + break; + + case UV_WORK: + uv_process_work_req(loop, (uv_work_t*) req); + break; + + case UV_FS_EVENT_REQ: + uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } +} + +#endif /* UV_WIN_REQ_INL_H_ */ diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c index ada4eb1ba..111cc5e28 100644 --- a/deps/uv/src/win/req.c +++ b/deps/uv/src/win/req.c @@ -23,147 +23,3 @@ #include "uv.h" #include "internal.h" - - -void uv_req_init(uv_loop_t* loop, uv_req_t* req) { - loop->counters.req_init++; - req->type = UV_UNKNOWN_REQ; - SET_REQ_SUCCESS(req); -} - - -uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { - return CONTAINING_RECORD(overlapped, uv_req_t, overlapped); -} - - -void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { - req->next_req = NULL; - if (loop->pending_reqs_tail) { - req->next_req = loop->pending_reqs_tail->next_req; - loop->pending_reqs_tail->next_req = req; - loop->pending_reqs_tail = req; - } else { - req->next_req = req; - loop->pending_reqs_tail = req; - } -} - - -#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ - do { \ - switch (((uv_handle_t*) (req)->handle_at)->type) { \ - case UV_TCP: \ - uv_process_tcp_##method##_req(loop, \ - (uv_tcp_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_NAMED_PIPE: \ - uv_process_pipe_##method##_req(loop, \ - (uv_pipe_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_TTY: \ - uv_process_tty_##method##_req(loop, \ - (uv_tty_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - default: \ - assert(0); \ - } \ - } while (0) - - -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; - - switch (req->type) { - case UV_READ: - DELEGATE_STREAM_REQ(loop, req, read, data); - break; - - case UV_WRITE: - DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); - break; - - case UV_ACCEPT: - DELEGATE_STREAM_REQ(loop, req, accept, data); - break; - - case UV_CONNECT: - DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); - break; - - case UV_SHUTDOWN: - /* Tcp shutdown requests don't come here. */ - assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); - uv_process_pipe_shutdown_req( - loop, - (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, - (uv_shutdown_t*) req); - break; - - case UV_UDP_RECV: - uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); - break; - - case UV_UDP_SEND: - uv_process_udp_send_req(loop, - ((uv_udp_send_t*) req)->handle, - (uv_udp_send_t*) req); - break; - - case UV_WAKEUP: - uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); - break; - - case UV_POLL_REQ: - uv_process_poll_req(loop, (uv_poll_t*) req->data, req); - break; - - case UV_GETADDRINFO: - uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); - break; - - case UV_PROCESS_EXIT: - uv_process_proc_exit(loop, (uv_process_t*) req->data); - break; - - case UV_PROCESS_CLOSE: - uv_process_proc_close(loop, (uv_process_t*) req->data); - break; - - case UV_FS: - uv_process_fs_req(loop, (uv_fs_t*) req); - break; - - case UV_WORK: - uv_process_work_req(loop, (uv_work_t*) req); - break; - - case UV_FS_EVENT_REQ: - uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); - break; - - default: - assert(0); - } - } -} diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h new file mode 100644 index 000000000..91313566a --- /dev/null +++ b/deps/uv/src/win/stream-inl.h @@ -0,0 +1,67 @@ +/* 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. + */ + +#ifndef UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include <assert.h> + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +INLINE static void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); + handle->write_queue_size = 0; + handle->activecnt = 0; + + loop->counters.stream_init++; +} + + +INLINE static void uv_connection_init(uv_stream_t* handle) { + handle->flags |= UV_HANDLE_CONNECTION; + handle->write_reqs_pending = 0; + + uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.type = UV_READ; + handle->read_req.data = handle; + + handle->shutdown_req = NULL; +} + + +INLINE static size_t uv_count_bufs(uv_buf_t bufs[], int count) { + size_t bytes = 0; + int i; + + for (i = 0; i < count; i++) { + bytes += (size_t)bufs[i].len; + } + + return bytes; +} + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index dad8669b1..195e0b801 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -23,29 +23,8 @@ #include "uv.h" #include "internal.h" - - -void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) { - uv_handle_init(loop, (uv_handle_t*) handle); - handle->write_queue_size = 0; - handle->activecnt = 0; - - loop->counters.stream_init++; -} - - -void uv_connection_init(uv_stream_t* handle) { - handle->flags |= UV_HANDLE_CONNECTION; - handle->write_reqs_pending = 0; - - uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); - handle->read_req.event_handle = NULL; - handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - handle->read_req.type = UV_READ; - handle->read_req.data = handle; - - handle->shutdown_req = NULL; -} +#include "handle-inl.h" +#include "req-inl.h" int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { @@ -178,18 +157,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { } -size_t uv_count_bufs(uv_buf_t bufs[], int count) { - size_t bytes = 0; - int i; - - for (i = 0; i < count; i++) { - bytes += (size_t)bufs[i].len; - } - - return bytes; -} - - int uv_is_readable(const uv_stream_t* handle) { return !(handle->flags & UV_HANDLE_EOF); } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index c049d64d4..6ea39a2b0 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -23,6 +23,10 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + /* diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 01b814088..aecfaf4f8 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -20,6 +20,7 @@ */ #include <assert.h> +#include <limits.h> #include "uv.h" #include "internal.h" @@ -207,6 +208,44 @@ void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { } +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + *sem = CreateSemaphore(NULL, value, INT_MAX, NULL); + return *sem ? 0 : -1; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (!CloseHandle(*sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (!ReleaseSemaphore(*sem, 1, NULL)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + DWORD r = WaitForSingleObject(*sem, 0); + + if (r == WAIT_OBJECT_0) + return 0; + + if (r == WAIT_TIMEOUT) + return -1; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) { pInitializeSRWLock(&rwlock->srwlock_); return 0; diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c index e066810d5..48e00b879 100644 --- a/deps/uv/src/win/threadpool.c +++ b/deps/uv/src/win/threadpool.c @@ -23,6 +23,7 @@ #include "uv.h" #include "internal.h" +#include "req-inl.h" static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req, diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index e71e4c658..69638bc9c 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -25,15 +25,7 @@ #include "uv.h" #include "internal.h" #include "tree.h" - - -#undef NANOSEC -#define NANOSEC 1000000000 - - -/* The resolution of the high-resolution clock. */ -static uint64_t uv_hrtime_frequency_ = 0; -static uv_once_t uv_hrtime_init_guard_ = UV_ONCE_INIT; +#include "handle-inl.h" void uv_update_time(uv_loop_t* loop) { @@ -58,43 +50,6 @@ int64_t uv_now(uv_loop_t* loop) { } -static void uv_hrtime_init(void) { - LARGE_INTEGER frequency; - - if (!QueryPerformanceFrequency(&frequency)) { - uv_hrtime_frequency_ = 0; - return; - } - - uv_hrtime_frequency_ = frequency.QuadPart; -} - - -uint64_t uv_hrtime(void) { - LARGE_INTEGER counter; - - uv_once(&uv_hrtime_init_guard_, uv_hrtime_init); - - /* If the performance frequency is zero, there's no support. */ - if (!uv_hrtime_frequency_) { - /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */ - return 0; - } - - if (!QueryPerformanceCounter(&counter)) { - /* uv__set_sys_error(loop, GetLastError()); */ - return 0; - } - - /* 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_) + - (((uint64_t) counter.HighPart * NANOSEC / uv_hrtime_frequency_) - << 32); -} - - static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { if (a->due < b->due) return -1; diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 07159922b..047cad26f 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -26,6 +26,9 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" #define UNICODE_REPLACEMENT_CHARACTER (0xfffd) @@ -690,7 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, if (!REQ_SUCCESS(req)) { /* Read was not successful */ if ((handle->flags & UV_HANDLE_READING) && - !(handle->flags & UV_HANDLE_TTY_RAW)) { + handle->read_line_handle != NULL) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 3ea23f9d7..10cca00af 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -23,6 +23,9 @@ #include "uv.h" #include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" /* diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 10c227123..87a999ff5 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -47,11 +47,32 @@ */ #define MAX_TITLE_LENGTH 8192 +/* The number of nanoseconds in one second. */ +#undef NANOSEC +#define NANOSEC 1000000000 + +/* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; -static uv_once_t uv_process_title_init_guard_ = UV_ONCE_INIT; static CRITICAL_SECTION process_title_lock; +/* The tick frequency of the high-resolution clock. */ +static uint64_t hrtime_frequency_ = 0; + + +/* + * One-time intialization code for functionality defined in util.c. + */ +void uv__util_init() { + /* Initialize process title access mutex. */ + InitializeCriticalSection(&process_title_lock); + + /* Retrieve high-resolution timer frequency. */ + if (!QueryPerformanceFrequency((LARGE_INTEGER*) &hrtime_frequency_)) + hrtime_frequency_ = 0; +} + + int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size) { return WideCharToMultiByte(CP_UTF8, @@ -76,90 +97,100 @@ int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, } -int uv_exepath(char* buffer, size_t* size) { - int retVal; - size_t utf16Size; - wchar_t* utf16Buffer; +int uv_exepath(char* buffer, size_t* size_ptr) { + int utf8_len, utf16_buffer_len, utf16_len; + WCHAR* utf16_buffer; - if (!buffer || !size) { + if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) { return -1; } - utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * *size); - if (!utf16Buffer) { - retVal = -1; - goto done; + if (*size_ptr > 32768) { + /* Windows paths can never be longer than this. */ + utf16_buffer_len = 32768; + } else { + utf16_buffer_len = (int) *size_ptr; } - /* Get the path as UTF-16 */ - utf16Size = GetModuleFileNameW(NULL, utf16Buffer, *size - 1); - if (utf16Size <= 0) { - /* uv__set_sys_error(loop, GetLastError()); */ - retVal = -1; - goto done; + utf16_buffer = (wchar_t*) malloc(sizeof(WCHAR) * utf16_buffer_len); + if (!utf16_buffer) { + return -1; } - utf16Buffer[utf16Size] = L'\0'; - - /* Convert to UTF-8 */ - *size = uv_utf16_to_utf8(utf16Buffer, utf16Size, buffer, *size); - if (!*size) { - /* uv__set_sys_error(loop, GetLastError()); */ - retVal = -1; - goto done; + /* Get the path as UTF-16. */ + utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len); + if (utf16_len <= 0) { + goto error; } - buffer[*size] = '\0'; - retVal = 0; + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; -done: - if (utf16Buffer) { - free(utf16Buffer); - } + /* Convert to UTF-8 */ + utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr, + NULL, + NULL); + if (utf8_len == 0) { + goto error; + } + + free(utf16_buffer); + + /* utf8_len *does* include the terminating null at this point, but the */ + /* returned size shouldn't. */ + *size_ptr = utf8_len - 1; + return 0; - return retVal; + error: + free(utf16_buffer); + return -1; } 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; - } + DWORD utf16_len; + WCHAR utf16_buffer[MAX_PATH + 1]; + int r; - utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * size); - if (!utf16Buffer) { - err.code = UV_ENOMEM; - goto done; + if (buffer == NULL || size == 0) { + return uv__new_artificial_error(UV_EINVAL); } - if (!_wgetcwd(utf16Buffer, size - 1)) { - err = uv__new_sys_error(_doserrno); - goto done; + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv__new_sys_error(GetLastError()); } - utf16Buffer[size - 1] = L'\0'; + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = 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; + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; } - buffer[utf8Size] = '\0'; - err = uv_ok_; - -done: - if (utf16Buffer) { - free(utf16Buffer); + /* Convert to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + size > INT_MAX ? INT_MAX : (int) size, + NULL, + NULL); + if (r == 0) { + return uv__new_sys_error(GetLastError()); } - return err; + return uv_ok_; } @@ -266,17 +297,12 @@ char** uv_setup_args(int argc, char** argv) { } -static void uv_process_title_init(void) { - InitializeCriticalSection(&process_title_lock); -} - - uv_err_t uv_set_process_title(const char* title) { uv_err_t err; int length; wchar_t* title_w = NULL; - uv_once(&uv_process_title_init_guard_, uv_process_title_init); + uv__once_init(); /* Find out how big the buffer for the wide-char title must be */ length = uv_utf8_to_utf16(title, NULL, 0); @@ -351,7 +377,7 @@ static int uv__get_process_title() { uv_err_t uv_get_process_title(char* buffer, size_t size) { - uv_once(&uv_process_title_init_guard_, uv_process_title_init); + uv__once_init(); EnterCriticalSection(&process_title_lock); /* @@ -370,6 +396,31 @@ uv_err_t uv_get_process_title(char* buffer, size_t size) { } +uint64_t uv_hrtime(void) { + LARGE_INTEGER counter; + + uv__once_init(); + + /* If the performance frequency is zero, there's no support. */ + if (!hrtime_frequency_) { + /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */ + return 0; + } + + if (!QueryPerformanceCounter(&counter)) { + /* uv__set_sys_error(loop, GetLastError()); */ + return 0; + } + + /* 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 / hrtime_frequency_) + + (((uint64_t) counter.HighPart * NANOSEC / hrtime_frequency_) + << 32); +} + + uv_err_t uv_resident_set_memory(size_t* rss) { HANDLE current_process; PROCESS_MEMORY_COUNTERS pmc; @@ -488,81 +539,148 @@ uv_err_t uv_uptime(double* uptime) { uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - uv_err_t err; - char key[128]; - HKEY processor_key = NULL; - DWORD cpu_speed = 0; - DWORD cpu_speed_length = sizeof(cpu_speed); - char cpu_brand[256]; - DWORD cpu_brand_length = sizeof(cpu_brand); + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; + DWORD sppi_size; SYSTEM_INFO system_info; + DWORD cpu_count, i, r; + ULONG result_size; + size_t size; + uv_err_t err; uv_cpu_info_t* cpu_info; - unsigned int i; - GetSystemInfo(&system_info); + *cpu_infos = NULL; + *count = 0; - *cpu_infos = (uv_cpu_info_t*)malloc(system_info.dwNumberOfProcessors * - sizeof(uv_cpu_info_t)); - if (!(*cpu_infos)) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } + uv__once_init(); - *count = 0; + GetSystemInfo(&system_info); + cpu_count = system_info.dwNumberOfProcessors; - for (i = 0; i < system_info.dwNumberOfProcessors; i++) { - _snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i); + size = cpu_count * sizeof(uv_cpu_info_t); + *cpu_infos = (uv_cpu_info_t*) malloc(size); + if (*cpu_infos == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto out; + } + memset(*cpu_infos, 0, size); - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, - &processor_key) != ERROR_SUCCESS) { - if (i == 0) { - err = uv__new_sys_error(GetLastError()); - goto done; - } + sppi_size = sizeof(*sppi) * cpu_count; + sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size); + if (!sppi) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } - continue; + r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (r != ERROR_SUCCESS || result_size != sppi_size) { + err = uv__new_sys_error(GetLastError()); + goto out; + } + + for (i = 0; i < cpu_count; i++) { + WCHAR key_name[128]; + HKEY processor_key; + DWORD cpu_speed; + DWORD cpu_speed_size = sizeof(cpu_speed); + WCHAR cpu_brand[256]; + DWORD cpu_brand_size = sizeof(cpu_brand); + + _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); + + r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (r != ERROR_SUCCESS) { + err = uv__new_sys_error(GetLastError()); + goto out; } - if (RegQueryValueEx(processor_key, "~MHz", NULL, NULL, - (LPBYTE)&cpu_speed, &cpu_speed_length) - != ERROR_SUCCESS) { + if (RegQueryValueExW(processor_key, + L"~MHz", + NULL, NULL, + (BYTE*) &cpu_speed, + &cpu_speed_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); - goto done; + RegCloseKey(processor_key); + goto out; } - if (RegQueryValueEx(processor_key, "ProcessorNameString", NULL, NULL, - (LPBYTE)&cpu_brand, &cpu_brand_length) - != ERROR_SUCCESS) { + if (RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, NULL, + (BYTE*) &cpu_brand, + &cpu_brand_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); - goto done; + RegCloseKey(processor_key); + goto out; } RegCloseKey(processor_key); - processor_key = NULL; cpu_info = &(*cpu_infos)[i]; - - /* $TODO: find times on windows */ - cpu_info->cpu_times.user = 0; + cpu_info->speed = cpu_speed; + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - + sppi[i].IdleTime.QuadPart) / 10000; + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; - cpu_info->cpu_times.sys = 0; - cpu_info->cpu_times.idle = 0; - cpu_info->cpu_times.irq = 0; - cpu_info->model = strdup(cpu_brand); - cpu_info->speed = cpu_speed; + size = uv_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + NULL, + 0); + if (size == 0) { + err = uv__new_sys_error(GetLastError()); + goto out; + } + + /* Allocate 1 extra byte for the null terminator. */ + cpu_info->model = (char*) malloc(size + 1); + if (cpu_info->model == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto out; + } + + if (uv_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + cpu_info->model, + size) == 0) { + err = uv__new_sys_error(GetLastError()); + goto out; + } + + /* Ensure that cpu_info->model is null terminated. */ + cpu_info->model[size] = '\0'; (*count)++; } err = uv_ok_; -done: - if (processor_key) { - RegCloseKey(processor_key); + out: + if (sppi) { + free(sppi); } - if (err.code != UV_OK) { + if (err.code != UV_OK && + *cpu_infos != NULL) { + int i; + + for (i = 0; i < *count; i++) { + /* This is safe because the cpu_infos memory area is zeroed out */ + /* immediately after allocating it. */ + free((*cpu_infos)[i].model); + } free(*cpu_infos); + *cpu_infos = NULL; *count = 0; } diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 4614a3ada..80c3e521c 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -29,6 +29,7 @@ sRtlNtStatusToDosError pRtlNtStatusToDosError; sNtDeviceIoControlFile pNtDeviceIoControlFile; sNtQueryInformationFile pNtQueryInformationFile; sNtSetInformationFile pNtSetInformationFile; +sNtQuerySystemInformation pNtQuerySystemInformation; sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; sCreateSymbolicLinkW pCreateSymbolicLinkW; @@ -79,6 +80,13 @@ void uv_winapi_init() { uv_fatal_error(GetLastError(), "GetProcAddress"); } + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( + ntdll_module, + "NtQuerySystemInformation"); + if (pNtQuerySystemInformation == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + kernel32_module = GetModuleHandleA("kernel32.dll"); if (kernel32_module == NULL) { uv_fatal_error(GetLastError(), "GetModuleHandleA"); diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 4b1a249fb..2f57e39ba 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -28,11 +28,6 @@ /* * Ntdll headers */ -#ifndef _NTDEF_ - typedef LONG NTSTATUS; - typedef NTSTATUS *PNTSTATUS; -#endif - #ifndef STATUS_SEVERITY_SUCCESS # define STATUS_SEVERITY_SUCCESS 0x0 #endif @@ -4207,6 +4202,19 @@ typedef enum _FILE_INFORMATION_CLASS { FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#ifndef SystemProcessorPerformanceInformation +# define SystemProcessorPerformanceInformation 8 +#endif + #ifndef DEVICE_TYPE # define DEVICE_TYPE DWORD #endif @@ -4323,6 +4331,12 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile) ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); +typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) + (UINT SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + /* * Kernel32 headers @@ -4410,6 +4424,7 @@ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; extern sNtQueryInformationFile pNtQueryInformationFile; extern sNtSetInformationFile pNtSetInformationFile; +extern sNtQuerySystemInformation pNtQuerySystemInformation; /* Kernel32 function pointers */ diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index 37f91da47..fb1630375 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -24,6 +24,8 @@ #ifdef _WIN32 # include <io.h> +#else +# include <unistd.h> #endif #include "uv.h" @@ -120,5 +122,17 @@ static int maybe_run_test(int argc, char **argv) { return 1; } + if (strcmp(argv[1], "spawn_helper6") == 0) { + int r; + + r = fprintf(stdout, "hello world\n"); + ASSERT(r > 0); + + r = fprintf(stderr, "hello errworld\n"); + ASSERT(r > 0); + + return 1; + } + return run_test(argv[1], TEST_TIMEOUT, 0); } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 9a5ba695a..b9104d6f8 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -22,6 +22,9 @@ TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (run_once) +TEST_DECLARE (semaphore_1) +TEST_DECLARE (semaphore_2) +TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ipc_listen_before_write) @@ -37,6 +40,8 @@ TEST_DECLARE (pipe_ping_pong) TEST_DECLARE (delayed_accept) TEST_DECLARE (multiple_listen) TEST_DECLARE (tcp_writealot) +TEST_DECLARE (tcp_connect_error_after_write) +TEST_DECLARE (tcp_shutdown_after_write) TEST_DECLARE (tcp_bind_error_addrinuse) TEST_DECLARE (tcp_bind_error_addrnotavail_1) TEST_DECLARE (tcp_bind_error_addrnotavail_2) @@ -120,6 +125,7 @@ TEST_DECLARE (spawn_exit_code) TEST_DECLARE (spawn_stdout) TEST_DECLARE (spawn_stdin) TEST_DECLARE (spawn_stdio_greater_than_3) +TEST_DECLARE (spawn_ignored_stdio) TEST_DECLARE (spawn_and_kill) TEST_DECLARE (spawn_detached) TEST_DECLARE (spawn_and_kill_with_std) @@ -168,6 +174,7 @@ TEST_DECLARE (counters_init) TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) +TEST_DECLARE (poll_close) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -191,6 +198,9 @@ TASK_LIST_START TEST_ENTRY (callback_order) #endif TEST_ENTRY (run_once) + TEST_ENTRY (semaphore_1) + TEST_ENTRY (semaphore_2) + TEST_ENTRY (semaphore_3) TEST_ENTRY (pipe_connect_bad_name) TEST_ENTRY (pipe_connect_to_file) @@ -220,6 +230,10 @@ TASK_LIST_START TEST_ENTRY (tcp_writealot) TEST_HELPER (tcp_writealot, tcp4_echo_server) + TEST_ENTRY (tcp_shutdown_after_write) + TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server) + + TEST_ENTRY (tcp_connect_error_after_write) TEST_ENTRY (tcp_bind_error_addrinuse) TEST_ENTRY (tcp_bind_error_addrnotavail_1) TEST_ENTRY (tcp_bind_error_addrnotavail_2) @@ -330,11 +344,13 @@ TASK_LIST_START TEST_ENTRY (poll_duplex) TEST_ENTRY (poll_unidirectional) + TEST_ENTRY (poll_close) TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) TEST_ENTRY (spawn_stdin) TEST_ENTRY (spawn_stdio_greater_than_3) + TEST_ENTRY (spawn_ignored_stdio) TEST_ENTRY (spawn_and_kill) TEST_ENTRY (spawn_detached) TEST_ENTRY (spawn_and_kill_with_std) diff --git a/deps/uv/test/test-poll-close.c b/deps/uv/test/test-poll-close.c new file mode 100644 index 000000000..4c3701bc8 --- /dev/null +++ b/deps/uv/test/test-poll-close.c @@ -0,0 +1,77 @@ +/* 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 <errno.h> + +#ifndef _WIN32 +# include <fcntl.h> +# include <sys/socket.h> +# include <unistd.h> +#endif + +#include "uv.h" +#include "task.h" + +#define NUM_SOCKETS 64 + + +static int close_cb_called = 0; + + +static void poll_cb_fail(uv_poll_t* handle, int status, int events) { + ASSERT(0 && "poll_fail_cb should never be called"); +} + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +TEST_IMPL(poll_close) { + uv_os_sock_t sockets[NUM_SOCKETS]; + uv_poll_t poll_handles[NUM_SOCKETS]; + int i; + +#ifdef _WIN32 + { + struct WSAData wsa_data; + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); + } +#endif + + for (i = 0; i < NUM_SOCKETS; i++) { + sockets[i] = socket(AF_INET, SOCK_STREAM, 0); + uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]); + uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL); + } + + for (i = 0; i < NUM_SOCKETS; i++) { + uv_close((uv_handle_t*) &poll_handles[i], close_cb); + } + + uv_run(uv_default_loop()); + + ASSERT(close_cb_called == NUM_SOCKETS); + + return 0; +} diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index 0033f01f9..5a20b9d52 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -537,7 +537,7 @@ static void start_poll_test() { #ifdef _WIN32 { struct WSAData wsa_data; - r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); ASSERT(r == 0); } #endif @@ -550,10 +550,10 @@ static void start_poll_test() { r = uv_run(uv_default_loop()); ASSERT(r == 0); - /* Assert that at most one percent of the writable wakeups was spurious. */ + /* Assert that at most five percent of the writable wakeups was spurious. */ ASSERT(spurious_writable_wakeups == 0 || (valid_writable_wakeups + spurious_writable_wakeups) / - spurious_writable_wakeups > 100); + spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); } diff --git a/deps/uv/test/test-semaphore.c b/deps/uv/test/test-semaphore.c new file mode 100644 index 000000000..ee89d4fca --- /dev/null +++ b/deps/uv/test/test-semaphore.c @@ -0,0 +1,111 @@ +/* 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 <stdlib.h> +#include <string.h> + +typedef struct { + uv_mutex_t mutex; + uv_sem_t sem; + int delay; + volatile int posted; +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + + if (c->delay) + uv_sleep(c->delay); + + uv_mutex_lock(&c->mutex); + ASSERT(c->posted == 0); + uv_sem_post(&c->sem); + c->posted = 1; + uv_mutex_unlock(&c->mutex); +} + + +TEST_IMPL(semaphore_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + + ASSERT(0 == uv_sem_init(&wc.sem, 0)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_sleep(100); + uv_mutex_lock(&wc.mutex); + ASSERT(wc.posted == 1); + uv_sem_wait(&wc.sem); /* should not block */ + uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */ + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_sem_destroy(&wc.sem); + + return 0; +} + + +TEST_IMPL(semaphore_2) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_sem_init(&wc.sem, 0)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_sem_wait(&wc.sem); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_sem_destroy(&wc.sem); + + return 0; +} + + +TEST_IMPL(semaphore_3) { + uv_sem_t sem; + + ASSERT(0 == uv_sem_init(&sem, 3)); + uv_sem_wait(&sem); /* should not block */ + uv_sem_wait(&sem); /* should not block */ + ASSERT(0 == uv_sem_trywait(&sem)); + ASSERT(-1 == uv_sem_trywait(&sem)); + + uv_sem_post(&sem); + ASSERT(0 == uv_sem_trywait(&sem)); + ASSERT(-1 == uv_sem_trywait(&sem)); + + uv_sem_destroy(&sem); + + return 0; +} diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 604304380..51ed2e59d 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -329,6 +329,27 @@ TEST_IMPL(spawn_stdio_greater_than_3) { } +TEST_IMPL(spawn_ignored_stdio) { + int r; + + init_process_options("spawn_helper6", exit_cb); + + options.stdio = NULL; + options.stdio_count = 0; + + r = uv_spawn(uv_default_loop(), &process, options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop()); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + return 0; +} + + TEST_IMPL(spawn_and_kill) { int r; diff --git a/deps/uv/test/test-tcp-connect-error-after-write.c b/deps/uv/test/test-tcp-connect-error-after-write.c new file mode 100644 index 000000000..a9c020378 --- /dev/null +++ b/deps/uv/test/test-tcp-connect-error-after-write.c @@ -0,0 +1,95 @@ +/* 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 <stdlib.h> +#include <string.h> + +static int connect_cb_called; +static int write_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(status == -1); + connect_cb_called++; + uv_close((uv_handle_t*)req->handle, close_cb); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == -1); + write_cb_called++; +} + + +/* + * Try to connect to an address on which nothing listens, get ECONNREFUSED + * (uv errno 12) and get connect_cb() called once with status != 0. + * Related issue: https://github.com/joyent/libuv/issues/443 + */ +TEST_IMPL(tcp_connect_error_after_write) { + uv_connect_t connect_req; + struct sockaddr_in addr; + uv_write_t write_req; + uv_tcp_t conn; + uv_buf_t buf; + int r; + +#ifdef _WIN32 + fprintf(stderr, "This test is disabled on Windows for now.\n"); + fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n"); + return 0; /* windows slackers... */ +#endif + + addr = uv_ip4_addr("127.0.0.1", TEST_PORT); + buf = uv_buf_init("TEST", 4); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == -1); + ASSERT(uv_last_error(uv_default_loop()).code == UV_EBADF); + + r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop()); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + return 0; +} diff --git a/deps/uv/test/test-tcp-shutdown-after-write.c b/deps/uv/test/test-tcp-shutdown-after-write.c new file mode 100644 index 000000000..8bf912361 --- /dev/null +++ b/deps/uv/test/test-tcp-shutdown-after-write.c @@ -0,0 +1,129 @@ +/* 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" + +static void write_cb(uv_write_t* req, int status); +static void shutdown_cb(uv_shutdown_t* req, int status); + +static uv_tcp_t conn; +static uv_timer_t timer; +static uv_connect_t connect_req; +static uv_write_t write_req; +static uv_shutdown_t shutdown_req; + +static int connect_cb_called; +static int write_cb_called; +static int shutdown_cb_called; + +static int conn_close_cb_called; +static int timer_close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + if (handle == (uv_handle_t*)&conn) + conn_close_cb_called++; + else if (handle == (uv_handle_t*)&timer) + timer_close_cb_called++; + else + ASSERT(0 && "bad handle in close_cb"); +} + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { + static char slab[64]; + return uv_buf_init(slab, sizeof(slab)); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_buf_t buf; + int r; + + uv_close((uv_handle_t*)handle, close_cb); + + buf = uv_buf_init("TEST", 4); + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb); + ASSERT(r == 0); +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(status == 0); + connect_cb_called++; +} + + +static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) { +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + write_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(status == 0); + shutdown_cb_called++; + uv_close((uv_handle_t*)&conn, close_cb); +} + + +TEST_IMPL(tcp_shutdown_after_write) { + struct sockaddr_in addr; + uv_loop_t* loop; + int r; + + addr = uv_ip4_addr("127.0.0.1", TEST_PORT); + loop = uv_default_loop(); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 125, 0); + ASSERT(r == 0); + + r = uv_tcp_init(loop, &conn); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb); + ASSERT(r == 0); + + r = uv_run(loop); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + ASSERT(conn_close_cb_called == 1); + ASSERT(timer_close_cb_called == 1); + + return 0; +} diff --git a/deps/uv/test/test-tcp-writealot.c b/deps/uv/test/test-tcp-writealot.c index 09c96f164..841df3c0d 100644 --- a/deps/uv/test/test-tcp-writealot.c +++ b/deps/uv/test/test-tcp-writealot.c @@ -37,9 +37,9 @@ static int shutdown_cb_called = 0; static int connect_cb_called = 0; static int write_cb_called = 0; static int close_cb_called = 0; -static int bytes_sent = 0; -static int bytes_sent_done = 0; -static int bytes_received_done = 0; +static size_t bytes_sent = 0; +static size_t bytes_sent_done = 0; +static size_t bytes_received_done = 0; static uv_connect_t connect_req; static uv_shutdown_t shutdown_req; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 47f876706..964933d51 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -142,6 +142,7 @@ 'src/win/fs-event.c', 'src/win/getaddrinfo.c', 'src/win/handle.c', + 'src/win/handle-inl.h', 'src/win/internal.h', 'src/win/loop-watcher.c', 'src/win/pipe.c', @@ -149,7 +150,9 @@ 'src/win/poll.c', 'src/win/process.c', 'src/win/req.c', + 'src/win/req-inl.h', 'src/win/stream.c', + 'src/win/stream-inl.h', 'src/win/tcp.c', 'src/win/tty.c', 'src/win/threadpool.c', @@ -327,9 +330,11 @@ 'test/test-pipe-connect-error.c', 'test/test-platform-output.c', 'test/test-poll.c', + 'test/test-poll-close.c', 'test/test-process-title.c', 'test/test-ref.c', 'test/test-run-once.c', + 'test/test-semaphore.c', 'test/test-shutdown-close.c', 'test/test-shutdown-eof.c', 'test/test-spawn.c', @@ -337,6 +342,8 @@ 'test/test-tcp-bind-error.c', 'test/test-tcp-bind6-error.c', 'test/test-tcp-close.c', + 'test/test-tcp-connect-error-after-write.c', + 'test/test-tcp-shutdown-after-write.c', 'test/test-tcp-flags.c', 'test/test-tcp-connect-error.c', 'test/test-tcp-connect-timeout.c', |