diff --git a/deps/uv/.gitignore b/deps/uv/.gitignore index d11c90bbf03..a2e2558115b 100644 --- a/deps/uv/.gitignore +++ b/deps/uv/.gitignore @@ -43,12 +43,13 @@ Makefile.in /out/ /build/gyp -/run-tests -/run-tests.exe -/run-tests.dSYM -/run-benchmarks -/run-benchmarks.exe -/run-benchmarks.dSYM +/test/.libs/ +/test/run-tests +/test/run-tests.exe +/test/run-tests.dSYM +/test/run-benchmarks +/test/run-benchmarks.exe +/test/run-benchmarks.dSYM *.sln *.vcproj diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 0f1d843ce8f..3b0e5f09252 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -12,9 +12,11 @@ Keno Fischer Keno Fischer Maciej Małecki Marc Schlaich +Rasmus Pedersen Robert Mustacchi Ryan Dahl Ryan Emery +Sam Roberts San-Tai Hsu Saúl Ibarra Corretgé Shigeki Ohtsu diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 6633f0651ed..b6ea5786946 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -111,4 +111,16 @@ Yazhong Liu Sam Roberts River Tarnell Nathan Sweet +Alex Crichton +Luca Bruno Trevor Norris +Oguz Bastemur +Dylan Cali +Austin Foxley +Benjamin Saunders +Geoffry Song +Rasmus Pedersen +William Light +Oleg Efimov +Lars Gierth +rcp diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index dacd4d6588e..a37b0e4766d 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,105 @@ -2014.01.23, Version 0.11.18 (Unstable) +2014.02.28, Version 0.11.21 (Unstable) + +Changes since version 0.11.20: + +* unix: fix uv_fs_write when using an empty buffer (Saúl Ibarra Corretgé) + +* unix, windows: add assertion in uv_loop_delete (Saúl Ibarra Corretgé) + + +2014.02.27, Version 0.11.20 (Unstable), 88355e081b51c69ee1e2b6b0015a4e3d38bd0579 + +Changes since version 0.11.19: + +* stream: start thread after assignments (Oguz Bastemur) + +* fs: `uv__cloexec()` opened fd (Fedor Indutny) + +* gyp: qualify `library` variable (Fedor Indutny) + +* unix, win: add uv_udp_set_multicast_interface() (Austin Foxley) + +* unix: fix uv_tcp_nodelay return value in case of error (Saúl Ibarra Corretgé) + +* unix: call setgoups before calling setuid/setgid (Saúl Ibarra Corretgé) + +* include: mark close_cb field as private (Saúl Ibarra Corretgé) + +* unix, windows: map EFBIG errno (Saúl Ibarra Corretgé) + +* unix: correct error when calling uv_shutdown twice (Keno Fischer) + +* windows: fix building on MinGW (Alex Crichton) + +* windows: always initialize uv_process_t (Alex Crichton) + +* include: expose libuv version in header files (Saúl Ibarra Corretgé) + +* fs: vectored IO API for filesystem read/write (Benjamin Saunders) + +* windows: freeze in uv_tcp_endgame (Alexis Campailla) + +* sunos: handle rearm errors (Fedor Indutny) + +* unix: use a heap for timers (Ben Noordhuis) + +* linux: always deregister closing fds from epoll (Geoffry Song) + +* linux: include grp.h for setgroups() (William Light) + +* unix, windows: add uv_loop_init and uv_loop_close (Saúl Ibarra Corretgé) + +* unix, windows: add uv_getrusage() function (Oleg Efimov) + +* win: minor error handle fix to uv_pipe_write_impl (Rasmus Pedersen) + +* heap: fix node removal (Keno Fischer) + +* win: fix C99/C++ comment (Rasmus Pedersen) + +* fs: vectored IO API for filesystem read/write (Benjamin Saunders) + +* unix, windows: add uv_pipe_getsockname (Saúl Ibarra Corretgé) + +* unix, windows: map ENOPROTOOPT errno (Saúl Ibarra Corretgé) + +* errno: add ETXTBSY (Fedor Indutny) + +* fsevent: rename filename field to path (Saúl Ibarra Corretgé) + +* unix, windows: add uv_fs_event_getpath (Saúl Ibarra Corretgé) + +* unix, windows: add uv_fs_poll_getpath (Saúl Ibarra Corretgé) + +* unix, windows: map ERANGE errno (Saúl Ibarra Corretgé) + +* unix, windows: set required size on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* unix, windows: clarify what uv_stream_set_blocking does (Saúl Ibarra + Corretgé) + +* fs: use preadv on Linux if available (Brian White) + + +2014.01.30, Version 0.11.19 (Unstable), 336a1825309744f920230ec3e427e78571772347 + +Changes since version 0.11.18: + +* linux: move sscanf() out of the assert() (Trevor Norris) + +* linux: fix C99/C++ comment (Fedor Indutny) + + +2014.01.30, Version 0.10.24 (Stable), aecd296b6bce9b40f06a61c5c94e43d45ac7308a + +Changes since version 0.10.23: + +* linux: move sscanf() out of the assert() (Trevor Norris) + +* linux: fix C99/C++ comment (Fedor Indutny) + + +2014.01.23, Version 0.11.18 (Unstable), d47962e9d93d4a55a9984623feaf546406c9cdbb Changes since version 0.11.17: @@ -21,7 +122,7 @@ Changes since version 0.11.17: * linux: move sscanf() out of the assert() (Trevor Norris) -2014.01.23, Version 0.10.23 (Stable) +2014.01.23, Version 0.10.23 (Stable), dbd218e699fec8be311d85e4788be9e28ae884f8 Changes since version 0.10.22: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index c1eae8cea06..75ec751b15b 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -17,7 +17,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_srcdir)/src -include_HEADERS=include/uv.h include/uv-errno.h +include_HEADERS=include/uv.h include/uv-errno.h include/uv-version.h CLEANFILES = @@ -25,6 +25,7 @@ lib_LTLIBRARIES = libuv.la libuv_la_CFLAGS = @CFLAGS@ libuv_la_LDFLAGS = -no-undefined -version-info 11:0:0 libuv_la_SOURCES = src/fs-poll.c \ + src/heap-inl.h \ src/inet.c \ src/queue.h \ src/uv-common.c \ @@ -146,6 +147,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-list.h \ test/test-loop-handles.c \ test/test-loop-alive.c \ + test/test-loop-close.c \ test/test-loop-stop.c \ test/test-loop-time.c \ test/test-multiple-listen.c \ @@ -155,6 +157,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-ping-pong.c \ test/test-pipe-bind-error.c \ test/test-pipe-connect-error.c \ + test/test-pipe-getsockname.c \ test/test-pipe-server-close.c \ test/test-platform-output.c \ test/test-poll-close.c \ @@ -166,6 +169,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-semaphore.c \ test/test-shutdown-close.c \ test/test-shutdown-eof.c \ + test/test-shutdown-twice.c \ test/test-signal-multiple-loops.c \ test/test-signal.c \ test/test-spawn.c \ @@ -196,6 +200,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tty.c \ test/test-udp-dgram-too-big.c \ test/test-udp-ipv6.c \ + test/test-udp-multicast-interface.c \ test/test-udp-multicast-join.c \ test/test-udp-multicast-ttl.c \ test/test-udp-open.c \ diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 28a1e274d59..b424f906df2 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -26,8 +26,10 @@ CFLAGS += -Wall \ INCLUDES = include/stdint-msvc2008.h \ include/tree.h \ include/uv-errno.h \ + include/uv-version.h \ include/uv-win.h \ include/uv.h \ + src/heap-inl.h \ src/queue.h \ src/uv-common.h \ src/win/atomicops-inl.h \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 5704c39e270..00b539ca14b 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -133,7 +133,7 @@ OS X using the GCC or XCode toolchain. Solaris 121 and later using GCC toolchain. -## patches +## Patches See the [guidelines for contributing][]. diff --git a/deps/uv/android-configure b/deps/uv/android-configure index 56625761fdd..9750581206e 100755 --- a/deps/uv/android-configure +++ b/deps/uv/android-configure @@ -3,7 +3,7 @@ export TOOLCHAIN=$PWD/android-toolchain mkdir -p $TOOLCHAIN $1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.7 \ + --toolchain=arm-linux-androideabi-4.8 \ --arch=arm \ --install-dir=$TOOLCHAIN \ --platform=android-9 diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 7adbbbdcc9f..a0e0eea06fe 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -3,7 +3,7 @@ 'visibility%': 'hidden', # V8's visibility setting 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture - 'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds + 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds 'component%': 'static_library', # NB. these names match with what V8 expects 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way 'gcc_version%': 'unknown', @@ -19,7 +19,7 @@ 'msvs_settings': { 'VCCLCompilerTool': { 'target_conditions': [ - ['library=="static_library"', { + ['uv_library=="static_library"', { 'RuntimeLibrary': 1, # static debug }, { 'RuntimeLibrary': 3, # DLL debug @@ -56,7 +56,7 @@ 'msvs_settings': { 'VCCLCompilerTool': { 'target_conditions': [ - ['library=="static_library"', { + ['uv_library=="static_library"', { 'RuntimeLibrary': 0, # static release }, { 'RuntimeLibrary': 2, # debug release diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 9aff4e90120..2b6eadfd8ea 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [0.11.18], [https://github.com/joyent/libuv/issues]) +AC_INIT([libuv], [0.11.21], [https://github.com/joyent/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index 4ba69167d91..f0c59d0786a 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -88,8 +88,8 @@ def run_gyp(args): if not any(a.startswith('-Dtarget_arch=') for a in args): args.append('-Dtarget_arch=%s' % host_arch()) - if not any(a.startswith('-Dlibrary=') for a in args): - args.append('-Dlibrary=static_library') + if not any(a.startswith('-Duv_library=') for a in args): + args.append('-Duv_library=static_library') if not any(a.startswith('-Dcomponent=') for a in args): args.append('-Dcomponent=static_library') diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv-errno.h index 797bcab93b7..466cdf2ca05 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv-errno.h @@ -364,10 +364,34 @@ # define UV__ETIMEDOUT (-4039) #endif +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY (-ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + #if defined(EXDEV) && !defined(_WIN32) # define UV__EXDEV (-EXDEV) #else # define UV__EXDEV (-4037) #endif +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG (-EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT (-ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE (-ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index 45006092be6..eea5a3f5358 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -169,6 +169,7 @@ typedef struct { void* wq[2]; \ uv_mutex_t wq_mutex; \ uv_async_t wq_async; \ + uv_rwlock_t cloexec_lock; \ uv_handle_t* closing_handles; \ void* process_handles[1][2]; \ void* prepare_handles[2]; \ @@ -176,16 +177,16 @@ typedef struct { void* idle_handles[2]; \ void* async_handles[2]; \ struct uv__async async_watcher; \ - /* RB_HEAD(uv__timers, uv_timer_s) */ \ - struct uv__timers { \ - struct uv_timer_s* rbh_root; \ - } timer_handles; \ + struct { \ + void* min; \ + unsigned int nelts; \ + } timer_heap; \ + uint64_t timer_counter; \ uint64_t time; \ int signal_pipefd[2]; \ uv__io_t signal_io_watcher; \ uv_signal_t child_watcher; \ int emfile_fd; \ - uint64_t timer_counter; \ UV_PLATFORM_LOOP_FIELDS \ #define UV_REQ_TYPE_PRIVATE /* empty */ @@ -264,14 +265,8 @@ typedef struct { int pending; \ #define UV_TIMER_PRIVATE_FIELDS \ - /* RB_ENTRY(uv_timer_s) tree_entry; */ \ - struct { \ - struct uv_timer_s* rbe_left; \ - struct uv_timer_s* rbe_right; \ - struct uv_timer_s* rbe_parent; \ - int rbe_color; \ - } tree_entry; \ uv_timer_cb timer_cb; \ + void* heap_node[3]; \ uint64_t timeout; \ uint64_t repeat; \ uint64_t start_id; @@ -294,14 +289,15 @@ typedef struct { uv_file file; \ int flags; \ mode_t mode; \ - void* buf; \ - size_t len; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ off_t off; \ uv_uid_t uid; \ uv_gid_t gid; \ double atime; \ double mtime; \ struct uv__work work_req; \ + uv_buf_t bufsml[4]; \ #define UV_WORK_PRIVATE_FIELDS \ struct uv__work work_req; diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h new file mode 100644 index 00000000000..e48082fbb21 --- /dev/null +++ b/deps/uv/include/uv-version.h @@ -0,0 +1,38 @@ +/* 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_VERSION_H +#define UV_VERSION_H + + /* + * Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI + * stable. When the minor version is odd, the API can change between patch + * releases. Make sure you update the -soname directives in configure.ac + * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * not UV_VERSION_PATCH.) + */ + +#define UV_VERSION_MAJOR 0 +#define UV_VERSION_MINOR 11 +#define UV_VERSION_PATCH 21 +#define UV_VERSION_IS_RELEASE 1 + +#endif /* UV_VERSION_H */ diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index e4e1f839f04..db8f861839a 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -552,9 +552,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); WCHAR* new_pathw; \ int file_flags; \ int fd_out; \ - void* buf; \ - size_t length; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ int64_t offset; \ + uv_buf_t bufsml[4]; \ }; \ struct { \ double atime; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 4eeade74c42..49c2a43ef8e 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -19,7 +19,7 @@ * IN THE SOFTWARE. */ -/* See http://nikhilm.github.com/uvbook/ for an introduction. */ +/* See https://github.com/joyent/libuv#documentation for documentation. */ #ifndef UV_H #define UV_H @@ -46,6 +46,7 @@ extern "C" { #endif #include "uv-errno.h" +#include "uv-version.h" #include #if defined(_MSC_VER) && _MSC_VER < 1600 @@ -94,6 +95,7 @@ extern "C" { XX(EDESTADDRREQ, "destination address required") \ XX(EEXIST, "file already exists") \ XX(EFAULT, "bad address in system call argument") \ + XX(EFBIG, "file too large") \ XX(EHOSTUNREACH, "host is unreachable") \ XX(EINTR, "interrupted system call") \ XX(EINVAL, "invalid argument") \ @@ -112,6 +114,7 @@ extern "C" { XX(ENOENT, "no such file or directory") \ XX(ENOMEM, "not enough memory") \ XX(ENONET, "machine is not on the network") \ + XX(ENOPROTOOPT, "protocol not available") \ XX(ENOSPC, "no space left on device") \ XX(ENOSYS, "function not implemented") \ XX(ENOTCONN, "socket is not connected") \ @@ -124,11 +127,13 @@ extern "C" { XX(EPROTO, "protocol error") \ XX(EPROTONOSUPPORT, "protocol not supported") \ XX(EPROTOTYPE, "protocol wrong type for socket") \ + XX(ERANGE, "result too large") \ XX(EROFS, "read-only file system") \ XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \ XX(ESPIPE, "invalid seek") \ XX(ESRCH, "no such process") \ XX(ETIMEDOUT, "connection timed out") \ + XX(ETXTBSY, "text file is busy") \ XX(EXDEV, "cross-device link not permitted") \ XX(UNKNOWN, "unknown error") \ XX(EOF, "end of file") \ @@ -243,21 +248,43 @@ UV_EXTERN const char* uv_version_string(void); /* - * This function must be called before any other functions in libuv. - * * All functions besides uv_run() are non-blocking. * * All callbacks in libuv are made asynchronously. That is they are never * made by the function that takes them as a parameter. */ -UV_EXTERN uv_loop_t* uv_loop_new(void); -UV_EXTERN void uv_loop_delete(uv_loop_t*); /* * Returns the default loop. */ UV_EXTERN uv_loop_t* uv_default_loop(void); +/* + * Initializes a uv_loop_t structure. + */ +UV_EXTERN int uv_loop_init(uv_loop_t* loop); + +/* + * Closes all internal loop resources. This function must only be called once + * the loop has finished it's execution or it will return UV_EBUSY. After this + * function returns the user shall free the memory allocated for the loop. + */ +UV_EXTERN int uv_loop_close(uv_loop_t* loop); + +/* + * Allocates and initializes a new loop. + * NOTE: This function is DEPRECATED (to be removed after 0.12), users should + * allocate the loop manually and use uv_loop_init instead. + */ +UV_EXTERN uv_loop_t* uv_loop_new(void); + +/* + * Cleans up a loop once it has finished executio and frees its memory. + * NOTE: This function is DEPRECATED (to be removed after 0.12). Users should use + * uv_loop_close and free the memory manually instead. + */ +UV_EXTERN void uv_loop_delete(uv_loop_t*); + /* * This function runs the event loop. It will act differently depending on the * specified mode: @@ -435,8 +462,10 @@ typedef struct { * will be a relative path to a file contained in the directory. * The events parameter is an ORed mask of enum uv_fs_event elements. */ -typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, - int events, int status); +typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, + const char* filename, + int events, + int status); typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, int status, @@ -486,8 +515,9 @@ UV_PRIVATE_REQ_TYPES * initialized stream. req should be an uninitialized shutdown request * struct. The cb is called after shutdown is complete. */ -UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, - uv_shutdown_cb cb); +UV_EXTERN int uv_shutdown(uv_shutdown_t* req, + uv_stream_t* handle, + uv_shutdown_cb cb); struct uv_shutdown_s { UV_REQ_FIELDS @@ -499,12 +529,12 @@ struct uv_shutdown_s { #define UV_HANDLE_FIELDS \ /* public */ \ - uv_close_cb close_cb; \ void* data; \ /* read-only */ \ uv_loop_t* loop; \ uv_handle_type type; \ /* private */ \ + uv_close_cb close_cb; \ void* handle_queue[2]; \ UV_HANDLE_PRIVATE_FIELDS \ @@ -590,8 +620,7 @@ UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); * * uv_stream is an abstract class. * - * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t, and - * soon uv_file_t. + * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t. */ struct uv_stream_s { UV_HANDLE_FIELDS @@ -625,8 +654,9 @@ UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); * eof; it happens when libuv requested a buffer through the alloc callback * but then decided that it didn't need that buffer. */ -UV_EXTERN int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, - uv_read_cb read_cb); +UV_EXTERN int uv_read_start(uv_stream_t*, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb); UV_EXTERN int uv_read_stop(uv_stream_t*); @@ -719,11 +749,7 @@ UV_EXTERN int uv_is_writable(const uv_stream_t* handle); * Relying too much on this API is not recommended. It is likely to change * significantly in the future. * - * On windows this currently works only for uv_pipe_t instances. On unix it - * works for tcp, pipe and tty instances. Be aware that changing the blocking - * mode on unix sets or clears the O_NONBLOCK bit. If you are sharing a handle - * with another process, the other process is affected by the change too, - * which can lead to unexpected results. + * Currently this only works on Windows and only for uv_pipe_t handles. * * Also libuv currently makes no ordering guarantee when the blocking mode * is changed after write requests have already been submitted. Therefore it is @@ -843,7 +869,7 @@ enum uv_udp_flags { }; /* - * Called after a uv_udp_send() or uv_udp_send6(). status 0 indicates + * Called after uv_udp_send(). status 0 indicates * success otherwise error. */ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); @@ -908,7 +934,7 @@ UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); /* - * Bind to a IPv4 address and port. + * Bind to an IP address and port. * * Arguments: * handle UDP handle. Should have been initialized with `uv_udp_init`. @@ -931,8 +957,9 @@ UV_EXTERN int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags); -UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, - int* namelen); +UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, + struct sockaddr* name, + int* namelen); /* * Set membership for a multicast address @@ -948,8 +975,9 @@ UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, * 0 on success, or an error code < 0 on failure. */ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, - const char* multicast_addr, const char* interface_addr, - uv_membership membership); + const char* multicast_addr, + const char* interface_addr, + uv_membership membership); /* * Set IP multicast loop flag. Makes multicast packets loop back to @@ -978,6 +1006,21 @@ UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); */ UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); + +/* + * Set the multicast interface to send on + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * interface_addr interface address + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, + const char* interface_addr); + /* * Set broadcast on or off * @@ -1005,16 +1048,17 @@ UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); /* - * Send data. If the socket has not previously been bound with `uv_udp_bind` - * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address) - * and a random port number. + * Send data. If the socket has not previously been bound with `uv_udp_bind,` + * it is bound to 0.0.0.0 (the "all interfaces" address) and a random + * port number. * * Arguments: * req UDP request handle. Need not be initialized. * handle UDP handle. Should have been initialized with `uv_udp_init`. * bufs List of buffers to send. * nbufs Number of buffers in `bufs`. - * addr Address of the remote peer. See `uv_ip4_addr`. + * addr struct sockaddr_in or struct sockaddr_in6 with the address and + * port of the remote peer. * send_cb Callback to invoke when the data has been sent out. * * Returns: @@ -1029,8 +1073,8 @@ UV_EXTERN int uv_udp_send(uv_udp_send_t* req, /* * Receive data. If the socket has not previously been bound with `uv_udp_bind` - * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address) - * and a random port number. + * it is bound to 0.0.0.0 (the "all interfaces" address) and a random + * port number. * * Arguments: * handle UDP handle. Should have been initialized with `uv_udp_init`. @@ -1040,8 +1084,9 @@ UV_EXTERN int uv_udp_send(uv_udp_send_t* req, * Returns: * 0 on success, or an error code < 0 on failure. */ -UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, - uv_udp_recv_cb recv_cb); +UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb); /* * Stop listening for incoming datagrams. @@ -1144,8 +1189,22 @@ UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); * Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, * typically between 92 and 108 bytes. */ -UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, - const char* name, uv_connect_cb cb); +UV_EXTERN void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb); + +/* + * Get the name of the UNIX domain socket or the named pipe. + * + * A preallocated buffer must be provided. The len parameter holds the + * length of the buffer and it's set to the number of bytes written to the + * buffer on output. If the buffer is not big enough UV_ENOBUFS will be + * returned and len will contain the required size. + */ +UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, + char* buf, + size_t* len); /* * This setting applies to Windows only. @@ -1200,8 +1259,9 @@ UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); /* Initialize the poll watcher using a socket descriptor. On unix this is */ /* identical to uv_poll_init. On windows it takes a SOCKET handle. */ -UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, - uv_os_sock_t socket); +UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, + uv_poll_t* handle, + uv_os_sock_t socket); /* * Starts polling the file descriptor. `events` is a bitmask consisting made up @@ -1299,13 +1359,12 @@ struct uv_async_s { * Note that uv_async_init(), unlike other libuv functions, immediately * starts the handle. To stop the handle again, close it with uv_close(). */ -UV_EXTERN int uv_async_init(uv_loop_t*, uv_async_t* async, - uv_async_cb async_cb); +UV_EXTERN int uv_async_init(uv_loop_t*, + uv_async_t* async, + uv_async_cb async_cb); /* * This can be called from other threads to wake up a libuv thread. - * - * libuv is single threaded at the moment. */ UV_EXTERN int uv_async_send(uv_async_t* async); @@ -1425,7 +1484,7 @@ typedef struct uv_stdio_container_s { typedef struct uv_process_options_s { uv_exit_cb exit_cb; /* Called after the process exits. */ - const char* file; /* Path to program to execute. */ + const char* file; /* Path to program to execute. */ /* * Command line arguments. args[0] should be the path to the program. On * Windows this uses CreateProcess which concatenates the arguments into a @@ -1535,11 +1594,27 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop, /* * Kills the process with the specified signal. The user must still * call uv_close on the process. + * + * Emulates some aspects of Unix exit status on Windows, in that while the + * underlying process will be terminated with a status of `1`, + * `uv_process_t.exit_signal` will be set to signum, so the process will appear + * to have been killed by `signum`. */ UV_EXTERN int uv_process_kill(uv_process_t*, int signum); -/* Kills the process with the specified signal. */ +/* Kills the process with the specified signal. + * + * Emulates some aspects of Unix signals on Windows: + * - SIGTERM, SIGKILL, and SIGINT call TerminateProcess() to unconditionally + * cause the target to exit with status 1. Unlike Unix, this cannot be caught + * or ignored (but see uv_process_kill() and uv_signal_start()). + * - Signal number `0` causes a check for target existence, as in Unix. Return + * value is 0 on existence, UV_ESRCH on non-existence. + * + * Returns 0 on success, or an error code on failure. UV_ESRCH is portably used + * for non-existence of target process, other errors may be system specific. + */ UV_EXTERN int uv_kill(int pid, int signum); @@ -1555,8 +1630,10 @@ struct uv_work_s { }; /* Queues a work request to execute asynchronously on the thread pool. */ -UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req, - uv_work_cb work_cb, uv_after_work_cb after_work_cb); +UV_EXTERN int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb); /* Cancel a pending request. Fails if the request is executing or has finished * executing. @@ -1615,6 +1692,36 @@ UV_EXTERN int uv_set_process_title(const char* title); UV_EXTERN int uv_resident_set_memory(size_t* rss); UV_EXTERN int uv_uptime(double* uptime); +typedef struct { + long tv_sec; + long tv_usec; +} uv_timeval_t; + +typedef struct { + uv_timeval_t ru_utime; /* user CPU time used */ + uv_timeval_t ru_stime; /* system CPU time used */ + uint64_t ru_maxrss; /* maximum resident set size */ + uint64_t ru_ixrss; /* integral shared memory size */ + uint64_t ru_idrss; /* integral unshared data size */ + uint64_t ru_isrss; /* integral unshared stack size */ + uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent */ + uint64_t ru_msgrcv; /* IPC messages received */ + uint64_t ru_nsignals; /* signals received */ + uint64_t ru_nvcsw; /* voluntary context switches */ + uint64_t ru_nivcsw; /* involuntary context switches */ +} uv_rusage_t; + +/* + * Get information about OS resource utilization for the current process. + * Please note that not all uv_rusage_t struct fields will be filled on Windows. + */ +UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); + /* * This allocates cpu_infos array, and sets count. The array * is freed using uv_free_cpu_info(). @@ -1697,13 +1804,13 @@ UV_EXTERN int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb); UV_EXTERN int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, - void* buf, size_t length, int64_t offset, uv_fs_cb cb); + const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb); UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, - const void* buf, size_t length, int64_t offset, uv_fs_cb cb); + const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb); UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb); @@ -1786,7 +1893,8 @@ enum uv_fs_event { struct uv_fs_event_s { UV_HANDLE_FIELDS - char* filename; + /* private */ + char* path; UV_FS_EVENT_PRIVATE_FIELDS }; @@ -1824,6 +1932,15 @@ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); +/* + * Get the path being monitored by the handle. The buffer must be preallocated + * by the user. Returns 0 on success or an error code < 0 in case of failure. + * On sucess, `buf` will contain the path and `len` its length. If the buffer + * is not big enough UV_ENOBUFS will be returned and len will be set to the + * required size. + */ +UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len); + /* * UNIX signal handling on a per-event loop basis. The implementation is not @@ -1835,7 +1952,7 @@ UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); * signals will lead to unpredictable behavior and is strongly discouraged. * Future versions of libuv may simply reject them. * - * Some signal support is available on Windows: + * Reception of some signals is emulated 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. @@ -1854,11 +1971,14 @@ UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); * the console buffer will also trigger a SIGWINCH signal. * * Watchers for other signals can be successfully created, but these signals - * are never generated. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV, + * are never received. 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. + * + * See uv_process_kill() and uv_kill() for information about support for sending + * signals. */ struct uv_signal_s { UV_HANDLE_FIELDS @@ -1919,11 +2039,22 @@ UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle); UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, + const char* path, unsigned int flags); UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle); +/* + * Get the path being monitored by the handle. The buffer must be preallocated + * by the user. Returns 0 on success or an error code < 0 in case of failure. + * On sucess, `buf` will contain the path and `len` its length. If the buffer + * is not big enough UV_ENOBUFS will be returned and len will be set to the + * required size. + */ +UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle, + char* buf, + size_t* len); + /* Utility */ diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 7fdaaeb17a2..abde00302fd 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -118,6 +118,31 @@ int uv_fs_poll_stop(uv_fs_poll_t* handle) { } +int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len) { + struct poll_ctx* ctx; + size_t required_len; + + if (!uv__is_active(handle)) { + *len = 0; + return UV_EINVAL; + } + + ctx = handle->poll_ctx; + assert(ctx != NULL); + + required_len = strlen(ctx->path) + 1; + if (required_len > *len) { + *len = required_len; + return UV_ENOBUFS; + } + + memcpy(buf, ctx->path, required_len); + *len = required_len; + + return 0; +} + + void uv__fs_poll_close(uv_fs_poll_t* handle) { uv_fs_poll_stop(handle); } diff --git a/deps/uv/src/heap-inl.h b/deps/uv/src/heap-inl.h new file mode 100644 index 00000000000..907abe65a0a --- /dev/null +++ b/deps/uv/src/heap-inl.h @@ -0,0 +1,238 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SRC_HEAP_H_ +#define UV_SRC_HEAP_H_ + +#include /* NULL */ + +#if defined(__GNUC__) +# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration +#else +# define HEAP_EXPORT(declaration) static declaration +#endif + +struct heap_node { + struct heap_node* left; + struct heap_node* right; + struct heap_node* parent; +}; + +/* A binary min heap. The usual properties hold: the root is the lowest + * element in the set, the height of the tree is at most log2(nodes) and + * it's always a complete binary tree. + * + * The heap function try hard to detect corrupted tree nodes at the cost + * of a minor reduction in performance. Compile with -DNDEBUG to disable. + */ +struct heap { + struct heap_node* min; + unsigned int nelts; +}; + +/* Return non-zero if a < b. */ +typedef int (*heap_compare_fn)(const struct heap_node* a, + const struct heap_node* b); + +/* Public functions. */ +HEAP_EXPORT(void heap_init(struct heap* heap)); +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)); +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)); + +/* Implementation follows. */ + +HEAP_EXPORT(void heap_init(struct heap* heap)) { + heap->min = NULL; + heap->nelts = 0; +} + +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) { + return heap->min; +} + +/* Swap parent with child. Child moves closer to the root, parent moves away. */ +static void heap_node_swap(struct heap* heap, + struct heap_node* parent, + struct heap_node* child) { + struct heap_node* sibling; + struct heap_node t; + + t = *parent; + *parent = *child; + *child = t; + + parent->parent = child; + if (child->left == child) { + child->left = parent; + sibling = child->right; + } else { + child->right = parent; + sibling = child->left; + } + if (sibling != NULL) + sibling->parent = child; + + if (parent->left != NULL) + parent->left->parent = parent; + if (parent->right != NULL) + parent->right->parent = parent; + + if (child->parent == NULL) + heap->min = child; + else if (child->parent->left == parent) + child->parent->left = child; + else + child->parent->right = child; +} + +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)) { + struct heap_node** parent; + struct heap_node** child; + unsigned int path; + unsigned int n; + unsigned int k; + + newnode->left = NULL; + newnode->right = NULL; + newnode->parent = NULL; + + /* Calculate the path from the root to the insertion point. This is a min + * heap so we always insert at the left-most free node of the bottom row. + */ + path = 0; + for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + parent = child = &heap->min; + while (k > 0) { + parent = child; + if (path & 1) + child = &(*child)->right; + else + child = &(*child)->left; + path >>= 1; + k -= 1; + } + + /* Insert the new node. */ + newnode->parent = *parent; + *child = newnode; + heap->nelts += 1; + + /* Walk up the tree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. + */ + while (newnode->parent != NULL && less_than(newnode, newnode->parent)) + heap_node_swap(heap, newnode->parent, newnode); +} + +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)) { + struct heap_node* smallest; + struct heap_node** max; + struct heap_node* child; + unsigned int path; + unsigned int k; + unsigned int n; + + if (heap->nelts == 0) + return; + + /* Calculate the path from the min (the root) to the max, the left-most node + * of the bottom row. + */ + path = 0; + for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + max = &heap->min; + while (k > 0) { + if (path & 1) + max = &(*max)->right; + else + max = &(*max)->left; + path >>= 1; + k -= 1; + } + + heap->nelts -= 1; + + /* Unlink the max node. */ + child = *max; + *max = NULL; + + if (child == node) { + /* We're removing either the max or the last node in the tree. */ + if (child == heap->min) { + heap->min = NULL; + } + return; + } + + /* Replace the to be deleted node with the max node. */ + child->left = node->left; + child->right = node->right; + child->parent = node->parent; + + if (child->left != NULL) { + child->left->parent = child; + } + + if (child->right != NULL) { + child->right->parent = child; + } + + if (node->parent == NULL) { + heap->min = child; + } else if (node->parent->left == node) { + node->parent->left = child; + } else { + node->parent->right = child; + } + + /* Walk down the subtree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. If the parent is bigger, + * swap it with the smallest child. + */ + for (;;) { + smallest = child; + if (child->left != NULL && less_than(child->left, smallest)) + smallest = child->left; + if (child->right != NULL && less_than(child->right, smallest)) + smallest = child->right; + if (smallest == child) + break; + heap_node_swap(heap, child, smallest); + } +} + +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) { + heap_remove(heap, heap->min, less_than); +} + +#undef HEAP_EXPORT + +#endif /* UV_SRC_HEAP_H_ */ diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index df2a5f80428..a84304497c9 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -37,6 +37,7 @@ #include #include /* INT_MAX, PATH_MAX */ #include /* writev */ +#include /* getrusage */ #ifdef __linux__ # include @@ -785,3 +786,34 @@ int uv__io_active(const uv__io_t* w, unsigned int events) { assert(0 != events); return 0 != (w->pevents & events); } + + +int uv_getrusage(uv_rusage_t* rusage) { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + return -errno; + + rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; + rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; + + rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; + rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; + + rusage->ru_maxrss = usage.ru_maxrss; + rusage->ru_ixrss = usage.ru_ixrss; + rusage->ru_idrss = usage.ru_idrss; + rusage->ru_isrss = usage.ru_isrss; + rusage->ru_minflt = usage.ru_minflt; + rusage->ru_majflt = usage.ru_majflt; + rusage->ru_nswap = usage.ru_nswap; + rusage->ru_inblock = usage.ru_inblock; + rusage->ru_oublock = usage.ru_oublock; + rusage->ru_msgsnd = usage.ru_msgsnd; + rusage->ru_msgrcv = usage.ru_msgrcv; + rusage->ru_nsignals = usage.ru_nsignals; + rusage->ru_nvcsw = usage.ru_nvcsw; + rusage->ru_nivcsw = usage.ru_nivcsw; + + return 0; +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 1aa6539cb42..b06f992dc72 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -44,10 +44,34 @@ #include #include +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_PREADV 1 +#elif defined(__linux__) +# include +# if defined(__GLIBC_PREREQ) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) && \ + __GLIBC_PREREQ(2,10) +# define HAVE_PREADV 1 +# else +# define HAVE_PREADV 0 +# endif +# else +# define HAVE_PREADV 0 +# endif +#else +# define HAVE_PREADV 0 +#endif + #if defined(__linux__) || defined(__sun) # include #elif defined(__APPLE__) || defined(__FreeBSD__) # include +#endif + +#if HAVE_PREADV || defined(__APPLE__) # include #endif @@ -191,10 +215,59 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { static ssize_t uv__fs_read(uv_fs_t* req) { + ssize_t result; + if (req->off < 0) - return read(req->file, req->buf, req->len); - else - return pread(req->file, req->buf, req->len, req->off); + result = readv(req->file, (struct iovec*) req->bufs, req->nbufs); + else { +#if HAVE_PREADV + result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + static int no_preadv; + if (no_preadv) +# endif + { + off_t nread; + size_t index; + +# if defined(__linux__) + retry: +# endif + nread = 0; + index = 0; + result = 1; + do { + if (req->bufs[index].len > 0) { + result = pread(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + nread); + if (result > 0) + nread += result; + } + index++; + } while (index < req->nbufs && result > 0); + if (nread > 0) + result = nread; + } +# if defined(__linux__) + else { + result = uv__preadv(req->file, + (struct iovec*)req->bufs, + req->nbufs, + req->off); + if (result == -1 && errno == ENOSYS) { + no_preadv = 1; + goto retry; + } + } +# endif +#endif + } + if (req->bufs != req->bufsml) + free(req->bufs); + return result; } @@ -306,7 +379,7 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { int out_fd; char buf[8192]; - len = req->len; + len = req->bufsml[0].len; in_fd = req->flags; out_fd = req->file; offset = req->off; @@ -419,7 +492,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { ssize_t r; off = req->off; - r = sendfile(out_fd, in_fd, &off, req->len); + r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len); /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but * it still writes out data. Fortunately, we can detect it by checking if @@ -453,11 +526,11 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { #if defined(__FreeBSD__) len = 0; - r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0); + r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); #else /* The darwin sendfile takes len as an input for the length to send, * so make sure to initialize it with the caller's value. */ - len = req->len; + len = req->bufsml[0].len; r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); #endif @@ -507,14 +580,61 @@ static ssize_t uv__fs_write(uv_fs_t* req) { #endif if (req->off < 0) - r = write(req->file, req->buf, req->len); - else - r = pwrite(req->file, req->buf, req->len, req->off); + r = writev(req->file, (struct iovec*) req->bufs, req->nbufs); + else { +#if HAVE_PREADV + r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + static int no_pwritev; + if (no_pwritev) +# endif + { + off_t written; + size_t index; + +# if defined(__linux__) + retry: +# endif + written = 0; + index = 0; + r = 0; + do { + if (req->bufs[index].len > 0) { + r = pwrite(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + written); + if (r > 0) + written += r; + } + index++; + } while (index < req->nbufs && r >= 0); + if (written > 0) + r = written; + } +# if defined(__linux__) + else { + r = uv__pwritev(req->file, + (struct iovec*) req->bufs, + req->nbufs, + req->off); + if (r == -1 && errno == ENOSYS) { + no_pwritev = 1; + goto retry; + } + } +# endif +#endif + } #if defined(__APPLE__) pthread_mutex_unlock(&lock); #endif + if (req->bufs != req->bufsml) + free(req->bufs); + return r; } @@ -608,6 +728,9 @@ static void uv__fs_work(struct uv__work* w) { int retry_on_eintr; uv_fs_t* req; ssize_t r; +#ifdef O_CLOEXEC + static int no_cloexec_support; +#endif /* O_CLOEXEC */ req = container_of(w, uv_fs_t, work_req); retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); @@ -634,7 +757,6 @@ static void uv__fs_work(struct uv__work* w) { X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); X(LINK, link(req->path, req->new_path)); X(MKDIR, mkdir(req->path, req->mode)); - X(OPEN, open(req->path, req->flags, req->mode)); X(READ, uv__fs_read(req)); X(READDIR, uv__fs_readdir(req)); X(READLINK, uv__fs_readlink(req)); @@ -646,6 +768,35 @@ static void uv__fs_work(struct uv__work* w) { X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); X(WRITE, uv__fs_write(req)); + case UV_FS_OPEN: +#ifdef O_CLOEXEC + /* Try O_CLOEXEC before entering locks */ + if (!no_cloexec_support) { + r = open(req->path, req->flags | O_CLOEXEC, req->mode); + if (r >= 0) + break; + if (errno != EINVAL) + break; + no_cloexec_support = 1; + } +#endif /* O_CLOEXEC */ + if (req->cb != NULL) + uv_rwlock_rdlock(&req->loop->cloexec_lock); + r = open(req->path, req->flags, req->mode); + + /* + * In case of failure `uv__cloexec` will leave error in `errno`, + * so it is enough to just set `r` to `-1`. + */ + if (r >= 0 && uv__cloexec(r, 1) != 0) { + r = uv__close(r); + if (r != 0 && r != -EINPROGRESS) + abort(); + r = -1; + } + if (req->cb != NULL) + uv_rwlock_rdunlock(&req->loop->cloexec_lock); + break; default: abort(); } @@ -834,14 +985,23 @@ int uv_fs_open(uv_loop_t* loop, int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, - void* buf, - size_t len, + const uv_buf_t bufs[], + unsigned int nbufs, int64_t off, uv_fs_cb cb) { INIT(READ); req->file = file; - req->buf = buf; - req->len = len; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + req->off = off; POST; } @@ -898,7 +1058,7 @@ int uv_fs_sendfile(uv_loop_t* loop, req->flags = in_fd; /* hack */ req->file = out_fd; req->off = off; - req->len = len; + req->bufsml[0].len = len; POST; } @@ -947,14 +1107,23 @@ int uv_fs_utime(uv_loop_t* loop, int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, - const void* buf, - size_t len, + const uv_buf_t bufs[], + unsigned int nbufs, int64_t off, uv_fs_cb cb) { INIT(WRITE); req->file = file; - req->buf = (void*) buf; - req->len = len; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + req->off = off; POST; } diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index 7faa1562a61..f9c3a400fbc 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -795,7 +795,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { return err; /* Get absolute path to file */ - handle->realpath = realpath(handle->filename, NULL); + handle->realpath = realpath(handle->path, NULL); if (handle->realpath == NULL) return -errno; handle->realpath_len = strlen(handle->realpath); diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 0ea82b51a0a..4a4656a562c 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -27,6 +27,7 @@ #include #include /* abort */ #include /* strrchr */ +#include /* O_CLOEXEC, may be */ #if defined(__STRICT_ANSI__) # define inline __inline @@ -111,6 +112,14 @@ # define UV__POLLHUP 8 #endif +#if !defined(O_CLOEXEC) && defined(__FreeBSD__) +/* + * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. + * Try using fixed value const and give up, if it doesn't work + */ +# define O_CLOEXEC 0x00100000 +#endif + /* handle flags */ enum { UV_CLOSING = 0x01, /* uv_close() called but not finished. */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index f86f291fc0d..5a25e117c9a 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -331,7 +331,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, + const char* path, unsigned int flags) { #if defined(__APPLE__) struct stat statbuf; @@ -342,13 +342,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, return -EINVAL; /* TODO open asynchronously - but how do we report back errors? */ - fd = open(filename, O_RDONLY); + fd = open(path, O_RDONLY); if (fd == -1) return -errno; uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__fs_event, fd); - handle->filename = strdup(filename); + handle->path = strdup(path); handle->cb = cb; #if defined(__APPLE__) @@ -388,8 +388,8 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN); #endif /* defined(__APPLE__) */ - free(handle->filename); - handle->filename = NULL; + free(handle->path); + handle->path = NULL; uv__close(handle->event_watcher.fd); handle->event_watcher.fd = -1; diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 4f11d88eed7..97a5126f6a6 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -107,6 +107,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct uv__epoll_event* events; + struct uv__epoll_event dummy; uintptr_t i; uintptr_t nfds; @@ -114,13 +115,20 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; - if (events == NULL) - return; - - /* Invalidate events with same file descriptor */ - for (i = 0; i < nfds; i++) - if ((int) events[i].data == fd) - events[i].data = -1; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].data == fd) + events[i].data = -1; + + /* Remove the file descriptor from the epoll. + * This avoids a problem where the same file description remains open + * in another process, causing repeated junk epoll events. + * + * We pass in a dummy epoll_event, to work around a bug in old kernels. + */ + if (loop->backend_fd >= 0) + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); } @@ -638,7 +646,7 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { unsigned int n; int r = sscanf(buf, "cpu%u ", &n); assert(r == 1); - (void) r; // silence build warning + (void) r; /* silence build warning */ for (len = sizeof("cpu0"); n /= 10; len++); } diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index 7641f383c42..20bc173554d 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -124,7 +124,7 @@ static void uv__inotify_read(uv_loop_t* loop, const char* path; ssize_t size; const char *p; - /* needs to be large enough for sizeof(inotify_event) + strlen(filename) */ + /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ char buf[4096]; while (1) { @@ -219,7 +219,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, no_insert: uv__handle_start(handle); QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); - handle->filename = w->path; + handle->path = w->path; handle->cb = cb; handle->wd = wd; @@ -237,7 +237,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { assert(w != NULL); handle->wd = -1; - handle->filename = NULL; + handle->path = NULL; uv__handle_stop(handle); QUEUE_REMOVE(&handle->watchers); diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 06cc5943cf4..c9cc44d8cda 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -199,6 +199,26 @@ # endif #endif /* __NR_utimensat */ +#ifndef __NR_preadv +# if defined(__x86_64__) +# define __NR_preadv 295 +# elif defined(__i386__) +# define __NR_preadv 333 +# elif defined(__arm__) +# define __NR_preadv (UV_SYSCALL_BASE + 361) +# endif +#endif /* __NR_preadv */ + +#ifndef __NR_pwritev +# if defined(__x86_64__) +# define __NR_pwritev 296 +# elif defined(__i386__) +# define __NR_pwritev 334 +# elif defined(__arm__) +# define __NR_pwritev (UV_SYSCALL_BASE + 362) +# endif +#endif /* __NR_pwritev */ + int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if defined(__i386__) @@ -386,3 +406,19 @@ int uv__utimesat(int dirfd, return errno = ENOSYS, -1; #endif } + +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +#if defined(__NR_preadv) + return syscall(__NR_preadv, fd, iov, iovcnt, offset); +#else + return errno = ENOSYS, -1; +#endif +} + +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +#if defined(__NR_pwritev) + return syscall(__NR_pwritev, fd, iov, iovcnt, offset); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 1ad95185489..6d9ec9f22cf 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -147,5 +147,7 @@ int uv__utimesat(int dirfd, const char* path, const struct timespec times[2], int flags); +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); #endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 94a5c038198..52c9328e75f 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -22,12 +22,13 @@ #include "uv.h" #include "tree.h" #include "internal.h" +#include "heap-inl.h" #include #include #include static int uv__loop_init(uv_loop_t* loop, int default_loop); -static void uv__loop_delete(uv_loop_t* loop); +static void uv__loop_close(uv_loop_t* loop); static uv_loop_t default_loop_struct; static uv_loop_t* default_loop_ptr; @@ -45,6 +46,31 @@ uv_loop_t* uv_default_loop(void) { } +int uv_loop_init(uv_loop_t* loop) { + return uv__loop_init(loop, /* default_loop? */ 0); +} + + +int uv_loop_close(uv_loop_t* loop) { + QUEUE* q; + uv_handle_t* h; + if (!QUEUE_EMPTY(&(loop)->active_reqs)) + return -EBUSY; + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + if (!(h->flags & UV__HANDLE_INTERNAL)) + return -EBUSY; + } + uv__loop_close(loop); +#ifndef NDEBUG + memset(loop, -1, sizeof(*loop)); +#endif + if (loop == default_loop_ptr) + default_loop_ptr = NULL; + return 0; +} + + uv_loop_t* uv_loop_new(void) { uv_loop_t* loop; @@ -52,7 +78,7 @@ uv_loop_t* uv_loop_new(void) { if (loop == NULL) return NULL; - if (uv__loop_init(loop, /* default_loop? */ 0)) { + if (uv_loop_init(loop)) { free(loop); return NULL; } @@ -62,13 +88,10 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { - uv__loop_delete(loop); -#ifndef NDEBUG - memset(loop, -1, sizeof(*loop)); -#endif - if (loop == default_loop_ptr) - default_loop_ptr = NULL; - else + uv_loop_t* default_loop; + default_loop = default_loop_ptr; + assert(uv_loop_close(loop) == 0); + if (loop != default_loop) free(loop); } @@ -80,7 +103,7 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) { uv__signal_global_once_init(); memset(loop, 0, sizeof(*loop)); - RB_INIT(&loop->timer_handles); + heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->active_reqs); QUEUE_INIT(&loop->idle_handles); @@ -117,6 +140,9 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) { for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) QUEUE_INIT(loop->process_handles + i); + if (uv_rwlock_init(&loop->cloexec_lock)) + abort(); + if (uv_mutex_init(&loop->wq_mutex)) abort(); @@ -130,7 +156,7 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) { } -static void uv__loop_delete(uv_loop_t* loop) { +static void uv__loop_close(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); uv__async_stop(loop, &loop->async_watcher); @@ -151,6 +177,12 @@ static void uv__loop_delete(uv_loop_t* loop) { uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); + /* + * Note that all thread pool stuff is finished at this point and + * it is safe to just destroy rw lock + */ + uv_rwlock_destroy(&loop->cloexec_lock); + #if 0 assert(QUEUE_EMPTY(&loop->pending_queue)); assert(QUEUE_EMPTY(&loop->watcher_queue)); diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index fd4afb63704..34c118b773d 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -212,5 +212,37 @@ void uv_pipe_connect(uv_connect_t* req, } +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { + struct sockaddr_un sa; + socklen_t addrlen; + int err; + + addrlen = sizeof(sa); + memset(&sa, 0, addrlen); + err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); + if (err < 0) { + *len = 0; + return -errno; + } + + if (sa.sun_path[0] == 0) + /* Linux abstract namespace */ + addrlen -= offsetof(struct sockaddr_un, sun_path); + else + addrlen = strlen(sa.sun_path) + 1; + + + if (addrlen > *len) { + *len = addrlen; + return UV_ENOBUFS; + } + + memcpy(buf, sa.sun_path, addrlen); + *len = addrlen; + + return 0; +} + + void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { } diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 6f96b754d8b..55f6ac5806b 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -40,6 +40,10 @@ extern char **environ; #endif +#ifdef __linux__ +# include +#endif + static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) { assert(pid > 0); @@ -330,6 +334,17 @@ static void uv__process_child_init(const uv_process_options_t* options, _exit(127); } + if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { + /* When dropping privileges from root, the `setgroups` call will + * remove any extraneous groups. If we don't call this, then + * even though our uid has dropped, we may still have groups + * that enable us to do super-user things. This will fail if we + * aren't root, so don't bother checking the return value, this + * is just done as an optimistic privilege dropping function. + */ + SAVE_ERRNO(setgroups(0, NULL)); + } + if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { uv__write_int(error_fd, -errno); perror("setgid()"); @@ -422,10 +437,13 @@ int uv_spawn(uv_loop_t* loop, uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); + /* Acquire write lock to prevent opening new fds in worker threads */ + uv_rwlock_wrlock(&loop->cloexec_lock); pid = fork(); if (pid == -1) { err = -errno; + uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[0]); uv__close(signal_pipe[1]); goto error; @@ -436,6 +454,8 @@ int uv_spawn(uv_loop_t* loop, abort(); } + /* Release lock in parent process */ + uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[1]); process->status = 0; diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9f5d40cf4b0..ad6856b4b76 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -301,6 +301,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { int err; int ret; int kq; + int old_fd; kq = kqueue(); if (kq == -1) { @@ -353,16 +354,20 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { s->fake_fd = fds[0]; s->int_fd = fds[1]; - if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) - goto fatal4; - + old_fd = *fd; s->stream = stream; stream->select = s; *fd = s->fake_fd; + if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) + goto fatal4; + return 0; fatal4: + s->stream = NULL; + stream->select = NULL; + *fd = old_fd; uv__close(s->fake_fd); uv__close(s->int_fd); s->fake_fd = -1; @@ -1103,6 +1108,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { if (!(stream->flags & UV_STREAM_WRITABLE) || stream->flags & UV_STREAM_SHUT || + stream->flags & UV_STREAM_SHUTTING || stream->flags & UV_CLOSED || stream->flags & UV_CLOSING) { return -ENOTCONN; @@ -1505,7 +1511,5 @@ void uv__stream_close(uv_stream_t* handle) { int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { - assert(0 && "implement me"); - abort(); - return 0; + return UV_ENOSYS; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index f31a23fb3cf..b8a39c7017c 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -372,11 +372,14 @@ static void uv__fs_event_read(uv_loop_t* loop, assert(events != 0); handle->fd = PORT_FIRED; handle->cb(handle, NULL, events, 0); + + if (handle->fd != PORT_DELETED) { + r = uv__fs_event_rearm(handle); + if (r != 0) + handle->cb(handle, NULL, 0, r); + } } while (handle->fd != PORT_DELETED); - - if (handle != NULL && handle->fd != PORT_DELETED) - uv__fs_event_rearm(handle); /* FIXME(bnoordhuis) Check return code. */ } @@ -388,10 +391,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, + const char* path, unsigned int flags) { int portfd; int first_run; + int err; if (uv__is_active(handle)) return -EINVAL; @@ -406,13 +410,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, } uv__handle_start(handle); - handle->filename = strdup(filename); + handle->path = strdup(path); handle->fd = PORT_UNUSED; handle->cb = cb; memset(&handle->fo, 0, sizeof handle->fo); - handle->fo.fo_name = handle->filename; - uv__fs_event_rearm(handle); /* FIXME(bnoordhuis) Check return code. */ + handle->fo.fo_name = handle->path; + err = uv__fs_event_rearm(handle); + if (err != 0) + return err; if (first_run) { uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); @@ -434,8 +440,8 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { } handle->fd = PORT_DELETED; - free(handle->filename); - handle->filename = NULL; + free(handle->path); + handle->path = NULL; handle->fo.fo_name = NULL; uv__handle_stop(handle); diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 2c36dc3ffcc..9c50b2d8a16 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -232,7 +232,9 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int uv__tcp_nodelay(int fd, int on) { - return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) + return -errno; + return 0; } diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/unix/timer.c index 240efad5038..b373f4db876 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/unix/timer.c @@ -20,35 +20,41 @@ #include "uv.h" #include "internal.h" +#include "heap-inl.h" + #include #include -static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) { +static int timer_less_than(const struct heap_node* ha, + const struct heap_node* hb) { + const uv_timer_t* a; + const uv_timer_t* b; + + a = container_of(ha, const uv_timer_t, heap_node); + b = container_of(hb, const uv_timer_t, heap_node); + if (a->timeout < b->timeout) - return -1; - if (a->timeout > b->timeout) return 1; - /* - * compare start_id when both has the same timeout. start_id is - * allocated with loop->timer_counter in uv_timer_start(). + if (b->timeout < a->timeout) + return 0; + + /* Compare start_id when both have the same timeout. start_id is + * allocated with loop->timer_counter in uv_timer_start(). */ if (a->start_id < b->start_id) - return -1; - if (a->start_id > b->start_id) return 1; + if (b->start_id < a->start_id) + return 0; + return 0; } -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) { uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); handle->timer_cb = NULL; handle->repeat = 0; - return 0; } @@ -72,7 +78,9 @@ int uv_timer_start(uv_timer_t* handle, /* start_id is the second index to be compared in uv__timer_cmp() */ handle->start_id = handle->loop->timer_counter++; - RB_INSERT(uv__timers, &handle->loop->timer_handles, handle); + heap_insert((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); uv__handle_start(handle); return 0; @@ -83,7 +91,9 @@ int uv_timer_stop(uv_timer_t* handle) { if (!uv__is_active(handle)) return 0; - RB_REMOVE(uv__timers, &handle->loop->timer_handles, handle); + heap_remove((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); uv__handle_stop(handle); return 0; @@ -114,15 +124,15 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { int uv__next_timeout(const uv_loop_t* loop) { + const struct heap_node* heap_node; const uv_timer_t* handle; uint64_t diff; - /* RB_MIN expects a non-const tree root. That's okay, it doesn't modify it. */ - handle = RB_MIN(uv__timers, (struct uv__timers*) &loop->timer_handles); - - if (handle == NULL) + heap_node = heap_min((const struct heap*) &loop->timer_heap); + if (heap_node == NULL) return -1; /* block indefinitely */ + handle = container_of(heap_node, const uv_timer_t, heap_node); if (handle->timeout <= loop->time) return 0; @@ -135,9 +145,15 @@ int uv__next_timeout(const uv_loop_t* loop) { void uv__run_timers(uv_loop_t* loop) { + struct heap_node* heap_node; uv_timer_t* handle; - while ((handle = RB_MIN(uv__timers, &loop->timer_handles))) { + for (;;) { + heap_node = heap_min((struct heap*) &loop->timer_heap); + if (heap_node == NULL) + break; + + handle = container_of(heap_node, uv_timer_t, heap_node); if (handle->timeout > loop->time) break; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index a2b3dc3298b..ae3cc8dc659 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -539,6 +539,31 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on); } +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct in_addr addr; + int err; + + memset(&addr, 0, sizeof addr); + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &addr.s_addr); + if (err) + return err; + } else { + addr.s_addr = htonl(INADDR_ANY); + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + IP_MULTICAST_IF, + (void*) &addr, + sizeof addr) == -1) { + return -errno; + } + + return 0; +} + int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { socklen_t socklen; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index e5fc5077566..2a6316a878e 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -444,3 +444,23 @@ int uv__getaddrinfo_translate_error(int sys_err) { abort(); return 0; /* Pacify compiler. */ } + +int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) { + size_t required_len; + + if (!uv__is_active(handle)) { + *len = 0; + return UV_EINVAL; + } + + required_len = strlen(handle->path) + 1; + if (required_len > *len) { + *len = required_len; + return UV_ENOBUFS; + } + + memcpy(buf, handle->path, required_len); + *len = required_len; + + return 0; +} diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c index 725872b452e..02de6de305c 100644 --- a/deps/uv/src/version.c +++ b/deps/uv/src/version.c @@ -21,20 +21,6 @@ #include "uv.h" - /* - * Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI - * stable. When the minor version is odd, the API can change between patch - * releases. Make sure you update the -soname directives in config-unix.mk - * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but - * not UV_VERSION_PATCH.) - */ - -#define UV_VERSION_MAJOR 0 -#define UV_VERSION_MINOR 11 -#define UV_VERSION_PATCH 18 -#define UV_VERSION_IS_RELEASE 1 - - #define UV_VERSION ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ (UV_VERSION_PATCH)) diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e1a77655ac4..2e702768ed5 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -26,7 +26,9 @@ #include #include #include +#if !defined(__MINGW32__) #include +#endif #include "uv.h" #include "internal.h" @@ -42,7 +44,7 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT; -#ifdef _DEBUG +#if defined(_DEBUG) && !defined(__MINGW32__) /* Our crt debug report handler allows us to temporarily disable asserts */ /* just for the current thread. */ @@ -89,7 +91,7 @@ static void uv_init(void) { /* We also need to setup our debug report handler because some CRT */ /* functions (eg _get_osfhandle) raise an assert when called with invalid */ /* FDs even though they return the proper error code in the release build. */ -#ifdef _DEBUG +#if defined(_DEBUG) && !defined(__MINGW32__) _CrtSetReportHook(uv__crt_dbg_report_handler); #endif @@ -114,12 +116,14 @@ static void uv_init(void) { } -static void uv_loop_init(uv_loop_t* loop) { +int uv_loop_init(uv_loop_t* loop) { + /* Initialize libuv itself first */ + uv__once_init(); + /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); - if (loop->iocp == NULL) { - uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); - } + if (loop->iocp == NULL) + return uv_translate_sys_error(GetLastError()); /* To prevent uninitialized memory access, loop->time must be intialized */ /* to zero before calling uv_update_time for the first time. */ @@ -152,6 +156,8 @@ static void uv_loop_init(uv_loop_t* loop) { loop->timer_counter = 0; loop->stop_flag = 0; + + return 0; } @@ -175,35 +181,50 @@ uv_loop_t* uv_default_loop(void) { } +int uv_loop_close(uv_loop_t* loop) { + QUEUE* q; + uv_handle_t* h; + if (!QUEUE_EMPTY(&(loop)->active_reqs)) + return UV_EBUSY; + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + if (!(h->flags & UV__HANDLE_INTERNAL)) + return UV_EBUSY; + } + if (loop != &uv_default_loop_) { + int i; + for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { + SOCKET sock = loop->poll_peer_sockets[i]; + if (sock != 0 && sock != INVALID_SOCKET) + closesocket(sock); + } + } + /* TODO: cleanup default loop*/ + return 0; +} + + uv_loop_t* uv_loop_new(void) { uv_loop_t* loop; - /* Initialize libuv itself first */ - uv__once_init(); - loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); + if (loop == NULL) { + return NULL; + } - if (!loop) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + if (uv_loop_init(loop)) { + free(loop); + return NULL; } - uv_loop_init(loop); return loop; } void uv_loop_delete(uv_loop_t* loop) { - if (loop != &uv_default_loop_) { - int i; - for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { - SOCKET sock = loop->poll_peer_sockets[i]; - if (sock != 0 && sock != INVALID_SOCKET) { - closesocket(sock); - } - } - + assert(uv_loop_close(loop) == 0); + if (loop != &uv_default_loop_) free(loop); - } } diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 6132b79c82f..f3de5756852 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -126,38 +126,38 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, + const char* path, unsigned int flags) { int name_size, is_path_dir; DWORD attr, last_error; - WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL; + WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; WCHAR short_path[MAX_PATH]; if (uv__is_active(handle)) return UV_EINVAL; handle->cb = cb; - handle->filename = strdup(filename); - if (!handle->filename) { + handle->path = strdup(path); + if (!handle->path) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } uv__handle_start(handle); /* Convert name to UTF16. */ - name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(WCHAR); - filenamew = (WCHAR*)malloc(name_size); - if (!filenamew) { + name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR); + pathw = (WCHAR*)malloc(name_size); + if (!pathw) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(filename, filenamew, + if (!uv_utf8_to_utf16(path, pathw, name_size / sizeof(WCHAR))) { return uv_translate_sys_error(GetLastError()); } - /* Determine whether filename is a file or a directory. */ - attr = GetFileAttributesW(filenamew); + /* Determine whether path is a file or a directory. */ + attr = GetFileAttributesW(pathw); if (attr == INVALID_FILE_ATTRIBUTES) { last_error = GetLastError(); goto error; @@ -166,22 +166,22 @@ int uv_fs_event_start(uv_fs_event_t* handle, is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; if (is_path_dir) { - /* filename is a directory, so that's the directory that we will watch. */ - handle->dirw = filenamew; - dir_to_watch = filenamew; + /* path is a directory, so that's the directory that we will watch. */ + handle->dirw = pathw; + dir_to_watch = pathw; } else { /* - * filename is a file. So we split filename into dir & file parts, and + * path is a file. So we split path into dir & file parts, and * watch the dir directory. */ /* Convert to short path. */ - if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) { + if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { last_error = GetLastError(); goto error; } - if (uv_split_path(filenamew, &dir, &handle->filew) != 0) { + if (uv_split_path(pathw, &dir, &handle->filew) != 0) { last_error = GetLastError(); goto error; } @@ -192,8 +192,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, } dir_to_watch = dir; - free(filenamew); - filenamew = NULL; + free(pathw); + pathw = NULL; } handle->dir_handle = CreateFileW(dir_to_watch, @@ -257,9 +257,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, return 0; error: - if (handle->filename) { - free(handle->filename); - handle->filename = NULL; + if (handle->path) { + free(handle->path); + handle->path = NULL; } if (handle->filew) { @@ -272,7 +272,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->short_filew = NULL; } - free(filenamew); + free(pathw); if (handle->dir_handle != INVALID_HANDLE_VALUE) { CloseHandle(handle->dir_handle); @@ -309,9 +309,9 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { handle->short_filew = NULL; } - if (handle->filename) { - free(handle->filename); - handle->filename = NULL; + if (handle->path) { + free(handle->path); + handle->path = NULL; } if (handle->dirw) { diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index c4182758c7a..d997b0ee7d7 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -539,13 +539,14 @@ void fs__close(uv_fs_t* req) { void fs__read(uv_fs_t* req) { int fd = req->fd; - size_t length = req->length; int64_t offset = req->offset; HANDLE handle; OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; DWORD error; + int result; + unsigned int index; VERIFY_FD(fd, req); @@ -556,11 +557,6 @@ void fs__read(uv_fs_t* req) { return; } - if (length > INT_MAX) { - SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER); - return; - } - if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); @@ -573,7 +569,20 @@ void fs__read(uv_fs_t* req) { overlapped_ptr = NULL; } - if (ReadFile(handle, req->buf, req->length, &bytes, overlapped_ptr)) { + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + result = ReadFile(handle, + req->bufs[index].base, + req->bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->nbufs); + + if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { error = GetLastError(); @@ -588,12 +597,13 @@ void fs__read(uv_fs_t* req) { void fs__write(uv_fs_t* req) { int fd = req->fd; - size_t length = req->length; int64_t offset = req->offset; HANDLE handle; OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; + int result; + unsigned int index; VERIFY_FD(fd, req); @@ -603,11 +613,6 @@ void fs__write(uv_fs_t* req) { return; } - if (length > INT_MAX) { - SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER); - return; - } - if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); @@ -620,7 +625,20 @@ void fs__write(uv_fs_t* req) { overlapped_ptr = NULL; } - if (WriteFile(handle, req->buf, length, &bytes, overlapped_ptr)) { + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + result = WriteFile(handle, + req->bufs[index].base, + req->bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->nbufs); + + if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { SET_REQ_WIN32_ERROR(req, GetLastError()); @@ -1087,7 +1105,7 @@ static void fs__ftruncate(uv_fs_t* req) { static void fs__sendfile(uv_fs_t* req) { int fd_in = req->fd, fd_out = req->fd_out; - size_t length = req->length; + size_t length = req->bufsml[0].len; int64_t offset = req->offset; const size_t max_buf_size = 65536; size_t buf_size = length < max_buf_size ? length : max_buf_size; @@ -1283,23 +1301,23 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, return; } - // Do a pessimistic calculation of the required buffer size + /* Do a pessimistic calculation of the required buffer size */ needed_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + JUNCTION_PREFIX_LEN * sizeof(WCHAR) + 2 * (target_len + 2) * sizeof(WCHAR); - // Allocate the buffer + /* Allocate the buffer */ buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size); if (!buffer) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - // Grab a pointer to the part of the buffer where filenames go + /* Grab a pointer to the part of the buffer where filenames go */ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer); path_buf_len = 0; - // Copy the substitute (internal) target path + /* Copy the substitute (internal) target path */ start = path_buf_len; wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX, @@ -1323,14 +1341,14 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, path_buf[path_buf_len++] = L'\\'; len = path_buf_len - start; - // Set the info about the substitute name + /* Set the info about the substitute name */ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR); buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); - // Insert null terminator + /* Insert null terminator */ path_buf[path_buf_len++] = L'\0'; - // Copy the print name of the target path + /* Copy the print name of the target path */ start = path_buf_len; add_slash = 0; for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { @@ -1352,32 +1370,32 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, len++; } - // Set the info about the print name + /* Set the info about the print name */ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR); buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR); - // Insert another null terminator + /* Insert another null terminator */ path_buf[path_buf_len++] = L'\0'; - // Calculate how much buffer space was actually used + /* Calculate how much buffer space was actually used */ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + path_buf_len * sizeof(WCHAR); used_data_size = used_buf_size - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); - // Put general info in the data buffer + /* Put general info in the data buffer */ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; buffer->ReparseDataLength = used_data_size; buffer->Reserved = 0; - // Create a new directory + /* Create a new directory */ if (!CreateDirectoryW(new_path, NULL)) { SET_REQ_WIN32_ERROR(req, GetLastError()); goto error; } created = 1; - // Open the directory + /* Open the directory */ handle = CreateFileW(new_path, GENERIC_ALL, 0, @@ -1391,7 +1409,7 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, goto error; } - // Create the actual reparse point + /* Create the actual reparse point */ if (!DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, buffer, @@ -1404,7 +1422,7 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, goto error; } - // Clean up + /* Clean up */ CloseHandle(handle); free(buffer); @@ -1569,13 +1587,27 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { } -int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, - size_t length, int64_t offset, uv_fs_cb cb) { +int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_READ, cb); req->fd = fd; - req->buf = buf; - req->length = length; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) + return UV_ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + req->offset = offset; if (cb) { @@ -1588,13 +1620,27 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, } -int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, const void* buf, - size_t length, int64_t offset, uv_fs_cb cb) { +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_WRITE, cb); req->fd = fd; - req->buf = (void*) buf; - req->length = length; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) + return UV_ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + req->offset = offset; if (cb) { @@ -1922,7 +1968,7 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, req->fd = fd_in; req->fd_out = fd_out; req->offset = in_offset; - req->length = length; + req->bufsml[0].len = length; if (cb) { QUEUE_FS_TP_JOB(loop, req); diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index f3d3110d314..69c5cde6283 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -44,6 +44,10 @@ static const int64_t eof_timeout = 50; /* ms */ static const int default_pending_pipe_instances = 4; +/* Pipe prefix */ +static char pipe_prefix[] = "\\\\?\\pipe"; +static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; + /* IPC protocol flags. */ #define UV_IPC_RAW_DATA 0x0001 #define UV_IPC_TCP_SERVER 0x0002 @@ -70,7 +74,7 @@ static void eof_timer_close_cb(uv_handle_t* handle); static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { - _snprintf(name, size, "\\\\.\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); + _snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); } @@ -433,7 +437,8 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { - return uv_translate_sys_error(GetLastError()); + err = GetLastError(); + goto error; } /* @@ -1174,6 +1179,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, NULL); if (!result) { + err = GetLastError(); return err; } else { /* Request completed immediately. */ @@ -1745,3 +1751,111 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { } return 0; } + + +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_NAME_INFORMATION tmp_name_info; + FILE_NAME_INFORMATION* name_info; + WCHAR* name_buf; + unsigned int addrlen; + unsigned int name_size; + unsigned int name_len; + int err; + + name_info = NULL; + + if (handle->handle == INVALID_HANDLE_VALUE) { + *len = 0; + return UV_EINVAL; + } + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &tmp_name_info, + sizeof tmp_name_info, + FileNameInformation); + if (nt_status == STATUS_BUFFER_OVERFLOW) { + name_size = sizeof(*name_info) + tmp_name_info.FileNameLength; + name_info = malloc(name_size); + if (!name_info) { + *len = 0; + return UV_ENOMEM; + } + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + name_info, + name_size, + FileNameInformation); + } + + if (nt_status != STATUS_SUCCESS) { + *len = 0; + err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status)); + goto error; + } + + if (!name_info) { + /* the struct on stack was used */ + name_buf = tmp_name_info.FileName; + name_len = tmp_name_info.FileNameLength; + } else { + name_buf = name_info->FileName; + name_len = name_info->FileNameLength; + } + + if (name_len == 0) { + *len = 0; + err = 0; + goto error; + } + + name_len /= sizeof(WCHAR); + + /* check how much space we need */ + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + NULL, + 0, + NULL, + NULL); + if (!addrlen) { + *len = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } else if (pipe_prefix_len + addrlen + 1 > *len) { + /* "\\\\.\\pipe" + name + '\0' */ + *len = pipe_prefix_len + addrlen + 1; + err = UV_ENOBUFS; + goto error; + } + + memcpy(buf, pipe_prefix, pipe_prefix_len); + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + buf+pipe_prefix_len, + *len-pipe_prefix_len, + NULL, + NULL); + if (!addrlen) { + *len = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } + + addrlen += pipe_prefix_len; + buf[addrlen++] = '\0'; + *len = addrlen; + + return 0; + +error: + free(name_info); + return err; +} diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 813e522f758..88a141950db 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -811,6 +811,9 @@ int uv_spawn(uv_loop_t* loop, PROCESS_INFORMATION info; DWORD process_flags; + uv_process_init(loop, process); + process->exit_cb = options->exit_cb; + if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { return UV_ENOTSUP; } @@ -827,9 +830,6 @@ int uv_spawn(uv_loop_t* loop, UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); - uv_process_init(loop, process); - process->exit_cb = options->exit_cb; - err = uv_utf8_to_utf16_alloc(options->file, &application); if (err) goto done; diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 2eaa74e766a..0abca3adcf4 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -244,6 +244,9 @@ int uv_is_writable(const uv_stream_t* handle) { int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + if (handle->type != UV_NAMED_PIPE) + return UV_EINVAL; + if (blocking != 0) handle->flags |= UV_HANDLE_BLOCKING_WRITES; else diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 8fa2146a066..f77db3b95c6 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -271,7 +271,11 @@ static int uv_tcp_try_bind(uv_tcp_t* handle, /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ /* available, or when run on XP/2003 which have no support for dualstack */ /* sockets. For now we're silently ignoring the error. */ - setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on); + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (const char*)&on, + sizeof on); } #endif @@ -575,6 +579,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { req->accept_socket = INVALID_SOCKET; req->data = handle; req->wait_handle = INVALID_HANDLE_VALUE; + req->event_handle = NULL; } } @@ -988,9 +993,11 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; } if (req->event_handle) { CloseHandle(req->event_handle); + req->event_handle = NULL; } } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 31812e4642f..282d49480e7 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -585,6 +585,46 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, } +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct in_addr addr; + int err; + + memset(&addr, 0, sizeof addr); + + if (handle->flags & UV_HANDLE_IPV6) { + return UV_ENOSYS; + } + + /* If the socket is unbound, bind to inaddr_any. */ + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_udp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return uv_translate_sys_error(err); + } + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &addr.s_addr); + if (err) + return err; + } else { + addr.s_addr = htonl(INADDR_ANY); + } + + if (setsockopt(handle->socket, + IPPROTO_IP, + IP_MULTICAST_IF, + (char*) &addr, + sizeof addr) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + int uv_udp_set_broadcast(uv_udp_t* handle, int value) { BOOL optval = (BOOL) value; int err; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 266b8816406..c9ca773df75 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -36,6 +36,7 @@ #include #include #include +#include /* @@ -988,3 +989,39 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { free(addresses); } + + +int uv_getrusage(uv_rusage_t *uv_rusage) { + FILETIME createTime, exitTime, kernelTime, userTime; + SYSTEMTIME kernelSystemTime, userSystemTime; + int ret; + + ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&userTime, &userSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + memset(uv_rusage, 0, sizeof(*uv_rusage)); + + uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + + userSystemTime.wMinute * 60 + + userSystemTime.wSecond; + uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; + + uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + + kernelSystemTime.wMinute * 60 + + kernelSystemTime.wSecond; + uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + + return 0; +} diff --git a/deps/uv/test/benchmark-async.c b/deps/uv/test/benchmark-async.c index 33d9ab446a8..defed67bf8f 100644 --- a/deps/uv/test/benchmark-async.c +++ b/deps/uv/test/benchmark-async.c @@ -28,7 +28,7 @@ #define NUM_PINGS (1000 * 1000) struct ctx { - uv_loop_t* loop; + uv_loop_t loop; uv_thread_t thread; uv_async_t main_async; /* wake up main thread */ uv_async_t worker_async; /* wake up worker */ @@ -67,7 +67,8 @@ static void main_async_cb(uv_async_t* handle, int status) { static void worker(void* arg) { struct ctx* ctx = arg; ASSERT(0 == uv_async_send(&ctx->main_async)); - ASSERT(0 == uv_run(ctx->loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT)); + uv_loop_close(&ctx->loop); } @@ -83,9 +84,8 @@ static int test_async(int nthreads) { for (i = 0; i < nthreads; i++) { ctx = threads + i; ctx->nthreads = nthreads; - ctx->loop = uv_loop_new(); - ASSERT(ctx->loop != NULL); - ASSERT(0 == uv_async_init(ctx->loop, &ctx->worker_async, worker_async_cb)); + ASSERT(0 == uv_loop_init(&ctx->loop)); + ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb)); ASSERT(0 == uv_async_init(uv_default_loop(), &ctx->main_async, main_async_cb)); diff --git a/deps/uv/test/benchmark-multi-accept.c b/deps/uv/test/benchmark-multi-accept.c index d71235ef3bb..b1b0c1e3ce1 100644 --- a/deps/uv/test/benchmark-multi-accept.c +++ b/deps/uv/test/benchmark-multi-accept.c @@ -249,27 +249,26 @@ static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) { static void server_cb(void *arg) { struct server_ctx *ctx; - uv_loop_t* loop; + uv_loop_t loop; ctx = arg; - loop = uv_loop_new(); - ASSERT(loop != NULL); + ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_async_init(loop, &ctx->async_handle, sv_async_cb)); + ASSERT(0 == uv_async_init(&loop, &ctx->async_handle, sv_async_cb)); uv_unref((uv_handle_t*) &ctx->async_handle); /* Wait until the main thread is ready. */ uv_sem_wait(&ctx->semaphore); - get_listen_handle(loop, (uv_stream_t*) &ctx->server_handle); + get_listen_handle(&loop, (uv_stream_t*) &ctx->server_handle); uv_sem_post(&ctx->semaphore); /* Now start the actual benchmark. */ ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle, 128, sv_connection_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - uv_loop_delete(loop); + uv_loop_close(&loop); } diff --git a/deps/uv/test/run-benchmarks.c b/deps/uv/test/run-benchmarks.c index 06732b71d34..61f062f99aa 100644 --- a/deps/uv/test/run-benchmarks.c +++ b/deps/uv/test/run-benchmarks.c @@ -29,9 +29,6 @@ #include "benchmark-list.h" -/* The time in milliseconds after which a single benchmark times out. */ -#define BENCHMARK_TIMEOUT 60000 - static int maybe_run_test(int argc, char **argv); @@ -39,7 +36,7 @@ int main(int argc, char **argv) { platform_init(argc, argv); switch (argc) { - case 1: return run_tests(BENCHMARK_TIMEOUT, 1); + case 1: return run_tests(1); case 2: return maybe_run_test(argc, argv); case 3: return run_test_part(argv[1], argv[2]); default: @@ -60,5 +57,5 @@ static int maybe_run_test(int argc, char **argv) { return 42; } - return run_test(argv[1], BENCHMARK_TIMEOUT, 1, 1); + return run_test(argv[1], 1, 1); } diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index d84be6a1a5a..cd50ee09f36 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -36,9 +36,6 @@ /* Actual tests and helpers are defined in test-list.h */ #include "test-list.h" -/* The time in milliseconds after which a single test times out. */ -#define TEST_TIMEOUT 5000 - int ipc_helper(int listen_after_write); int ipc_helper_tcp_connection(void); int ipc_send_recv_helper(void); @@ -53,7 +50,7 @@ int main(int argc, char **argv) { argv = uv_setup_args(argc, argv); switch (argc) { - case 1: return run_tests(TEST_TIMEOUT, 0); + case 1: return run_tests(0); case 2: return maybe_run_test(argc, argv); case 3: return run_test_part(argv[1], argv[2]); default: @@ -155,5 +152,16 @@ static int maybe_run_test(int argc, char **argv) { return 1; } - return run_test(argv[1], TEST_TIMEOUT, 0, 1); +#ifndef _WIN32 + if (strcmp(argv[1], "spawn_helper8") == 0) { + int fd; + ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd))); + ASSERT(fd > 2); + ASSERT(-1 == write(fd, "x", 1)); + + return 1; + } +#endif /* !_WIN32 */ + + return run_test(argv[1], 0, 1); } diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index f4d982c5b6a..a934b24c6e5 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -90,7 +90,7 @@ const char* fmt(double d) { } -int run_tests(int timeout, int benchmark_output) { +int run_tests(int benchmark_output) { int total; int passed; int failed; @@ -130,7 +130,7 @@ int run_tests(int timeout, int benchmark_output) { log_progress(total, passed, failed, todos, skipped, task->task_name); } - test_result = run_test(task->task_name, timeout, benchmark_output, current); + test_result = run_test(task->task_name, benchmark_output, current); switch (test_result) { case TEST_OK: passed++; break; case TEST_TODO: todos++; break; @@ -189,7 +189,6 @@ void log_tap_result(int test_count, int run_test(const char* test, - int timeout, int benchmark_output, int test_count) { char errmsg[1024] = "no error"; @@ -279,7 +278,7 @@ int run_test(const char* test, goto out; } - result = process_wait(main_proc, 1, timeout); + result = process_wait(main_proc, 1, task->timeout); if (result == -1) { FATAL("process_wait failed"); } else if (result == -2) { diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index aa7f205407d..97c7312da7b 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -41,6 +41,11 @@ typedef struct { int (*main)(void); int is_helper; int show_output; + + /* + * The time in milliseconds after which a single test or benchmark times out. + */ + int timeout; } task_entry_t, bench_entry_t; @@ -51,29 +56,29 @@ typedef struct { task_entry_t TASKS[] = { #define TASK_LIST_END \ - { 0, 0, 0, 0, 0 } \ + { 0, 0, 0, 0, 0, 0 } \ }; #define TEST_DECLARE(name) \ int run_test_##name(void); #define TEST_ENTRY(name) \ - { #name, #name, &run_test_##name, 0, 0 }, + { #name, #name, &run_test_##name, 0, 0, 5000 }, -#define TEST_OUTPUT_ENTRY(name) \ - { #name, #name, &run_test_##name, 0, 1 }, +#define TEST_ENTRY_CUSTOM(name, is_helper, show_output, timeout) \ + { #name, #name, &run_test_##name, is_helper, show_output, timeout }, #define BENCHMARK_DECLARE(name) \ int run_benchmark_##name(void); #define BENCHMARK_ENTRY(name) \ - { #name, #name, &run_benchmark_##name, 0, 0 }, + { #name, #name, &run_benchmark_##name, 0, 0, 60000 }, #define HELPER_DECLARE(name) \ int run_helper_##name(void); #define HELPER_ENTRY(task_name, name) \ - { #task_name, #name, &run_helper_##name, 1, 0 }, + { #task_name, #name, &run_helper_##name, 1, 0, 0 }, #define TEST_HELPER HELPER_ENTRY #define BENCHMARK_HELPER HELPER_ENTRY @@ -97,13 +102,12 @@ extern task_entry_t TASKS[]; /* * Run all tests. */ -int run_tests(int timeout, int benchmark_output); +int run_tests(int benchmark_output); /* * Run a single test. Starts up any helpers. */ int run_test(const char* test, - int timeout, int benchmark_output, int test_count); diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index b736c375c7d..3b786a8c6ea 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -41,8 +41,8 @@ #define TEST_PORT_2 9124 #ifdef _WIN32 -# define TEST_PIPENAME "\\\\.\\pipe\\uv-test" -# define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2" +# define TEST_PIPENAME "\\\\?\\pipe\\uv-test" +# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2" #else # define TEST_PIPENAME "/tmp/uv-test-sock" # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" diff --git a/deps/uv/test/test-embed.c b/deps/uv/test/test-embed.c index ac1b3b67505..909d2d5d99c 100644 --- a/deps/uv/test/test-embed.c +++ b/deps/uv/test/test-embed.c @@ -108,15 +108,14 @@ static void embed_timer_cb(uv_timer_t* timer, int status) { TEST_IMPL(embed) { #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) - uv_loop_t* external; + uv_loop_t external; - external = uv_loop_new(); - ASSERT(external != NULL); + ASSERT(0 == uv_loop_init(&external)); embed_timer_called = 0; embed_closed = 0; - uv_async_init(external, &embed_async, embed_cb); + uv_async_init(&external, &embed_async, embed_cb); /* Start timer in default loop */ uv_timer_init(uv_default_loop(), &embed_timer); @@ -127,10 +126,10 @@ TEST_IMPL(embed) { uv_thread_create(&embed_thread, embed_thread_runner, NULL); /* But run external loop */ - uv_run(external, UV_RUN_DEFAULT); + uv_run(&external, UV_RUN_DEFAULT); uv_thread_join(&embed_thread); - uv_loop_delete(external); + uv_loop_close(&external); ASSERT(embed_timer_called == 1); #endif diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 3286de51f98..fec5fd67319 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -79,13 +79,15 @@ static void touch_file(uv_loop_t* loop, const char* name) { int r; uv_file file; uv_fs_t req; + uv_buf_t buf; r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL); ASSERT(r >= 0); file = r; uv_fs_req_cleanup(&req); - r = uv_fs_write(loop, &req, file, "foo", 4, -1, NULL); + buf = uv_buf_init("foo", 4); + r = uv_fs_write(loop, &req, file, &buf, 1, -1, NULL); ASSERT(r >= 0); uv_fs_req_cleanup(&req); @@ -626,6 +628,38 @@ TEST_IMPL(fs_event_start_and_close) { return 0; } +TEST_IMPL(fs_event_getpath) { + uv_loop_t* loop = uv_default_loop(); + int r; + char buf[1024]; + size_t len; + + create_dir(loop, "watch_dir"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + len = sizeof buf; + r = uv_fs_event_getpath(&fs_event, buf, &len); + ASSERT(r == UV_EINVAL); + r = uv_fs_event_start(&fs_event, fail_cb, "watch_dir", 0); + ASSERT(r == 0); + len = sizeof buf; + r = uv_fs_event_getpath(&fs_event, buf, &len); + ASSERT(r == 0); + ASSERT(memcmp(buf, "watch_dir", len) == 0); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, close_cb); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + remove("watch_dir/"); + MAKE_VALGRIND_HAPPY(); + return 0; +} + #if defined(__APPLE__) static int fs_event_error_reported; @@ -653,7 +687,7 @@ static void fs_event_error_report_close_cb(uv_handle_t* handle) { TEST_IMPL(fs_event_error_reporting) { unsigned int i; - uv_loop_t* loops[1024]; + uv_loop_t loops[1024]; uv_fs_event_t events[ARRAY_SIZE(loops)]; uv_loop_t* loop; uv_fs_event_t* event; @@ -668,11 +702,10 @@ TEST_IMPL(fs_event_error_reporting) { * fail. */ for (i = 0; i < ARRAY_SIZE(loops); i++) { - loop = uv_loop_new(); + loop = &loops[i]; + ASSERT(0 == uv_loop_init(loop)); event = &events[i]; - ASSERT(loop != NULL); - loops[i] = loop; timer_cb_called = 0; close_cb_called = 0; ASSERT(0 == uv_fs_event_init(loop, event)); @@ -697,7 +730,7 @@ TEST_IMPL(fs_event_error_reporting) { /* Stop and close all events, and destroy loops */ do { - loop = loops[i]; + loop = &loops[i]; event = &events[i]; ASSERT(0 == uv_fs_event_stop(event)); @@ -708,9 +741,7 @@ TEST_IMPL(fs_event_error_reporting) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(close_cb_called == 1); - uv_loop_delete(loop); - - loops[i] = NULL; + uv_loop_close(loop); } while (i-- != 0); remove("watch_dir/"); diff --git a/deps/uv/test/test-fs-poll.c b/deps/uv/test/test-fs-poll.c index 9213f04b34a..27c6c3c3dba 100644 --- a/deps/uv/test/test-fs-poll.c +++ b/deps/uv/test/test-fs-poll.c @@ -33,6 +33,11 @@ static void poll_cb(uv_fs_poll_t* handle, const uv_stat_t* prev, const uv_stat_t* curr); +static void poll_cb_fail(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr); + static uv_fs_poll_t poll_handle; static uv_timer_t timer_handle; static uv_loop_t* loop; @@ -72,6 +77,14 @@ static void timer_cb(uv_timer_t* handle, int status) { } +static void poll_cb_fail(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr) { + ASSERT(0 && "fail_cb called"); +} + + static void poll_cb(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, @@ -144,3 +157,29 @@ TEST_IMPL(fs_poll) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(fs_poll_getpath) { + char buf[1024]; + size_t len; + loop = uv_default_loop(); + + remove(FIXTURE); + + ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); + len = sizeof buf; + ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len)); + ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + len = sizeof buf; + ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len)); + ASSERT(0 == memcmp(buf, FIXTURE, len)); + + uv_close((uv_handle_t*) &poll_handle, close_cb); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index f0ff824f401..940672f8bcd 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -102,7 +102,7 @@ static uv_fs_t futime_req; static char buf[32]; static char test_buf[] = "test-buffer\n"; - +static uv_buf_t iov; static void check_permission(const char* filename, unsigned int mode) { int r; @@ -284,7 +284,8 @@ static void open_cb(uv_fs_t* req) { ASSERT(memcmp(req->path, "test_file2\0", 11) == 0); uv_fs_req_cleanup(req); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, read_cb); ASSERT(r == 0); } @@ -345,8 +346,8 @@ static void create_cb(uv_fs_t* req) { ASSERT(req->result >= 0); create_cb_count++; uv_fs_req_cleanup(req); - r = uv_fs_write(loop, &write_req, req->result, test_buf, sizeof(test_buf), - -1, write_cb); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb); ASSERT(r == 0); } @@ -663,8 +664,8 @@ TEST_IMPL(fs_file_sync) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, - sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(write_req.result >= 0); uv_fs_req_cleanup(&write_req); @@ -679,8 +680,8 @@ TEST_IMPL(fs_file_sync) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, - NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(read_req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); @@ -707,7 +708,8 @@ TEST_IMPL(fs_file_sync) { uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(read_req.result >= 0); @@ -733,6 +735,38 @@ TEST_IMPL(fs_file_sync) { } +TEST_IMPL(fs_file_write_null_buffer) { + int r; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); + ASSERT(r == 0); + ASSERT(write_req.result == 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_async_dir) { int r; @@ -910,7 +944,8 @@ TEST_IMPL(fs_fstat) { file = req.result; uv_fs_req_cleanup(&req); - r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL); ASSERT(r == sizeof(test_buf)); ASSERT(req.result == sizeof(test_buf)); uv_fs_req_cleanup(&req); @@ -1020,7 +1055,8 @@ TEST_IMPL(fs_chmod) { file = req.result; uv_fs_req_cleanup(&req); - r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL); ASSERT(r == sizeof(test_buf)); ASSERT(req.result == sizeof(test_buf)); uv_fs_req_cleanup(&req); @@ -1183,7 +1219,8 @@ TEST_IMPL(fs_link) { file = req.result; uv_fs_req_cleanup(&req); - r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL); ASSERT(r == sizeof(test_buf)); ASSERT(req.result == sizeof(test_buf)); uv_fs_req_cleanup(&req); @@ -1203,7 +1240,8 @@ TEST_IMPL(fs_link) { uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); @@ -1223,7 +1261,8 @@ TEST_IMPL(fs_link) { uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); @@ -1289,7 +1328,8 @@ TEST_IMPL(fs_symlink) { file = req.result; uv_fs_req_cleanup(&req); - r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL); ASSERT(r == sizeof(test_buf)); ASSERT(req.result == sizeof(test_buf)); uv_fs_req_cleanup(&req); @@ -1326,7 +1366,8 @@ TEST_IMPL(fs_symlink) { uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); @@ -1365,7 +1406,8 @@ TEST_IMPL(fs_symlink) { uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); @@ -1774,8 +1816,8 @@ TEST_IMPL(fs_file_open_append) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, - sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(write_req.result >= 0); uv_fs_req_cleanup(&write_req); @@ -1790,8 +1832,8 @@ TEST_IMPL(fs_file_open_append) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, - sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(write_req.result >= 0); uv_fs_req_cleanup(&write_req); @@ -1806,7 +1848,8 @@ TEST_IMPL(fs_file_open_append) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); printf("read = %d\n", r); ASSERT(r == 26); @@ -1844,8 +1887,8 @@ TEST_IMPL(fs_rename_to_existing_file) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, - sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(write_req.result >= 0); uv_fs_req_cleanup(&write_req); @@ -1877,7 +1920,8 @@ TEST_IMPL(fs_rename_to_existing_file) { uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(read_req.result >= 0); @@ -1912,8 +1956,8 @@ TEST_IMPL(fs_read_file_eof) { ASSERT(open_req1.result >= 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, - sizeof(test_buf), -1, NULL); + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(write_req.result >= 0); uv_fs_req_cleanup(&write_req); @@ -1929,15 +1973,16 @@ TEST_IMPL(fs_read_file_eof) { uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, - NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); ASSERT(r >= 0); ASSERT(read_req.result >= 0); ASSERT(strcmp(buf, test_buf) == 0); uv_fs_req_cleanup(&read_req); - r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), - read_req.result, NULL); + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, + read_req.result, NULL); ASSERT(r == 0); ASSERT(read_req.result == 0); uv_fs_req_cleanup(&read_req); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index c3e15783b57..0252acc354e 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -25,6 +25,7 @@ TEST_DECLARE (close_order) TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) TEST_DECLARE (loop_alive) +TEST_DECLARE (loop_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (barrier_1) @@ -81,6 +82,7 @@ TEST_DECLARE (tcp_bind6_localhost_ok) TEST_DECLARE (udp_send_and_recv) TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_ttl) +TEST_DECLARE (udp_multicast_interface) TEST_DECLARE (udp_dgram_too_big) TEST_DECLARE (udp_dual_stack) TEST_DECLARE (udp_ipv6_only) @@ -92,12 +94,15 @@ TEST_DECLARE (pipe_bind_error_inval) TEST_DECLARE (pipe_listen_without_bind) TEST_DECLARE (pipe_connect_bad_name) TEST_DECLARE (pipe_connect_to_file) +TEST_DECLARE (pipe_getsockname) +TEST_DECLARE (pipe_getsockname_abstract) TEST_DECLARE (pipe_server_close) TEST_DECLARE (connection_fail) TEST_DECLARE (connection_fail_doesnt_auto_close) TEST_DECLARE (shutdown_close_tcp) TEST_DECLARE (shutdown_close_pipe) TEST_DECLARE (shutdown_eof) +TEST_DECLARE (shutdown_twice) TEST_DECLARE (callback_stack) TEST_DECLARE (error_message) TEST_DECLARE (timer) @@ -171,12 +176,14 @@ TEST_DECLARE (spawn_stdout_to_file) TEST_DECLARE (spawn_stdout_and_stderr_to_file) TEST_DECLARE (spawn_auto_unref) TEST_DECLARE (fs_poll) +TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (kill) TEST_DECLARE (fs_file_noent) TEST_DECLARE (fs_file_nametoolong) TEST_DECLARE (fs_file_loop) TEST_DECLARE (fs_file_async) TEST_DECLARE (fs_file_sync) +TEST_DECLARE (fs_file_write_null_buffer) TEST_DECLARE (fs_async_dir) TEST_DECLARE (fs_async_sendfile) TEST_DECLARE (fs_fstat) @@ -202,6 +209,7 @@ TEST_DECLARE (fs_event_close_with_pending_event) TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) +TEST_DECLARE (fs_event_getpath) TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) @@ -233,10 +241,12 @@ TEST_DECLARE (fs_stat_root) #else TEST_DECLARE (emfile) TEST_DECLARE (close_fd) +TEST_DECLARE (spawn_fs_open) TEST_DECLARE (spawn_setuid_setgid) TEST_DECLARE (we_get_signal) TEST_DECLARE (we_get_signals) TEST_DECLARE (signal_multiple_loops) +TEST_DECLARE (closed_fd_events) #endif #ifdef __APPLE__ TEST_DECLARE (osx_select) @@ -248,7 +258,7 @@ HELPER_DECLARE (pipe_echo_server) TASK_LIST_START - TEST_OUTPUT_ENTRY (platform_output) + TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) #if 0 TEST_ENTRY (callback_order) @@ -257,6 +267,7 @@ TASK_LIST_START TEST_ENTRY (run_once) TEST_ENTRY (run_nowait) TEST_ENTRY (loop_alive) + TEST_ENTRY (loop_close) TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (barrier_1) @@ -349,6 +360,8 @@ TASK_LIST_START TEST_ENTRY (pipe_bind_error_addrnotavail) TEST_ENTRY (pipe_bind_error_inval) TEST_ENTRY (pipe_listen_without_bind) + TEST_ENTRY (pipe_getsockname) + TEST_ENTRY (pipe_getsockname_abstract) TEST_ENTRY (connection_fail) TEST_ENTRY (connection_fail_doesnt_auto_close) @@ -361,6 +374,9 @@ TASK_LIST_START TEST_ENTRY (shutdown_eof) TEST_HELPER (shutdown_eof, tcp4_echo_server) + TEST_ENTRY (shutdown_twice) + TEST_HELPER (shutdown_twice, tcp4_echo_server) + TEST_ENTRY (callback_stack) TEST_HELPER (callback_stack, tcp4_echo_server) @@ -432,7 +448,8 @@ TASK_LIST_START TEST_ENTRY (hrtime) - TEST_ENTRY (getaddrinfo_fail) + TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) + TEST_ENTRY (getaddrinfo_basic) TEST_ENTRY (getaddrinfo_concurrent) @@ -460,6 +477,7 @@ TASK_LIST_START TEST_ENTRY (spawn_stdout_and_stderr_to_file) TEST_ENTRY (spawn_auto_unref) TEST_ENTRY (fs_poll) + TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) #ifdef _WIN32 @@ -472,10 +490,12 @@ TASK_LIST_START #else TEST_ENTRY (emfile) TEST_ENTRY (close_fd) + TEST_ENTRY (spawn_fs_open) TEST_ENTRY (spawn_setuid_setgid) TEST_ENTRY (we_get_signal) TEST_ENTRY (we_get_signals) TEST_ENTRY (signal_multiple_loops) + TEST_ENTRY (closed_fd_events) #endif #ifdef __APPLE__ @@ -487,6 +507,7 @@ TASK_LIST_START TEST_ENTRY (fs_file_loop) TEST_ENTRY (fs_file_async) TEST_ENTRY (fs_file_sync) + TEST_ENTRY (fs_file_write_null_buffer) TEST_ENTRY (fs_async_dir) TEST_ENTRY (fs_async_sendfile) TEST_ENTRY (fs_fstat) @@ -511,6 +532,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY (fs_event_error_reporting) + TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir) diff --git a/deps/uv/test/test-loop-close.c b/deps/uv/test/test-loop-close.c new file mode 100644 index 00000000000..fa053469b84 --- /dev/null +++ b/deps/uv/test/test-loop-close.c @@ -0,0 +1,54 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer_handle; + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle); + ASSERT(status == 0); + uv_stop(handle->loop); +} + + +TEST_IMPL(loop_close) { + int r; + uv_loop_t loop; + + ASSERT(0 == uv_loop_init(&loop)); + + uv_timer_init(&loop, &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + ASSERT(UV_EBUSY == uv_loop_close(&loop)); + + uv_run(&loop, UV_RUN_DEFAULT); + + uv_close((uv_handle_t*) &timer_handle, NULL); + r = uv_run(&loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(0 == uv_loop_close(&loop)); + + return 0; +} diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c new file mode 100644 index 00000000000..396f72577db --- /dev/null +++ b/deps/uv/test/test-pipe-getsockname.c @@ -0,0 +1,122 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include + +#if defined(__linux__) + #include + #include +#endif + +#ifndef _WIN32 +# include /* close */ +#endif + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(pipe_getsockname) { + uv_pipe_t server; + char buf[1024]; + size_t len; + int r; + + r = uv_pipe_init(uv_default_loop(), &server, 0); + ASSERT(r == 0); + r = uv_pipe_bind(&server, TEST_PIPENAME); + ASSERT(r == 0); + + len = sizeof buf; + r = uv_pipe_getsockname(&server, buf, &len); + ASSERT(r == 0); + + ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_getsockname_abstract) { +#if defined(__linux__) + uv_pipe_t server; + char buf[1024]; + size_t len; + int r; + int sock; + struct sockaddr_un sun; + socklen_t sun_len; + char abstract_pipe[] = "\0test-pipe"; + + sock = socket(AF_LOCAL, SOCK_STREAM, 0); + ASSERT(sock != -1); + + sun_len = sizeof sun; + memset(&sun, 0, sun_len); + sun.sun_family = AF_UNIX; + memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe); + + r = bind(sock, (struct sockaddr*)&sun, sun_len); + ASSERT(r == 0); + + r = uv_pipe_init(uv_default_loop(), &server, 0); + ASSERT(r == 0); + r = uv_pipe_open(&server, sock); + ASSERT(r == 0); + + len = sizeof buf; + r = uv_pipe_getsockname(&server, buf, &len); + ASSERT(r == 0); + + ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + close(sock); + + ASSERT(close_cb_called == 1); + MAKE_VALGRIND_HAPPY(); + return 0; +#else + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index d2104f40a1f..931311985bb 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -28,6 +28,7 @@ TEST_IMPL(platform_output) { char buffer[512]; size_t rss; double uptime; + uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; int count; @@ -47,6 +48,20 @@ TEST_IMPL(platform_output) { ASSERT(uptime > 0); printf("uv_uptime: %f\n", uptime); + err = uv_getrusage(&rusage); + ASSERT(err == 0); + ASSERT(rusage.ru_utime.tv_sec >= 0); + ASSERT(rusage.ru_utime.tv_usec >= 0); + ASSERT(rusage.ru_stime.tv_sec >= 0); + ASSERT(rusage.ru_stime.tv_usec >= 0); + printf("uv_getrusage:\n"); + printf(" user: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_utime.tv_sec, + (unsigned long long) rusage.ru_utime.tv_usec); + printf(" system: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_stime.tv_sec, + (unsigned long long) rusage.ru_stime.tv_usec); + err = uv_cpu_info(&cpus, &count); ASSERT(err == 0); diff --git a/deps/uv/test/test-shutdown-twice.c b/deps/uv/test/test-shutdown-twice.c new file mode 100644 index 00000000000..75c05435499 --- /dev/null +++ b/deps/uv/test/test-shutdown-twice.c @@ -0,0 +1,84 @@ +/* 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. + */ + +/* + * This is a regression test for issue #1113 (calling uv_shutdown twice will + * leave a ghost request in the system) + */ + +#include "uv.h" +#include "task.h" + +static uv_shutdown_t req1; +static uv_shutdown_t req2; + +static int shutdown_cb_called = 0; + +static void close_cb(uv_handle_t* handle) { + +} + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &req1); + ASSERT(status == 0); + shutdown_cb_called++; + uv_close((uv_handle_t*) req->handle, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + + ASSERT(status == 0); + + r = uv_shutdown(&req1, req->handle, shutdown_cb); + ASSERT(r == 0); + r = uv_shutdown(&req2, req->handle, shutdown_cb); + ASSERT(r != 0); + +} + +TEST_IMPL(shutdown_twice) { + struct sockaddr_in addr; + uv_loop_t* loop; + int r; + uv_tcp_t h; + + uv_connect_t connect_req; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + loop = uv_default_loop(); + + r = uv_tcp_init(loop, &h); + + r = uv_tcp_connect(&connect_req, + &h, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(shutdown_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-signal-multiple-loops.c b/deps/uv/test/test-signal-multiple-loops.c index e80154e3e80..f8fef36ee04 100644 --- a/deps/uv/test/test-signal-multiple-loops.c +++ b/deps/uv/test/test-signal-multiple-loops.c @@ -84,28 +84,27 @@ static void signal_handling_worker(void* context) { uv_signal_t signal1a; uv_signal_t signal1b; uv_signal_t signal2; - uv_loop_t* loop; + uv_loop_t loop; int r; action = (enum signal_action) (uintptr_t) context; - loop = uv_loop_new(); - ASSERT(loop != NULL); + ASSERT(0 == uv_loop_init(&loop)); /* Setup the signal watchers and start them. */ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { - r = uv_signal_init(loop, &signal1a); + r = uv_signal_init(&loop, &signal1a); ASSERT(r == 0); r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); ASSERT(r == 0); - r = uv_signal_init(loop, &signal1b); + r = uv_signal_init(&loop, &signal1b); ASSERT(r == 0); r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); ASSERT(r == 0); } if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { - r = uv_signal_init(loop, &signal2); + r = uv_signal_init(&loop, &signal2); ASSERT(r == 0); r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); ASSERT(r == 0); @@ -117,7 +116,7 @@ static void signal_handling_worker(void* context) { /* Wait for all signals. The signal callbacks stop the watcher, so uv_run * will return when all signal watchers caught a signal. */ - r = uv_run(loop, UV_RUN_DEFAULT); + r = uv_run(&loop, UV_RUN_DEFAULT); ASSERT(r == 0); /* Restart the signal watchers. */ @@ -136,7 +135,7 @@ static void signal_handling_worker(void* context) { /* Wait for signals once more. */ uv_sem_post(&sem); - r = uv_run(loop, UV_RUN_DEFAULT); + r = uv_run(&loop, UV_RUN_DEFAULT); ASSERT(r == 0); /* Close the watchers. */ @@ -150,10 +149,10 @@ static void signal_handling_worker(void* context) { } /* Wait for the signal watchers to close. */ - r = uv_run(loop, UV_RUN_DEFAULT); + r = uv_run(&loop, UV_RUN_DEFAULT); ASSERT(r == 0); - uv_loop_delete(loop); + uv_loop_close(&loop); } @@ -166,12 +165,13 @@ static void loop_creating_worker(void* context) { (void) context; do { - uv_loop_t* loop; + uv_loop_t *loop; uv_signal_t signal; int r; - loop = uv_loop_new(); + loop = malloc(sizeof(*loop)); ASSERT(loop != NULL); + ASSERT(0 == uv_loop_init(loop)); r = uv_signal_init(loop, &signal); ASSERT(r == 0); @@ -184,7 +184,7 @@ static void loop_creating_worker(void* context) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - uv_loop_delete(loop); + uv_loop_close(loop); increment_counter(&loop_creation_counter); } while (!stop); diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 5f71fce2c03..84dd2001759 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -40,6 +40,7 @@ static char exepath[1024]; static size_t exepath_size = 1024; static char* args[3]; static int no_term_signal; +static int timer_counter; #define OUTPUT_SIZE 1024 static char output[OUTPUT_SIZE]; @@ -118,6 +119,12 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { } +static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + uv_read_stop(tcp); + on_read(tcp, nread, buf); +} + + static void write_cb(uv_write_t* req, int status) { ASSERT(status == 0); uv_close((uv_handle_t*)req->handle, close_cb); @@ -145,6 +152,11 @@ static void timer_cb(uv_timer_t* handle, int status) { } +static void timer_counter_cb(uv_timer_t* handle, int status) { + ++timer_counter; +} + + TEST_IMPL(spawn_fails) { int r; @@ -218,6 +230,7 @@ TEST_IMPL(spawn_stdout_to_file) { uv_file file; uv_fs_t fs_req; uv_stdio_container_t stdio[2]; + uv_buf_t buf; /* Setup. */ unlink("stdout_file"); @@ -246,8 +259,8 @@ TEST_IMPL(spawn_stdout_to_file) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output), - 0, NULL); + buf = uv_buf_init(output, sizeof(output)); + r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL); ASSERT(r == 12); uv_fs_req_cleanup(&fs_req); @@ -271,6 +284,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { uv_file file; uv_fs_t fs_req; uv_stdio_container_t stdio[3]; + uv_buf_t buf; /* Setup. */ unlink("stdout_file"); @@ -278,7 +292,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { init_process_options("spawn_helper6", exit_cb); r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR, - S_IREAD | S_IWRITE, NULL); + S_IRUSR | S_IWUSR, NULL); ASSERT(r != -1); uv_fs_req_cleanup(&fs_req); @@ -301,8 +315,8 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output), - 0, NULL); + buf = uv_buf_init(output, sizeof(output)); + r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL); ASSERT(r == 27); uv_fs_req_cleanup(&fs_req); @@ -1049,3 +1063,102 @@ TEST_IMPL(spawn_auto_unref) { MAKE_VALGRIND_HAPPY(); return 0; } + + +#ifndef _WIN32 +TEST_IMPL(spawn_fs_open) { + int fd; + uv_fs_t fs_req; + uv_pipe_t in; + uv_write_t write_req; + uv_buf_t buf; + uv_stdio_container_t stdio[1]; + + fd = uv_fs_open(uv_default_loop(), &fs_req, "/dev/null", O_RDWR, 0, NULL); + ASSERT(fd >= 0); + + init_process_options("spawn_helper8", exit_cb); + + ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0)); + + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*) ∈ + options.stdio_count = 1; + + ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + + buf = uv_buf_init((char*) &fd, sizeof(fd)); + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == uv_fs_close(uv_default_loop(), &fs_req, fd, NULL)); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); /* One for `in`, one for process */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* !_WIN32 */ + + +#ifndef _WIN32 +TEST_IMPL(closed_fd_events) { + uv_stdio_container_t stdio[3]; + uv_pipe_t pipe_handle; + int fd[2]; + + /* create a pipe and share it with a child process */ + ASSERT(0 == pipe(fd)); + ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK)); + + /* spawn_helper4 blocks indefinitely. */ + init_process_options("spawn_helper4", exit_cb); + options.stdio_count = 3; + options.stdio = stdio; + options.stdio[0].flags = UV_INHERIT_FD; + options.stdio[0].data.fd = fd[0]; + options.stdio[1].flags = UV_IGNORE; + options.stdio[2].flags = UV_IGNORE; + + ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + uv_unref((uv_handle_t*) &process); + + /* read from the pipe with uv */ + ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); + ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0])); + fd[0] = -1; + + ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once)); + + ASSERT(1 == write(fd[1], "", 1)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + + /* should have received just one byte */ + ASSERT(output_used == 1); + + /* close the pipe and see if we still get events */ + uv_close((uv_handle_t*) &pipe_handle, close_cb); + + ASSERT(1 == write(fd[1], "", 1)); + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0)); + + /* see if any spurious events interrupt the timer */ + if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE)) + /* have to run again to really trigger the timer */ + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + + ASSERT(timer_counter == 1); + + /* cleanup */ + ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15)); + ASSERT(0 == close(fd[1])); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-thread.c b/deps/uv/test/test-thread.c index c396baa100c..7f3321aa06d 100644 --- a/deps/uv/test/test-thread.c +++ b/deps/uv/test/test-thread.c @@ -112,8 +112,9 @@ static void do_work(void* arg) { int r; struct test_thread* thread = arg; - loop = uv_loop_new(); + loop = malloc(sizeof *loop); ASSERT(loop != NULL); + ASSERT(0 == uv_loop_init(loop)); for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { struct getaddrinfo_req* req = getaddrinfo_reqs + i; @@ -132,7 +133,8 @@ static void do_work(void* arg) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - uv_loop_delete(loop); + ASSERT(0 == uv_loop_close(loop)); + free(loop); thread->thread_called = 1; } diff --git a/deps/uv/test/test-threadpool-cancel.c b/deps/uv/test/test-threadpool-cancel.c index 1443773cc21..c3186ea5dfa 100644 --- a/deps/uv/test/test-threadpool-cancel.c +++ b/deps/uv/test/test-threadpool-cancel.c @@ -86,7 +86,7 @@ static void saturate_threadpool(void) { * the thread pool is saturated. As with any timing dependent test, * this is obviously not ideal. */ - if (uv_cond_timedwait(&signal_cond, &signal_mutex, 350 * 1e6)) { + if (uv_cond_timedwait(&signal_cond, &signal_mutex, (uint64_t)(350 * 1e6))) { ASSERT(0 == uv_cancel((uv_req_t*) req)); break; } diff --git a/deps/uv/test/test-udp-multicast-interface.c b/deps/uv/test/test-udp-multicast-interface.c new file mode 100644 index 00000000000..643df318024 --- /dev/null +++ b/deps/uv/test/test-udp-multicast-interface.c @@ -0,0 +1,96 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int sv_send_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + sv_send_cb_called++; + + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +TEST_IMPL(udp_multicast_interface) { + int r; + uv_udp_send_t req; + uv_buf_t buf; + struct sockaddr_in addr; + struct sockaddr_in baddr; + + ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr)); + r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); + ASSERT(r == 0); + + r = uv_udp_set_multicast_interface(&server, "0.0.0.0"); + ASSERT(r == 0); + + /* server sends "PING" */ + buf = uv_buf_init("PING", 4); + r = uv_udp_send(&req, + &server, + &buf, + 1, + (const struct sockaddr*)&addr, + sv_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + + /* run the loop till all events are processed */ + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(sv_send_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 50e19357de7..d84755aab27 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -31,7 +31,7 @@ 'targets': [ { 'target_name': 'libuv', - 'type': '<(library)', + 'type': '<(uv_library)', 'include_dirs': [ 'include', 'src/', @@ -61,7 +61,9 @@ 'include/uv.h', 'include/tree.h', 'include/uv-errno.h', + 'include/uv-version.h', 'src/fs-poll.c', + 'src/heap-inl.h', 'src/inet.c', 'src/queue.h', 'src/uv-common.c', @@ -167,10 +169,10 @@ ], }, 'conditions': [ - ['library=="shared_library"', { + ['uv_library=="shared_library"', { 'cflags': [ '-fPIC' ], }], - ['library=="shared_library" and OS!="mac"', { + ['uv_library=="shared_library" and OS!="mac"', { 'link_settings': { # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR # in src/version.c @@ -265,7 +267,7 @@ [ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', { 'sources': [ 'src/unix/kqueue.c' ], }], - ['library=="shared_library"', { + ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. @@ -324,6 +326,7 @@ 'test/test-list.h', 'test/test-loop-handles.c', 'test/test-loop-alive.c', + 'test/test-loop-close.c', 'test/test-loop-stop.c', 'test/test-loop-time.c', 'test/test-walk-handles.c', @@ -334,6 +337,7 @@ 'test/test-ping-pong.c', 'test/test-pipe-bind-error.c', 'test/test-pipe-connect-error.c', + 'test/test-pipe-getsockname.c', 'test/test-pipe-server-close.c', 'test/test-platform-output.c', 'test/test-poll.c', @@ -345,6 +349,7 @@ 'test/test-semaphore.c', 'test/test-shutdown-close.c', 'test/test-shutdown-eof.c', + 'test/test-shutdown-twice.c', 'test/test-signal.c', 'test/test-signal-multiple-loops.c', 'test/test-spawn.c', @@ -387,6 +392,7 @@ 'test/test-udp-multicast-ttl.c', 'test/test-ip4-addr.c', 'test/test-ip6-addr.c', + 'test/test-udp-multicast-interface.c', ], 'conditions': [ [ 'OS=="win"', { diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 8545b2635be..df6eda01787 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -33,7 +33,7 @@ if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok if /i "%1"=="nobuild" set nobuild=1&goto arg-ok if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="x64" set target_arch=x64&set platform=amd64&set vs_toolset=x64&goto arg-ok +if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok if /i "%1"=="shared" set library=shared_library&goto arg-ok if /i "%1"=="static" set library=static_library&goto arg-ok :arg-ok @@ -41,6 +41,9 @@ shift goto next-arg :args-done +if defined WindowsSDKDir goto select-target +if defined VCINSTALLDIR goto select-target + @rem Look for Visual Studio 2013 if not defined VS120COMNTOOLS goto vc-set-2012 if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 @@ -99,7 +102,7 @@ exit /b 1 :have_gyp if not defined PYTHON set PYTHON="python" -%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Dlibrary=%library% +%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library% if errorlevel 1 goto create-msvs-files-failed if not exist uv.sln goto create-msvs-files-failed echo Project files generated. @@ -109,10 +112,8 @@ echo Project files generated. if defined nobuild goto run @rem Check if VS build env is available -if not defined VCINSTALLDIR goto msbuild-not-found -goto msbuild-found - -:msbuild-not-found +if defined VCINSTALLDIR goto msbuild-found +if defined WindowsSDKDir goto msbuild-found echo Build skipped. To build, this file needs to run from VS cmd prompt. goto run