From 6bec5440ebced1bc2b91c1c9f3fbc7a361995331 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 20 Aug 2012 18:41:07 +0200 Subject: [PATCH] uv: upgrade to 8073a26 --- deps/uv/config-unix.mk | 1 + deps/uv/gyp_uv | 4 +- deps/uv/include/uv-private/eio.h | 2 +- deps/uv/include/uv-private/ngx-queue.h | 2 +- deps/uv/include/uv-private/uv-bsd.h | 30 ++ deps/uv/include/uv-private/uv-darwin.h | 37 +++ deps/uv/include/uv-private/uv-linux.h | 34 +++ deps/uv/include/uv-private/uv-sunos.h | 40 +++ deps/uv/include/uv-private/uv-unix.h | 293 ++++++++----------- deps/uv/include/uv-private/uv-win.h | 481 ++++++++++++++++--------------- deps/uv/include/uv.h | 294 +++++++++++-------- deps/uv/src/fs-poll.c | 150 +++++----- deps/uv/src/unix/async.c | 2 - deps/uv/src/unix/core.c | 5 + deps/uv/src/unix/cygwin.c | 12 +- deps/uv/src/unix/darwin.c | 10 + deps/uv/src/unix/freebsd.c | 11 +- deps/uv/src/unix/fs.c | 42 ++- deps/uv/src/unix/internal.h | 16 +- deps/uv/src/unix/kqueue.c | 2 - deps/uv/src/unix/linux/inotify.c | 2 - deps/uv/src/unix/linux/linux-core.c | 244 +++++++++++----- deps/uv/src/unix/loop-watcher.c | 1 - deps/uv/src/unix/loop.c | 38 ++- deps/uv/src/unix/netbsd.c | 11 +- deps/uv/src/unix/openbsd.c | 11 +- deps/uv/src/unix/pipe.c | 1 - deps/uv/src/unix/poll.c | 2 - deps/uv/src/unix/process.c | 296 +++++++++++-------- deps/uv/src/unix/signal.c | 269 ++++++++++++++++++ deps/uv/src/unix/stream.c | 15 +- deps/uv/src/unix/sunos.c | 22 +- deps/uv/src/unix/tcp.c | 1 - deps/uv/src/unix/timer.c | 2 - deps/uv/src/unix/tty.c | 1 - deps/uv/src/unix/udp.c | 6 +- deps/uv/src/unix/uv-eio.c | 4 +- deps/uv/src/uv-common.h | 1 - deps/uv/src/win/async.c | 34 +-- deps/uv/src/win/atomicops-inl.h | 56 ++++ deps/uv/src/win/core.c | 5 +- deps/uv/src/win/dl.c | 2 +- deps/uv/src/win/error.c | 4 +- deps/uv/src/win/fs-event.c | 36 ++- deps/uv/src/win/getaddrinfo.c | 22 +- deps/uv/src/win/handle-inl.h | 4 + deps/uv/src/win/handle.c | 4 + deps/uv/src/win/internal.h | 25 +- deps/uv/src/win/loop-watcher.c | 1 - deps/uv/src/win/pipe.c | 35 ++- deps/uv/src/win/poll.c | 2 - deps/uv/src/win/process-stdio.c | 66 ++--- deps/uv/src/win/process.c | 484 ++++++++++++++++---------------- deps/uv/src/win/req-inl.h | 9 +- deps/uv/src/win/signal.c | 349 +++++++++++++++++++++++ deps/uv/src/win/stream-inl.h | 2 - deps/uv/src/win/tcp.c | 2 - deps/uv/src/win/timer.c | 2 - deps/uv/src/win/tty.c | 120 +++++--- deps/uv/src/win/udp.c | 2 - deps/uv/src/win/util.c | 12 +- deps/uv/test/benchmark-fs-stat.c | 2 +- deps/uv/test/benchmark-sizes.c | 1 + deps/uv/test/runner-win.c | 8 +- deps/uv/test/runner.c | 2 +- deps/uv/test/test-counters-init.c | 215 -------------- deps/uv/test/test-delayed-accept.c | 9 - deps/uv/test/test-list.h | 10 +- deps/uv/test/test-signal.c | 162 +++++++++++ deps/uv/test/test-spawn.c | 56 ++-- deps/uv/test/test-tcp-unexpected-read.c | 2 +- deps/uv/uv.gyp | 10 +- 72 files changed, 2625 insertions(+), 1525 deletions(-) create mode 100644 deps/uv/include/uv-private/uv-bsd.h create mode 100644 deps/uv/include/uv-private/uv-darwin.h create mode 100644 deps/uv/include/uv-private/uv-linux.h create mode 100644 deps/uv/include/uv-private/uv-sunos.h create mode 100644 deps/uv/src/unix/signal.c create mode 100644 deps/uv/src/win/atomicops-inl.h create mode 100644 deps/uv/src/win/signal.c delete mode 100644 deps/uv/test/test-counters-init.c create mode 100644 deps/uv/test/test-signal.c diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index e3e9545..53c636d 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -37,6 +37,7 @@ OBJS += src/unix/loop-watcher.o OBJS += src/unix/pipe.o OBJS += src/unix/poll.o OBJS += src/unix/process.o +OBJS += src/unix/signal.o OBJS += src/unix/stream.o OBJS += src/unix/tcp.o OBJS += src/unix/thread.o diff --git a/deps/uv/gyp_uv b/deps/uv/gyp_uv index 00da3ae..a8528fa 100755 --- a/deps/uv/gyp_uv +++ b/deps/uv/gyp_uv @@ -22,7 +22,9 @@ def compiler_version(): proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE) is_clang = 'clang' in proc.communicate()[0].split('\n')[0] proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE) - version = tuple(map(int, proc.communicate()[0].split('.'))) + version = proc.communicate()[0].split('.') + version = map(int, version[:2]) + version = tuple(version) return (version, is_clang) diff --git a/deps/uv/include/uv-private/eio.h b/deps/uv/include/uv-private/eio.h index aab9988..975f7ef 100644 --- a/deps/uv/include/uv-private/eio.h +++ b/deps/uv/include/uv-private/eio.h @@ -251,7 +251,7 @@ struct eio_req eio_channel *channel; /* data used to direct poll callbacks arising from this req */ -#if __i386 || __amd64 +#if defined(__i386) || defined(__amd64) unsigned char cancelled; #else sig_atomic_t cancelled; diff --git a/deps/uv/include/uv-private/ngx-queue.h b/deps/uv/include/uv-private/ngx-queue.h index 6fd0071..201107e 100644 --- a/deps/uv/include/uv-private/ngx-queue.h +++ b/deps/uv/include/uv-private/ngx-queue.h @@ -62,7 +62,7 @@ struct ngx_queue_s { (q)->prev -#if (NGX_DEBUG) +#if defined(NGX_DEBUG) #define ngx_queue_remove(x) \ (x)->next->prev = (x)->prev; \ diff --git a/deps/uv/include/uv-private/uv-bsd.h b/deps/uv/include/uv-private/uv-bsd.h new file mode 100644 index 0000000..26830a6 --- /dev/null +++ b/deps/uv/include/uv-private/uv-bsd.h @@ -0,0 +1,30 @@ +/* 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_BSD_H +#define UV_BSD_H + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + int fflags; \ + int fd; \ + +#endif /* UV_BSD_H */ diff --git a/deps/uv/include/uv-private/uv-darwin.h b/deps/uv/include/uv-private/uv-darwin.h new file mode 100644 index 0000000..93f2ca4 --- /dev/null +++ b/deps/uv/include/uv-private/uv-darwin.h @@ -0,0 +1,37 @@ +/* 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_DARWIN_H +#define UV_DARWIN_H + +#if defined(__APPLE__) && defined(__MACH__) +# include +# include +# include +# define UV_PLATFORM_SEM_T semaphore_t +#endif + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + ev_io event_watcher; \ + int fflags; \ + int fd; \ + +#endif /* UV_DARWIN_H */ diff --git a/deps/uv/include/uv-private/uv-linux.h b/deps/uv/include/uv-private/uv-linux.h new file mode 100644 index 0000000..0d50123 --- /dev/null +++ b/deps/uv/include/uv-private/uv-linux.h @@ -0,0 +1,34 @@ +/* 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_LINUX_H +#define UV_LINUX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t inotify_read_watcher; \ + void* inotify_watchers; \ + int inotify_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + ngx_queue_t watchers; \ + int wd; \ + +#endif /* UV_LINUX_H */ diff --git a/deps/uv/include/uv-private/uv-sunos.h b/deps/uv/include/uv-private/uv-sunos.h new file mode 100644 index 0000000..9d55e23 --- /dev/null +++ b/deps/uv/include/uv-private/uv-sunos.h @@ -0,0 +1,40 @@ +/* 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_SUNOS_H +#define UV_SUNOS_H + +#include +#include + +#if defined(PORT_SOURCE_FILE) + +# define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t fs_event_watcher; \ + int fs_fd; \ + +# define UV_PLATFORM_FS_EVENT_FIELDS \ + file_obj_t fo; \ + int fd; \ + +#endif /* defined(PORT_SOURCE_FILE) */ + +#endif /* UV_SUNOS_H */ diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index a8dda72..560889e 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/include/uv-private/uv-unix.h @@ -40,20 +40,43 @@ #include #include +#include #include #include -#if defined(__APPLE__) && defined(__MACH__) -# include -# include -# include -#else -# include +struct uv__io_s; +struct uv_loop_s; + +typedef struct uv__io_s uv__io_t; +typedef void (*uv__io_cb)(struct uv_loop_s* loop, uv__io_t* handle, int events); + +struct uv__io_s { + ev_io io_watcher; +}; + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined(__sun) +# include "uv-sunos.h" +#elif defined(__APPLE__) +# include "uv-darwin.h" +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#endif + +#ifndef UV_PLATFORM_SEM_T +# define UV_PLATFORM_SEM_T sem_t +#endif + +#ifndef UV_PLATFORM_LOOP_FIELDS +# define UV_PLATFORM_LOOP_FIELDS /* empty */ #endif -#if __sun -# include -# include +#ifndef UV_PLATFORM_FS_EVENT_FIELDS +# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */ #endif /* Note: May be cast to struct iovec. See writev(2). */ @@ -63,9 +86,7 @@ typedef struct { } uv_buf_t; typedef int uv_file; - typedef int uv_os_sock_t; - typedef struct stat uv_statbuf_t; #define UV_ONCE_INIT PTHREAD_ONCE_INIT @@ -74,11 +95,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; -#if defined(__APPLE__) && defined(__MACH__) -typedef semaphore_t uv_sem_t; -#else -typedef sem_t uv_sem_t; -#endif +typedef UV_PLATFORM_SEM_T uv_sem_t; /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; @@ -86,37 +103,14 @@ typedef uid_t uv_uid_t; /* Platform-specific definitions for uv_dlopen support. */ #define UV_DYNAMIC /* empty */ + typedef struct { void* handle; char* errmsg; } uv_lib_t; -struct uv__io_s; -struct uv_loop_s; - -typedef struct uv__io_s uv__io_t; -typedef void (*uv__io_cb)(struct uv_loop_s* loop, uv__io_t* handle, int events); - -struct uv__io_s { - ev_io io_watcher; -}; - -#define UV_REQ_TYPE_PRIVATE /* empty */ - -#if __linux__ -# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \ - uv__io_t inotify_read_watcher; \ - void* inotify_watchers; \ - int inotify_fd; -#elif defined(PORT_SOURCE_FILE) -# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \ - uv__io_t fs_event_watcher; \ - int fs_fd; -#else -# define UV_LOOP_PRIVATE_PLATFORM_FIELDS -#endif - #define UV_LOOP_PRIVATE_FIELDS \ + unsigned long flags; \ /* Poll result queue */ \ eio_channel uv_eio_channel; \ struct ev_loop* ev; \ @@ -125,6 +119,7 @@ struct uv__io_s { uv_async_t uv_eio_done_poll_notifier; \ uv_idle_t uv_eio_poller; \ uv_handle_t* closing_handles; \ + ngx_queue_t process_handles[1]; \ ngx_queue_t prepare_handles; \ ngx_queue_t check_handles; \ ngx_queue_t idle_handles; \ @@ -132,111 +127,94 @@ struct uv__io_s { uv__io_t async_watcher; \ int async_pipefd[2]; \ /* RB_HEAD(uv__timers, uv_timer_s) */ \ - struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \ + struct uv__timers { \ + struct uv_timer_s* rbh_root; \ + } timer_handles; \ uint64_t time; \ - UV_LOOP_PRIVATE_PLATFORM_FIELDS + void* signal_ctx; \ + uv_signal_t child_watcher; \ + UV_PLATFORM_LOOP_FIELDS \ -#define UV_REQ_BUFSML_SIZE (4) +#define UV_REQ_TYPE_PRIVATE /* empty */ #define UV_REQ_PRIVATE_FIELDS /* empty */ -#define UV_WRITE_PRIVATE_FIELDS \ - ngx_queue_t queue; \ - int write_index; \ - uv_buf_t* bufs; \ - int bufcnt; \ - int error; \ - uv_buf_t bufsml[UV_REQ_BUFSML_SIZE]; - -#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ - -#define UV_CONNECT_PRIVATE_FIELDS \ - ngx_queue_t queue; - -#define UV_UDP_SEND_PRIVATE_FIELDS \ - ngx_queue_t queue; \ - struct sockaddr_in6 addr; \ - int bufcnt; \ - uv_buf_t* bufs; \ - ssize_t status; \ - uv_udp_send_cb send_cb; \ - uv_buf_t bufsml[UV_REQ_BUFSML_SIZE]; \ - #define UV_PRIVATE_REQ_TYPES /* empty */ +#define UV_WRITE_PRIVATE_FIELDS \ + ngx_queue_t queue; \ + int write_index; \ + uv_buf_t* bufs; \ + int bufcnt; \ + int error; \ + uv_buf_t bufsml[4]; \ -/* TODO: union or classes please! */ -#define UV_HANDLE_PRIVATE_FIELDS \ - int flags; \ - uv_handle_t* next_closing; \ - - -#define UV_STREAM_PRIVATE_FIELDS \ - uv_connect_t *connect_req; \ - uv_shutdown_t *shutdown_req; \ - uv__io_t read_watcher; \ - uv__io_t write_watcher; \ - ngx_queue_t write_queue; \ - ngx_queue_t write_completed_queue; \ - uv_connection_cb connection_cb; \ - int delayed_error; \ - int accepted_fd; \ - int fd; \ - - -/* UV_TCP, idle_handle is for UV_TCP_SINGLE_ACCEPT handles */ -#define UV_TCP_PRIVATE_FIELDS \ - uv_idle_t* idle_handle; \ - - -/* UV_UDP */ -#define UV_UDP_PRIVATE_FIELDS \ - int fd; \ - uv_alloc_cb alloc_cb; \ - uv_udp_recv_cb recv_cb; \ - uv__io_t read_watcher; \ - uv__io_t write_watcher; \ - ngx_queue_t write_queue; \ - ngx_queue_t write_completed_queue; \ +#define UV_CONNECT_PRIVATE_FIELDS \ + ngx_queue_t queue; \ +#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ -/* UV_NAMED_PIPE */ -#define UV_PIPE_PRIVATE_FIELDS \ +#define UV_UDP_SEND_PRIVATE_FIELDS \ + ngx_queue_t queue; \ + struct sockaddr_in6 addr; \ + int bufcnt; \ + uv_buf_t* bufs; \ + ssize_t status; \ + uv_udp_send_cb send_cb; \ + uv_buf_t bufsml[4]; \ + +#define UV_HANDLE_PRIVATE_FIELDS \ + int flags; \ + uv_handle_t* next_closing; \ + +#define UV_STREAM_PRIVATE_FIELDS \ + uv_connect_t *connect_req; \ + uv_shutdown_t *shutdown_req; \ + uv__io_t read_watcher; \ + uv__io_t write_watcher; \ + ngx_queue_t write_queue; \ + ngx_queue_t write_completed_queue; \ + uv_connection_cb connection_cb; \ + int delayed_error; \ + int accepted_fd; \ + int fd; \ + +#define UV_TCP_PRIVATE_FIELDS \ + uv_idle_t* idle_handle; /* for UV_TCP_SINGLE_ACCEPT handles */ \ + +#define UV_UDP_PRIVATE_FIELDS \ + int fd; \ + uv_alloc_cb alloc_cb; \ + uv_udp_recv_cb recv_cb; \ + uv__io_t read_watcher; \ + uv__io_t write_watcher; \ + ngx_queue_t write_queue; \ + ngx_queue_t write_completed_queue; \ + +#define UV_PIPE_PRIVATE_FIELDS \ const char* pipe_fname; /* strdup'ed */ - -/* UV_POLL */ -#define UV_POLL_PRIVATE_FIELDS \ - int fd; \ +#define UV_POLL_PRIVATE_FIELDS \ + int fd; \ uv__io_t io_watcher; - -/* UV_PREPARE */ -#define UV_PREPARE_PRIVATE_FIELDS \ - uv_prepare_cb prepare_cb; \ +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_cb prepare_cb; \ ngx_queue_t queue; - -/* UV_CHECK */ -#define UV_CHECK_PRIVATE_FIELDS \ - uv_check_cb check_cb; \ +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_cb check_cb; \ ngx_queue_t queue; - -/* UV_IDLE */ -#define UV_IDLE_PRIVATE_FIELDS \ - uv_idle_cb idle_cb; \ +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_cb idle_cb; \ ngx_queue_t queue; - -/* UV_ASYNC */ #define UV_ASYNC_PRIVATE_FIELDS \ volatile sig_atomic_t pending; \ uv_async_cb async_cb; \ ngx_queue_t queue; - -/* UV_TIMER */ #define UV_TIMER_PRIVATE_FIELDS \ /* RB_ENTRY(uv_timer_s) node; */ \ struct { \ @@ -249,66 +227,35 @@ struct uv__io_s { uint64_t timeout; \ uint64_t repeat; -#define UV_GETADDRINFO_PRIVATE_FIELDS \ - uv_getaddrinfo_cb cb; \ - struct addrinfo* hints; \ - char* hostname; \ - char* service; \ - struct addrinfo* res; \ +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + uv_getaddrinfo_cb cb; \ + struct addrinfo* hints; \ + char* hostname; \ + char* service; \ + struct addrinfo* res; \ int retcode; -#define UV_PROCESS_PRIVATE_FIELDS \ - ev_child child_watcher; +#define UV_PROCESS_PRIVATE_FIELDS \ + ngx_queue_t queue; \ + int errorno; \ -#define UV_FS_PRIVATE_FIELDS \ - struct stat statbuf; \ - eio_req* eio; +#define UV_FS_PRIVATE_FIELDS \ + struct stat statbuf; \ + uv_file file; \ + eio_req* eio; \ -#define UV_WORK_PRIVATE_FIELDS \ +#define UV_WORK_PRIVATE_FIELDS \ eio_req* eio; -#define UV_TTY_PRIVATE_FIELDS \ - struct termios orig_termios; \ +#define UV_TTY_PRIVATE_FIELDS \ + struct termios orig_termios; \ int mode; -/* UV_FS_EVENT_PRIVATE_FIELDS */ -#if defined(__linux__) - -#define UV_FS_EVENT_PRIVATE_FIELDS \ - ngx_queue_t watchers; \ - uv_fs_event_cb cb; \ - int wd; \ - void* pad0; \ - void* pad1; \ - -#elif defined(__APPLE__) \ - || defined(__FreeBSD__) \ - || defined(__DragonFly__) \ - || defined(__OpenBSD__) \ - || defined(__NetBSD__) - -#define UV_FS_EVENT_PRIVATE_FIELDS \ - ev_io event_watcher; \ - uv_fs_event_cb cb; \ - int fflags; \ - int fd; - -#elif defined(__sun) - -#ifdef PORT_SOURCE_FILE -# define UV_FS_EVENT_PRIVATE_FIELDS \ - uv_fs_event_cb cb; \ - file_obj_t fo; \ - int fd; -#else /* !PORT_SOURCE_FILE */ -# define UV_FS_EVENT_PRIVATE_FIELDS -#endif - -#else - -/* Stub for platforms where the file watcher isn't implemented yet. */ -#define UV_FS_EVENT_PRIVATE_FIELDS +#define UV_SIGNAL_PRIVATE_FIELDS \ + ngx_queue_t queue; -#endif +#define UV_FS_EVENT_PRIVATE_FIELDS \ + uv_fs_event_cb cb; \ + UV_PLATFORM_FS_EVENT_FIELDS \ #endif /* UV_UNIX_H */ diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 5b0aba6..dbbeced 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -29,12 +29,14 @@ typedef intptr_t ssize_t; # define _SSIZE_T_DEFINED #endif -#include -#include #include #include #include #include + +#include +#include +#include #include #include "tree.h" @@ -43,32 +45,50 @@ typedef intptr_t ssize_t; #define MAX_PIPENAME_LEN 256 #ifndef S_IFLNK -# define S_IFLNK 0xA000 +# define S_IFLNK 0xA000 #endif +/* Additional signals supported by uv_signal and or uv_kill. The CRT defines + * the following signals already: + * + * #define SIGINT 2 + * #define SIGILL 4 + * #define SIGABRT_COMPAT 6 + * #define SIGFPE 8 + * #define SIGSEGV 11 + * #define SIGTERM 15 + * #define SIGBREAK 21 + * #define SIGABRT 22 + * + * The additional signals have values that are common on other Unix + * variants (Linux and Darwin) + */ +#define SIGHUP 1 +#define SIGKILL 9 + /* * Guids and typedefs for winsock extension functions * Mingw32 doesn't have these :-( */ #ifndef WSAID_ACCEPTEX -# define WSAID_ACCEPTEX \ - {0xb5367df1, 0xcbac, 0x11cf, \ +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} -# define WSAID_CONNECTEX \ - {0x25a207b9, 0xddf3, 0x4660, \ +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} -# define WSAID_GETACCEPTEXSOCKADDRS \ - {0xb5367df2, 0xcbac, 0x11cf, \ +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} -# define WSAID_DISCONNECTEX \ - {0x7fda2e11, 0x8630, 0x436f, \ +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} -# define WSAID_TRANSMITFILE \ - {0xb5367df0, 0xcbac, 0x11cf, \ +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} typedef BOOL PASCAL (*LPFN_ACCEPTEX) @@ -246,272 +266,281 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); /* Counter to keep track of active udp streams */ \ unsigned int active_udp_streams; -#define UV_REQ_TYPE_PRIVATE \ - /* TODO: remove the req suffix */ \ - UV_ACCEPT, \ - UV_FS_EVENT_REQ, \ - UV_POLL_REQ, \ - UV_PROCESS_EXIT, \ - UV_PROCESS_CLOSE, \ - UV_READ, \ - UV_UDP_RECV, \ - UV_WAKEUP, - -#define UV_REQ_PRIVATE_FIELDS \ - union { \ - /* Used by I/O operations */ \ - struct { \ - OVERLAPPED overlapped; \ - size_t queued_bytes; \ - }; \ - }; \ +#define UV_REQ_TYPE_PRIVATE \ + /* TODO: remove the req suffix */ \ + UV_ACCEPT, \ + UV_FS_EVENT_REQ, \ + UV_POLL_REQ, \ + UV_PROCESS_EXIT, \ + UV_READ, \ + UV_UDP_RECV, \ + UV_WAKEUP, \ + UV_SIGNAL_REQ, + +#define UV_REQ_PRIVATE_FIELDS \ + union { \ + /* Used by I/O operations */ \ + struct { \ + OVERLAPPED overlapped; \ + size_t queued_bytes; \ + }; \ + }; \ struct uv_req_s* next_req; -#define UV_WRITE_PRIVATE_FIELDS \ - int ipc_header; \ - uv_buf_t write_buffer; \ - HANDLE event_handle; \ +#define UV_WRITE_PRIVATE_FIELDS \ + int ipc_header; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ HANDLE wait_handle; -#define UV_CONNECT_PRIVATE_FIELDS \ +#define UV_CONNECT_PRIVATE_FIELDS \ /* empty */ -#define UV_SHUTDOWN_PRIVATE_FIELDS \ +#define UV_SHUTDOWN_PRIVATE_FIELDS \ /* empty */ -#define UV_UDP_SEND_PRIVATE_FIELDS \ +#define UV_UDP_SEND_PRIVATE_FIELDS \ /* empty */ -#define UV_PRIVATE_REQ_TYPES \ - typedef struct uv_pipe_accept_s { \ - UV_REQ_FIELDS \ - HANDLE pipeHandle; \ - struct uv_pipe_accept_s* next_pending; \ - } uv_pipe_accept_t; \ - \ - typedef struct uv_tcp_accept_s { \ - UV_REQ_FIELDS \ - SOCKET accept_socket; \ - char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ - HANDLE event_handle; \ - HANDLE wait_handle; \ - struct uv_tcp_accept_s* next_pending; \ - } uv_tcp_accept_t; \ - \ - typedef struct uv_read_s { \ - UV_REQ_FIELDS \ - HANDLE event_handle; \ - HANDLE wait_handle; \ +#define UV_PRIVATE_REQ_TYPES \ + typedef struct uv_pipe_accept_s { \ + UV_REQ_FIELDS \ + HANDLE pipeHandle; \ + struct uv_pipe_accept_s* next_pending; \ + } uv_pipe_accept_t; \ + \ + typedef struct uv_tcp_accept_s { \ + UV_REQ_FIELDS \ + SOCKET accept_socket; \ + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + struct uv_tcp_accept_s* next_pending; \ + } uv_tcp_accept_t; \ + \ + typedef struct uv_read_s { \ + UV_REQ_FIELDS \ + HANDLE event_handle; \ + HANDLE wait_handle; \ } uv_read_t; -#define uv_stream_connection_fields \ - unsigned int write_reqs_pending; \ +#define uv_stream_connection_fields \ + unsigned int write_reqs_pending; \ uv_shutdown_t* shutdown_req; -#define uv_stream_server_fields \ +#define uv_stream_server_fields \ uv_connection_cb connection_cb; -#define UV_STREAM_PRIVATE_FIELDS \ - unsigned int reqs_pending; \ - int activecnt; \ - uv_read_t read_req; \ - union { \ - struct { uv_stream_connection_fields }; \ - struct { uv_stream_server_fields }; \ +#define UV_STREAM_PRIVATE_FIELDS \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_read_t read_req; \ + union { \ + struct { uv_stream_connection_fields }; \ + struct { uv_stream_server_fields }; \ }; -#define uv_tcp_server_fields \ - uv_tcp_accept_t* accept_reqs; \ - unsigned int processed_accepts; \ - uv_tcp_accept_t* pending_accepts; \ +#define uv_tcp_server_fields \ + uv_tcp_accept_t* accept_reqs; \ + unsigned int processed_accepts; \ + uv_tcp_accept_t* pending_accepts; \ LPFN_ACCEPTEX func_acceptex; -#define uv_tcp_connection_fields \ - uv_buf_t read_buffer; \ +#define uv_tcp_connection_fields \ + uv_buf_t read_buffer; \ LPFN_CONNECTEX func_connectex; -#define UV_TCP_PRIVATE_FIELDS \ - SOCKET socket; \ - int bind_error; \ - union { \ - struct { uv_tcp_server_fields }; \ - struct { uv_tcp_connection_fields }; \ +#define UV_TCP_PRIVATE_FIELDS \ + SOCKET socket; \ + int bind_error; \ + union { \ + struct { uv_tcp_server_fields }; \ + struct { uv_tcp_connection_fields }; \ }; -#define UV_UDP_PRIVATE_FIELDS \ - SOCKET socket; \ - unsigned int reqs_pending; \ - int activecnt; \ - uv_req_t recv_req; \ - uv_buf_t recv_buffer; \ - struct sockaddr_storage recv_from; \ - int recv_from_len; \ - uv_udp_recv_cb recv_cb; \ - uv_alloc_cb alloc_cb; \ - LPFN_WSARECV func_wsarecv; \ +#define UV_UDP_PRIVATE_FIELDS \ + SOCKET socket; \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_req_t recv_req; \ + uv_buf_t recv_buffer; \ + struct sockaddr_storage recv_from; \ + int recv_from_len; \ + uv_udp_recv_cb recv_cb; \ + uv_alloc_cb alloc_cb; \ + LPFN_WSARECV func_wsarecv; \ LPFN_WSARECVFROM func_wsarecvfrom; -#define uv_pipe_server_fields \ - int pending_instances; \ - uv_pipe_accept_t* accept_reqs; \ +#define uv_pipe_server_fields \ + int pending_instances; \ + uv_pipe_accept_t* accept_reqs; \ uv_pipe_accept_t* pending_accepts; -#define uv_pipe_connection_fields \ - uv_timer_t* eof_timer; \ - uv_write_t ipc_header_write_req; \ - int ipc_pid; \ - uint64_t remaining_ipc_rawdata_bytes; \ - unsigned char reserved[sizeof(void*)]; \ - struct { \ - WSAPROTOCOL_INFOW* socket_info; \ - int tcp_connection; \ - } pending_ipc_info; \ +#define uv_pipe_connection_fields \ + uv_timer_t* eof_timer; \ + uv_write_t ipc_header_write_req; \ + int ipc_pid; \ + uint64_t remaining_ipc_rawdata_bytes; \ + unsigned char reserved[sizeof(void*)]; \ + struct { \ + WSAPROTOCOL_INFOW* socket_info; \ + int tcp_connection; \ + } pending_ipc_info; \ uv_write_t* non_overlapped_writes_tail; -#define UV_PIPE_PRIVATE_FIELDS \ - HANDLE handle; \ - wchar_t* name; \ - union { \ - struct { uv_pipe_server_fields }; \ - struct { uv_pipe_connection_fields }; \ +#define UV_PIPE_PRIVATE_FIELDS \ + HANDLE handle; \ + WCHAR* name; \ + union { \ + struct { uv_pipe_server_fields }; \ + struct { uv_pipe_connection_fields }; \ }; /* TODO: put the parser states in an union - TTY handles are always */ /* half-duplex so read-state can safely overlap write-state. */ -#define UV_TTY_PRIVATE_FIELDS \ - HANDLE handle; \ - HANDLE read_line_handle; \ - uv_buf_t read_line_buffer; \ - HANDLE read_raw_wait; \ - DWORD original_console_mode; \ - /* Fields used for translating win */ \ - /* keystrokes into vt100 characters */ \ - char last_key[8]; \ - unsigned char last_key_offset; \ - unsigned char last_key_len; \ - INPUT_RECORD last_input_record; \ - WCHAR last_utf16_high_surrogate; \ - /* utf8-to-utf16 conversion state */ \ - unsigned char utf8_bytes_left; \ - unsigned int utf8_codepoint; \ - /* eol conversion state */ \ - unsigned char previous_eol; \ - /* ansi parser state */ \ - unsigned char ansi_parser_state; \ - unsigned char ansi_csi_argc; \ - unsigned short ansi_csi_argv[4]; \ - COORD saved_position; \ - WORD saved_attributes; - -#define UV_POLL_PRIVATE_FIELDS \ - SOCKET socket; \ - /* Used in fast mode */ \ - SOCKET peer_socket; \ - AFD_POLL_INFO afd_poll_info_1; \ - AFD_POLL_INFO afd_poll_info_2; \ - /* Used in fast and slow mode. */ \ - uv_req_t poll_req_1; \ - uv_req_t poll_req_2; \ - unsigned char submitted_events_1; \ - unsigned char submitted_events_2; \ - unsigned char mask_events_1; \ - unsigned char mask_events_2; \ +#define UV_TTY_PRIVATE_FIELDS \ + HANDLE handle; \ + union { \ + struct { \ + /* Used for readable TTY handles */ \ + HANDLE read_line_handle; \ + uv_buf_t read_line_buffer; \ + HANDLE read_raw_wait; \ + DWORD original_console_mode; \ + /* Fields used for translating win keystrokes into vt100 characters */ \ + char last_key[8]; \ + unsigned char last_key_offset; \ + unsigned char last_key_len; \ + WCHAR last_utf16_high_surrogate; \ + INPUT_RECORD last_input_record; \ + }; \ + struct { \ + /* Used for writable TTY handles */ \ + /* utf8-to-utf16 conversion state */ \ + unsigned int utf8_codepoint; \ + unsigned char utf8_bytes_left; \ + /* eol conversion state */ \ + unsigned char previous_eol; \ + /* ansi parser state */ \ + unsigned char ansi_parser_state; \ + unsigned char ansi_csi_argc; \ + unsigned short ansi_csi_argv[4]; \ + COORD saved_position; \ + WORD saved_attributes; \ + }; \ + }; + +#define UV_POLL_PRIVATE_FIELDS \ + SOCKET socket; \ + /* Used in fast mode */ \ + SOCKET peer_socket; \ + AFD_POLL_INFO afd_poll_info_1; \ + AFD_POLL_INFO afd_poll_info_2; \ + /* Used in fast and slow mode. */ \ + uv_req_t poll_req_1; \ + uv_req_t poll_req_2; \ + unsigned char submitted_events_1; \ + unsigned char submitted_events_2; \ + unsigned char mask_events_1; \ + unsigned char mask_events_2; \ unsigned char events; -#define UV_TIMER_PRIVATE_FIELDS \ - RB_ENTRY(uv_timer_s) tree_entry; \ - int64_t due; \ - int64_t repeat; \ +#define UV_TIMER_PRIVATE_FIELDS \ + RB_ENTRY(uv_timer_s) tree_entry; \ + int64_t due; \ + int64_t repeat; \ uv_timer_cb timer_cb; -#define UV_ASYNC_PRIVATE_FIELDS \ - struct uv_req_s async_req; \ - uv_async_cb async_cb; \ - /* char to avoid alignment issues */ \ +#define UV_ASYNC_PRIVATE_FIELDS \ + struct uv_req_s async_req; \ + uv_async_cb async_cb; \ + /* char to avoid alignment issues */ \ char volatile async_sent; -#define UV_PREPARE_PRIVATE_FIELDS \ - uv_prepare_t* prepare_prev; \ - uv_prepare_t* prepare_next; \ +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_t* prepare_prev; \ + uv_prepare_t* prepare_next; \ uv_prepare_cb prepare_cb; -#define UV_CHECK_PRIVATE_FIELDS \ - uv_check_t* check_prev; \ - uv_check_t* check_next; \ +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_t* check_prev; \ + uv_check_t* check_next; \ uv_check_cb check_cb; -#define UV_IDLE_PRIVATE_FIELDS \ - uv_idle_t* idle_prev; \ - uv_idle_t* idle_next; \ +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_t* idle_prev; \ + uv_idle_t* idle_next; \ uv_idle_cb idle_cb; -#define UV_HANDLE_PRIVATE_FIELDS \ - uv_handle_t* endgame_next; \ +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* endgame_next; \ unsigned int flags; -#define UV_GETADDRINFO_PRIVATE_FIELDS \ - uv_getaddrinfo_cb getaddrinfo_cb; \ - void* alloc; \ - wchar_t* node; \ - wchar_t* service; \ - struct addrinfoW* hints; \ - struct addrinfoW* res; \ +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + uv_getaddrinfo_cb getaddrinfo_cb; \ + void* alloc; \ + WCHAR* node; \ + WCHAR* service; \ + struct addrinfoW* hints; \ + struct addrinfoW* res; \ int retcode; -#define UV_PROCESS_PRIVATE_FIELDS \ - struct uv_process_exit_s { \ - UV_REQ_FIELDS \ - } exit_req; \ - struct uv_process_close_s { \ - UV_REQ_FIELDS \ - } close_req; \ - BYTE* child_stdio_buffer; \ - int exit_signal; \ - DWORD spawn_errno; \ - HANDLE wait_handle; \ - HANDLE process_handle; \ - HANDLE close_handle; - -#define UV_FS_PRIVATE_FIELDS \ - int flags; \ - DWORD sys_errno_; \ - union { \ - /* TODO: remove me in 0.9. */ \ - WCHAR* pathw; \ - int fd; \ - }; \ - union { \ - struct { \ - int mode; \ - WCHAR* new_pathw; \ - int file_flags; \ - int fd_out; \ - void* buf; \ - size_t length; \ - int64_t offset; \ - }; \ - struct _stati64 stat; \ - struct { \ - double atime; \ - double mtime; \ - }; \ +#define UV_PROCESS_PRIVATE_FIELDS \ + struct uv_process_exit_s { \ + UV_REQ_FIELDS \ + } exit_req; \ + BYTE* child_stdio_buffer; \ + uv_err_t spawn_error; \ + int exit_signal; \ + HANDLE wait_handle; \ + HANDLE process_handle; \ + volatile char exit_cb_pending; + +#define UV_FS_PRIVATE_FIELDS \ + int flags; \ + DWORD sys_errno_; \ + union { \ + /* TODO: remove me in 0.9. */ \ + WCHAR* pathw; \ + int fd; \ + }; \ + union { \ + struct { \ + int mode; \ + WCHAR* new_pathw; \ + int file_flags; \ + int fd_out; \ + void* buf; \ + size_t length; \ + int64_t offset; \ + }; \ + struct _stati64 stat; \ + struct { \ + double atime; \ + double mtime; \ + }; \ }; -#define UV_WORK_PRIVATE_FIELDS \ - -#define UV_FS_EVENT_PRIVATE_FIELDS \ - struct uv_fs_event_req_s { \ - UV_REQ_FIELDS \ - } req; \ - HANDLE dir_handle; \ - int req_pending; \ - uv_fs_event_cb cb; \ - wchar_t* filew; \ - wchar_t* short_filew; \ - wchar_t* dirw; \ +#define UV_WORK_PRIVATE_FIELDS \ + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + struct uv_fs_event_req_s { \ + UV_REQ_FIELDS \ + } req; \ + HANDLE dir_handle; \ + int req_pending; \ + uv_fs_event_cb cb; \ + WCHAR* filew; \ + WCHAR* short_filew; \ + WCHAR* dirw; \ char* buffer; -int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, +#define UV_SIGNAL_PRIVATE_FIELDS \ + RB_ENTRY(uv_signal_s) tree_entry; \ + struct uv_req_s signal_req; \ + unsigned long pending_signum; + +int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size); -int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, +int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, size_t utf16Size); diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 19fa6e0..66ee41c 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -19,7 +19,7 @@ * IN THE SOFTWARE. */ -/* See uv_loop_new for an introduction. */ +/* See http://nikhilm.github.com/uvbook/ for an introduction. */ #ifndef UV_H #define UV_H @@ -53,6 +53,10 @@ extern "C" { #include /* int64_t */ #include /* size_t */ +#if defined(__SVR4) && !defined(__unix__) +# define __unix__ +#endif + #if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) # include "uv-private/uv-unix.h" #else @@ -60,64 +64,64 @@ extern "C" { #endif /* Expand this list if necessary. */ -#define UV_ERRNO_MAP(XX) \ - XX( -1, UNKNOWN, "unknown error") \ - XX( 0, OK, "success") \ - XX( 1, EOF, "end of file") \ - XX( 2, EADDRINFO, "getaddrinfo error") \ - XX( 3, EACCES, "permission denied") \ - XX( 4, EAGAIN, "no more processes") \ - XX( 5, EADDRINUSE, "address already in use") \ - XX( 6, EADDRNOTAVAIL, "") \ - XX( 7, EAFNOSUPPORT, "") \ - XX( 8, EALREADY, "") \ - XX( 9, EBADF, "bad file descriptor") \ - XX( 10, EBUSY, "resource busy or locked") \ - XX( 11, ECONNABORTED, "software caused connection abort") \ - XX( 12, ECONNREFUSED, "connection refused") \ - XX( 13, ECONNRESET, "connection reset by peer") \ - XX( 14, EDESTADDRREQ, "destination address required") \ - XX( 15, EFAULT, "bad address in system call argument") \ - XX( 16, EHOSTUNREACH, "host is unreachable") \ - XX( 17, EINTR, "interrupted system call") \ - XX( 18, EINVAL, "invalid argument") \ - XX( 19, EISCONN, "socket is already connected") \ - XX( 20, EMFILE, "too many open files") \ - XX( 21, EMSGSIZE, "message too long") \ - XX( 22, ENETDOWN, "network is down") \ - XX( 23, ENETUNREACH, "network is unreachable") \ - XX( 24, ENFILE, "file table overflow") \ - XX( 25, ENOBUFS, "no buffer space available") \ - XX( 26, ENOMEM, "not enough memory") \ - XX( 27, ENOTDIR, "not a directory") \ - XX( 28, EISDIR, "illegal operation on a directory") \ - XX( 29, ENONET, "machine is not on the network") \ - XX( 31, ENOTCONN, "socket is not connected") \ - XX( 32, ENOTSOCK, "socket operation on non-socket") \ - XX( 33, ENOTSUP, "operation not supported on socket") \ - XX( 34, ENOENT, "no such file or directory") \ - XX( 35, ENOSYS, "function not implemented") \ - XX( 36, EPIPE, "broken pipe") \ - XX( 37, EPROTO, "protocol error") \ - XX( 38, EPROTONOSUPPORT, "protocol not supported") \ - XX( 39, EPROTOTYPE, "protocol wrong type for socket") \ - XX( 40, ETIMEDOUT, "connection timed out") \ - XX( 41, ECHARSET, "") \ - XX( 42, EAIFAMNOSUPPORT, "") \ - XX( 44, EAISERVICE, "") \ - XX( 45, EAISOCKTYPE, "") \ - XX( 46, ESHUTDOWN, "") \ - XX( 47, EEXIST, "file already exists") \ - XX( 48, ESRCH, "no such process") \ - XX( 49, ENAMETOOLONG, "name too long") \ - XX( 50, EPERM, "operation not permitted") \ - XX( 51, ELOOP, "too many symbolic links encountered") \ - XX( 52, EXDEV, "cross-device link not permitted") \ - XX( 53, ENOTEMPTY, "directory not empty") \ - XX( 54, ENOSPC, "no space left on device") \ - XX( 55, EIO, "i/o error") \ - XX( 56, EROFS, "read-only file system" ) \ - XX( 57, ENODEV, "no such device" ) \ +#define UV_ERRNO_MAP(XX) \ + XX( -1, UNKNOWN, "unknown error") \ + XX( 0, OK, "success") \ + XX( 1, EOF, "end of file") \ + XX( 2, EADDRINFO, "getaddrinfo error") \ + XX( 3, EACCES, "permission denied") \ + XX( 4, EAGAIN, "no more processes") \ + XX( 5, EADDRINUSE, "address already in use") \ + XX( 6, EADDRNOTAVAIL, "") \ + XX( 7, EAFNOSUPPORT, "") \ + XX( 8, EALREADY, "") \ + XX( 9, EBADF, "bad file descriptor") \ + XX( 10, EBUSY, "resource busy or locked") \ + XX( 11, ECONNABORTED, "software caused connection abort") \ + XX( 12, ECONNREFUSED, "connection refused") \ + XX( 13, ECONNRESET, "connection reset by peer") \ + XX( 14, EDESTADDRREQ, "destination address required") \ + XX( 15, EFAULT, "bad address in system call argument") \ + XX( 16, EHOSTUNREACH, "host is unreachable") \ + XX( 17, EINTR, "interrupted system call") \ + XX( 18, EINVAL, "invalid argument") \ + XX( 19, EISCONN, "socket is already connected") \ + XX( 20, EMFILE, "too many open files") \ + XX( 21, EMSGSIZE, "message too long") \ + XX( 22, ENETDOWN, "network is down") \ + XX( 23, ENETUNREACH, "network is unreachable") \ + XX( 24, ENFILE, "file table overflow") \ + XX( 25, ENOBUFS, "no buffer space available") \ + XX( 26, ENOMEM, "not enough memory") \ + XX( 27, ENOTDIR, "not a directory") \ + XX( 28, EISDIR, "illegal operation on a directory") \ + XX( 29, ENONET, "machine is not on the network") \ + XX( 31, ENOTCONN, "socket is not connected") \ + XX( 32, ENOTSOCK, "socket operation on non-socket") \ + XX( 33, ENOTSUP, "operation not supported on socket") \ + XX( 34, ENOENT, "no such file or directory") \ + XX( 35, ENOSYS, "function not implemented") \ + XX( 36, EPIPE, "broken pipe") \ + XX( 37, EPROTO, "protocol error") \ + XX( 38, EPROTONOSUPPORT, "protocol not supported") \ + XX( 39, EPROTOTYPE, "protocol wrong type for socket") \ + XX( 40, ETIMEDOUT, "connection timed out") \ + XX( 41, ECHARSET, "") \ + XX( 42, EAIFAMNOSUPPORT, "") \ + XX( 44, EAISERVICE, "") \ + XX( 45, EAISOCKTYPE, "") \ + XX( 46, ESHUTDOWN, "") \ + XX( 47, EEXIST, "file already exists") \ + XX( 48, ESRCH, "no such process") \ + XX( 49, ENAMETOOLONG, "name too long") \ + XX( 50, EPERM, "operation not permitted") \ + XX( 51, ELOOP, "too many symbolic links encountered") \ + XX( 52, EXDEV, "cross-device link not permitted") \ + XX( 53, ENOTEMPTY, "directory not empty") \ + XX( 54, ENOSPC, "no space left on device") \ + XX( 55, EIO, "i/o error") \ + XX( 56, EROFS, "read-only file system" ) \ + XX( 57, ENODEV, "no such device" ) \ XX( 58, ECANCELED, "operation canceled" ) @@ -128,29 +132,30 @@ typedef enum { } uv_err_code; #undef UV_ERRNO_GEN -#define UV_HANDLE_TYPE_MAP(XX) \ - XX(ASYNC, async) \ - XX(CHECK, check) \ - XX(FS_EVENT, fs_event) \ - XX(FS_POLL, fs_poll) \ - XX(IDLE, idle) \ - XX(NAMED_PIPE, pipe) \ - XX(POLL, poll) \ - XX(PREPARE, prepare) \ - XX(PROCESS, process) \ - XX(TCP, tcp) \ - XX(TIMER, timer) \ - XX(TTY, tty) \ - XX(UDP, udp) \ - -#define UV_REQ_TYPE_MAP(XX) \ - XX(CONNECT, connect) \ - XX(WRITE, write) \ - XX(SHUTDOWN, shutdown) \ - XX(UDP_SEND, udp_send) \ - XX(FS, fs) \ - XX(WORK, work) \ - XX(GETADDRINFO, getaddrinfo) \ +#define UV_HANDLE_TYPE_MAP(XX) \ + XX(ASYNC, async) \ + XX(CHECK, check) \ + XX(FS_EVENT, fs_event) \ + XX(FS_POLL, fs_poll) \ + XX(IDLE, idle) \ + XX(NAMED_PIPE, pipe) \ + XX(POLL, poll) \ + XX(PREPARE, prepare) \ + XX(PROCESS, process) \ + XX(TCP, tcp) \ + XX(TIMER, timer) \ + XX(TTY, tty) \ + XX(UDP, udp) \ + XX(SIGNAL, signal) \ + +#define UV_REQ_TYPE_MAP(XX) \ + XX(CONNECT, connect) \ + XX(WRITE, write) \ + XX(SHUTDOWN, shutdown) \ + XX(UDP_SEND, udp_send) \ + XX(FS, fs) \ + XX(WORK, work) \ + XX(GETADDRINFO, getaddrinfo) \ typedef enum { UV_UNKNOWN_HANDLE = 0, @@ -189,6 +194,7 @@ typedef struct uv_async_s uv_async_t; typedef struct uv_process_s uv_process_t; typedef struct uv_fs_event_s uv_fs_event_t; typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; /* Request types. */ typedef struct uv_req_s uv_req_t; @@ -312,6 +318,9 @@ typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, const uv_statbuf_t* prev, const uv_statbuf_t* curr); +typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum); + + typedef enum { UV_LEAVE_GROUP = 0, UV_JOIN_GROUP @@ -336,14 +345,14 @@ UV_EXTERN const char* uv_strerror(uv_err_t err); UV_EXTERN const char* uv_err_name(uv_err_t err); -#define UV_REQ_FIELDS \ - /* public */ \ - void* data; \ - /* private */ \ - ngx_queue_t active_queue; \ - UV_REQ_PRIVATE_FIELDS \ - /* read-only */ \ - uv_req_type type; \ +#define UV_REQ_FIELDS \ + /* public */ \ + void* data; \ + /* private */ \ + ngx_queue_t active_queue; \ + UV_REQ_PRIVATE_FIELDS \ + /* read-only */ \ + uv_req_type type; \ /* Abstract base class of all requests. */ struct uv_req_s { @@ -454,13 +463,13 @@ UV_EXTERN size_t uv_strlcpy(char* dst, const char* src, size_t size); UV_EXTERN size_t uv_strlcat(char* dst, const char* src, size_t size); -#define UV_STREAM_FIELDS \ - /* number of bytes queued for writing */ \ - size_t write_queue_size; \ - uv_alloc_cb alloc_cb; \ - uv_read_cb read_cb; \ - uv_read2_cb read2_cb; \ - /* private */ \ +#define UV_STREAM_FIELDS \ + /* number of bytes queued for writing */ \ + size_t write_queue_size; \ + uv_alloc_cb alloc_cb; \ + uv_read_cb read_cb; \ + uv_read2_cb read2_cb; \ + /* private */ \ UV_STREAM_PRIVATE_FIELDS /* @@ -1098,8 +1107,7 @@ UV_EXTERN int uv_async_send(uv_async_t* async); /* * uv_timer_t is a subclass of uv_handle_t. * - * Wraps libev's ev_timer watcher. Used to get woken up at a specified time - * in the future. + * Used to get woken up at a specified time in the future. */ struct uv_timer_s { UV_HANDLE_FIELDS @@ -1108,8 +1116,22 @@ struct uv_timer_s { UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* timer); -UV_EXTERN int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, - int64_t timeout, int64_t repeat); +/* + * Start the timer. `timeout` and `repeat` are in milliseconds. + * + * If timeout is zero, the callback fires on the next tick of the event loop. + * + * If repeat is non-zero, the callback fires first after timeout milliseconds + * and then repeatedly after repeat milliseconds. + * + * timeout and repeat are signed integers but that will change in a future + * version of libuv. Don't pass in negative values, you'll get a nasty surprise + * when that change becomes effective. + */ +UV_EXTERN int uv_timer_start(uv_timer_t* timer, + uv_timer_cb cb, + int64_t timeout, + int64_t repeat); UV_EXTERN int uv_timer_stop(uv_timer_t* timer); @@ -1121,10 +1143,10 @@ UV_EXTERN int uv_timer_stop(uv_timer_t* timer); 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 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. + * Set the repeat value in milliseconds. Note that if the repeat value is set + * from a timer 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. */ UV_EXTERN void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat); @@ -1529,14 +1551,17 @@ struct uv_fs_event_s { struct uv_fs_poll_s { UV_HANDLE_FIELDS /* Private, don't touch. */ - int busy_polling; /* TODO(bnoordhuis) Fold into flags field. */ - unsigned int interval; - uint64_t start_time; - char* path; - uv_fs_poll_cb poll_cb; - uv_timer_t timer_handle; - uv_fs_t* fs_req; - uv_statbuf_t statbuf; + void* poll_ctx; + /* v0.8 ABI compatibility */ + char padding[sizeof(int) + + sizeof(unsigned int) + + sizeof(uint64_t) + + sizeof(char*) + + sizeof(uv_fs_poll_cb) + + sizeof(uv_timer_t) + + sizeof(uv_fs_t*) + + sizeof(uv_statbuf_t) + - sizeof(void*)]; }; UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle); @@ -1563,6 +1588,46 @@ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); + +/* + * UNIX signal handling on a per-event loop basis. The implementation is not + * ultra efficient so don't go creating a million event loops with a million + * signal watchers. + * + * TODO(bnoordhuis) As of 2012-08-10 only the default event loop supports + * signals. That will be fixed. + * + * Some signal support is available on Windows: + * + * SIGINT is normally delivered when the user presses CTRL+C. However, like + * on Unix, it is not generated when terminal raw mode is enabled. + * + * SIGBREAK is delivered when the user pressed CTRL+BREAK. + * + * SIGHUP is generated when the user closes the console window. On SIGHUP the + * program is given approximately 10 seconds to perform cleanup. After that + * Windows will unconditionally terminate it. + * + * Watchers for other signals can be successfully created, but these signals + * are never generated. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV, + * SIGTERM and SIGKILL. + * + * Note that calls to raise() or abort() to programmatically raise a signal are + * not detected by libuv; these will not trigger a signal watcher. + */ +struct uv_signal_s { + UV_HANDLE_FIELDS + uv_signal_cb signal_cb; + UV_SIGNAL_PRIVATE_FIELDS + int signum; +}; + +/* These functions are no-ops on Windows. */ +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum); +int uv_signal_stop(uv_signal_t* handle); + + /* * Gets load avg * See: http://en.wikipedia.org/wiki/Load_(computing) @@ -1772,8 +1837,6 @@ struct uv_counters_s { struct uv_loop_s { UV_LOOP_PRIVATE_FIELDS - /* Diagnostic counters */ - uv_counters_t counters; /* The last error */ uv_err_t last_err; /* Loop reference counting */ @@ -1800,6 +1863,7 @@ struct uv_loop_s { #undef UV_FS_REQ_PRIVATE_FIELDS #undef UV_WORK_PRIVATE_FIELDS #undef UV_FS_EVENT_PRIVATE_FIELDS +#undef UV_SIGNAL_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_PLATFORM_FIELDS diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 99d3bcf..c952dfc 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -26,24 +26,29 @@ #include #include +struct poll_ctx { + uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */ + int busy_polling; + unsigned int interval; + uint64_t start_time; + uv_loop_t* loop; + uv_fs_poll_cb poll_cb; + uv_timer_t timer_handle; + uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ + uv_statbuf_t statbuf; + char path[1]; /* variable length */ +}; + static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b); -static void timer_cb(uv_timer_t* timer, int status); static void poll_cb(uv_fs_t* req); +static void timer_cb(uv_timer_t* timer, int status); +static void timer_close_cb(uv_handle_t* handle); static uv_statbuf_t zero_statbuf; int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { - /* TODO(bnoordhuis) Mark fs_req internal. */ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); - loop->counters.fs_poll_init++; - - if (uv_timer_init(loop, &handle->timer_handle)) - return -1; - - handle->timer_handle.flags |= UV__HANDLE_INTERNAL; - uv__handle_unref(&handle->timer_handle); - return 0; } @@ -52,30 +57,37 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, uv_fs_poll_cb cb, const char* path, unsigned int interval) { - uv_fs_t* req; + struct poll_ctx* ctx; + uv_loop_t* loop; size_t len; if (uv__is_active(handle)) return 0; - len = strlen(path) + 1; - req = malloc(sizeof(*req) + len); + loop = handle->loop; + len = strlen(path); + ctx = calloc(1, sizeof(*ctx) + len); + + if (ctx == NULL) + return uv__set_artificial_error(loop, UV_ENOMEM); - if (req == NULL) - return uv__set_artificial_error(handle->loop, UV_ENOMEM); + ctx->loop = loop; + ctx->poll_cb = cb; + ctx->interval = interval ? interval : 1; + ctx->start_time = uv_now(loop); + ctx->parent_handle = handle; + memcpy(ctx->path, path, len + 1); - req->data = handle; - handle->path = memcpy(req + 1, path, len); - handle->fs_req = req; - handle->poll_cb = cb; - handle->interval = interval ? interval : 1; - handle->start_time = uv_now(handle->loop); - handle->busy_polling = 0; - memset(&handle->statbuf, 0, sizeof(handle->statbuf)); + if (uv_timer_init(loop, &ctx->timer_handle)) + abort(); + + ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&ctx->timer_handle); - if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb)) + if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb)) abort(); + handle->poll_ctx = ctx; uv__handle_start(handle); return 0; @@ -83,25 +95,19 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, int uv_fs_poll_stop(uv_fs_poll_t* handle) { + struct poll_ctx* ctx; + if (!uv__is_active(handle)) return 0; - /* Don't free the fs req if it's active. Signal poll_cb that it needs to free - * the req by removing the handle backlink. - * - * TODO(bnoordhuis) Have uv-unix postpone the close callback until the req - * finishes so we don't need this pointer / lifecycle hackery. The callback - * always runs on the next tick now. - */ - if (handle->fs_req->data) - handle->fs_req->data = NULL; - else - free(handle->fs_req); + ctx = handle->poll_ctx; + assert(ctx != NULL); + assert(ctx->parent_handle != NULL); - handle->fs_req = NULL; - handle->path = NULL; + ctx->parent_handle = NULL; + uv_timer_stop(&ctx->timer_handle); - uv_timer_stop(&handle->timer_handle); + handle->poll_ctx = NULL; uv__handle_stop(handle); return 0; @@ -110,73 +116,75 @@ int uv_fs_poll_stop(uv_fs_poll_t* handle) { void uv__fs_poll_close(uv_fs_poll_t* handle) { uv_fs_poll_stop(handle); - uv_close((uv_handle_t*)&handle->timer_handle, NULL); } static void timer_cb(uv_timer_t* timer, int status) { - uv_fs_poll_t* handle; + struct poll_ctx* ctx; - handle = container_of(timer, uv_fs_poll_t, timer_handle); - handle->start_time = uv_now(handle->loop); - handle->fs_req->data = handle; + ctx = container_of(timer, struct poll_ctx, timer_handle); - if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb)) - abort(); + if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + return; + } - assert(uv__is_active(handle)); + assert(ctx->parent_handle->poll_ctx == ctx); + ctx->start_time = uv_now(ctx->loop); + + if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb)) + abort(); } static void poll_cb(uv_fs_t* req) { uv_statbuf_t* statbuf; - uv_fs_poll_t* handle; + struct poll_ctx* ctx; uint64_t interval; - handle = req->data; - - if (handle == NULL) /* Handle has been stopped or closed. */ - goto out; + ctx = container_of(req, struct poll_ctx, fs_req); - assert(req == handle->fs_req); + if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + uv_fs_req_cleanup(req); + return; + } if (req->result != 0) { - if (handle->busy_polling != -req->errorno) { - uv__set_artificial_error(handle->loop, req->errorno); - handle->poll_cb(handle, -1, &handle->statbuf, &zero_statbuf); - handle->busy_polling = -req->errorno; + if (ctx->busy_polling != -req->errorno) { + uv__set_artificial_error(ctx->loop, req->errorno); + ctx->poll_cb(ctx->parent_handle, -1, &ctx->statbuf, &zero_statbuf); + ctx->busy_polling = -req->errorno; } goto out; } statbuf = req->ptr; - if (handle->busy_polling != 0) - if (handle->busy_polling < 0 || !statbuf_eq(&handle->statbuf, statbuf)) - handle->poll_cb(handle, 0, &handle->statbuf, statbuf); + if (ctx->busy_polling != 0) + if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf)) + ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf); - handle->statbuf = *statbuf; - handle->busy_polling = 1; + ctx->statbuf = *statbuf; + ctx->busy_polling = 1; out: uv_fs_req_cleanup(req); - if (req->data == NULL) { /* Handle has been stopped or closed. */ - free(req); - return; - } - - req->data = NULL; /* Tell uv_fs_poll_stop() it's safe to free the req. */ - /* Reschedule timer, subtract the delay from doing the stat(). */ - interval = handle->interval; - interval -= (uv_now(handle->loop) - handle->start_time) % interval; + interval = ctx->interval; + interval -= (uv_now(ctx->loop) - ctx->start_time) % interval; - if (uv_timer_start(&handle->timer_handle, timer_cb, interval, 0)) + if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0)) abort(); } +static void timer_close_cb(uv_handle_t* handle) { + free(container_of(handle, struct poll_ctx, timer_handle)); +} + + static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b) { #ifdef _WIN32 return a->st_mtime == b->st_mtime diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 192a361..6386c6d 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -65,8 +65,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { return uv__set_sys_error(loop, errno); uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); - loop->counters.async_init++; - handle->async_cb = async_cb; handle->pending = 0; diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 4bc6b77..7b26172 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -116,6 +116,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv__fs_poll_close((uv_fs_poll_t*)handle); break; + case UV_SIGNAL: + uv__signal_close((uv_signal_t*)handle); + break; + default: assert(0); } @@ -143,6 +147,7 @@ static void uv__finish_close(uv_handle_t* handle) { case UV_FS_EVENT: case UV_FS_POLL: case UV_POLL: + case UV_SIGNAL: break; case UV_NAMED_PIPE: diff --git a/deps/uv/src/unix/cygwin.c b/deps/uv/src/unix/cygwin.c index a99779d..8c0797e 100644 --- a/deps/uv/src/unix/cygwin.c +++ b/deps/uv/src/unix/cygwin.c @@ -32,10 +32,19 @@ #define NANOSEC ((uint64_t) 1e9) +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + uint64_t uv_hrtime() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * NANOSEC + ts.tv_nsec); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } void uv_loadavg(double avg[3]) { @@ -73,7 +82,6 @@ int uv_fs_event_init(uv_loop_t* loop, const char* filename, uv_fs_event_cb cb, int flags) { - loop->counters.fs_event_init++; uv__set_sys_error(loop, ENOSYS); return -1; } diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index cb45db0..b1586a3 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -43,6 +43,16 @@ static char *process_title; + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + #if TARGET_OS_IPHONE /* see: http://developer.apple.com/library/mac/#qa/qa1398/_index.html */ uint64_t uv_hrtime() { diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index be8006c..76f2793 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -54,10 +54,19 @@ static char *process_title; +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + uint64_t uv_hrtime(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * NANOSEC + ts.tv_nsec); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index e62832d..875f0b9 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -72,6 +72,7 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, req->result = 0; req->ptr = NULL; req->path = path ? strdup(path) : NULL; + req->file = -1; req->errorno = 0; req->eio = NULL; @@ -85,7 +86,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->cb) uv__req_unregister(req->loop, req); - free(req->path); + free((void*)req->path); req->path = NULL; switch (req->fs_type) { @@ -445,6 +446,20 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { } +#if defined(__APPLE__) && defined(F_FULLFSYNC) +ssize_t uv__fs_fdatasync(uv_file file) { + return fcntl(file, F_FULLFSYNC); +} + + +void uv__fs_fdatasync_work(eio_req* eio) { + uv_fs_t* req = eio->data; + + eio->result = uv__fs_fdatasync(req->file); +} +#endif + + int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { char* path = NULL; #if defined(__FreeBSD__) \ @@ -453,6 +468,31 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { * do a full fsync instead. */ WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fsync, ARGS1(file)) +#elif defined(__APPLE__) && defined(F_FULLFSYNC) + /* OSX >= 10.6 does have fdatasync, but better use fcntl anyway */ + uv_fs_req_init(loop, req, UV_FS_FDATASYNC, path, cb); + req->file = file; + + if (cb) { + /* async */ + req->eio = eio_custom(uv__fs_fdatasync_work, + EIO_PRI_DEFAULT, + uv__fs_after, + req, + &loop->uv_eio_channel); + if (req->eio == NULL) { + uv__set_sys_error(loop, ENOMEM); + return -1; + } + } else { + /* sync */ + req->result = uv__fs_fdatasync(file); + if (req->result) { + uv__set_sys_error(loop, errno); + } + return req->result; + } + return 0; #else WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fdatasync, ARGS1(file)) #endif diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 233f742..6e16b2c 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -82,7 +82,7 @@ #define UV__IO_WRITE EV_WRITE #define UV__IO_ERROR EV_ERROR -/* flags */ +/* handle flags */ enum { UV_CLOSING = 0x01, /* uv_close() called but not finished. */ UV_CLOSED = 0x02, /* close(2) finished. */ @@ -97,10 +97,14 @@ enum { UV_TCP_SINGLE_ACCEPT = 0x400 /* Only accept() when idle. */ }; +/* loop flags */ +enum { + UV_LOOP_EIO_INITIALIZED = 1 +}; + inline static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) { - loop->counters.req_init++; req->type = type; uv__req_register(loop, req); } @@ -153,6 +157,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); void uv__run_timers(uv_loop_t* loop); unsigned int uv__next_timeout(uv_loop_t* loop); +/* signal */ +void uv__signal_close(uv_signal_t* handle); +void uv__signal_unregister(uv_loop_t* loop); + +/* platform specific */ +int uv__platform_loop_init(uv_loop_t* loop, int default_loop); +void uv__platform_loop_delete(uv_loop_t* loop); + /* various */ void uv__async_close(uv_async_t* handle); void uv__check_close(uv_check_t* handle); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index ee1bbd1..be68b58 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -90,8 +90,6 @@ int uv_fs_event_init(uv_loop_t* loop, int flags) { int fd; - loop->counters.fs_event_init++; - /* We don't support any flags yet. */ assert(!flags); diff --git a/deps/uv/src/unix/linux/inotify.c b/deps/uv/src/unix/linux/inotify.c index 51ea996..3c29088 100644 --- a/deps/uv/src/unix/linux/inotify.c +++ b/deps/uv/src/unix/linux/inotify.c @@ -176,8 +176,6 @@ int uv_fs_event_init(uv_loop_t* loop, int events; int wd; - loop->counters.fs_event_init++; - /* We don't support any flags yet. */ assert(!flags); diff --git a/deps/uv/src/unix/linux/linux-core.c b/deps/uv/src/unix/linux/linux-core.c index 34f48a9..f20edd0 100644 --- a/deps/uv/src/unix/linux/linux-core.c +++ b/deps/uv/src/unix/linux/linux-core.c @@ -63,15 +63,31 @@ static struct { size_t len; } process_title; +static void read_models(unsigned int numcpus, uv_cpu_info_t* ci); +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); +static void read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static unsigned long read_cpufreq(unsigned int cpunum); + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + loop->inotify_watchers = NULL; + loop->inotify_fd = -1; + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher); + close(loop->inotify_fd); + loop->inotify_fd = -1; +} + -/* - * There's probably some way to get time from Linux than gettimeofday(). What - * it is, I don't know. - */ uint64_t uv_hrtime() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * NANOSEC + ts.tv_nsec); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } @@ -301,81 +317,163 @@ uv_err_t uv_uptime(double* uptime) { uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), - multiplier = ((uint64_t)1000L / ticks), cpuspeed; - int numcpus = 0, i = 0; - unsigned long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr; - char line[512], speedPath[256], model[512]; - FILE *fpStat = fopen("/proc/stat", "r"); - FILE *fpModel = fopen("/proc/cpuinfo", "r"); - FILE *fpSpeed; - uv_cpu_info_t* cpu_info; - - if (fpModel) { - while (fgets(line, 511, fpModel) != NULL) { - if (strncmp(line, "model name", 10) == 0) { - numcpus++; - if (numcpus == 1) { - char *p = strchr(line, ':') + 2; - strcpy(model, p); - model[strlen(model)-1] = 0; - } - } else if (strncmp(line, "cpu MHz", 7) == 0) { - if (numcpus == 1) { - sscanf(line, "%*s %*s : %u", &cpuspeed); - } - } - } - fclose(fpModel); - } + unsigned int numcpus; + uv_cpu_info_t* ci; - *cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t)); - if (!(*cpu_infos)) { - return uv__new_artificial_error(UV_ENOMEM); - } + *cpu_infos = NULL; + *count = 0; + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(numcpus != (unsigned int) -1); + assert(numcpus != 0); + + ci = calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + return uv__new_sys_error(ENOMEM); + + read_speeds(numcpus, ci); + read_models(numcpus, ci); + read_times(numcpus, ci); + + *cpu_infos = ci; *count = numcpus; - cpu_info = *cpu_infos; - - if (fpStat) { - while (fgets(line, 511, fpStat) != NULL) { - if (strncmp(line, "cpu ", 4) == 0) { - continue; - } else if (strncmp(line, "cpu", 3) != 0) { - break; - } - - sscanf(line, "%*s %lu %lu %lu %lu %*s %lu", - &ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr); - snprintf(speedPath, sizeof(speedPath), - "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i); - - fpSpeed = fopen(speedPath, "r"); - - if (fpSpeed) { - if (fgets(line, 511, fpSpeed) != NULL) { - sscanf(line, "%u", &cpuspeed); - cpuspeed /= 1000; - } - fclose(fpSpeed); - } - - cpu_info->cpu_times.user = ticks_user * multiplier; - cpu_info->cpu_times.nice = ticks_nice * multiplier; - cpu_info->cpu_times.sys = ticks_sys * multiplier; - cpu_info->cpu_times.idle = ticks_idle * multiplier; - cpu_info->cpu_times.irq = ticks_intr * multiplier; - - cpu_info->model = strdup(model); - cpu_info->speed = cpuspeed; - - cpu_info++; + return uv_ok_; +} + + +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned int num; + + for (num = 0; num < numcpus; num++) + ci[num].speed = read_cpufreq(num) / 1000; +} + + +static void read_models(unsigned int numcpus, uv_cpu_info_t* ci) { +#if defined(__i386__) || defined(__x86_64__) + static const char marker[] = "model name\t: "; +#elif defined(__arm__) + static const char marker[] = "Processor\t: "; +#elif defined(__mips__) + static const char marker[] = "cpu model\t\t: "; +#else +# warning uv_cpu_info() is not supported on this architecture. + static const char marker[] = "(dummy)"; +#endif + unsigned int num; + char buf[1024]; + char* model; + FILE* fp; + + fp = fopen("/proc/cpuinfo", "r"); + if (fp == NULL) + return; + + num = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + + model = buf + sizeof(marker) - 1; + model = strndup(model, strlen(model) - 1); /* strip newline */ + ci[num++].model = model; + } + fclose(fp); +} + + +static void read_times(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned long clock_ticks; + struct uv_cpu_times_s ts; + unsigned long user; + unsigned long nice; + unsigned long sys; + unsigned long idle; + unsigned long dummy; + unsigned long irq; + unsigned int num; + unsigned int len; + char buf[1024]; + FILE* fp; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + fp = fopen("/proc/stat", "r"); + if (fp == NULL) + return; + + if (!fgets(buf, sizeof(buf), fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " marker */ + { + unsigned int n = num; + for (len = sizeof("cpu0"); n /= 10; len++); + assert(sscanf(buf, "cpu%u ", &n) == 1 && n == num); } - fclose(fpStat); + + /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, + * guest, guest_nice but we're only interested in the first four + irq. + * + * Don't use %*s to skip fields or %ll to read straight into the uint64_t + * fields, they're not allowed in C89 mode. + */ + if (6 != sscanf(buf + len, + "%lu %lu %lu %lu %lu %lu", + &user, + &nice, + &sys, + &idle, + &dummy, + &irq)) + abort(); + + ts.user = clock_ticks * user; + ts.nice = clock_ticks * nice; + ts.sys = clock_ticks * sys; + ts.idle = clock_ticks * idle; + ts.irq = clock_ticks * irq; + ci[num++].cpu_times = ts; } + fclose(fp); +} - return uv_ok_; + +static unsigned long read_cpufreq(unsigned int cpunum) { + unsigned long val; + char buf[1024]; + FILE* fp; + + snprintf(buf, + sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", + cpunum); + + fp = fopen(buf, "r"); + if (fp == NULL) + return 0; + + val = 0; + fscanf(fp, "%lu", &val); + fclose(fp); + + return val; } diff --git a/deps/uv/src/unix/loop-watcher.c b/deps/uv/src/unix/loop-watcher.c index 6e6a689..9d1414b 100644 --- a/deps/uv/src/unix/loop-watcher.c +++ b/deps/uv/src/unix/loop-watcher.c @@ -25,7 +25,6 @@ #define UV_LOOP_WATCHER_DEFINE(name, type) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ - loop->counters.name##_init++; \ handle->name##_cb = NULL; \ return 0; \ } \ diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index bd91c01..70cdc82 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -28,10 +28,13 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { + unsigned int i; + int flags; + #if HAVE_KQUEUE - int flags = EVBACKEND_KQUEUE; + flags = EVBACKEND_KQUEUE; #else - int flags = EVFLAG_AUTO; + flags = EVFLAG_AUTO; #endif memset(loop, 0, sizeof(*loop)); @@ -44,6 +47,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { ngx_queue_init(&loop->prepare_handles); ngx_queue_init(&loop->handle_queue); loop->closing_handles = NULL; + loop->signal_ctx = NULL; loop->time = uv_hrtime() / 1000000; loop->async_pipefd[0] = -1; loop->async_pipefd[1] = -1; @@ -51,28 +55,22 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { ev_set_userdata(loop->ev, loop); eio_channel_init(&loop->uv_eio_channel, loop); -#if __linux__ - loop->inotify_watchers = NULL; - loop->inotify_fd = -1; -#endif -#if HAVE_PORTS_FS - loop->fs_fd = -1; -#endif + uv_signal_init(loop, &loop->child_watcher); + uv__handle_unref(&loop->child_watcher); + loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + + for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) + ngx_queue_init(loop->process_handles + i); + + if (uv__platform_loop_init(loop, default_loop)) + return -1; + return 0; } void uv__loop_delete(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + uv__signal_unregister(loop); ev_loop_destroy(loop->ev); -#if __linux__ - if (loop->inotify_fd != -1) { - uv__io_stop(loop, &loop->inotify_read_watcher); - close(loop->inotify_fd); - loop->inotify_fd = -1; - } -#endif -#if HAVE_PORTS_FS - if (loop->fs_fd != -1) - close(loop->fs_fd); -#endif } diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index a1a7091..b1c437b 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -35,10 +35,19 @@ #define NANOSEC ((uint64_t) 1e9) +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + uint64_t uv_hrtime(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * NANOSEC + ts.tv_nsec); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } void uv_loadavg(double avg[3]) { diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 865f8e9..4319270 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -43,10 +43,19 @@ static char *process_title; +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + uint64_t uv_hrtime(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * NANOSEC + ts.tv_nsec); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 957e96f..30809dc 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -34,7 +34,6 @@ static void uv__pipe_accept(uv_loop_t* loop, uv__io_t* w, int events); int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); - loop->counters.pipe_init++; handle->shutdown_req = NULL; handle->connect_req = NULL; handle->pipe_fname = NULL; diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 13796ab..8d6e299 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -54,8 +54,6 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); - loop->counters.poll_init++; - handle->fd = fd; handle->poll_cb = NULL; uv__io_init(&handle->io_watcher, uv__poll_io, fd, 0); diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 4d54e04..67f2d73 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -22,13 +22,16 @@ #include "uv.h" #include "internal.h" +#include +#include #include #include + +#include #include -#include #include -#include #include +#include #ifdef __APPLE__ # include @@ -42,26 +45,71 @@ extern char **environ; #endif -static void uv__chld(EV_P_ ev_child* watcher, int revents) { - int status = watcher->rstatus; - int exit_status = 0; - int term_signal = 0; - uv_process_t *process = watcher->data; +static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) { + assert(pid > 0); + return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles); +} - assert(&process->child_watcher == watcher); - assert(revents & EV_CHILD); - ev_child_stop(EV_A_ &process->child_watcher); +static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) { + uv_process_t* handle; + ngx_queue_t* h; + ngx_queue_t* q; - if (WIFEXITED(status)) { - exit_status = WEXITSTATUS(status); - } + h = uv__process_queue(loop, pid); - if (WIFSIGNALED(status)) { - term_signal = WTERMSIG(status); + ngx_queue_foreach(q, h) { + handle = ngx_queue_data(q, uv_process_t, queue); + if (handle->pid == pid) return handle; } - if (process->exit_cb) { + return NULL; +} + + +static void uv__chld(uv_signal_t* handle, int signum) { + uv_process_t* process; + int exit_status; + int term_signal; + int status; + pid_t pid; + + assert(signum == SIGCHLD); + + for (;;) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) + return; + + if (pid == -1) { + if (errno == ECHILD) + return; /* XXX stop signal watcher? */ + else + abort(); + } + + process = uv__process_find(handle->loop, pid); + if (process == NULL) + continue; /* XXX bug? abort? */ + + if (process->exit_cb == NULL) + continue; + + exit_status = 0; + term_signal = 0; + + if (WIFEXITED(status)) + exit_status = WEXITSTATUS(status); + + if (WIFSIGNALED(status)) + term_signal = WTERMSIG(status); + + if (process->errorno) { + uv__set_sys_error(process->loop, process->errorno); + exit_status = -1; /* execve() failed */ + } + process->exit_cb(process, exit_status, term_signal); } } @@ -122,8 +170,7 @@ int uv__make_pipe(int fds[2], int flags) { * Used for initializing stdio streams like options.stdin_stream. Returns * zero on success. */ -static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2], - int writable) { +static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int fd = -1; switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM)) { @@ -151,7 +198,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2], return -1; } - fds[writable ? 1 : 0] = fd; + fds[1] = fd; return 0; default: @@ -174,16 +221,19 @@ static int uv__process_stdio_flags(uv_stdio_container_t* container, } -static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2], +static int uv__process_open_stream(uv_stdio_container_t* container, + int fds[2], int writable) { - int fd = fds[writable ? 1 : 0]; - int child_fd = fds[writable ? 0 : 1]; + int child_fd; int flags; + int fd; + + fd = fds[0]; + child_fd = fds[1]; /* No need to create stream */ - if (!(container->flags & UV_CREATE_PIPE) || fd < 0) { + if (!(container->flags & UV_CREATE_PIPE) || fd < 0) return 0; - } assert(child_fd >= 0); close(child_fd); @@ -197,62 +247,78 @@ static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2], static void uv__process_close_stream(uv_stdio_container_t* container) { if (!(container->flags & UV_CREATE_PIPE)) return; - uv__stream_close((uv_stream_t*)container->data.stream); } +static void uv__write_int(int fd, int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == -1 && errno == EPIPE) + return; /* parent process has quit */ + + assert(n == sizeof(val)); +} + + static void uv__process_child_init(uv_process_options_t options, int stdio_count, - int* pipes) { + int (*pipes)[2], + int error_fd) { + int close_fd; + int use_fd; int i; - if (options.flags & UV_PROCESS_DETACHED) { + 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_fd = pipes[i][0]; + use_fd = pipes[i][1]; + + if (use_fd >= 0) close(close_fd); - } else if (i < 3) { - /* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */ + else if (i >= 3) + continue; + else { + /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set + */ use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR); - if (use_fd < 0) { + if (use_fd == -1) { + uv__write_int(error_fd, errno); perror("failed to open stdio"); _exit(127); } - } else { - continue; } - if (i != use_fd) { + if (i == use_fd) + uv__cloexec(use_fd, 0); + else { dup2(use_fd, i); close(use_fd); - } else { - uv__cloexec(use_fd, 0); } } if (options.cwd && chdir(options.cwd)) { + uv__write_int(error_fd, errno); perror("chdir()"); _exit(127); } if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) { + uv__write_int(error_fd, errno); perror("setgid()"); _exit(127); } if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) { + uv__write_int(error_fd, errno); perror("setuid()"); _exit(127); } @@ -260,63 +326,57 @@ static void uv__process_child_init(uv_process_options_t options, environ = options.env; execvp(options.file, options.args); + uv__write_int(error_fd, errno); perror("execvp()"); _exit(127); } -#ifndef SPAWN_WAIT_EXEC -# define SPAWN_WAIT_EXEC 1 -#endif - -int uv_spawn(uv_loop_t* loop, uv_process_t* process, - uv_process_options_t options) { - /* - * Save environ in the case that we get it clobbered - * by the child process. - */ - char** save_our_env = environ; - - int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count; - int* pipes = malloc(2 * stdio_count * sizeof(int)); - -#if SPAWN_WAIT_EXEC +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t options) { int signal_pipe[2] = { -1, -1 }; - struct pollfd pfd; -#endif - int status; + int (*pipes)[2]; + int stdio_count; + ngx_queue_t* q; + ssize_t r; pid_t pid; int i; - if (pipes == NULL) { - errno = ENOMEM; - goto error; - } - assert(options.file != NULL); assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID))); - uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); - loop->counters.process_init++; - uv__handle_start(process); + ngx_queue_init(&process->queue); - process->exit_cb = options.exit_cb; + stdio_count = options.stdio_count; + if (stdio_count < 3) + stdio_count = 3; + + pipes = malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) { + errno = ENOMEM; + goto error; + } - /* Init pipe pairs */ for (i = 0; i < stdio_count; i++) { - pipes[i * 2] = -1; - pipes[i * 2 + 1] = -1; + pipes[i][0] = -1; + pipes[i][1] = -1; } - /* Create socketpairs/pipes, or use raw fd */ - for (i = 0; i < options.stdio_count; i++) { - if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) { + for (i = 0; i < options.stdio_count; i++) + if (uv__process_init_stdio(options.stdio + i, pipes[i])) goto error; - } + + /* swap stdin file descriptors, it's the only writable stream */ + { + int* p = pipes[0]; + int t = p[0]; + p[0] = p[1]; + p[1] = t; } /* This pipe is used by the parent to wait until @@ -337,81 +397,68 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, * * To avoid ambiguity, we create a pipe with both ends * marked close-on-exec. Then, after the call to `fork()`, - * the parent polls the read end until it sees POLLHUP. + * the parent polls the read end until it EOFs or errors with EPIPE. */ -#if SPAWN_WAIT_EXEC - if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK)) + if (uv__make_pipe(signal_pipe, 0)) goto error; -#endif + + uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); pid = fork(); if (pid == -1) { -#if SPAWN_WAIT_EXEC close(signal_pipe[0]); close(signal_pipe[1]); -#endif - environ = save_our_env; goto error; } if (pid == 0) { - /* Child */ - uv__process_child_init(options, stdio_count, pipes); - - /* Execution never reaches here. */ + uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + abort(); } - /* Parent. */ - - /* Restore environment. */ - environ = save_our_env; - -#if SPAWN_WAIT_EXEC - /* POLLHUP signals child has exited or execve()'d. */ close(signal_pipe[1]); - do { - pfd.fd = signal_pipe[0]; - pfd.events = POLLIN|POLLHUP; - pfd.revents = 0; - errno = 0, status = poll(&pfd, 1, -1); - } - while (status == -1 && (errno == EINTR || errno == ENOMEM)); - assert((status == 1) && "poll() on pipe read end failed"); - close(signal_pipe[0]); -#endif + process->errorno = 0; + do + r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno)); + while (r == -1 && errno == EINTR); - process->pid = pid; + if (r == 0) + ; /* okay, EOF */ + else if (r == sizeof(process->errorno)) + ; /* okay, read errorno */ + else if (r == -1 && errno == EPIPE) + ; /* okay, got EPIPE */ + else + abort(); - ev_child_init(&process->child_watcher, uv__chld, pid, 0); - ev_child_start(process->loop->ev, &process->child_watcher); - process->child_watcher.data = process; + close(signal_pipe[0]); for (i = 0; i < options.stdio_count; i++) { - if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) { - int j; - /* Close all opened streams */ - for (j = 0; j < i; j++) { - uv__process_close_stream(&options.stdio[j]); - } - + if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) { + while (i--) uv__process_close_stream(options.stdio + i); goto error; } } - free(pipes); + q = uv__process_queue(loop, pid); + ngx_queue_insert_tail(q, &process->queue); + + process->pid = pid; + process->exit_cb = options.exit_cb; + uv__handle_start(process); + free(pipes); return 0; error: uv__set_sys_error(process->loop, errno); for (i = 0; i < stdio_count; i++) { - close(pipes[i * 2]); - close(pipes[i * 2 + 1]); + close(pipes[i][0]); + close(pipes[i][1]); } - free(pipes); return -1; @@ -442,6 +489,7 @@ uv_err_t uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { - ev_child_stop(handle->loop->ev, &handle->child_watcher); + /* TODO stop signal watcher when this is the last handle */ + ngx_queue_remove(&handle->queue); uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c new file mode 100644 index 0000000..8ef640b --- /dev/null +++ b/deps/uv/src/unix/signal.c @@ -0,0 +1,269 @@ +/* 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 "internal.h" + +#include +#include +#include +#include +#include +#include + +struct signal_ctx { + int pipefd[2]; + uv__io_t io_watcher; + unsigned int nqueues; + ngx_queue_t queues[1]; /* variable length */ +}; + +static void uv__signal_handler(int signum); +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events); +static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop); +static void uv__signal_ctx_delete(struct signal_ctx* ctx); +static void uv__signal_write(int fd, unsigned int val); +static unsigned int uv__signal_read(int fd); +static unsigned int uv__signal_max(void); + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_SIGNAL); + handle->signum = 0; + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum_) { + struct signal_ctx* ctx; + struct sigaction sa; + unsigned int signum; + uv_loop_t* loop; + ngx_queue_t* q; + + /* XXX doing this check in uv_signal_init() - the logical place for it - + * leads to an infinite loop when uv__loop_init() inits a signal watcher + */ + /* FIXME */ + assert(handle->loop == uv_default_loop() && + "uv_signal_t is currently only supported by the default loop"); + + loop = handle->loop; + signum = signum_; + + if (uv__is_active(handle)) + return uv__set_artificial_error(loop, UV_EBUSY); + + if (signal_cb == NULL) + return uv__set_artificial_error(loop, UV_EINVAL); + + if (signum <= 0) + return uv__set_artificial_error(loop, UV_EINVAL); + + ctx = loop->signal_ctx; + + if (ctx == NULL) { + ctx = uv__signal_ctx_new(loop); + + if (ctx == NULL) + return uv__set_artificial_error(loop, UV_ENOMEM); + + loop->signal_ctx = ctx; + } + + if (signum > ctx->nqueues) + return uv__set_artificial_error(loop, UV_EINVAL); + + q = ctx->queues + signum; + + if (!ngx_queue_empty(q)) + goto skip; + + /* XXX use a separate signal stack? */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = uv__signal_handler; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return uv__set_artificial_error(loop, UV_EINVAL); + +skip: + ngx_queue_insert_tail(q, &handle->queue); + uv__handle_start(handle); + handle->signum = signum; + handle->signal_cb = signal_cb; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + struct signal_ctx* ctx; + struct sigaction sa; + unsigned int signum; + uv_loop_t* loop; + + if (!uv__is_active(handle)) + return 0; + + signum = handle->signum; + loop = handle->loop; + ctx = loop->signal_ctx; + assert(signum > 0); + assert(signum <= ctx->nqueues); + + ngx_queue_remove(&handle->queue); + uv__handle_stop(handle); + handle->signum = 0; + + if (!ngx_queue_empty(ctx->queues + signum)) + goto skip; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; /* XXX restore previous action? */ + + if (sigaction(signum, &sa, NULL)) + return uv__set_artificial_error(loop, UV_EINVAL); + +skip: + return 0; +} + + +void uv__signal_close(uv_signal_t* handle) { + uv_signal_stop(handle); +} + + +void uv__signal_unregister(uv_loop_t* loop) { + uv__signal_ctx_delete(loop->signal_ctx); + loop->signal_ctx = NULL; +} + + +static void uv__signal_handler(int signum) { + struct signal_ctx* ctx = uv_default_loop()->signal_ctx; + uv__signal_write(ctx->pipefd[1], (unsigned int) signum); +} + + +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events) { + struct signal_ctx* ctx; + unsigned int signum; + uv_signal_t* h; + ngx_queue_t* q; + + ctx = container_of(w, struct signal_ctx, io_watcher); + signum = uv__signal_read(ctx->pipefd[0]); + assert(signum > 0); + assert(signum <= ctx->nqueues); + + ngx_queue_foreach(q, ctx->queues + signum) { + h = ngx_queue_data(q, uv_signal_t, queue); + h->signal_cb(h, signum); + } +} + + +static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop) { + struct signal_ctx* ctx; + unsigned int nqueues; + unsigned int i; + + nqueues = uv__signal_max(); + assert(nqueues > 0); + + /* The first ctx->queues entry is never used. It wastes a few bytes of memory + * but it saves us from having to substract 1 from the signum all the time - + * which inevitably someone will forget to do. + */ + ctx = calloc(1, sizeof(*ctx) + sizeof(ctx->queues[0]) * (nqueues + 1)); + if (ctx == NULL) + return NULL; + + if (uv__make_pipe(ctx->pipefd, UV__F_NONBLOCK)) { + free(ctx); + return NULL; + } + + uv__io_init(&ctx->io_watcher, uv__signal_event, ctx->pipefd[0], UV__IO_READ); + uv__io_start(loop, &ctx->io_watcher); + ctx->nqueues = nqueues; + + for (i = 1; i <= nqueues; i++) + ngx_queue_init(ctx->queues + i); + + return ctx; +} + + +static void uv__signal_ctx_delete(struct signal_ctx* ctx) { + if (ctx == NULL) return; + close(ctx->pipefd[0]); + close(ctx->pipefd[1]); + free(ctx); +} + + +static void uv__signal_write(int fd, unsigned int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == sizeof(val)) + return; + + if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return; /* pipe full - nothing we can do about that */ + + abort(); +} + + +static unsigned int uv__signal_read(int fd) { + unsigned int val; + ssize_t n; + + do + n = read(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == sizeof(val)) + return val; + + abort(); +} + + +static unsigned int uv__signal_max(void) { +#if defined(_SC_RTSIG_MAX) + int max = sysconf(_SC_RTSIG_MAX); + if (max != -1) return max; +#endif +#if defined(SIGRTMAX) + return SIGRTMAX; +#elif defined(NSIG) + return NSIG; +#else + return 32; +#endif +} diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 26875a7..0ab86f3a 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -57,8 +57,6 @@ void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, uv_handle_type type) { uv__handle_init(loop, (uv_handle_t*)stream, type); - loop->counters.stream_init++; - stream->alloc_cb = NULL; stream->close_cb = NULL; stream->connection_cb = NULL; @@ -489,7 +487,6 @@ start: } else { /* Successful write */ - /* Update the counters. */ while (n >= 0) { uv_buf_t* buf = &(req->bufs[req->write_index]); size_t len = buf->len; @@ -834,10 +831,16 @@ static void uv__stream_connect(uv_stream_t* stream) { } -int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt, - uv_stream_t* send_handle, uv_write_cb cb) { +int uv_write2(uv_write_t* req, + uv_stream_t* stream, + uv_buf_t bufs[], + int bufcnt, + uv_stream_t* send_handle, + uv_write_cb cb) { int empty_queue; + assert(bufcnt > 0); + assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY) && "uv_write (unix) does not yet support other types of streams"); @@ -864,7 +867,7 @@ 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 <= (int) ARRAY_SIZE(req->bufsml)) req->bufs = req->bufsml; else req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 8c626a3..18412b8 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -63,6 +63,19 @@ #endif +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + loop->fs_fd = -1; + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd == -1) return; + close(loop->fs_fd); + loop->fs_fd = -1; +} + + uint64_t uv_hrtime() { return (gethrtime()); } @@ -183,8 +196,6 @@ int uv_fs_event_init(uv_loop_t* loop, int portfd; int first_run = 0; - loop->counters.fs_event_init++; - /* We don't support any flags yet. */ assert(!flags); if (loop->fs_fd == -1) { @@ -233,7 +244,6 @@ int uv_fs_event_init(uv_loop_t* loop, const char* filename, uv_fs_event_cb cb, int flags) { - loop->counters.fs_event_init++; uv__set_sys_error(loop, ENOSYS); return -1; } @@ -344,8 +354,10 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cpu_info->model = NULL; } else { knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz"); - assert(knp->data_type == KSTAT_DATA_INT32); - cpu_info->speed = knp->value.i32; + assert(knp->data_type == KSTAT_DATA_INT32 || + knp->data_type == KSTAT_DATA_INT64); + cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32 + : knp->value.i64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand"); assert(knp->data_type == KSTAT_DATA_STRING); diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index d9cbd0b..441473c 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -30,7 +30,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); - loop->counters.tcp_init++; tcp->idle_handle = NULL; return 0; } diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/unix/timer.c index 0d81997..a560584 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/unix/timer.c @@ -39,8 +39,6 @@ RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp) int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - loop->counters.timer_init++; - uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); handle->timer_cb = NULL; diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7193db8..3ef9064 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -45,7 +45,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { tty->flags |= UV_STREAM_BLOCKING; } - loop->counters.tty_init++; tty->mode = 0; return 0; } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 9f87060..1838bc7 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -418,6 +418,8 @@ static int uv__udp_send(uv_udp_send_t* req, struct sockaddr* addr, socklen_t addrlen, uv_udp_send_cb send_cb) { + assert(bufcnt > 0); + if (uv__udp_maybe_deferred_bind(handle, addr->sa_family)) return -1; @@ -429,7 +431,7 @@ static int uv__udp_send(uv_udp_send_t* req, req->handle = handle; req->bufcnt = bufcnt; - if (bufcnt <= UV_REQ_BUFSML_SIZE) { + if (bufcnt <= (int) ARRAY_SIZE(req->bufsml)) { req->bufs = req->bufsml; } else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) { @@ -453,8 +455,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { memset(handle, 0, sizeof *handle); uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); - loop->counters.udp_init++; - handle->fd = -1; ngx_queue_init(&handle->write_queue); ngx_queue_init(&handle->write_completed_queue); diff --git a/deps/uv/src/unix/uv-eio.c b/deps/uv/src/unix/uv-eio.c index 0d931b8..e5ba2f2 100644 --- a/deps/uv/src/unix/uv-eio.c +++ b/deps/uv/src/unix/uv-eio.c @@ -83,8 +83,8 @@ static void uv__eio_init(void) { void uv_eio_init(uv_loop_t* loop) { - if (loop->counters.eio_init) return; - loop->counters.eio_init = 1; + if (loop->flags & UV_LOOP_EIO_INITIALIZED) return; + loop->flags |= UV_LOOP_EIO_INITIALIZED; uv_idle_init(loop, &loop->uv_eio_poller); uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index d159727..4608ee5 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -158,7 +158,6 @@ UNUSED static void uv__handle_unref(uv_handle_t* h) { UNUSED static void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle, uv_handle_type type) { - loop->counters.handle_init++; handle->loop = loop; handle->type = type; handle->flags = UV__HANDLE_REF; /* ref the loop when active */ diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index 1b733c4..40dee1f 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -23,39 +23,11 @@ #include "uv.h" #include "internal.h" +#include "atomicops-inl.h" #include "handle-inl.h" #include "req-inl.h" -/* Atomic set operation on char */ -#ifdef _MSC_VER /* MSVC */ - -/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ -/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ -/* exist, and interlocked operations on larger targets might require the */ -/* target to be aligned. */ -#pragma intrinsic(_InterlockedOr8) - -static char __declspec(inline) uv_atomic_exchange_set(char volatile* target) { - return _InterlockedOr8(target, 1); -} - -#else /* GCC */ - -/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ -static inline char uv_atomic_exchange_set(char volatile* target) { - const char one = 1; - char old_value; - __asm__ __volatile__ ("lock xchgb %0, %1\n\t" - : "=r"(old_value), "=m"(*target) - : "0"(one), "m"(*target) - : "memory"); - return old_value; -} - -#endif - - void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && !handle->async_sent) { @@ -78,8 +50,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { req->type = UV_WAKEUP; req->data = handle; - loop->counters.async_init++; - uv__handle_start(handle); return 0; @@ -107,7 +77,7 @@ int uv_async_send(uv_async_t* handle) { /* or closed handle. */ assert(!(handle->flags & UV_HANDLE_CLOSING)); - if (!uv_atomic_exchange_set(&handle->async_sent)) { + if (!uv__atomic_exchange_set(&handle->async_sent)) { POST_COMPLETION_FOR_REQ(loop, &handle->async_req); } diff --git a/deps/uv/src/win/atomicops-inl.h b/deps/uv/src/win/atomicops-inl.h new file mode 100644 index 0000000..61e0060 --- /dev/null +++ b/deps/uv/src/win/atomicops-inl.h @@ -0,0 +1,56 @@ +/* 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_ATOMICOPS_INL_H_ +#define UV_WIN_ATOMICOPS_INL_H_ + +#include "uv.h" + + +/* Atomic set operation on char */ +#ifdef _MSC_VER /* MSVC */ + +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ +/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ +/* exist, and interlocked operations on larger targets might require the */ +/* target to be aligned. */ +#pragma intrinsic(_InterlockedOr8) + +static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC */ + +/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ +static inline char uv__atomic_exchange_set(char volatile* target) { + const char one = 1; + char old_value; + __asm__ __volatile__ ("lock xchgb %0, %1\n\t" + : "=r"(old_value), "=m"(*target) + : "0"(one), "m"(*target) + : "memory"); + return old_value; +} + +#endif + +#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e288fc4..2c76b10 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -55,6 +55,9 @@ static void uv_init(void) { /* Initialize FS */ uv_fs_init(); + /* Initialize signal stuff */ + uv_signals_init(); + /* Initialize console */ uv_console_init(); @@ -96,8 +99,6 @@ static void uv_loop_init(uv_loop_t* loop) { loop->active_udp_streams = 0; loop->last_err = uv_ok_; - - memset(&loop->counters, 0, sizeof loop->counters); } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index 88ddd74..d5b8f7c 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -26,7 +26,7 @@ static int uv__dlerror(uv_lib_t* lib, int errorno); int uv_dlopen(const char* filename, uv_lib_t* lib) { - wchar_t filename_w[32768]; + WCHAR filename_w[32768]; lib->handle = NULL; lib->errmsg = NULL; diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 91f5111..bb7a46f 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -110,8 +110,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case WSAEFAULT: return UV_EFAULT; case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; - case ERROR_OPERATION_ABORTED: return UV_EINTR; - case WSAEINTR: return UV_EINTR; + case ERROR_OPERATION_ABORTED: return UV_ECANCELED; + case WSAEINTR: return UV_ECANCELED; case ERROR_INVALID_DATA: return UV_EINVAL; case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 68e03e3..810be4f 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -55,8 +55,6 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, } uv__handle_start(handle); - - loop->counters.fs_event_init++; } @@ -90,15 +88,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, } -static int uv_split_path(const wchar_t* filename, wchar_t** dir, - wchar_t** file) { +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { int len = wcslen(filename); int i = len; while (i > 0 && filename[--i] != '\\' && filename[i] != '/'); if (i == 0) { if (dir) { - *dir = (wchar_t*)malloc((MAX_PATH + 1) * sizeof(wchar_t)); + *dir = (WCHAR*)malloc((MAX_PATH + 1) * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -113,7 +111,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, *file = wcsdup(filename); } else { if (dir) { - *dir = (wchar_t*)malloc((i + 1) * sizeof(wchar_t)); + *dir = (WCHAR*)malloc((i + 1) * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -121,7 +119,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, (*dir)[i] = L'\0'; } - *file = (wchar_t*)malloc((len - i) * sizeof(wchar_t)); + *file = (WCHAR*)malloc((len - i) * sizeof(WCHAR)); if (!*file) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -137,8 +135,8 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb, int flags) { int name_size, is_path_dir; DWORD attr, last_error; - wchar_t* dir = NULL, *dir_to_watch, *filenamew = NULL; - wchar_t short_path[MAX_PATH]; + WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL; + WCHAR short_path[MAX_PATH]; /* We don't support any flags yet. */ assert(!flags); @@ -146,14 +144,14 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, uv_fs_event_init_handle(loop, handle, filename, cb); /* Convert name to UTF16. */ - name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(wchar_t); - filenamew = (wchar_t*)malloc(name_size); + name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(WCHAR); + filenamew = (WCHAR*)malloc(name_size); if (!filenamew) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(filename, filenamew, - name_size / sizeof(wchar_t))) { + name_size / sizeof(WCHAR))) { uv__set_sys_error(loop, GetLastError()); return -1; } @@ -294,7 +292,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, FILE_NOTIFY_INFORMATION* file_info; int sizew, size, result; char* filename = NULL; - wchar_t* filenamew, *long_filenamew = NULL; + WCHAR* filenamew, *long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); @@ -323,9 +321,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, */ if (handle->dirw || _wcsnicmp(handle->filew, file_info->FileName, - file_info->FileNameLength / sizeof(wchar_t)) == 0 || + file_info->FileNameLength / sizeof(WCHAR)) == 0 || _wcsnicmp(handle->short_filew, file_info->FileName, - file_info->FileNameLength / sizeof(wchar_t)) == 0) { + file_info->FileNameLength / sizeof(WCHAR)) == 0) { if (handle->dirw) { /* @@ -337,9 +335,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { /* Construct a full path to the file. */ size = wcslen(handle->dirw) + - file_info->FileNameLength / sizeof(wchar_t) + 2; + file_info->FileNameLength / sizeof(WCHAR) + 2; - filenamew = (wchar_t*)malloc(size * sizeof(wchar_t)); + filenamew = (WCHAR*)malloc(size * sizeof(WCHAR)); if (!filenamew) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -353,7 +351,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, size = GetLongPathNameW(filenamew, NULL, 0); if (size) { - long_filenamew = (wchar_t*)malloc(size * sizeof(wchar_t)); + long_filenamew = (WCHAR*)malloc(size * sizeof(WCHAR)); if (!long_filenamew) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -388,7 +386,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, */ if (!long_filenamew) { filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(wchar_t); + sizew = file_info->FileNameLength / sizeof(WCHAR); } } else { /* Removed or renamed callbacks don't provide filename. */ diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 41e7a4a..c2017ef 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -37,13 +37,13 @@ int ai_socktype; int ai_protocol; size_t ai_addrlen; - wchar_t* ai_canonname; + WCHAR* ai_canonname; struct sockaddr* ai_addr; struct addrinfoW* ai_next; } ADDRINFOW, *PADDRINFOW; - DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node, - const wchar_t* service, + DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node, + const WCHAR* service, const ADDRINFOW* hints, PADDRINFOW* result); @@ -271,7 +271,7 @@ int uv_getaddrinfo(uv_loop_t* loop, /* calculate required memory size for all input values */ if (node != NULL) { - nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t)); + nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR)); if (nodesize == 0) { uv__set_sys_error(loop, GetLastError()); goto error; @@ -280,7 +280,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (service != NULL) { servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * - sizeof(wchar_t)); + sizeof(WCHAR)); if (servicesize == 0) { uv__set_sys_error(loop, GetLastError()); goto error; @@ -303,10 +303,10 @@ int uv_getaddrinfo(uv_loop_t* loop, /* convert node string to UTF16 into allocated memory and save pointer in */ /* the reques. */ if (node != NULL) { - req->node = (wchar_t*)alloc_ptr; + req->node = (WCHAR*)alloc_ptr; if (uv_utf8_to_utf16(node, - (wchar_t*) alloc_ptr, - nodesize / sizeof(wchar_t)) == 0) { + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { uv__set_sys_error(loop, GetLastError()); goto error; } @@ -318,10 +318,10 @@ int uv_getaddrinfo(uv_loop_t* loop, /* convert service string to UTF16 into allocated memory and save pointer */ /* in the req. */ if (service != NULL) { - req->service = (wchar_t*)alloc_ptr; + req->service = (WCHAR*)alloc_ptr; if (uv_utf8_to_utf16(service, - (wchar_t*) alloc_ptr, - servicesize / sizeof(wchar_t)) == 0) { + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { uv__set_sys_error(loop, GetLastError()); goto error; } diff --git a/deps/uv/src/win/handle-inl.h b/deps/uv/src/win/handle-inl.h index 4064c24..18db5e6 100644 --- a/deps/uv/src/win/handle-inl.h +++ b/deps/uv/src/win/handle-inl.h @@ -123,6 +123,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { uv_async_endgame(loop, (uv_async_t*) handle); break; + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + case UV_PROCESS: uv_process_endgame(loop, (uv_process_t*) handle); break; diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index d4b86de..74bd56c 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -124,6 +124,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_async_close(loop, (uv_async_t*) handle); return; + case UV_SIGNAL: + uv_signal_close(loop, (uv_signal_t*) handle); + return; + case UV_PROCESS: uv_process_close(loop, (uv_process_t*) handle); return; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index b9f8bba..b0d1d18 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -74,9 +74,10 @@ #define UV_HANDLE_PIPESERVER 0x02000000 /* Only used by uv_tty_t handles. */ -#define UV_HANDLE_TTY_RAW 0x01000000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x02000000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x04000000 +#define UV_HANDLE_TTY_READABLE 0x01000000 +#define UV_HANDLE_TTY_RAW 0x02000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 /* Only used by uv_poll_t handles. */ #define UV_HANDLE_POLL_SLOW 0x02000000 @@ -134,7 +135,7 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); /* * Pipes */ -int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, +uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); @@ -232,10 +233,22 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, /* + * Signal watcher + */ +void uv_signals_init(); +int uv__signal_dispatch(int signum); + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req); + + +/* * Spawn */ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); -void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle); void uv_process_close(uv_loop_t* loop, uv_process_t* handle); void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); @@ -287,7 +300,7 @@ uv_err_code uv_translate_sys_error(int sys_errno); /* * Process stdio handles. */ -int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, +uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, BYTE** buffer_ptr); void uv__stdio_destroy(BYTE* buffer); void uv__stdio_noinherit(BYTE* buffer); diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index 615f7cd..1a02862 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -39,7 +39,6 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { #define UV_LOOP_WATCHER_DEFINE(name, NAME) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \ - loop->counters.name##_init++; \ \ return 0; \ } \ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 5da14ea..a4bb764 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -88,8 +88,6 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req); - loop->counters.pipe_init++; - return 0; } @@ -159,11 +157,11 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) { } -int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, +uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize) { HANDLE pipeHandle; int errorno; - int err; + uv_err_t err; char* ptr = (char*)handle; for (;;) { @@ -181,9 +179,8 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, errorno = GetLastError(); if (errorno != ERROR_PIPE_BUSY && errorno != ERROR_ACCESS_DENIED) { - uv__set_sys_error(loop, errorno); - err = -1; - goto done; + err = uv__new_sys_error(errorno); + goto error; } /* Pipe name collision. Increment the pointer and try again. */ @@ -194,17 +191,17 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, loop->iocp, (ULONG_PTR)handle, 0) == NULL) { - uv__set_sys_error(loop, GetLastError()); - err = -1; - goto done; + err = uv__new_sys_error(GetLastError()); + goto error; } uv_pipe_connection_init(handle); handle->handle = pipeHandle; - err = 0; -done: - if (err && pipeHandle != INVALID_HANDLE_VALUE) { + return uv_ok_; + + error: + if (pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(pipeHandle); } @@ -433,13 +430,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t); - handle->name = (wchar_t*)malloc(nameSize); + nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) { + if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { uv__set_sys_error(loop, GetLastError()); return -1; } @@ -545,13 +542,13 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, req->cb = cb; /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t); - handle->name = (wchar_t*)malloc(nameSize); + nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) { + if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { errorno = GetLastError(); goto error; } diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 9800b71..3081989 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -558,8 +558,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, handle->poll_req_2.type = UV_POLL_REQ; handle->poll_req_2.data = handle; - loop->counters.poll_init++; - return 0; } diff --git a/deps/uv/src/win/process-stdio.c b/deps/uv/src/win/process-stdio.c index ad845a0..7777740 100644 --- a/deps/uv/src/win/process-stdio.c +++ b/deps/uv/src/win/process-stdio.c @@ -94,13 +94,14 @@ void uv_disable_stdio_inheritance(void) { } -static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, - HANDLE* child_pipe_ptr, unsigned int flags) { +static uv_err_t uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { char pipe_name[64]; SECURITY_ATTRIBUTES sa; DWORD server_access = 0; DWORD client_access = 0; HANDLE child_pipe = INVALID_HANDLE_VALUE; + uv_err_t err; if (flags & UV_READABLE_PIPE) { server_access |= PIPE_ACCESS_OUTBOUND; @@ -112,13 +113,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, } /* Create server pipe handle. */ - if (uv_stdio_pipe_server(loop, - server_pipe, - server_access, - pipe_name, - sizeof(pipe_name)) < 0) { + err = uv_stdio_pipe_server(loop, + server_pipe, + server_access, + pipe_name, + sizeof(pipe_name)); + if (err.code != UV_OK) goto error; - } /* Create child pipe handle. */ sa.nLength = sizeof sa; @@ -133,7 +134,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { - uv__set_sys_error(loop, GetLastError()); + err = uv__new_sys_error(GetLastError()); goto error; } @@ -157,13 +158,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, /* both ends of the pipe created. */ if (!ConnectNamedPipe(server_pipe->handle, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) { - uv__set_sys_error(loop, GetLastError()); + err = uv__new_sys_error(GetLastError()); goto error; } } *child_pipe_ptr = child_pipe; - return 0; + return uv_ok_; error: if (server_pipe->handle != INVALID_HANDLE_VALUE) { @@ -174,7 +175,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, CloseHandle(child_pipe); } - return -1; + return err; } @@ -227,7 +228,7 @@ static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { } -static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr, +uv_err_t uv__create_nul_handle(HANDLE* handle_ptr, DWORD access) { HANDLE handle; SECURITY_ATTRIBUTES sa; @@ -244,36 +245,34 @@ static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr, 0, NULL); if (handle == INVALID_HANDLE_VALUE) { - uv__set_sys_error(loop, GetLastError()); - return -1; + return uv__new_sys_error(GetLastError()); } *handle_ptr = handle; - return 0; + return uv_ok_; } -int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, +uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, BYTE** buffer_ptr) { BYTE* buffer; int count, i; + uv_err_t err; count = options->stdio_count; if (count < 0 || count > 255) { /* Only support FDs 0-255 */ - uv__set_artificial_error(loop, UV_ENOTSUP); - return -1; + return uv__new_artificial_error(UV_ENOTSUP); } else if (count < 3) { /* There should always be at least 3 stdio handles. */ count = 3; } /* Allocate the child stdio buffer */ - buffer = malloc(CHILD_STDIO_SIZE(count)); + buffer = (BYTE*) malloc(CHILD_STDIO_SIZE(count)); if (buffer == NULL) { - uv__set_artificial_error(loop, UV_ENOMEM); - return -1; + return uv__new_artificial_error(UV_ENOMEM); } /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ @@ -304,11 +303,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, if (i <= 2) { DWORD access = (i == 0) ? FILE_GENERIC_READ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; - if (uv__create_nul_handle(loop, - &CHILD_STDIO_HANDLE(buffer, i), - access) < 0) { + + err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i), + access); + if (err.code != UV_OK) goto error; - } + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; } break; @@ -326,12 +326,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); - if (uv__create_stdio_pipe_pair(loop, - parent_pipe, - &child_pipe, - fdopt.flags) < 0) { + err = uv__create_stdio_pipe_pair(loop, + parent_pipe, + &child_pipe, + fdopt.flags); + if (err.code != UV_OK) goto error; - } CHILD_STDIO_HANDLE(buffer, i) = child_pipe; CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; @@ -430,11 +430,11 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, } *buffer_ptr = buffer; - return 0; + return uv_ok_; error: uv__stdio_destroy(buffer); - return -1; + return err; } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index a8f690d..dac9769 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -36,7 +36,7 @@ typedef struct env_var { const char* narrow; - const wchar_t* wide; + const WCHAR* wide; int len; /* including null or '=' */ int supplied; int value_len; @@ -45,38 +45,52 @@ typedef struct env_var { #define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } -#define UTF8_TO_UTF16(s, t) \ - size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t); \ - t = (wchar_t*)malloc(size); \ - if (!t) { \ - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); \ - } \ - if (!uv_utf8_to_utf16(s, t, size / sizeof(wchar_t))) { \ - uv__set_sys_error(loop, GetLastError()); \ - err = -1; \ - goto done; \ +static uv_err_t uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { + int ws_len, r; + WCHAR* ws; + + ws_len = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + NULL, + 0); + if (ws_len <= 0) { + return uv__new_sys_error(GetLastError()); + } + + ws = (WCHAR*) malloc(ws_len * sizeof(WCHAR)); + if (ws == NULL) { + return uv__new_artificial_error(UV_ENOMEM); } + r = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + ws, + ws_len); + assert(r == ws_len); + + *ws_ptr = ws; + return uv_ok_; +} + static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); handle->exit_cb = NULL; handle->pid = 0; + handle->spawn_error = uv_ok_; handle->exit_signal = 0; handle->wait_handle = INVALID_HANDLE_VALUE; handle->process_handle = INVALID_HANDLE_VALUE; - handle->close_handle = INVALID_HANDLE_VALUE; handle->child_stdio_buffer = NULL; + handle->exit_cb_pending = 0; uv_req_init(loop, (uv_req_t*)&handle->exit_req); handle->exit_req.type = UV_PROCESS_EXIT; handle->exit_req.data = handle; - uv_req_init(loop, (uv_req_t*)&handle->close_req); - handle->close_req.type = UV_PROCESS_CLOSE; - handle->close_req.data = handle; - - loop->counters.handle_init++; - loop->counters.process_init++; } @@ -87,15 +101,15 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { /* * Helper function for search_path */ -static wchar_t* search_path_join_test(const wchar_t* dir, +static WCHAR* search_path_join_test(const WCHAR* dir, int dir_len, - const wchar_t* name, + const WCHAR* name, int name_len, - const wchar_t* ext, + const WCHAR* ext, int ext_len, - const wchar_t* cwd, + const WCHAR* cwd, int cwd_len) { - wchar_t *result, *result_pos; + WCHAR *result, *result_pos; DWORD attrs; if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { @@ -121,7 +135,7 @@ static wchar_t* search_path_join_test(const wchar_t* dir, } /* Allocate buffer for output */ - result = result_pos = (wchar_t*)malloc(sizeof(wchar_t) * + result = result_pos = (WCHAR*)malloc(sizeof(WCHAR) * (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1)); /* Copy cwd */ @@ -178,14 +192,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir, /* * Helper function for search_path */ -static wchar_t* path_search_walk_ext(const wchar_t *dir, +static WCHAR* path_search_walk_ext(const WCHAR *dir, int dir_len, - const wchar_t *name, + const WCHAR *name, int name_len, - wchar_t *cwd, + WCHAR *cwd, int cwd_len, int name_has_ext) { - wchar_t* result; + WCHAR* result; /* If the name itself has a nonempty extension, try this extension first */ if (name_has_ext) { @@ -259,14 +273,14 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * * TODO: correctly interpret UNC paths */ -static wchar_t* search_path(const wchar_t *file, - wchar_t *cwd, - const wchar_t *path) { +static WCHAR* search_path(const WCHAR *file, + WCHAR *cwd, + const WCHAR *path) { int file_has_dir; - wchar_t* result = NULL; - wchar_t *file_name_start; - wchar_t *dot; - const wchar_t *dir_start, *dir_end, *dir_path; + WCHAR* result = NULL; + WCHAR *file_name_start; + WCHAR *dot; + const WCHAR *dir_start, *dir_end, *dir_path; int dir_len; int name_has_ext; @@ -283,7 +297,7 @@ static wchar_t* search_path(const wchar_t *file, /* Find the start of the filename so we can split the directory from the */ /* name. */ - for (file_name_start = (wchar_t*)file + file_len; + for (file_name_start = (WCHAR*)file + file_len; file_name_start > file && file_name_start[-1] != L'\\' && file_name_start[-1] != L'/' @@ -365,10 +379,10 @@ static wchar_t* search_path(const wchar_t *file, * Quotes command line arguments * Returns a pointer to the end (next char to be written) of the buffer */ -wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { int len = wcslen(source), i, quote_hit; - wchar_t* start; + WCHAR* start; /* * Check if the string must be quoted; @@ -438,61 +452,92 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { } -wchar_t* make_program_args(char** args, int verbatim_arguments) { - wchar_t* dst; - wchar_t* ptr; +uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { char** arg; - size_t size = 0; - size_t len; + WCHAR* dst = NULL; + WCHAR* temp_buffer = NULL; + size_t dst_len = 0; + size_t temp_buffer_len = 0; + WCHAR* pos; int arg_count = 0; - wchar_t* buffer; - int arg_size; - int buffer_size = 0; + uv_err_t err = uv_ok_; /* Count the required size. */ for (arg = args; *arg; arg++) { - arg_size = uv_utf8_to_utf16(*arg, NULL, 0) * sizeof(wchar_t); - size += arg_size; - buffer_size = arg_size > buffer_size ? arg_size : buffer_size; + DWORD arg_len; + + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + NULL, + 0); + if (arg_len == 0) { + return uv__new_sys_error(GetLastError()); + } + + dst_len += arg_len; + + if (arg_len > temp_buffer_len) + temp_buffer_len = arg_len; + arg_count++; } - /* Adjust for potential quotes. Also assume the worst-case scenario + /* Adjust for potential quotes. Also assume the worst-case scenario */ /* that every character needs escaping, so we need twice as much space. */ - size = size * 2 + arg_count * 2; + dst_len = dst_len * 2 + arg_count * 2; - dst = (wchar_t*)malloc(size); - if (!dst) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + /* Allocate buffer for the final command line. */ + dst = (WCHAR*) malloc(dst_len * sizeof(WCHAR)); + if (dst == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto error; } - buffer = (wchar_t*)malloc(buffer_size); - if (!buffer) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + /* Allocate temporary working buffer. */ + temp_buffer = (WCHAR*) malloc(temp_buffer_len * sizeof(WCHAR)); + if (temp_buffer == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto error; } - ptr = dst; + pos = dst; for (arg = args; *arg; arg++) { - len = uv_utf8_to_utf16(*arg, buffer, (size_t)(size - (ptr - dst))); - if (!len) { + DWORD arg_len; + + /* Convert argument to wide char. */ + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + temp_buffer, + dst + dst_len - pos); + if (arg_len == 0) { goto error; } + if (verbatim_arguments) { - wcscpy(ptr, buffer); - ptr += len - 1; + /* Copy verbatim. */ + wcscpy(pos, temp_buffer); + pos += arg_len - 1; } else { - ptr = quote_cmd_arg(buffer, ptr); + /* Quote/escape, if needed. */ + pos = quote_cmd_arg(temp_buffer, pos); } - *ptr++ = *(arg + 1) ? L' ' : L'\0'; + + *pos++ = *(arg + 1) ? L' ' : L'\0'; } - free(buffer); - return dst; + free(temp_buffer); + + *dst_ptr = dst; + return uv_ok_; error: free(dst); - free(buffer); - return NULL; + free(temp_buffer); + return err; } @@ -526,11 +571,11 @@ static void check_required_vars_contains_var(env_var_t* required, int size, * these get defined if the input environment block does not contain any * values for them. */ -wchar_t* make_program_env(char** env_block) { - wchar_t* dst; - wchar_t* ptr; +WCHAR* make_program_env(char** env_block) { + WCHAR* dst; + WCHAR* ptr; char** env; - int env_len = 1 * sizeof(wchar_t); /* room for closing null */ + int env_len = 1 * sizeof(WCHAR); /* room for closing null */ int len; int i; DWORD var_size; @@ -545,18 +590,18 @@ wchar_t* make_program_env(char** env_block) { check_required_vars_contains_var(required_vars, ARRAY_SIZE(required_vars), *env); - env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(wchar_t)); + env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(WCHAR)); } for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { if (!required_vars[i].supplied) { - env_len += required_vars[i].len * sizeof(wchar_t); + env_len += required_vars[i].len * sizeof(WCHAR); var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); if (var_size == 0) { uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); } required_vars[i].value_len = (int)var_size; - env_len += (int)var_size * sizeof(wchar_t); + env_len += (int)var_size * sizeof(WCHAR); } } @@ -600,74 +645,17 @@ wchar_t* make_program_env(char** env_block) { * a child process has exited. */ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { - uv_process_t* process = (uv_process_t*)data; - uv_loop_t* loop = process->loop; - - assert(didTimeout == FALSE); - assert(process); - - /* Post completed */ - POST_COMPLETION_FOR_REQ(loop, &process->exit_req); -} - - -/* - * Called on Windows thread-pool thread to indicate that - * UnregisterWaitEx has completed. - */ -static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) { - uv_process_t* process = (uv_process_t*)data; + uv_process_t* process = (uv_process_t*) data; uv_loop_t* loop = process->loop; assert(didTimeout == FALSE); assert(process); + assert(!process->exit_cb_pending); - /* Post completed */ - POST_COMPLETION_FOR_REQ(loop, &process->close_req); -} - - -/* - * Called on windows thread pool when CreateProcess failed. It writes an error - * message to the process' intended stderr and then posts a PROCESS_EXIT - * packet to the completion port. - */ -static DWORD WINAPI spawn_failure(void* data) { - char syscall[] = "CreateProcessW: "; - char unknown[] = "unknown error\n"; - uv_process_t* process = (uv_process_t*) data; - uv_loop_t* loop = process->loop; - HANDLE child_stderr = uv__stdio_handle(process->child_stdio_buffer, 2); - char* buf = NULL; - DWORD count, written; - - if (child_stderr != INVALID_HANDLE_VALUE) { - WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL); - - count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - process->spawn_errno, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR) &buf, - 0, - NULL); - - if (buf != NULL && count > 0) { - WriteFile(child_stderr, buf, count, &written, NULL); - LocalFree(buf); - } else { - WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL); - } - - FlushFileBuffers(child_stderr); - } + process->exit_cb_pending = 1; /* Post completed */ POST_COMPLETION_FOR_REQ(loop, &process->exit_req); - - return 0; } @@ -675,8 +663,13 @@ static DWORD WINAPI spawn_failure(void* data) { void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { DWORD exit_code; - /* FIXME: race condition. */ + assert(handle->exit_cb_pending); + handle->exit_cb_pending = 0; + + /* If we're closing, don't call the exit callback. Just schedule a close */ + /* callback now. */ if (handle->flags & UV_HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); return; } @@ -686,71 +679,68 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { handle->wait_handle = INVALID_HANDLE_VALUE; } - if (handle->process_handle == INVALID_HANDLE_VALUE || - !GetExitCodeProcess(handle->process_handle, &exit_code)) { - /* The process never even started in the first place, or we were unable */ - /* to obtain the exit code. */ - exit_code = 127; - } - /* Set the handle to inactive: no callbacks will be made after the exit */ /* callback.*/ uv__handle_stop(handle); + if (handle->spawn_error.code != UV_OK) { + /* Spawning failed. */ + exit_code = (DWORD) -1; + } else if (!GetExitCodeProcess(handle->process_handle, &exit_code)) { + /* Unable to to obtain the exit code. This should never happen. */ + exit_code = (DWORD) -1; + } + /* Fire the exit callback. */ if (handle->exit_cb) { + loop->last_err = handle->spawn_error; handle->exit_cb(handle, exit_code, handle->exit_signal); } } -/* Called on main thread after UnregisterWaitEx finishes. */ -void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) { - uv_want_endgame(loop, (uv_handle_t*)handle); -} - - void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { uv__handle_start(handle); if (handle->wait_handle != INVALID_HANDLE_VALUE) { - handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL); - UnregisterWaitEx(handle->wait_handle, handle->close_handle); - handle->wait_handle = NULL; + /* This blocks until either the wait was cancelled, or the callback has */ + /* completed. */ + BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); + if (!r) { + /* This should never happen, and if it happens, we can't recover... */ + uv_fatal_error(GetLastError(), "UnregisterWaitEx"); + } - RegisterWaitForSingleObject(&handle->wait_handle, handle->close_handle, - close_wait_callback, (void*)handle, INFINITE, - WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); - } else { + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + if (!handle->exit_cb_pending) { uv_want_endgame(loop, (uv_handle_t*)handle); } } void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - uv__handle_stop(handle); + assert(!handle->exit_cb_pending); + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); - /* Clean-up the process handle. */ - CloseHandle(handle->process_handle); + uv__handle_stop(handle); - /* Clean up the child stdio ends that may have been left open. */ - if (handle->child_stdio_buffer != NULL) { - uv__stdio_destroy(handle->child_stdio_buffer); - } + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); - uv__handle_close(handle); - } + uv__handle_close(handle); } int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv_process_options_t options) { - int i, size, err = 0, keep_child_stdio_open = 0; - wchar_t* path = NULL; + int i; + uv_err_t err = uv_ok_; + WCHAR* path = NULL; BOOL result; - wchar_t* application_path = NULL, *application = NULL, *arguments = NULL, + WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; @@ -761,6 +751,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, return -1; } + if (options.file == NULL || + options.args == NULL) { + uv__set_artificial_error(loop, UV_EINVAL); + return -1; + } + assert(options.file != NULL); assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_DETACHED | @@ -768,57 +764,84 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, UV_PROCESS_SETUID))); uv_process_init(loop, process); - process->exit_cb = options.exit_cb; - UTF8_TO_UTF16(options.file, application); - arguments = options.args ? make_program_args(options.args, - options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL; - env = options.env ? make_program_env(options.env) : NULL; + + err = uv_utf8_to_utf16_alloc(options.file, &application); + if (err.code != UV_OK) + goto done; + + err = make_program_args(options.args, + options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, + &arguments); + if (err.code != UV_OK) + goto done; if (options.cwd) { - UTF8_TO_UTF16(options.cwd, cwd); + /* Explicit cwd */ + err = uv_utf8_to_utf16_alloc(options.cwd, &cwd); + if (err.code != UV_OK) + goto done; + } else { - size = GetCurrentDirectoryW(0, NULL) * sizeof(wchar_t); - if (size) { - cwd = (wchar_t*)malloc(size); - if (!cwd) { - uv__set_artificial_error(loop, UV_ENOMEM); - err = -1; - goto done; - } + /* Inherit cwd */ + DWORD cwd_len, r; - GetCurrentDirectoryW(size, cwd); - } else { - uv__set_sys_error(loop, GetLastError()); - err = -1; + cwd_len = GetCurrentDirectoryW(0, NULL); + if (!cwd_len) { + err = uv__new_sys_error(GetLastError()); + goto done; + } + + cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR)); + if (cwd == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto done; + } + + r = GetCurrentDirectoryW(cwd_len, cwd); + if (r == 0 || r >= cwd_len) { + err = uv__new_sys_error(GetLastError()); goto done; } } - /* Get PATH env. variable. */ - size = GetEnvironmentVariableW(L"PATH", NULL, 0) + 1; - path = (wchar_t*)malloc(size * sizeof(wchar_t)); - if (!path) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + /* Get PATH environment variable. */ + { + DWORD path_len, r; + + path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); + if (path_len == 0) { + err = uv__new_sys_error(GetLastError()); + goto done; + } + + + path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); + if (path == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto done; + } + + r = GetEnvironmentVariableW(L"PATH", path, path_len); + if (r == 0 || r >= path_len) { + err = uv__new_sys_error(GetLastError()); + goto done; + } } - GetEnvironmentVariableW(L"PATH", path, size * sizeof(wchar_t)); - path[size - 1] = L'\0'; application_path = search_path(application, cwd, path); - - if (!application_path) { - /* CreateProcess will fail, but this allows us to pass this error to */ - /* the user asynchronously. */ - application_path = application; + if (application_path == NULL) { + /* Not found. */ + err = uv__new_artificial_error(UV_ENOENT); + goto done; } - if (uv__stdio_create(loop, &options, &process->child_stdio_buffer) < 0) { - err = -1; - goto done; - } + err = uv__stdio_create(loop, &options, &process->child_stdio_buffer); + if (err.code != UV_OK) + goto done; startup.cb = sizeof(startup); startup.lpReserved = NULL; @@ -871,60 +894,37 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, CloseHandle(info.hThread); } else { - /* CreateProcessW failed, but this failure should be delivered */ - /* 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(); - keep_child_stdio_open = 1; - if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) { - uv_fatal_error(GetLastError(), "QueueUserWorkItem"); - } + /* CreateProcessW failed. */ + err = uv__new_sys_error(GetLastError()); } done: free(application); - if (application_path != application) { - free(application_path); - } + free(application_path); free(arguments); free(cwd); free(env); free(path); - /* Under normal circumstances we should close the stdio handles now - the */ - /* the child now has its own duplicates, or something went horribly wrong */ - /* The only exception is when CreateProcess has failed, then we actually */ - /* need to keep the stdio handles to report the error asynchronously. */ - if (process->child_stdio_buffer == NULL) { - /* Something went wrong before child stdio was initialized. */ - } else if (!keep_child_stdio_open) { + process->spawn_error = err; + + if (process->child_stdio_buffer != NULL) { + /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; - } else { - /* We're keeping the handles open, the thread pool is going to have */ - /* it's way with them. But at least make them non-inheritable. */ - uv__stdio_noinherit(process->child_stdio_buffer); } - if (err == 0) { - /* Spawn was succesful. The handle will be active until the exit */ - /* is made or the handle is closed, whichever happens first. */ - uv__handle_start(process); - } else { - /* Spawn was not successful. Clean up. */ - if (process->wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(process->wait_handle); - process->wait_handle = INVALID_HANDLE_VALUE; - } + /* Make the handle active. It will remain active until the exit callback */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); - if (process->process_handle != INVALID_HANDLE_VALUE) { - CloseHandle(process->process_handle); - process->process_handle = INVALID_HANDLE_VALUE; - } + /* If an error happened, queue the exit req. */ + if (err.code != UV_OK) { + process->exit_cb_pending = 1; + uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req); } - return err; + return 0; } diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h index a0d91cb..353fe90 100644 --- a/deps/uv/src/win/req-inl.h +++ b/deps/uv/src/win/req-inl.h @@ -80,7 +80,6 @@ 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); } @@ -188,6 +187,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) { uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); break; + case UV_SIGNAL_REQ: + uv_process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + case UV_POLL_REQ: uv_process_poll_req(loop, (uv_poll_t*) req->data, req); break; @@ -200,10 +203,6 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) { 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; diff --git a/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c new file mode 100644 index 0000000..3407c6c --- /dev/null +++ b/deps/uv/src/win/signal.c @@ -0,0 +1,349 @@ +/* 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 +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +RB_HEAD(uv_signal_tree_s, uv_signal_s); + +static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); +static ssize_t volatile uv__signal_control_handler_refs = 0; +static CRITICAL_SECTION uv__signal_lock; + + +void uv_signals_init() { + InitializeCriticalSection(&uv__signal_lock); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up */ + /* adjacent. */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after */ + /* { .signum = x, .loop = NULL } */ + if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; + if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; + + if ((uintptr_t) w1 < (uintptr_t) w2) return -1; + if ((uintptr_t) w1 > (uintptr_t) w2) return 1; + + return 0; +} + + +RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare); + + +/* + * Dispatches signal {signum} to all active uv_signal_t watchers in all loops. + * Returns 1 if the signal was dispatched to any watcher, or 0 if there were + * no active signal watchers observing this signal. + */ +int uv__signal_dispatch(int signum) { + uv_signal_t lookup; + uv_signal_t* handle; + int dispatched = 0; + + EnterCriticalSection(&uv__signal_lock); + + lookup.signum = signum; + lookup.loop = NULL; + + for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { + unsigned long previous = InterlockedExchange(&handle->pending_signum, signum); + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + } + + LeaveCriticalSection(&uv__signal_lock); + + return dispatched; +} + + +static BOOL WINAPI uv__signal_control_handler(DWORD type) { + switch (type) { + case CTRL_C_EVENT: + return uv__signal_dispatch(SIGINT); + + case CTRL_BREAK_EVENT: + return uv__signal_dispatch(SIGBREAK); + + case CTRL_CLOSE_EVENT: + if (uv__signal_dispatch(SIGHUP)) { + /* Windows will terminate the process after the control handler */ + /* returns. After that it will just terminate our process. Therefore */ + /* block the signal handler so the main loop has some time to pick */ + /* up the signal and do something for a few seconds. */ + Sleep(INFINITE); + return TRUE; + } + return FALSE; + + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + /* These signals are only sent to services. Services have their own */ + /* notification mechanism, so there's no point in handling these. */ + + default: + /* We don't handle these. */ + return FALSE; + } +} + + +static uv_err_t uv__signal_register_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + + /* If the console control handler has already been hooked, just add a */ + /* reference. */ + if (uv__signal_control_handler_refs > 0) + return uv_ok_; + + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + return uv__new_sys_error(GetLastError()); + + uv__signal_control_handler_refs++; + + return uv_ok_; +} + + +static void uv__signal_unregister_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + BOOL r; + + /* Don't unregister if the number of console control handlers exceeds one. */ + /* Just remove a reference in that case. */ + if (uv__signal_control_handler_refs > 1) { + uv__signal_control_handler_refs--; + return; + } + + assert(uv__signal_control_handler_refs == 1); + + r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); + /* This should never fail; if it does it is probably a bug in libuv. */ + assert(r); + + uv__signal_control_handler_refs--; +} + + +static uv_err_t uv__signal_register(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + return uv__signal_register_control_handler(); + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Signal is never raised. */ + return uv_ok_; + + default: + /* Invalid signal. */ + return uv__new_artificial_error(UV_EINVAL); + } +} + + +static void uv__signal_unregister(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + uv__signal_unregister_control_handler(); + return; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Nothing is registered for this signal. */ + return; + + default: + /* Libuv bug. */ + assert(0 && "Invalid signum"); + return; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + req = &handle->signal_req; + uv_req_init(loop, req); + req->type = UV_SIGNAL_REQ; + req->data = handle; + + uv__handle_start(handle); + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return 0; + + EnterCriticalSection(&uv__signal_lock); + + uv__signal_unregister(handle->signum); + + removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signum = 0; + uv__handle_stop(handle); + + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + uv_err_t err; + + /* If the user supplies signum == 0, then return an error already. If the */ + /* signum is otherwise invalid then uv__signal_register will find out */ + /* eventually. */ + if (signum == 0) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + + /* Short circuit: if the signal watcher is already watching {signum} don't */ + /* go through the process of deregistering and registering the handler. */ + /* Additionally, this avoids pending signals getting lost in the (small) */ + /* time frame that handle->signum == 0. */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + int r = uv_signal_stop(handle); + /* uv_signal_stop is infallible. */ + assert(r == 0); + } + + EnterCriticalSection(&uv__signal_lock); + + err = uv__signal_register(signum); + if (err.code != UV_OK) { + /* Uh-oh, didn't work. */ + handle->loop->last_err = err; + LeaveCriticalSection(&uv__signal_lock); + return -1; + } + + handle->signum = signum; + RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req) { + unsigned long dispatched_signum; + + assert(handle->type == UV_SIGNAL); + assert(req->type == UV_SIGNAL_REQ); + + dispatched_signum = InterlockedExchange(&handle->pending_signum, 0); + assert(dispatched_signum != 0); + + /* Check if the pending signal equals the signum that we are watching for. */ + /* These can get out of sync when the handler is stopped and restarted */ + /* while the signal_req is pending. */ + if (dispatched_signum == handle->signum) + handle->signal_cb(handle, dispatched_signum); + + if (handle->flags & UV_HANDLE_CLOSING) { + /* When it is closing, it must be stopped at this point. */ + assert(handle->signum == 0); + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { + uv_signal_stop(handle); + + if (handle->pending_signum == 0) { + uv__handle_start(handle); + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->signum == 0); + assert(handle->pending_signum == 0); + + handle->flags |= UV_HANDLE_CLOSED; + + uv__handle_stop(handle); + uv__handle_close(handle); +} diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h index 7e2311c..3cde668 100644 --- a/deps/uv/src/win/stream-inl.h +++ b/deps/uv/src/win/stream-inl.h @@ -36,8 +36,6 @@ INLINE static void uv_stream_init(uv_loop_t* loop, uv__handle_init(loop, (uv_handle_t*) handle, type); handle->write_queue_size = 0; handle->activecnt = 0; - - loop->counters.stream_init++; } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 2a25358..fdca452 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -149,8 +149,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { handle->func_connectex = NULL; handle->processed_accepts = 0; - loop->counters.tcp_init++; - return 0; } diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 94b7b21..e9eab9a 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -71,8 +71,6 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { handle->timer_cb = NULL; handle->repeat = 0; - loop->counters.timer_init++; - return 0; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 66103e6..8575f4f 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -89,54 +89,70 @@ void uv_console_init() { int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { - HANDLE win_handle; - CONSOLE_SCREEN_BUFFER_INFO info; - - loop->counters.tty_init++; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD original_console_mode = 0; + CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; - win_handle = (HANDLE) _get_osfhandle(fd); - if (win_handle == INVALID_HANDLE_VALUE) { - uv__set_sys_error(loop, ERROR_INVALID_HANDLE); + handle = (HANDLE) _get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { + uv__set_artificial_error(loop, UV_EBADF); return -1; } - if (!GetConsoleMode(win_handle, &tty->original_console_mode)) { - uv__set_sys_error(loop, GetLastError()); - return -1; - } + if (readable) { + /* Try to obtain the original console mode fromt he input handle. */ + if (!GetConsoleMode(handle, &original_console_mode)) { + uv__set_sys_error(loop, GetLastError()); + return -1; + } - /* Initialize virtual window size; if it fails, assume that this is stdin. */ - if (GetConsoleScreenBufferInfo(win_handle, &info)) { + } else { + /* Obtain the screen buffer info with the output handle. */ + if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { + uv__set_sys_error(loop, GetLastError()); + return -1; + } + + /* Update the virtual window. We must hold the tty_output_lock because the */ + /* virtual window state is shared between all uv_tty handles. */ EnterCriticalSection(&uv_tty_output_lock); - uv_tty_update_virtual_window(&info); + uv_tty_update_virtual_window(&screen_buffer_info); LeaveCriticalSection(&uv_tty_output_lock); } + uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); uv_connection_init((uv_stream_t*) tty); - tty->handle = win_handle; - tty->read_line_handle = NULL; - tty->read_line_buffer = uv_null_buf_; - tty->read_raw_wait = NULL; + tty->handle = handle; tty->reqs_pending = 0; tty->flags |= UV_HANDLE_BOUND; - /* Init keycode-to-vt100 mapper state. */ - tty->last_key_len = 0; - tty->last_key_offset = 0; - tty->last_utf16_high_surrogate = 0; - memset(&tty->last_input_record, 0, sizeof tty->last_input_record); - - /* Init utf8-to-utf16 conversion state. */ - tty->utf8_bytes_left = 0; - tty->utf8_codepoint = 0; + if (readable) { + /* Initialize TTY input specific fields. */ + tty->original_console_mode = original_console_mode; + tty->flags |= UV_HANDLE_TTY_READABLE; + tty->read_line_handle = NULL; + tty->read_line_buffer = uv_null_buf_; + tty->read_raw_wait = NULL; + + /* Init keycode-to-vt100 mapper state. */ + tty->last_key_len = 0; + tty->last_key_offset = 0; + tty->last_utf16_high_surrogate = 0; + memset(&tty->last_input_record, 0, sizeof tty->last_input_record); + } else { + /* TTY output specific fields. */ + /* Init utf8-to-utf16 conversion state. */ + tty->utf8_bytes_left = 0; + tty->utf8_codepoint = 0; - /* Initialize eol conversion state */ - tty->previous_eol = 0; + /* Initialize eol conversion state */ + tty->previous_eol = 0; - /* Init ANSI parser state. */ - tty->ansi_parser_state = ANSI_NORMAL; + /* Init ANSI parser state. */ + tty->ansi_parser_state = ANSI_NORMAL; + } return 0; } @@ -148,6 +164,11 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { uv_alloc_cb alloc_cb; uv_read_cb read_cb; + if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { + uv__set_artificial_error(tty->loop, UV_EINVAL); + return -1; + } + if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { return 0; } @@ -444,6 +465,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, off_t buf_used; assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); handle->flags &= ~UV_HANDLE_READ_PENDING; if (!(handle->flags & UV_HANDLE_READING) || @@ -683,6 +705,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, uv_buf_t buf; assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); buf = handle->read_line_buffer; @@ -726,6 +749,8 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req) { + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); /* If the read_line_buffer member is zero, it must have been an raw read. */ /* Otherwise it was a line-buffered read. */ @@ -742,6 +767,11 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { uv_loop_t* loop = handle->loop; + if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + handle->flags |= UV_HANDLE_READING; INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; @@ -769,6 +799,10 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { uv_loop_t* loop = handle->loop; + if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; @@ -1678,6 +1712,11 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, uv_buf_t bufs[], int bufcnt, uv_write_cb cb) { DWORD error; + if (handle->flags & UV_HANDLE_TTY_READABLE) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + if ((handle->flags & UV_HANDLE_SHUTTING) || (handle->flags & UV_HANDLE_CLOSING)) { uv__set_sys_error(loop, WSAESHUTDOWN); @@ -1729,11 +1768,16 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv_tty_close(uv_tty_t* handle) { - handle->flags |= UV_HANDLE_SHUTTING; - - uv_tty_read_stop(handle); CloseHandle(handle->handle); + if (handle->flags & UV_HANDLE_TTY_READABLE) { + /* Readable TTY handle */ + uv_tty_read_stop(handle); + } else { + /* Writable TTY handle */ + handle->flags |= UV_HANDLE_SHUTTING; + } + uv__handle_start(handle); if (handle->reqs_pending == 0) { @@ -1743,7 +1787,7 @@ void uv_tty_close(uv_tty_t* handle) { void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { - if ((handle->flags && UV_HANDLE_CONNECTION) && + if (!(handle->flags && UV_HANDLE_TTY_READABLE) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); @@ -1768,11 +1812,13 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { handle->reqs_pending == 0) { /* The console handle duplicate used for line reading should be destroyed */ /* by uv_tty_read_stop. */ - assert(handle->read_line_handle == NULL); + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->read_line_handle == NULL); /* The wait handle used for raw reading should be unregistered when the */ /* wait callback runs. */ - assert(handle->read_raw_wait == NULL); + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->read_raw_wait == NULL); assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_stop(handle); diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 3f19fe3..9ad2f69 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -135,8 +135,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { handle->recv_req.type = UV_UDP_RECV; handle->recv_req.data = handle; - loop->counters.udp_init++; - return 0; } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 49a3adc..e1a3504 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -74,7 +74,7 @@ void uv__util_init() { } -int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, +int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size) { return WideCharToMultiByte(CP_UTF8, 0, @@ -87,7 +87,7 @@ int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, } -int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, +int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, size_t utf16Size) { return MultiByteToWideChar(CP_UTF8, 0, @@ -113,7 +113,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) { utf16_buffer_len = (int) *size_ptr; } - utf16_buffer = (wchar_t*) malloc(sizeof(WCHAR) * utf16_buffer_len); + utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len); if (!utf16_buffer) { return -1; } @@ -340,7 +340,7 @@ char** uv_setup_args(int argc, char** argv) { uv_err_t uv_set_process_title(const char* title) { uv_err_t err; int length; - wchar_t* title_w = NULL; + WCHAR* title_w = NULL; uv__once_init(); @@ -352,7 +352,7 @@ uv_err_t uv_set_process_title(const char* title) { } /* Convert to wide-char string */ - title_w = (wchar_t*)malloc(sizeof(wchar_t) * length); + title_w = (WCHAR*)malloc(sizeof(WCHAR) * length); if (!title_w) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } @@ -387,7 +387,7 @@ done: static int uv__get_process_title() { - wchar_t title_w[MAX_TITLE_LENGTH]; + WCHAR title_w[MAX_TITLE_LENGTH]; int length; if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { diff --git a/deps/uv/test/benchmark-fs-stat.c b/deps/uv/test/benchmark-fs-stat.c index e6b8a63..ea5b597 100644 --- a/deps/uv/test/benchmark-fs-stat.c +++ b/deps/uv/test/benchmark-fs-stat.c @@ -26,7 +26,7 @@ #include #define NUM_SYNC_REQS (10 * 1e5) -#define NUM_ASYNC_REQS (1 * 1e5) +#define NUM_ASYNC_REQS (1 * (int) 1e5) #define MAX_CONCURRENT_REQS 32 #define sync_stat(req, path) \ diff --git a/deps/uv/test/benchmark-sizes.c b/deps/uv/test/benchmark-sizes.c index b9cf74f..8ccf10e 100644 --- a/deps/uv/test/benchmark-sizes.c +++ b/deps/uv/test/benchmark-sizes.c @@ -36,6 +36,7 @@ BENCHMARK_IMPL(sizes) { LOGF("uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t)); LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t)); LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t)); + LOGF("uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t)); LOGF("uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t)); LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t)); LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t)); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index ad36719..2f44ff3 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -103,8 +103,8 @@ int process_start(char *name, char *part, process_info_t *p) { goto error; if (part) { - if (_snwprintf((wchar_t*)args, - sizeof(args) / sizeof(wchar_t), + if (_snwprintf((WCHAR*)args, + sizeof(args) / sizeof(WCHAR), L"\"%s\" %S %S", image, name, @@ -112,8 +112,8 @@ int process_start(char *name, char *part, process_info_t *p) { goto error; } } else { - if (_snwprintf((wchar_t*)args, - sizeof(args) / sizeof(wchar_t), + if (_snwprintf((WCHAR*)args, + sizeof(args) / sizeof(WCHAR), L"\"%s\" %S", image, name) < 0) { diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index 5f878a4..b34acc8 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -42,7 +42,7 @@ const char* fmt(double d) { char* p; p = (char *) calloc(1, 32) + 31; /* leaks memory */ - v = d; + v = (uint64_t) d; #if 0 /* works but we don't care about fractional precision */ if (d - v >= 0.01) { diff --git a/deps/uv/test/test-counters-init.c b/deps/uv/test/test-counters-init.c deleted file mode 100644 index 6318684..0000000 --- a/deps/uv/test/test-counters-init.c +++ /dev/null @@ -1,215 +0,0 @@ -/* 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. - */ -#define UNIX (defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)) -#include "task.h" -#include "uv.h" -#include - -#if UNIX -#include /* unlink, rmdir, etc. */ -#else -# include -# include -# define unlink _unlink -# define rmdir _rmdir -# define stat _stati64 -# define open _open -# define write _write -# define lseek _lseek -# define close _close -#endif - -static char exepath[1024]; -static size_t exepath_size = 1024; -static char* args[3]; -static uv_fs_t open_req; -static uv_tcp_t tcp; -static uv_udp_t udp; -static uv_pipe_t uvpipe; -static uv_tty_t tty; -static uv_prepare_t prepare; -static uv_check_t check; -static uv_idle_t idle; -static uv_async_t async; -static uv_timer_t timer; -static uv_fs_event_t fs_event; -static uv_process_t process; -static uv_process_options_t options; -static uv_fs_t fs_req; - -static void exit_cb(uv_process_t* process, int exit_status, int term_signal) { - ASSERT(exit_status == 1); - ASSERT(term_signal == 0); - uv_close((uv_handle_t*)process, NULL); -} - -static void init_process_options(char* test, uv_exit_cb exit_cb) { - int r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); - exepath[exepath_size] = '\0'; - args[0] = exepath; - args[1] = test; - args[2] = NULL; - options.file = exepath; - options.args = args; - options.exit_cb = exit_cb; -} - -static void create_dir(uv_loop_t* loop, const char* name) { - int r; - uv_fs_t req; - r = uv_fs_rmdir(loop, &req, name, NULL); - r = uv_fs_mkdir(loop, &req, name, 0755, NULL); - ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST); - uv_fs_req_cleanup(&req); -} - -static void create_cb(uv_fs_t* req) { - ASSERT(req == &open_req); - ASSERT(req->fs_type == UV_FS_OPEN); - ASSERT(req->result != -1); - uv_fs_req_cleanup(req); - unlink("test_file"); -} - -TEST_IMPL(counters_init) { - int r; - uint64_t eio_init_prev; - uint64_t req_init_prev; - uint64_t handle_init_prev; - uint64_t stream_init_prev; - uint64_t tcp_init_prev; - uint64_t udp_init_prev; - uint64_t pipe_init_prev; - uint64_t tty_init_prev; - uint64_t prepare_init_prev; - uint64_t check_init_prev; - uint64_t idle_init_prev; - uint64_t async_init_prev; - uint64_t timer_init_prev; - uint64_t process_init_prev; - uint64_t fs_event_init_prev; - - /* req_init and eio_init test by uv_fs_open() */ - unlink("test_file"); - req_init_prev = uv_default_loop()->counters.req_init; - eio_init_prev = uv_default_loop()->counters.eio_init; - r = uv_fs_open(uv_default_loop(), &open_req, "test_file", O_WRONLY | O_CREAT, - S_IREAD | S_IWRITE, create_cb); - ASSERT(r == 0); - ASSERT(open_req.result == 0); - ASSERT(uv_default_loop()->counters.req_init == ++req_init_prev); -#ifndef _WIN32 - ASSERT(uv_default_loop()->counters.eio_init == ++eio_init_prev); -#endif - - /* tcp_init, stream_init and handle_init test by uv_tcp_init() */ - tcp_init_prev = uv_default_loop()->counters.tcp_init; - stream_init_prev = uv_default_loop()->counters.stream_init; - handle_init_prev = uv_default_loop()->counters.handle_init; - r = uv_tcp_init(uv_default_loop(), &tcp); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.tcp_init == ++tcp_init_prev); - ASSERT(uv_default_loop()->counters.stream_init == ++stream_init_prev); - ASSERT(uv_default_loop()->counters.handle_init == ++handle_init_prev); - uv_close((uv_handle_t*)&tcp, NULL); - - /* udp_init test by uv_udp_init() */ - udp_init_prev = uv_default_loop()->counters.udp_init; - r = uv_udp_init(uv_default_loop(), &udp); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.udp_init == ++udp_init_prev); - uv_close((uv_handle_t*)&udp, NULL); - - /* pipe_init uv_pipe_init() */ - pipe_init_prev = uv_default_loop()->counters.pipe_init; - uv_pipe_init(uv_default_loop(), &uvpipe, 0); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.pipe_init == ++pipe_init_prev); - uv_close((uv_handle_t*)&uvpipe, NULL); - - /* tty_init test by uv_tty_init()*/ - tty_init_prev = uv_default_loop()->counters.tty_init; - r = uv_tty_init(uv_default_loop(), &tty, 1, 0); - /* uv_tty_init() always returns -1 in run_test in Windows - so that we avoid to check return value. - */ -#ifndef _WIN32 - ASSERT(r == 0); - uv_close((uv_handle_t*)&tty, NULL); -#endif - ASSERT(uv_default_loop()->counters.tty_init == ++tty_init_prev); - - /* prepare_init test by uv_prepare_init() */ - prepare_init_prev = uv_default_loop()->counters.prepare_init; - r = uv_prepare_init(uv_default_loop(), &prepare); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.prepare_init == ++prepare_init_prev); - uv_close((uv_handle_t*)&prepare, NULL); - - /* check_init test by uv_check_init() */ - check_init_prev = uv_default_loop()->counters.check_init; - r = uv_check_init(uv_default_loop(), &check); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.check_init == ++check_init_prev); - uv_close((uv_handle_t*)&check, NULL); - - /* idle_init test by uv_idle_init() */ - idle_init_prev = uv_default_loop()->counters.idle_init; - r = uv_idle_init(uv_default_loop(), &idle); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.idle_init == ++idle_init_prev); - uv_close((uv_handle_t*)&idle, NULL); - - /* async_init test by uv_async_init() */ - async_init_prev = uv_default_loop()->counters.async_init; - r = uv_async_init(uv_default_loop(), &async, NULL); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.async_init == ++async_init_prev); - uv_close((uv_handle_t*)&async, NULL); - - /* timer_init test by uv_timer_init() */ - timer_init_prev = uv_default_loop()->counters.timer_init; - r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.timer_init == ++timer_init_prev); - uv_close((uv_handle_t*)&timer, NULL); - - /* process_init test by uv_spawn() */ - process_init_prev = uv_default_loop()->counters.process_init; - init_process_options("spawn_helper1", exit_cb); - r = uv_spawn(uv_default_loop(), &process, options); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.process_init == ++process_init_prev); - r = uv_run(uv_default_loop()); - ASSERT(r == 0); - - /* fs_event_init test by uv_fs_event_init() */ - create_dir(uv_default_loop(), "watch_dir"); - fs_event_init_prev = uv_default_loop()->counters.fs_event_init; - r = uv_fs_event_init(uv_default_loop(), &fs_event, "watch_dir", NULL, 0); - ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.fs_event_init == ++fs_event_init_prev); - uv_fs_rmdir(uv_default_loop(), &fs_req, "watch_dir", NULL); - uv_fs_req_cleanup(&fs_req); - - return 0; -} diff --git a/deps/uv/test/test-delayed-accept.c b/deps/uv/test/test-delayed-accept.c index 990444e..672672a 100644 --- a/deps/uv/test/test-delayed-accept.c +++ b/deps/uv/test/test-delayed-accept.c @@ -50,7 +50,6 @@ static void close_cb(uv_handle_t* handle) { static void do_accept(uv_timer_t* timer_handle, int status) { uv_tcp_t* server; uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle); - uint64_t tcpcnt; int r; ASSERT(timer_handle != NULL); @@ -60,15 +59,10 @@ static void do_accept(uv_timer_t* timer_handle, int status) { r = uv_tcp_init(uv_default_loop(), accepted_handle); ASSERT(r == 0); - /* Test to that uv_default_loop()->counters.tcp_init does not increase across the uv_accept. */ - tcpcnt = uv_default_loop()->counters.tcp_init; - server = (uv_tcp_t*)timer_handle->data; r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle); ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.tcp_init == tcpcnt); - do_accept_called++; /* Immediately close the accepted handle. */ @@ -115,9 +109,6 @@ static void start_server() { r = uv_tcp_init(uv_default_loop(), server); ASSERT(r == 0); - ASSERT(uv_default_loop()->counters.tcp_init == 1); - ASSERT(uv_default_loop()->counters.handle_init == 1); - r = uv_tcp_bind(server, addr); ASSERT(r == 0); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 8d201c9..47e47ee 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -123,6 +123,7 @@ TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_udp) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) +TEST_DECLARE (spawn_fails) TEST_DECLARE (spawn_exit_code) TEST_DECLARE (spawn_stdout) TEST_DECLARE (spawn_stdin) @@ -174,11 +175,12 @@ TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_create) TEST_DECLARE (strlcpy) TEST_DECLARE (strlcat) -TEST_DECLARE (counters_init) TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) +TEST_DECLARE (we_get_signal) +TEST_DECLARE (we_get_signals) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -350,6 +352,7 @@ TASK_LIST_START TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) + TEST_ENTRY (spawn_fails) TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) TEST_ENTRY (spawn_stdin) @@ -364,6 +367,10 @@ TASK_LIST_START TEST_ENTRY (spawn_stdout_to_file) TEST_ENTRY (fs_poll) TEST_ENTRY (kill) + + TEST_ENTRY (we_get_signal) + TEST_ENTRY (we_get_signals) + #ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) @@ -411,7 +418,6 @@ TASK_LIST_START TEST_ENTRY (thread_create) TEST_ENTRY (strlcpy) TEST_ENTRY (strlcat) - TEST_ENTRY (counters_init) TEST_ENTRY (dlerror) #if 0 /* These are for testing the test runner. */ diff --git a/deps/uv/test/test-signal.c b/deps/uv/test/test-signal.c new file mode 100644 index 0000000..b39bc24 --- /dev/null +++ b/deps/uv/test/test-signal.c @@ -0,0 +1,162 @@ +/* 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" + +#ifdef _WIN32 + +TEST_IMPL(we_get_signal) { + return 0; +} + + +TEST_IMPL(we_get_signals) { + return 0; +} + +#else /* !_WIN32 */ + +#include +#include +#include +#include +#include + +/* This test does not pretend to be cross-platform. */ +#include +#include +#include + +#define NSIGNALS 10 + +struct timer_ctx { + unsigned int ncalls; + uv_timer_t handle; + int signum; +}; + +struct signal_ctx { + enum { CLOSE, STOP } stop_or_close; + unsigned int ncalls; + uv_signal_t handle; + int signum; +}; + + +static void signal_cb(uv_signal_t* handle, int signum) { + struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); + ASSERT(signum == ctx->signum); + + if (++ctx->ncalls == NSIGNALS) { + if (ctx->stop_or_close == STOP) + uv_signal_stop(handle); + else if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); + else + ASSERT(0); + } +} + + +static void timer_cb(uv_timer_t* handle, int status) { + struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle); + + raise(ctx->signum); + + if (++ctx->ncalls == NSIGNALS) + uv_close((uv_handle_t*)handle, NULL); +} + + +static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ctx->stop_or_close = CLOSE; + ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum)); +} + + +static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ASSERT(0 == uv_timer_init(loop, &ctx->handle)); + ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5)); +} + + +TEST_IMPL(we_get_signal) { + struct signal_ctx sc; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, &sc); + sc.stop_or_close = STOP; /* stop, don't close the signal handle */ + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + sc.ncalls = 0; + sc.stop_or_close = CLOSE; /* now close it when it's done */ + uv_signal_start(&sc.handle, signal_cb, SIGCHLD); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + return 0; +} + + +TEST_IMPL(we_get_signals) { + struct signal_ctx sc[4]; + struct timer_ctx tc[2]; + uv_loop_t* loop; + unsigned int i; + + loop = uv_default_loop(); + start_watcher(loop, SIGUSR1, sc + 0); + start_watcher(loop, SIGUSR1, sc + 1); + start_watcher(loop, SIGUSR2, sc + 2); + start_watcher(loop, SIGUSR2, sc + 3); + start_timer(loop, SIGUSR1, tc + 0); + start_timer(loop, SIGUSR2, tc + 1); + ASSERT(0 == uv_run(loop)); + + for (i = 0; i < ARRAY_SIZE(sc); i++) + ASSERT(sc[i].ncalls == NSIGNALS); + + for (i = 0; i < ARRAY_SIZE(tc); i++) + ASSERT(tc[i].ncalls == NSIGNALS); + + return 0; +} + +#endif /* _WIN32 */ diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 06b211b..8cbb01c 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -65,7 +65,7 @@ static void exit_cb_failure_expected(uv_process_t* process, int exit_status, int term_signal) { printf("exit_cb\n"); exit_cb_called++; - ASSERT(exit_status == 127); + ASSERT(exit_status == -1); ASSERT(term_signal == 0); uv_close((uv_handle_t*)process, close_cb); } @@ -145,6 +145,17 @@ static void timer_cb(uv_timer_t* handle, int status) { } +TEST_IMPL(spawn_fails) { + init_process_options("", exit_cb_failure_expected); + options.file = options.args[0] = "program-that-had-better-not-exist"; + ASSERT(0 == uv_spawn(uv_default_loop(), &process, options)); + ASSERT(0 != uv_is_active((uv_handle_t*)&process)); + ASSERT(0 == uv_run(uv_default_loop())); + ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOENT); + return 0; +} + + TEST_IMPL(spawn_exit_code) { int r; @@ -578,11 +589,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { } -wchar_t* make_program_args(char** args, int verbatim_arguments); -wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target); +uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr); +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target); TEST_IMPL(argument_escaping) { - const wchar_t* test_str[] = { + const WCHAR* test_str[] = { L"HelloWorld", L"Hello World", L"Hello\"World", @@ -594,12 +605,13 @@ TEST_IMPL(argument_escaping) { L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"" }; const int count = sizeof(test_str) / sizeof(*test_str); - wchar_t** test_output; - wchar_t* command_line; - wchar_t** cracked; + WCHAR** test_output; + WCHAR* command_line; + WCHAR** cracked; size_t total_size = 0; int i; int num_args; + uv_err_t result; char* verbatim[] = { "cmd.exe", @@ -607,18 +619,18 @@ TEST_IMPL(argument_escaping) { "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"", NULL }; - wchar_t* verbatim_output; - wchar_t* non_verbatim_output; + WCHAR* verbatim_output; + WCHAR* non_verbatim_output; - test_output = calloc(count, sizeof(wchar_t*)); + test_output = calloc(count, sizeof(WCHAR*)); for (i = 0; i < count; ++i) { - test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(wchar_t)); + test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR)); quote_cmd_arg(test_str[i], test_output[i]); wprintf(L"input : %s\n", test_str[i]); wprintf(L"output: %s\n", test_output[i]); total_size += wcslen(test_output[i]) + 1; } - command_line = calloc(total_size + 1, sizeof(wchar_t)); + command_line = calloc(total_size + 1, sizeof(WCHAR)); for (i = 0; i < count; ++i) { wcscat(command_line, test_output[i]); wcscat(command_line, L" "); @@ -638,8 +650,10 @@ TEST_IMPL(argument_escaping) { free(test_output[i]); } - verbatim_output = make_program_args(verbatim, 1); - non_verbatim_output = make_program_args(verbatim, 0); + result = make_program_args(verbatim, 1, &verbatim_output); + ASSERT(result.code == UV_OK); + result = make_program_args(verbatim, 0, &non_verbatim_output); + ASSERT(result.code == UV_OK); wprintf(L" verbatim_output: %s\n", verbatim_output); wprintf(L"non_verbatim_output: %s\n", non_verbatim_output); @@ -653,7 +667,7 @@ TEST_IMPL(argument_escaping) { return 0; } -wchar_t* make_program_env(char** env_block); +WCHAR* make_program_env(char** env_block); TEST_IMPL(environment_creation) { int i; @@ -666,22 +680,22 @@ TEST_IMPL(environment_creation) { NULL }; - wchar_t expected[512]; - wchar_t* ptr = expected; - wchar_t* result; - wchar_t* str; + WCHAR expected[512]; + WCHAR* ptr = expected; + WCHAR* result; + WCHAR* str; for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) { ptr += uv_utf8_to_utf16(environment[i], ptr, expected + sizeof(expected) - ptr); } memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT=")); - ptr += sizeof(L"SYSTEMROOT=")/sizeof(wchar_t) - 1; + ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1; ptr += GetEnvironmentVariableW(L"SYSTEMROOT", ptr, expected + sizeof(expected) - ptr); ++ptr; memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE=")); - ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(wchar_t) - 1; + ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1; ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", ptr, expected + sizeof(expected) - ptr); ++ptr; *ptr = '\0'; diff --git a/deps/uv/test/test-tcp-unexpected-read.c b/deps/uv/test/test-tcp-unexpected-read.c index 45559c0..709d7dd 100644 --- a/deps/uv/test/test-tcp-unexpected-read.c +++ b/deps/uv/test/test-tcp-unexpected-read.c @@ -107,7 +107,7 @@ TEST_IMPL(tcp_unexpected_read) { * start busy looping when the server sends a message and the client isn't * reading. */ - ASSERT(ticks <= 10); + ASSERT(ticks <= 20); return 0; } diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 1fa285f..7b0fe1a 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -59,6 +59,7 @@ 'sources': [ 'include/uv-private/uv-win.h', 'src/win/async.c', + 'src/win/atomicops-inl.h', 'src/win/core.c', 'src/win/dl.c', 'src/win/error.c', @@ -76,6 +77,7 @@ 'src/win/process-stdio.c', 'src/win/req.c', 'src/win/req-inl.h', + 'src/win/signal.c', 'src/win/stream.c', 'src/win/stream-inl.h', 'src/win/tcp.c', @@ -109,6 +111,10 @@ 'include/uv-private/eio.h', 'include/uv-private/ev.h', 'include/uv-private/uv-unix.h', + 'include/uv-private/uv-linux.h', + 'include/uv-private/uv-sunos.h', + 'include/uv-private/uv-darwin.h', + 'include/uv-private/uv-bsd.h', 'src/unix/async.c', 'src/unix/core.c', 'src/unix/dl.c', @@ -127,6 +133,7 @@ 'src/unix/pipe.c', 'src/unix/poll.c', 'src/unix/process.c', + 'src/unix/signal.c', 'src/unix/stream.c', 'src/unix/tcp.c', 'src/unix/thread.c', @@ -256,6 +263,7 @@ 'test/test-semaphore.c', 'test/test-shutdown-close.c', 'test/test-shutdown-eof.c', + 'test/test-signal.c', 'test/test-spawn.c', 'test/test-fs-poll.c', 'test/test-stdio-over-pipes.c', @@ -275,6 +283,7 @@ 'test/test-tcp-unexpected-read.c', 'test/test-threadpool.c', 'test/test-mutexes.c', + 'test/test-signal.c', 'test/test-thread.c', 'test/test-timer-again.c', 'test/test-timer.c', @@ -284,7 +293,6 @@ 'test/test-udp-options.c', 'test/test-udp-send-and-recv.c', 'test/test-udp-multicast-join.c', - 'test/test-counters-init.c', 'test/test-dlerror.c', 'test/test-udp-multicast-ttl.c', ], -- 2.7.4