From 4dc660e164417e0a1bc86eadd825b41d7abb053f Mon Sep 17 00:00:00 2001 From: Julien Gilli Date: Tue, 2 Dec 2014 22:55:53 -0800 Subject: [PATCH 01/22] build: do not generate support for libuv's probes Dtrace probes were removed from libuv recently, but their usage by node was not completely removed, causing build breaks on SmartOS. Even though the build is working on other platforms, these probes are not fired by libuv anymore, so there's no point in using them on these platforms too. Reviewed-by: Trevor Norris --- node.gyp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/node.gyp b/node.gyp index 1ed8d673eeca2b..b59474ee0ac72a 100644 --- a/node.gyp +++ b/node.gyp @@ -245,8 +245,7 @@ 'conditions': [ [ 'OS=="linux"', { 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/node_dtrace_provider.o', - '<(SHARED_INTERMEDIATE_DIR)/libuv_dtrace_provider.o', + '<(SHARED_INTERMEDIATE_DIR)/node_dtrace_provider.o' ], }], [ 'OS!="mac" and OS!="linux"', { @@ -510,15 +509,13 @@ { 'action_name': 'node_dtrace_provider_o', 'inputs': [ - '<(OBJ_DIR)/libuv/deps/uv/src/unix/core.o', '<(OBJ_DIR)/node/src/node_dtrace.o', ], 'outputs': [ '<(OBJ_DIR)/node/src/node_dtrace_provider.o' ], 'action': [ 'dtrace', '-G', '-xnolibs', '-s', 'src/node_provider.d', - '-s', 'deps/uv/src/unix/uv-dtrace.d', '<@(_inputs)', - '-o', '<@(_outputs)' ] + '<@(_inputs)', '-o', '<@(_outputs)' ] } ] }], @@ -533,17 +530,7 @@ 'action': [ 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' ], - }, - { - 'action_name': 'libuv_dtrace_provider_o', - 'inputs': [ 'deps/uv/src/unix/uv-dtrace.d' ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/libuv_dtrace_provider.o' - ], - 'action': [ - 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' - ], - }, + } ], }], ] From 20a7088d9c62c43fedf9ab077fbbeae92c7e6617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 9 Dec 2014 21:01:35 +0100 Subject: [PATCH 02/22] deps: update libuv to 1.0.2 PR-URL: https://github.com/joyent/node/pull/8847 Reviewed-by: Trevor Norris --- deps/uv/AUTHORS | 6 +- deps/uv/ChangeLog | 89 +++++++++++++++++++ deps/uv/README.md | 3 +- deps/uv/configure.ac | 2 +- deps/uv/docs/src/conf.py | 2 +- deps/uv/docs/src/design.rst | 6 +- deps/uv/docs/src/dll.rst | 2 +- deps/uv/docs/src/fs.rst | 5 +- deps/uv/docs/src/fs_event.rst | 2 +- deps/uv/docs/src/fs_poll.rst | 2 +- deps/uv/docs/src/loop.rst | 19 +++- deps/uv/docs/src/migration_010_100.rst | 8 +- deps/uv/docs/src/misc.rst | 8 +- deps/uv/docs/src/pipe.rst | 2 +- deps/uv/docs/src/stream.rst | 4 +- deps/uv/docs/src/threadpool.rst | 2 +- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv-win.h | 5 +- deps/uv/include/uv.h | 4 + deps/uv/src/unix/aix.c | 4 +- deps/uv/src/unix/core.c | 2 +- deps/uv/src/unix/getaddrinfo.c | 4 +- deps/uv/src/unix/internal.h | 5 ++ deps/uv/src/unix/kqueue.c | 17 +++- deps/uv/src/unix/linux-core.c | 28 ++++-- deps/uv/src/unix/linux-syscalls.c | 3 +- deps/uv/src/unix/linux-syscalls.h | 8 +- deps/uv/src/unix/loop.c | 12 +++ deps/uv/src/unix/pipe.c | 13 +-- deps/uv/src/unix/stream.c | 24 +++-- deps/uv/src/unix/sunos.c | 29 ++++-- deps/uv/src/unix/udp.c | 3 - deps/uv/src/uv-common.c | 14 +++ deps/uv/src/uv-common.h | 3 + deps/uv/src/win/core.c | 15 ++-- deps/uv/src/win/fs.c | 4 +- deps/uv/src/win/getaddrinfo.c | 2 +- deps/uv/src/win/poll.c | 34 ++++--- deps/uv/src/win/process.c | 6 +- deps/uv/src/win/tcp.c | 6 +- deps/uv/src/win/thread.c | 4 +- deps/uv/src/win/udp.c | 2 +- deps/uv/src/win/util.c | 4 +- deps/uv/test/run-benchmarks.c | 7 +- deps/uv/test/run-tests.c | 7 +- deps/uv/test/runner-unix.c | 13 ++- deps/uv/test/runner-win.c | 4 +- deps/uv/test/runner.c | 2 +- deps/uv/test/runner.h | 10 ++- deps/uv/test/test-osx-select.c | 2 + .../test/test-pipe-close-stdout-read-stdin.c | 6 +- deps/uv/test/test-tty.c | 7 ++ 52 files changed, 356 insertions(+), 121 deletions(-) diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 72fa470dab518a..d4c18cf532f8ec 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -86,9 +86,7 @@ Nicholas Vavilov Miroslav Bajtoš Sean Silva Wynn Wilkes -Linus Mårtensson Andrei Sedoi -Navaneeth Kedaram Nambiathan Alex Crichton Brent Cook Brian Kaisner @@ -110,7 +108,6 @@ Yazhong Liu Sam Roberts River Tarnell Nathan Sweet -Luca Bruno Trevor Norris Oguz Bastemur Dylan Cali @@ -173,3 +170,6 @@ Yuri D'Elia Manos Nikolaidis Elijah Andrews Michael Ira Krufky +Helge Deller +Joey Geralnik +Tim Caswell diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 78600b78edd92e..e2169998429ec5 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,67 @@ +2014.12.10, Version 1.0.2 (Stable), eec671f0059953505f9a3c9aeb7f9f31466dd7cd + +Changes since version 1.0.1: + +* linux: fix sigmask size arg in epoll_pwait() call (Ben Noordhuis) + +* linux: handle O_NONBLOCK != SOCK_NONBLOCK case (Helge Deller) + +* doc: fix spelling (Joey Geralnik) + +* unix, windows: fix typos in comments (Joey Geralnik) + +* test: canonicalize test runner path (Ben Noordhuis) + +* test: fix compilation warnings (Saúl Ibarra Corretgé) + +* test: skip tty test if detected width and height are 0 (Saúl Ibarra Corretgé) + +* doc: update README with IRC channel (Saúl Ibarra Corretgé) + +* Revert "unix: use cfmakeraw() for setting raw TTY mode" (Ben Noordhuis) + +* doc: document how to get result of uv_fs_mkdtemp (Tim Caswell) + +* unix: add flag for blocking SIGPROF during poll (Ben Noordhuis) + +* unix, windows: add uv_loop_configure() function (Ben Noordhuis) + +* win: keep a reference to AFD_POLL_INFO in cancel poll (Marc Schlaich) + +* test: raise fd limit for OSX select test (Saúl Ibarra Corretgé) + +* unix: remove overzealous assert in uv_read_stop (Saúl Ibarra Corretgé) + +* unix: reset the reading flag when a stream gets EOF (Saúl Ibarra Corretgé) + +* unix: stop reading if an error is produced (Saúl Ibarra Corretgé) + +* cleanup: remove all dead assignments (Maciej Małecki) + +* linux: return early if we have no interfaces (Maciej Małecki) + +* cleanup: remove a dead increment (Maciej Małecki) + + +2014.12.10, Version 0.10.30 (Stable), 5a63f5e9546dca482eeebc3054139b21f509f21f + +Changes since version 0.10.29: + +* linux: fix sigmask size arg in epoll_pwait() call (Ben Noordhuis) + +* linux: handle O_NONBLOCK != SOCK_NONBLOCK case (Helge Deller) + +* doc: update project links (Ben Noordhuis) + +* windows: fix compilation of tests (Marc Schlaich) + +* unix: add flag for blocking SIGPROF during poll (Ben Noordhuis) + +* unix, windows: add uv_loop_configure() function (Ben Noordhuis) + +* win: keep a reference to AFD_POLL_INFO in cancel poll (Marc Schlaich) + + 2014.11.27, Version 1.0.1 (Stable), 0a8e81374e861d425b56c45c8599595d848911d2 Changes since version 1.0.0: @@ -85,6 +149,17 @@ Changes since version 1.0.0-rc1: * windows: fix fs_write with nbufs > 1 and offset (Unknown W. Brackets) +2014.10.21, Version 0.10.29 (Stable), 2d728542d3790183417f8f122a110693cd85db14 + +Changes since version 0.10.28: + +* darwin: allocate enough space for select() hack (Fedor Indutny) + +* linux: try epoll_pwait if epoll_wait is missing (Michael Hudson-Doyle) + +* windows: map ERROR_INVALID_DRIVE to UV_ENOENT (Saúl Ibarra Corretgé) + + 2014.09.18, Version 1.0.0-rc1 (Unstable), 0c28bbf7b42882853d1799ab96ff68b07f7f8d49 Changes since version 0.11.29: @@ -273,6 +348,20 @@ Changes since version 0.11.26: * windows: relay TCP bind errors via ipc (Alexis Campailla) +2014.07.32, Version 0.10.28 (Stable), 9c14b616f5fb84bfd7d45707bab4bbb85894443e + +Changes since version 0.10.27: + +* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra + Corretgé) + +* unix: return system error on EAI_SYSTEM (Saúl Ibarra Corretgé) + +* unix: fix bogus structure field name (Saúl Ibarra Corretgé) + +* darwin: invoke `mach_timebase_info` only once (Fedor Indutny) + + 2014.06.28, Version 0.11.26 (Unstable), 115281a1058c4034d5c5ccedacb667fe3f6327ea Changes since version 0.11.25: diff --git a/deps/uv/README.md b/deps/uv/README.md index 7fc7cfbd063ed4..a267f0d5b527e5 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -36,12 +36,13 @@ used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), ## Versioning Starting with version 1.0.0 libuv follows the [semantic versioning](http://semver.org/) -scheme. The API change and backwards compatiblity rules are those indicated by +scheme. The API change and backwards compatibility rules are those indicated by SemVer. libuv will keep a stable ABI across major releases. ## Community * [Mailing list](http://groups.google.com/group/libuv) + * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) ## Documentation diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 247e42bd272679..6ae53cc9164f19 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], [1.0.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.0.2], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/conf.py b/deps/uv/docs/src/conf.py index 9ec9ec2c98ddff..f614fc5b434b24 100644 --- a/deps/uv/docs/src/conf.py +++ b/deps/uv/docs/src/conf.py @@ -261,7 +261,7 @@ def get_libuv_version(): # dir menu entry, description, category) texinfo_documents = [ ('index', 'libuv', u'libuv API documentation', - u'libuv contributors', 'libuv', 'Cross-platform asychronous I/O', + u'libuv contributors', 'libuv', 'Cross-platform asynchronous I/O', 'Miscellaneous'), ] diff --git a/deps/uv/docs/src/design.rst b/deps/uv/docs/src/design.rst index 803a4219835003..63141bedf58438 100644 --- a/deps/uv/docs/src/design.rst +++ b/deps/uv/docs/src/design.rst @@ -8,7 +8,7 @@ libuv is cross-platform support library which was originally written for NodeJS. around the event-driven asynchronous I/O model. The library provides much more than simply abstraction over different I/O polling mechanisms: -'handles' and 'streams' provde a high level abstraction for sockets and other entities; +'handles' and 'streams' provide a high level abstraction for sockets and other entities; cross-platform file I/O and threading functionality is also provided, amongst other things. Here is a diagram illustrating the different parts that compose libuv and what subsystem they @@ -42,7 +42,7 @@ operations, and it's meant to be tied to a single thread. One can run multiple e as long as each runs in a different thread. The libuv event loop (or any other API involving the loop or handles, for that matter) **is not thread-safe** except stated otherwise. -The event loop follows the rather usual single threaded asynchronous I/O approah: all (network) +The event loop follows the rather usual single threaded asynchronous I/O approach: all (network) I/O is performed on non-blocking sockets which are polled using the best mechanism available on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets @@ -104,7 +104,7 @@ stages of a loop iteration: #. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the iteration is ended and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` - it will contionue from the start if it's asill *alive*, otherwise it will also end. + it will continue from the start if it's still *alive*, otherwise it will also end. .. important:: diff --git a/deps/uv/docs/src/dll.rst b/deps/uv/docs/src/dll.rst index 3afa31f39d0772..3fb11e192db411 100644 --- a/deps/uv/docs/src/dll.rst +++ b/deps/uv/docs/src/dll.rst @@ -4,7 +4,7 @@ Shared library handling ======================= -libuv prodives cross platform utilities for loading shared libraries and +libuv provides cross platform utilities for loading shared libraries and retrieving symbols from them, using the following API. diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 27d92d0b45319b..cd535f756fc1c9 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -191,6 +191,9 @@ API Equivalent to ``mkdtemp(3)``. + .. note:: + The result can be found as a null terminated string at `req->path`. + .. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) Equivalent to ``rmdir(2)``. @@ -258,7 +261,7 @@ API * ``UV_FS_SYMLINK_DIR``: indicates that `path` points to a directory. * ``UV_FS_SYMLINK_JUNCTION``: request that the symlink is created - using junktion points. + using junction points. .. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) diff --git a/deps/uv/docs/src/fs_event.rst b/deps/uv/docs/src/fs_event.rst index eeb6bfbcb9916d..9bc9939fc2cea8 100644 --- a/deps/uv/docs/src/fs_event.rst +++ b/deps/uv/docs/src/fs_event.rst @@ -95,7 +95,7 @@ API 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 + On success, `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. diff --git a/deps/uv/docs/src/fs_poll.rst b/deps/uv/docs/src/fs_poll.rst index 7459aac07b8217..df31053521431c 100644 --- a/deps/uv/docs/src/fs_poll.rst +++ b/deps/uv/docs/src/fs_poll.rst @@ -62,7 +62,7 @@ API 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 + On success, `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. diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index c63ef7eb67cd02..0a9e8a60869956 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -50,6 +50,23 @@ API Initializes the given `uv_loop_t` structure. +.. c:function:: int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) + + Set additional loop options. You should normally call this before the + first call to :c:func:`uv_run` unless mentioned otherwise. + + Returns 0 on success or a UV_E* error code on failure. Be prepared to + handle UV_ENOSYS; it means the loop option is not supported by the platform. + + Supported options: + + - UV_LOOP_BLOCK_SIGNAL: Block a signal when polling for new events. The + second argument to :c:func:`uv_loop_configure` is the signal number. + + This operation is currently only implemented for SIGPROF signals, + to suppress unnecessary wakeups when using a sampling profiler. + Requesting other signals will fail with UV_EINVAL. + .. c:function:: int uv_loop_close(uv_loop_t* loop) Closes all internal loop resources. This function must only be called once @@ -59,7 +76,7 @@ API .. c:function:: uv_loop_t* uv_default_loop(void) Returns the initialized default loop. It may return NULL in case of - allocation failture. + allocation failure. .. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode) diff --git a/deps/uv/docs/src/migration_010_100.rst b/deps/uv/docs/src/migration_010_100.rst index 83b3865567570c..bb6ac1a8092bc7 100644 --- a/deps/uv/docs/src/migration_010_100.rst +++ b/deps/uv/docs/src/migration_010_100.rst @@ -80,7 +80,7 @@ In libuv 0.10 Unix used a threadpool which defaulted to 4 threads, while Windows threads per process. In 1.0, we unified both implementations, so Windows now uses the same implementation Unix -does. The threadppol size can be set by exporting the ``UV_THREADPOOL_SIZE`` environment +does. The threadpool size can be set by exporting the ``UV_THREADPOOL_SIZE`` environment variable. See :c:ref:`threadpool`. @@ -95,7 +95,7 @@ In libuv 0.10 the callback had to return a filled :c:type:`uv_buf_t` by value: return uv_buf_init(malloc(size), size); } -In libuv 1.0 a pointer to a buffer is passed to the callbck, which the user +In libuv 1.0 a pointer to a buffer is passed to the callback, which the user needs to fill: :: @@ -200,7 +200,7 @@ for such function looked like this: ... } -In libuv 1.0, `uv_read2_start` was removed, and the user needs to check if there are penging +In libuv 1.0, `uv_read2_start` was removed, and the user needs to check if there are pending handles using :c:func:`uv_pipe_pending_count` and :c:func:`uv_pipe_pending_type` while in the read callback: @@ -222,7 +222,7 @@ Extracting the file descriptor out of a handle ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While it wasn't supported by the API, users often accessed the libuv internals in -order to get access to the file descript of a TCP handle, for example. +order to get access to the file descriptor of a TCP handle, for example. :: diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 1e1125ad6b06e6..4b810fe08475e8 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -1,10 +1,10 @@ .. _misc: -Miscelaneous utilities +Miscellaneous utilities ====================== -This section contains miscelaneous functions that don't really belong in any +This section contains miscellaneous functions that don't really belong in any other section. @@ -186,11 +186,11 @@ API .. c:function:: int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) - Convert a binary structure containing an IPv4 addres to a string. + Convert a binary structure containing an IPv4 address to a string. .. c:function:: int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) - Convert a binary structure containing an IPv6 addres to a string. + Convert a binary structure containing an IPv6 address to a string. .. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size) .. c:function:: int uv_inet_pton(int af, const char* src, void* dst) diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst index 9a4a19340b893d..614bb2e3b1ff03 100644 --- a/deps/uv/docs/src/pipe.rst +++ b/deps/uv/docs/src/pipe.rst @@ -39,7 +39,7 @@ API Open an existing file descriptor or HANDLE as a pipe. .. note:: - The user is responsible for setting the dile descriptor in non-blocking mode. + The user is responsible for setting the file descriptor in non-blocking mode. .. c:function:: int uv_pipe_bind(uv_pipe_t* handle, const char* name) diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index 44dccbe94267c6..2c669cf0418fcd 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -62,7 +62,7 @@ Data types Callback called when a stream server has received an incoming connection. The user can accept the connection by calling :c:func:`uv_accept`. - `status` will de 0 in case of success, < 0 otherwise. + `status` will be 0 in case of success, < 0 otherwise. Public members @@ -200,7 +200,7 @@ API When blocking mode is enabled all writes complete synchronously. The interface remains unchanged otherwise, e.g. completion or failure of the operation will still be reported through a callback which is made - asychronously. + asynchronously. .. warning:: Relying too much on this API is not recommended. It is likely to change diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst index 875bb36aeab026..66ff53e230599c 100644 --- a/deps/uv/docs/src/threadpool.rst +++ b/deps/uv/docs/src/threadpool.rst @@ -5,7 +5,7 @@ Thread pool work scheduling =========================== libuv provides a threadpool which can be used to run user code and get notified -in the loop thread. This thread pool is internally used to run al filesystem +in the loop thread. This thread pool is internally used to run all filesystem operations, as well as getaddrinfo and getnameinfo requests. Its default size is 4, but it can be changed at startup time by setting the diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 889abffca30897..25c31ab5e1093d 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,7 +32,7 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 0 -#define UV_VERSION_PATCH 1 +#define UV_VERSION_PATCH 2 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 4abb294c0517db..0c188e7e22af85 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -517,7 +517,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); /* Used in fast mode */ \ SOCKET peer_socket; \ AFD_POLL_INFO afd_poll_info_1; \ - AFD_POLL_INFO afd_poll_info_2; \ + union { \ + AFD_POLL_INFO* afd_poll_info_ptr; \ + AFD_POLL_INFO afd_poll_info; \ + } afd_poll_info_2; \ /* Used in fast and slow mode. */ \ uv_req_t poll_req_1; \ uv_req_t poll_req_2; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 7f4fa6dd8ad8de..7b3c25223b29ed 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -229,6 +229,9 @@ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; +typedef enum { + UV_LOOP_BLOCK_SIGNAL +} uv_loop_option; typedef enum { UV_RUN_DEFAULT = 0, @@ -257,6 +260,7 @@ UV_EXTERN uv_loop_t* uv_loop_new(void); UV_EXTERN void uv_loop_delete(uv_loop_t*); UV_EXTERN size_t uv_loop_size(void); UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); +UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...); UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); UV_EXTERN void uv_stop(uv_loop_t*); diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index eb901113451d9f..349c2b558e4fac 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -151,7 +151,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Could maybe mod if we knew for sure no events are removed, but * content of w->events is handled above as not reliable (falls back) * so may require a pollset_query() which would have to be pretty cheap - * compared to a PS_DELETE to be worth optimising. Alternatively, could + * compared to a PS_DELETE to be worth optimizing. Alternatively, could * lazily remove events, squelching them in the mean time. */ pc.cmd = PS_DELETE; if (pollset_ctl(loop->backend_fd, &pc, 1)) { @@ -332,7 +332,7 @@ int uv_exepath(char* buffer, size_t* size) { res = readlink(symlink, temp_buffer, PATH_MAX-1); /* if readlink fails, it is a normal file just copy symlink to the - * outbut buffer. + * output buffer. */ if (res < 0) { assert(*size > strlen(symlink)); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index e6a076831ccf4a..c08040e5378f5f 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -325,7 +325,7 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { uv__run_closing_handles(loop); if (mode == UV_RUN_ONCE) { - /* UV_RUN_ONCE implies forward progess: at least one callback must have + /* UV_RUN_ONCE implies forward progress: at least one callback must have * been invoked when it returns. uv__io_poll() can return without doing * I/O (meaning: no callbacks) when its timeout expires - which means we * have pending timers that satisfy the forward progress constraint. diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index f6c2de9b438773..faf9add9285e14 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -182,10 +182,8 @@ int uv_getaddrinfo(uv_loop_t* loop, len += service_len; } - if (hostname) { + if (hostname) req->hostname = memcpy(buf + len, hostname, hostname_len); - len += hostname_len; - } uv__work_submit(loop, &req->work_req, diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index b94508cba5932d..daad61b782f17f 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -146,6 +146,11 @@ enum { UV_HANDLE_IPV6 = 0x10000 /* Handle is bound to a IPv6 socket. */ }; +/* loop flags */ +enum { + UV_LOOP_BLOCK_SIGPROF = 1 +}; + typedef enum { UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index b4f9f5d8405521..aaadcd8419a3f3 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -55,9 +55,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { unsigned int nevents; unsigned int revents; QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; uint64_t base; uint64_t diff; - uv__io_t* w; int filter; int fflags; int count; @@ -117,6 +119,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; } + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ @@ -127,6 +136,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { spec.tv_nsec = (timeout % 1000) * 1000000; } + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + nfds = kevent(loop->backend_fd, events, nevents, @@ -134,6 +146,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 7a43630494df38..a2145b0f369eee 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event e; QUEUE* q; uv__io_t* w; + sigset_t* pset; + sigset_t set; uint64_t base; uint64_t diff; int nevents; @@ -191,12 +194,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; } + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { - if (!no_epoll_wait) { + if (no_epoll_wait || pset != NULL) { + nfds = uv__epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + pset); + } else { nfds = uv__epoll_wait(loop->backend_fd, events, ARRAY_SIZE(events), @@ -205,12 +221,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { no_epoll_wait = 1; continue; } - } else { - nfds = uv__epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - NULL); } /* Update loop->time unconditionally. It's tempting to skip the update when @@ -744,6 +754,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, return -errno; *count = 0; + *addresses = NULL; /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { @@ -756,6 +767,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, (*count)++; } + if (*count == 0) + return 0; + *addresses = malloc(*count * sizeof(**addresses)); if (!(*addresses)) return -ENOMEM; diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 1ff8abd197fbf3..e036fad5ef6427 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -21,6 +21,7 @@ #include "linux-syscalls.h" #include +#include #include #include #include @@ -328,7 +329,7 @@ int uv__epoll_pwait(int epfd, nevents, timeout, sigmask, - sizeof(*sigmask)); + _NSIG / 8); #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 0f0b34b1ed32f9..fd6bb48665fb9c 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -44,7 +44,7 @@ #if defined(__alpha__) # define UV__O_NONBLOCK 0x4 #elif defined(__hppa__) -# define UV__O_NONBLOCK 0x10004 +# define UV__O_NONBLOCK O_NONBLOCK #elif defined(__mips__) # define UV__O_NONBLOCK 0x80 #elif defined(__sparc__) @@ -60,7 +60,11 @@ #define UV__IN_NONBLOCK UV__O_NONBLOCK #define UV__SOCK_CLOEXEC UV__O_CLOEXEC -#define UV__SOCK_NONBLOCK UV__O_NONBLOCK +#if defined(SOCK_NONBLOCK) +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +#else +# define UV__SOCK_NONBLOCK UV__O_NONBLOCK +#endif /* epoll flags */ #define UV__EPOLL_CLOEXEC UV__O_CLOEXEC diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 002224855c2bef..616cf5bc43b030 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -192,3 +192,15 @@ static void uv__loop_close(uv_loop_t* loop) { loop->watchers = NULL; loop->nwatchers = 0; } + + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + if (option != UV_LOOP_BLOCK_SIGNAL) + return UV_ENOSYS; + + if (va_arg(ap, int) != SIGPROF) + return UV_EINVAL; + + loop->flags |= UV_LOOP_BLOCK_SIGPROF; + return 0; +} diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index a26c3dbc135095..b20fb9210c074b 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -44,13 +44,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un saddr; const char* pipe_fname; int sockfd; - int bound; int err; pipe_fname = NULL; sockfd = -1; - bound = 0; - err = -EINVAL; /* Already bound? */ if (uv__stream_fd(handle) >= 0) @@ -83,7 +80,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { err = -EACCES; goto out; } - bound = 1; /* Success. */ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ @@ -91,11 +87,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { return 0; out: - if (bound) { - /* unlink() before uv__close() to avoid races. */ - assert(pipe_fname != NULL); - unlink(pipe_fname); - } + /* unlink() before uv__close() to avoid races. */ + assert(pipe_fname != NULL); + unlink(pipe_fname); uv__close(sockfd); free((void*)pipe_fname); return err; @@ -158,7 +152,6 @@ void uv_pipe_connect(uv_connect_t* req, int r; new_sock = (uv__stream_fd(handle) == -1); - err = -EINVAL; if (new_sock) { err = uv__socket(AF_UNIX, SOCK_STREAM, 0); diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9c7d28cbf4d792..d41a3429a78b2e 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -549,7 +549,6 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { if (server->accepted_fd == -1) return -EAGAIN; - err = 0; switch (client->type) { case UV_NAMED_PIPE: case UV_TCP: @@ -951,6 +950,7 @@ static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); + stream->flags &= ~UV_STREAM_READING; } @@ -1117,8 +1117,13 @@ static void uv__read(uv_stream_t* stream) { } else { /* Error. User should call uv_close(). */ stream->read_cb(stream, -errno, &buf); - assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) && - "stream->read_cb(status=-1) did not call uv_close()"); + if (stream->flags & UV_STREAM_READING) { + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); + if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + } } return; } else if (nread == 0) { @@ -1319,7 +1324,7 @@ int uv_write2(uv_write_t* req, /* It's legal for write_queue_size > 0 even when the write_queue is empty; * it means there are error-state requests in the write_completed_queue that * will touch up write_queue_size later, see also uv__write_req_finish(). - * We chould check that write_queue is empty instead but that implies making + * We could check that write_queue is empty instead but that implies making * a write() syscall when we know that the handle is in error mode. */ empty_queue = (stream->write_queue_size == 0); @@ -1471,15 +1476,8 @@ int uv_read_start(uv_stream_t* stream, int uv_read_stop(uv_stream_t* stream) { - /* Sanity check. We're going to stop the handle unless it's primed for - * writing but that means there should be some kind of write action in - * progress. - */ - assert(!uv__io_active(&stream->io_watcher, UV__POLLOUT) || - !QUEUE_EMPTY(&stream->write_completed_queue) || - !QUEUE_EMPTY(&stream->write_queue) || - stream->shutdown_req != NULL || - stream->connect_req != NULL); + if (!(stream->flags & UV_STREAM_READING)) + return 0; stream->flags &= ~UV_STREAM_READING; uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index a630dba759a6a2..d6fb7f49509185 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -122,6 +122,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct timespec spec; QUEUE* q; uv__io_t* w; + sigset_t* pset; + sigset_t set; uint64_t base; uint64_t diff; unsigned int nfds; @@ -129,6 +131,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int saved_errno; int nevents; int count; + int err; int fd; if (loop->nfds == 0) { @@ -150,6 +153,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; } + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ @@ -165,11 +175,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nfds = 1; saved_errno = 0; - if (port_getn(loop->backend_fd, - events, - ARRAY_SIZE(events), - &nfds, - timeout == -1 ? NULL : &spec)) { + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + err = port_getn(loop->backend_fd, + events, + ARRAY_SIZE(events), + &nfds, + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + if (err) { /* Work around another kernel bug: port_getn() may return events even * on error. */ diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 7cafea1d089f27..71a0e41f1f743e 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -278,9 +278,6 @@ int uv__udp_bind(uv_udp_t* handle, int yes; int fd; - err = -EINVAL; - fd = -1; - /* Check for bad flags. */ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) return -EINVAL; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 5ba1ea4df4df47..f84f8c4ae10d50 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -24,6 +24,7 @@ #include #include +#include #include /* NULL */ #include /* malloc */ #include /* memset */ @@ -442,3 +443,16 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { return 0; } + + +int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) { + va_list ap; + int err; + + va_start(ap, option); + /* Any platform-agnostic options should be handled here. */ + err = uv__loop_configure(loop, option, ap); + va_end(ap); + + return err; +} diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index e06606c19baecf..7d3c58f1218501 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -28,6 +28,7 @@ #define UV_COMMON_H_ #include +#include #include #if defined(_MSC_VER) && _MSC_VER < 1600 @@ -59,6 +60,8 @@ enum { # define UV__HANDLE_CLOSING 0x01 #endif +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); + int uv__tcp_bind(uv_tcp_t* tcp, const struct sockaddr* addr, unsigned int addrlen, diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index c9e4c88fa731a9..48897cf29bc735 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -39,7 +39,7 @@ static uv_loop_t default_loop_struct; static uv_loop_t* default_loop_ptr; -/* uv_once intialization guards */ +/* uv_once initialization guards */ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; @@ -103,7 +103,7 @@ static void uv_init(void) { #endif /* Fetch winapi function pointers. This must be done first because other - * intialization code might need these function pointers to be loaded. + * initialization code might need these function pointers to be loaded. */ uv_winapi_init(); @@ -133,7 +133,7 @@ int uv_loop_init(uv_loop_t* loop) { if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); - /* To prevent uninitialized memory access, loop->time must be intialized + /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. */ loop->time = 0; @@ -199,7 +199,7 @@ uv_loop_t* uv_default_loop(void) { static void uv__loop_close(uv_loop_t* loop) { size_t i; - /* close the async handle without needeing an extra loop iteration */ + /* close the async handle without needing an extra loop iteration */ assert(!loop->wq_async.async_sent); loop->wq_async.close_cb = NULL; uv__handle_closing(&loop->wq_async); @@ -272,6 +272,11 @@ void uv_loop_delete(uv_loop_t* loop) { } +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + return UV_ENOSYS; +} + + int uv_backend_fd(const uv_loop_t* loop) { return -1; } @@ -411,7 +416,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv_process_endgames(loop); if (mode == UV_RUN_ONCE) { - /* UV_RUN_ONCE implies forward progess: at least one callback must have + /* UV_RUN_ONCE implies forward progress: at least one callback must have * been invoked when it returns. uv__io_poll() can return without doing * I/O (meaning: no callbacks) when its timeout expires - which means we * have pending timers that satisfy the forward progress constraint. diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 7208a65c424e06..30a457a023b490 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -947,7 +947,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { * * Currently it's based on whether the 'readonly' attribute is set, which * makes little sense because the semantics are so different: the 'read-only' - * flag is just a way for a user to protect against accidental deleteion, and + * flag is just a way for a user to protect against accidental deletion, and * serves no security purpose. Windows uses ACLs for that. * * Also people now use uv_fs_chmod() to take away the writable bit for good @@ -956,7 +956,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { * deleted. * * IOW it's all just a clusterfuck and we should think of something that - * makes slighty more sense. + * makes slightly more sense. * * And uv_fs_chmod should probably just fail on windows or be a total no-op. * There's nothing sensible it can do anyway. diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 787cfd53664d35..53a6084efe5bb3 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -296,7 +296,7 @@ int uv_getaddrinfo(uv_loop_t* loop, req->alloc = (void*)alloc_ptr; /* convert node string to UTF16 into allocated memory and save pointer in */ - /* the reques. */ + /* the request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; if (uv_utf8_to_utf16(node, diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 85c314828bc197..622cbabe399eb2 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -79,7 +79,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_2 = handle->events; } else if (handle->submitted_events_2 == 0) { req = &handle->poll_req_2; - afd_poll_info = &handle->afd_poll_info_2; + afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0]; handle->submitted_events_2 = handle->events; handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; @@ -119,18 +119,19 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { - AFD_POLL_INFO afd_poll_info; - int result; + AFD_POLL_INFO* afd_poll_info; + DWORD result; - afd_poll_info.Exclusive = TRUE; - afd_poll_info.NumberOfHandles = 1; - afd_poll_info.Timeout.QuadPart = INT64_MAX; - afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; - afd_poll_info.Handles[0].Status = 0; - afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[1]; + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = AFD_POLL_ALL; result = uv_msafd_poll(handle->socket, - &afd_poll_info, + afd_poll_info, uv__get_overlapped_dummy()); if (result == SOCKET_ERROR) { @@ -154,7 +155,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, handle->submitted_events_1 = 0; mask_events = handle->mask_events_1; } else if (req == &handle->poll_req_2) { - afd_poll_info = &handle->afd_poll_info_2; + afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0]; handle->submitted_events_2 = 0; mask_events = handle->mask_events_2; } else { @@ -546,7 +547,7 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, handle->flags |= UV_HANDLE_POLL_SLOW; } - /* Intialize 2 poll reqs. */ + /* Initialize 2 poll reqs. */ handle->submitted_events_1 = 0; uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); handle->poll_req_1.type = UV_POLL_REQ; @@ -557,6 +558,11 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, handle->poll_req_2.type = UV_POLL_REQ; handle->poll_req_2.data = handle; + handle->afd_poll_info_2.afd_poll_info_ptr = malloc(sizeof(*handle->afd_poll_info_2.afd_poll_info_ptr) * 2); + if (handle->afd_poll_info_2.afd_poll_info_ptr == NULL) { + return UV_ENOMEM; + } + return 0; } @@ -618,5 +624,9 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { assert(handle->submitted_events_1 == 0); assert(handle->submitted_events_2 == 0); + if (handle->afd_poll_info_2.afd_poll_info_ptr) { + free(handle->afd_poll_info_2.afd_poll_info_ptr); + handle->afd_poll_info_2.afd_poll_info_ptr = NULL; + } uv__handle_close(handle); } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 4d04a0e906194f..3a0106f82d63e3 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -1063,7 +1063,7 @@ int uv_spawn(uv_loop_t* loop, if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That - * means that libuv might not let you create a fully deamonized process + * means that libuv might not let you create a fully daemonized process * when run under job control. However the type of job control that libuv * itself creates doesn't trickle down to subprocesses so they can still * daemonize. @@ -1141,7 +1141,7 @@ int uv_spawn(uv_loop_t* loop, assert(!err); /* Make the handle active. It will remain active until the exit callback */ - /* iis made or the handle is closed, whichever happens first. */ + /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ @@ -1177,7 +1177,7 @@ static int uv__kill(HANDLE process_handle, int signum) { return 0; /* If the process already exited before TerminateProcess was called, */ - /* TerminateProcess will fail with ERROR_ACESS_DENIED. */ + /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); if (err == ERROR_ACCESS_DENIED && GetExitCodeProcess(process_handle, &status) && diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 23fadc220da03c..cff2929e4cc697 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -241,7 +241,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { * allow binding to addresses that are in use by sockets in TIME_WAIT, it * effectively allows 'stealing' a port which is in use by another application. * - * SO_EXCLUSIVEADDRUSE is also not good here because it does cehck all sockets, + * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets, * regardless of state, so we'd get an error even if the port is in use by a * socket in TIME_WAIT state. * @@ -590,7 +590,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } /* Initialize other unused requests too, because uv_tcp_endgame */ - /* doesn't know how how many requests were intialized, so it will */ + /* doesn't know how how many requests were initialized, so it will */ /* try to clean up {uv_simultaneous_server_accepts} requests. */ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { req = &handle->accept_reqs[i]; @@ -1342,7 +1342,7 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { if (uv_tcp_try_cancel_io(tcp) != 0) { /* When cancellation is not possible, there is another option: we can */ /* close the incoming sockets, which will also cancel the accept */ - /* operations. However this is not cool because we might inadvertedly */ + /* operations. However this is not cool because we might inadvertently */ /* close a socket that just accepted a new connection, which will */ /* cause the connection to be aborted. */ unsigned int i; diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 7143743926eee0..a697d7ae74456b 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -100,7 +100,7 @@ static NOINLINE void uv__once_inner(uv_once_t* guard, } else { /* We lost the race. Destroy the event we created and wait for the */ - /* existing one todv become signaled. */ + /* existing one to become signaled. */ CloseHandle(created_event); result = WaitForSingleObject(existing_event, INFINITE); assert(result == WAIT_OBJECT_0); @@ -155,7 +155,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->arg = arg; /* Create the thread in suspended state so we have a chance to pass - * its own creation handle to it */ + * its own creation handle to it */ thread = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 99fd80fce9dafc..73b5bd5e467b40 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -83,7 +83,7 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, } if (pSetFileCompletionNotificationModes) { - /* All know windowses that support SetFileCompletionNotificationModes */ + /* All known Windows that support SetFileCompletionNotificationModes */ /* have a bug that makes it impossible to use this function in */ /* conjunction with datagram sockets. We can work around that but only */ /* if the user is using the default UDP driver (AFD) and has no other */ diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 0bcb721a524a2d..43d843ff5c42b5 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -44,7 +44,7 @@ * of the console title is that it is smaller than 64K. However in practice * it is much smaller, and there is no way to figure out what the exact length * of the title is or can be, at least not on XP. To make it even more - * annoying, GetConsoleTitle failes when the buffer to be read into is bigger + * annoying, GetConsoleTitle fails when the buffer to be read into is bigger * than the actual maximum length. So we make a conservative guess here; * just don't put the novel you're writing in the title, unless the plot * survives truncation. @@ -64,7 +64,7 @@ static double hrtime_interval_ = 0; /* - * One-time intialization code for functionality defined in util.c. + * One-time initialization code for functionality defined in util.c. */ void uv__util_init() { LARGE_INTEGER perf_frequency; diff --git a/deps/uv/test/run-benchmarks.c b/deps/uv/test/run-benchmarks.c index 61f062f99aa90a..8d4f549799e8b3 100644 --- a/deps/uv/test/run-benchmarks.c +++ b/deps/uv/test/run-benchmarks.c @@ -33,7 +33,8 @@ static int maybe_run_test(int argc, char **argv); int main(int argc, char **argv) { - platform_init(argc, argv); + if (platform_init(argc, argv)) + return EXIT_FAILURE; switch (argc) { case 1: return run_tests(1); @@ -41,8 +42,10 @@ int main(int argc, char **argv) { case 3: return run_test_part(argv[1], argv[2]); default: LOGF("Too many arguments.\n"); - return 1; + return EXIT_FAILURE; } + + return EXIT_SUCCESS; } diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index d8f3cda540a819..e92c93008e72ef 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -46,7 +46,8 @@ static int maybe_run_test(int argc, char **argv); int main(int argc, char **argv) { - platform_init(argc, argv); + if (platform_init(argc, argv)) + return EXIT_FAILURE; argv = uv_setup_args(argc, argv); @@ -56,8 +57,10 @@ int main(int argc, char **argv) { case 3: return run_test_part(argv[1], argv[2]); default: LOGF("Too many arguments.\n"); - return 1; + return EXIT_FAILURE; } + + return EXIT_SUCCESS; } diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 9afcd1e48813ce..1f12c6f12d91b0 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -22,10 +22,11 @@ #include "runner-unix.h" #include "runner.h" +#include #include /* uintptr_t */ #include -#include /* usleep */ +#include /* readlink, usleep */ #include /* strdup */ #include #include @@ -40,7 +41,7 @@ /* Do platform-specific initialization. */ -void platform_init(int argc, char **argv) { +int platform_init(int argc, char **argv) { const char* tap; tap = getenv("UV_TAP_OUTPUT"); @@ -49,8 +50,14 @@ void platform_init(int argc, char **argv) { /* Disable stdio output buffering. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); - strncpy(executable_path, argv[0], sizeof(executable_path) - 1); signal(SIGPIPE, SIG_IGN); + + if (realpath(argv[0], executable_path) == NULL) { + perror("realpath"); + return -1; + } + + return 0; } diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 83d76783f6b1a0..97ef7599eb8e52 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -43,7 +43,7 @@ /* Do platform-specific initialization. */ -void platform_init(int argc, char **argv) { +int platform_init(int argc, char **argv) { const char* tap; tap = getenv("UV_TAP_OUTPUT"); @@ -66,6 +66,8 @@ void platform_init(int argc, char **argv) { setvbuf(stderr, NULL, _IONBF, 0); strcpy(executable_path, argv[0]); + + return 0; } diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index a934b24c6e5e7b..e896d43b7627df 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -26,7 +26,7 @@ #include "task.h" #include "uv.h" -char executable_path[PATHMAX] = { '\0' }; +char executable_path[sizeof(executable_path)]; int tap_output = 0; diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 97c7312da7ba4a..78f3c880a981fc 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -22,6 +22,7 @@ #ifndef RUNNER_H_ #define RUNNER_H_ +#include /* PATH_MAX */ #include /* FILE */ @@ -83,8 +84,11 @@ typedef struct { #define TEST_HELPER HELPER_ENTRY #define BENCHMARK_HELPER HELPER_ENTRY -#define PATHMAX 1024 -extern char executable_path[PATHMAX]; +#ifdef PATH_MAX +extern char executable_path[PATH_MAX]; +#else +extern char executable_path[4096]; +#endif /* * Include platform-dependent definitions @@ -130,7 +134,7 @@ void print_tests(FILE* stream); */ /* Do platform-specific initialization. */ -void platform_init(int argc, char** argv); +int platform_init(int argc, char** argv); /* Invoke "argv[0] test-name [test-part]". Store process info in *p. */ /* Make sure that all stdio output of the processes is buffered up. */ diff --git a/deps/uv/test/test-osx-select.c b/deps/uv/test/test-osx-select.c index 68e5a841678336..49b1bb8229aeb8 100644 --- a/deps/uv/test/test-osx-select.c +++ b/deps/uv/test/test-osx-select.c @@ -90,6 +90,8 @@ TEST_IMPL(osx_select_many_fds) { uv_tty_t tty; uv_tcp_t tcps[1500]; + TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 2); + r = uv_ip4_addr("127.0.0.1", 0, &addr); ASSERT(r == 0); diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c index 26a1ee76c93ecf..3064babf98c05f 100644 --- a/deps/uv/test/test-pipe-close-stdout-read-stdin.c +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -54,7 +54,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { int fd[2]; int status; - pipe(fd); + r = pipe(fd); + ASSERT(r == 0); if ((pid = fork()) == 0) { /* @@ -63,7 +64,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { */ close(fd[1]); close(0); - dup(fd[0]); + r = dup(fd[0]); + ASSERT(r != -1); /* Create a stream that reads from the pipe. */ uv_pipe_t stdin_pipe; diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index fb69910732ca2e..7e1ce2668899f8 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -96,6 +96,13 @@ TEST_IMPL(tty) { printf("width=%d height=%d\n", width, height); + if (width == 0 && height == 0) { + /* Some environments such as containers or Jenkins behave like this + * sometimes */ + MAKE_VALGRIND_HAPPY(); + return TEST_SKIP; + } + /* * Is it a safe assumption that most people have terminals larger than * 10x10? From 8708c7abe59cbcaacc1d59cbc268f2a1d3ba3061 Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Wed, 10 Dec 2014 12:58:32 +0100 Subject: [PATCH 03/22] test: mark more tests as flaky Marking these two tests as flaky, since they have been failing intermittenly in recent builds: test-debug-signal-cluster test-cluster-basic --- test/simple/simple.status | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/simple/simple.status b/test/simple/simple.status index f0aa4e99b9b59b..8a0cbfb3cb8ff3 100644 --- a/test/simple/simple.status +++ b/test/simple/simple.status @@ -1,6 +1,8 @@ prefix simple test-crypto-domains : PASS,FLAKY +test-debug-signal-cluster : PASS,FLAKY +test-cluster-basic : PASS,FLAKY [$system==win32] test-timers-first-fire : PASS,FLAKY @@ -14,4 +16,3 @@ test-util-debug : PASS,FLAKY [$system==macos] [$system==solaris] -test-debug-signal-cluster : PASS,FLAKY From 946cec7b65716f4781808f5ae3b3345f6d8b6c6d Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 14 Oct 2014 12:07:19 +0200 Subject: [PATCH 04/22] lib,src: fix spawnSync ignoring its 'env' option PR-URL: https://github.com/joyent/node/pull/8546 Reviewed-By: Colin Ihrig --- lib/child_process.js | 1 + src/spawn_sync.cc | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index c4345f90c2ab9f..e18b65435db578 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -1262,6 +1262,7 @@ function spawnSync(/*file, args, options*/) { options.file = opts.file; options.args = opts.args; + options.envPairs = opts.envPairs; if (options.killSignal) options.killSignal = lookupSignal(options.killSignal); diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index 59de8d46304118..f13a9e9ed3395a 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -737,9 +737,9 @@ int SyncProcessRunner::ParseOptions(Local js_value) { r = CopyJsStringArray(js_env_pairs, &env_buffer_); if (r < 0) return r; - uv_process_options_.args = reinterpret_cast(env_buffer_); - } + uv_process_options_.env = reinterpret_cast(env_buffer_); + } Local js_uid = js_options->Get(env()->uid_string()); if (IsSet(js_uid)) { if (!CheckRange(js_uid)) From 4bba87050c2b8aa801d982e93ea767b3abdc2f17 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 9 Dec 2014 13:47:49 -0500 Subject: [PATCH 05/22] test: add test for spawnSync() env option PR-URL: https://github.com/joyent/node/pull/8845 Reviewed-by: Trevor Norris --- .../test-child-process-spawnsync-env.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/simple/test-child-process-spawnsync-env.js diff --git a/test/simple/test-child-process-spawnsync-env.js b/test/simple/test-child-process-spawnsync-env.js new file mode 100644 index 00000000000000..0cde9ffeefa0f7 --- /dev/null +++ b/test/simple/test-child-process-spawnsync-env.js @@ -0,0 +1,35 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +var common = require('../common'); +var assert = require('assert'); +var cp = require('child_process'); + +if (process.argv[2] === 'child') { + console.log(process.env.foo); +} else { + var expected = 'bar'; + var child = cp.spawnSync(process.execPath, [__filename, 'child'], { + env: {foo: expected} + }); + + assert.equal(child.stdout.toString().trim(), expected); +} From 5b9e5bdd03ef5c53f370e414c5a964fccb4ac030 Mon Sep 17 00:00:00 2001 From: Ben Burns Date: Sun, 27 Jul 2014 02:04:46 +1200 Subject: [PATCH 06/22] doc: clarify create{Read,Write}Stream fd option Clarify the fd option: it is preferred to the path parameter, omits the "open" event if given, and is available on WriteStreams as well. PR-URL: https://github.com/joyent/node/issues/7707 Fixes: https://github.com/joyent/node/issues/7707 Fixes: https://github.com/joyent/node/issues/7708 Fixes: https://github.com/joyent/node/issues/4367 Reviewed-By: Chris Dickinson --- doc/api/fs.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index c6bfa2456bc17d..124962c2a1100b 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -745,6 +745,9 @@ Returns a new ReadStream object (See `Readable Stream`). the file instead of the entire file. Both `start` and `end` are inclusive and start at 0. The `encoding` can be `'utf8'`, `'ascii'`, or `'base64'`. +If `fd` is specified, `ReadStream` will ignore the `path` argument and will use +the specified file descriptor. This means that no `open` event will be emitted. + If `autoClose` is false, then the file descriptor won't be closed, even if there's an error. It is your responsibility to close it and make sure there's no file descriptor leak. If `autoClose` is set to true (default @@ -775,6 +778,7 @@ Returns a new WriteStream object (See `Writable Stream`). { flags: 'w', encoding: null, + fd: null, mode: 0666 } `options` may also include a `start` option to allow writing data at @@ -782,6 +786,11 @@ some position past the beginning of the file. Modifying a file rather than replacing it may require a `flags` mode of `r+` rather than the default mode `w`. +Like `ReadStream` above, if `fd` is specified, `WriteStream` will ignore the +`path` argument and will use the specified file descriptor. This means that no +`open` event will be emitted. + + ## Class: fs.WriteStream `WriteStream` is a [Writable Stream](stream.html#stream_class_stream_writable). From 6f6a97958e8723b4b4a3ccf352252b36cf7a0d85 Mon Sep 17 00:00:00 2001 From: Luis Reis Date: Tue, 9 Sep 2014 17:30:15 +0100 Subject: [PATCH 07/22] zlib: support concatenated gzip files Reviewed-By: Fedor Indutny PR-URL: https://github.com/joyent/node/pull/6442 --- lib/zlib.js | 9 +- src/node_zlib.cc | 31 +++++-- ...st-zlib-from-multiple-gzip-with-garbage.js | 83 +++++++++++++++++ test/simple/test-zlib-from-multiple-gzip.js | 74 +++++++++++++++ .../test-zlib-from-multiple-huge-gzip.js | 93 +++++++++++++++++++ 5 files changed, 282 insertions(+), 8 deletions(-) create mode 100644 test/simple/test-zlib-from-multiple-gzip-with-garbage.js create mode 100644 test/simple/test-zlib-from-multiple-gzip.js create mode 100644 test/simple/test-zlib-from-multiple-huge-gzip.js diff --git a/lib/zlib.js b/lib/zlib.js index a44e69fe7af7c4..2acde58fd4053e 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -580,7 +580,7 @@ Zlib.prototype._processChunk = function(chunk, flushFlag, cb) { self._buffer = new Buffer(self._chunkSize); } - if (availOutAfter === 0) { + if (availOutAfter === 0 || availInAfter > 0) { // Not actually done. Need to reprocess. // Also, update the availInBefore to the availInAfter value, // so that if we have to hit it a third (fourth, etc.) time, @@ -588,6 +588,13 @@ Zlib.prototype._processChunk = function(chunk, flushFlag, cb) { inOff += (availInBefore - availInAfter); availInBefore = availInAfter; + if (availOutAfter !== 0) { + // There is still some data available for reading. + // This is usually a concatenated stream, so, reset and restart. + self.reset(); + self._offset = 0; + } + if (!async) return true; diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 4f0c938998afb0..95907dd03fdc37 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -63,6 +63,11 @@ enum node_zlib_mode { UNZIP }; +enum node_zlib_error { + NO_ERROR, + FAILED, + WRITE_PENDING +}; void InitZlib(v8::Handle target); @@ -207,7 +212,7 @@ class ZCtx : public AsyncWrap { if (!async) { // sync version Process(work_req); - if (CheckError(ctx)) + if (CheckError(ctx) == NO_ERROR) AfterSync(ctx, args); return; } @@ -292,7 +297,7 @@ class ZCtx : public AsyncWrap { } - static bool CheckError(ZCtx* ctx) { + static node_zlib_error CheckError(ZCtx* ctx) { // Acceptable error states depend on the type of zlib stream. switch (ctx->err_) { case Z_OK: @@ -305,14 +310,18 @@ class ZCtx : public AsyncWrap { ZCtx::Error(ctx, "Missing dictionary"); else ZCtx::Error(ctx, "Bad dictionary"); - return false; + return FAILED; default: // something else. - ZCtx::Error(ctx, "Zlib error"); - return false; + if (ctx->strm_.total_out == 0) { + ZCtx::Error(ctx, "Zlib error"); + return FAILED; + } else { + return WRITE_PENDING; + } } - return true; + return NO_ERROR; } @@ -326,7 +335,8 @@ class ZCtx : public AsyncWrap { HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); - if (!CheckError(ctx)) + node_zlib_error error = CheckError(ctx); + if (error == FAILED) return; Local avail_out = Integer::New(env->isolate(), @@ -340,6 +350,11 @@ class ZCtx : public AsyncWrap { Local args[2] = { avail_in, avail_out }; ctx->MakeCallback(env->callback_string(), ARRAY_SIZE(args), args); + if (error == WRITE_PENDING) { + ZCtx::Error(ctx, "Zlib error"); + return; + } + ctx->Unref(); if (ctx->pending_close_) ctx->Close(); @@ -557,10 +572,12 @@ class ZCtx : public AsyncWrap { switch (ctx->mode_) { case DEFLATE: case DEFLATERAW: + case GZIP: ctx->err_ = deflateReset(&ctx->strm_); break; case INFLATE: case INFLATERAW: + case GUNZIP: ctx->err_ = inflateReset(&ctx->strm_); break; default: diff --git a/test/simple/test-zlib-from-multiple-gzip-with-garbage.js b/test/simple/test-zlib-from-multiple-gzip-with-garbage.js new file mode 100644 index 00000000000000..f6a0185e0119d6 --- /dev/null +++ b/test/simple/test-zlib-from-multiple-gzip-with-garbage.js @@ -0,0 +1,83 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +// test unzipping a file that was created by concatenating multiple gzip +// streams. + +var common = require('../common'); +var assert = require('assert'); +var zlib = require('zlib'); + +var util = require('util'); + +var gzipBuffer = new Buffer(128); +var gzipOffset = 0; + +var stream1 = '123\n'; +var stream2 = '456\n'; +var stream3 = '789\n'; + +function gzipAppend(data) { + data.copy(gzipBuffer, gzipOffset); + gzipOffset += data.length; +} + +function writeGzipStream(text, cb) { + var gzip = zlib.createGzip(); + gzip.on('data', gzipAppend); + gzip.write(text, function() { + gzip.flush(function() { + gzip.end(function() { + cb(); + }); + }); + }); +} + +function writeGarbageStream(text, cb) { + gzipAppend(new Buffer(text)); + cb(); +} + +writeGzipStream(stream1, function() { + writeGzipStream(stream2, function() { + writeGarbageStream(stream3, function() { + var gunzip = zlib.createGunzip(); + var gunzippedData = new Buffer(2 * 1024); + var gunzippedOffset = 0; + gunzip.on('data', function (data) { + data.copy(gunzippedData, gunzippedOffset); + gunzippedOffset += data.length; + }); + gunzip.on('error', function() { + assert.equal(gunzippedData.toString('utf8', 0, gunzippedOffset), + stream1 + stream2); + }); + gunzip.on('end', function() { + assert.fail('end event not expected'); + }); + + gunzip.write(gzipBuffer.slice(0, gzipOffset), 'binary', function() { + gunzip.end(); + }); + }); + }); +}); diff --git a/test/simple/test-zlib-from-multiple-gzip.js b/test/simple/test-zlib-from-multiple-gzip.js new file mode 100644 index 00000000000000..6f4127a4d304c5 --- /dev/null +++ b/test/simple/test-zlib-from-multiple-gzip.js @@ -0,0 +1,74 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +// test unzipping a file that was created by concatenating multiple gzip +// streams. + +var common = require('../common'); +var assert = require('assert'); +var zlib = require('zlib'); + +var util = require('util'); + +var gzipBuffer = new Buffer(128); +var gzipOffset = 0; + +var stream1 = '123\n'; +var stream2 = '456\n'; +var stream3 = '789\n'; + +function gzipAppend(data) { + data.copy(gzipBuffer, gzipOffset); + gzipOffset += data.length; +} + +function writeGzipStream(text, cb) { + var gzip = zlib.createGzip(); + gzip.on('data', gzipAppend); + gzip.write(text, function() { + gzip.flush(function() { + gzip.end(function() { + cb(); + }); + }); + }); +} + +writeGzipStream(stream1, function() { + writeGzipStream(stream2, function() { + writeGzipStream(stream3, function() { + var gunzip = zlib.createGunzip(); + var gunzippedData = new Buffer(2 * 1024); + var gunzippedOffset = 0; + gunzip.on('data', function (data) { + data.copy(gunzippedData, gunzippedOffset); + gunzippedOffset += data.length; + }); + gunzip.on('end', function() { + assert.equal(gunzippedData.toString('utf8', 0, gunzippedOffset), stream1 + stream2 + stream3); + }); + + gunzip.write(gzipBuffer.slice(0, gzipOffset), 'binary', function() { + gunzip.end(); + }); + }); + }); +}); diff --git a/test/simple/test-zlib-from-multiple-huge-gzip.js b/test/simple/test-zlib-from-multiple-huge-gzip.js new file mode 100644 index 00000000000000..5533aafeb72f9a --- /dev/null +++ b/test/simple/test-zlib-from-multiple-huge-gzip.js @@ -0,0 +1,93 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +// test unzipping a file that was created by concatenating multiple gzip +// streams. + +var common = require('../common'); +var assert = require('assert'); +var zlib = require('zlib'); + +var util = require('util'); + +var HUGE = 64 * 1024; + +var originalBuffer = new Buffer(3 * HUGE); +var originalOffset = 0; + +var gzipBuffer = new Buffer(3 * HUGE); +var gzipOffset = 0; + +function getRandomLetter() { + return (Math.random() * (122 - 97)) + 97; +} + +function generateHugeStream() { + var buffer = new Buffer(HUGE); + for (var i = 0; i < HUGE; i++) + buffer.writeUInt8(getRandomLetter(), i); + + buffer.copy(originalBuffer, originalOffset); + originalOffset += HUGE; + + return buffer; +} + +function gzipAppend(data) { + data.copy(gzipBuffer, gzipOffset); + gzipOffset += data.length; +} + +function writeGzipStream(text, cb) { + var gzip = zlib.createGzip(); + gzip.on('data', gzipAppend); + gzip.write(text, function() { + gzip.flush(function() { + gzip.end(function() { + cb(); + }); + }); + }); +} + +writeGzipStream(generateHugeStream(), function() { + writeGzipStream(generateHugeStream(), function() { + writeGzipStream(generateHugeStream(), function() { + var gunzip = zlib.createGunzip(); + var gunzippedData = new Buffer(3 * HUGE); + var gunzippedOffset = 0; + gunzip.on('data', function (data) { + data.copy(gunzippedData, gunzippedOffset); + gunzippedOffset += data.length; + }); + gunzip.on('end', function() { + var gunzippedStr = gunzippedData.toString('utf8', 0, gunzippedOffset); + var originalStr = originalBuffer.toString('utf8', 0, 3 * HUGE); + + assert.equal(gunzippedStr, originalStr); + }); + + gunzip.write(gzipBuffer.slice(0, gzipOffset), 'binary', function() { + gunzip.end(); + }); + }); + }); +}); From e93ff4f0ce1b6e9077dfa64598006478276325b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 4 Nov 2013 15:59:25 +0100 Subject: [PATCH 08/22] debugger: fix unhandled error in setBreakpoint Fix Interface.setBreakpoint() to correctly handle an attempt to set a breakpoint in the current script when there is no current script. This usually happens when the debugged process is not paused. Fixes: https://github.com/joyent/node/issues/6453 PR-URL: https://github.com/joyent/node/pull/6460 Reviewed-By: Chris Dickinson --- lib/_debugger.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/_debugger.js b/lib/_debugger.js index 41d3fc42101a77..b8a3177d687775 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -1360,6 +1360,12 @@ Interface.prototype.setBreakpoint = function(script, line, script = this.client.currentScript; } + if (script === undefined) { + this.print('Cannot determine the current script, ' + + 'make sure the debugged process is paused.'); + return; + } + if (/\(\)$/.test(script)) { // setBreakpoint('functionname()'); var req = { From 93533e98f76c2c9e577af3352b4eb709791f4d1e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 11 Nov 2014 12:06:55 +0100 Subject: [PATCH 09/22] src: fix windows build error Fix a Windows-only build error that was introduced in commit 1183ba4 ("zlib: support concatenated gzip files"). Rename the NO_ERROR and FAILED enumerations, they conflict with macros of the same name in . PR-URL: https://github.com/joyent/node/pull/8893 Reviewed-By: Fedor Indutny Reviewed-By: Rod Vagg Reviewed-by: Timothy J Fontaine --- src/node_zlib.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 95907dd03fdc37..b930d1d8c3c5a9 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -64,9 +64,9 @@ enum node_zlib_mode { }; enum node_zlib_error { - NO_ERROR, - FAILED, - WRITE_PENDING + kNoError, + kFailed, + kWritePending }; void InitZlib(v8::Handle target); @@ -212,7 +212,7 @@ class ZCtx : public AsyncWrap { if (!async) { // sync version Process(work_req); - if (CheckError(ctx) == NO_ERROR) + if (CheckError(ctx) == kNoError) AfterSync(ctx, args); return; } @@ -310,18 +310,18 @@ class ZCtx : public AsyncWrap { ZCtx::Error(ctx, "Missing dictionary"); else ZCtx::Error(ctx, "Bad dictionary"); - return FAILED; + return kFailed; default: // something else. if (ctx->strm_.total_out == 0) { ZCtx::Error(ctx, "Zlib error"); - return FAILED; + return kFailed; } else { - return WRITE_PENDING; + return kWritePending; } } - return NO_ERROR; + return kNoError; } @@ -336,7 +336,7 @@ class ZCtx : public AsyncWrap { Context::Scope context_scope(env->context()); node_zlib_error error = CheckError(ctx); - if (error == FAILED) + if (error == kFailed) return; Local avail_out = Integer::New(env->isolate(), @@ -350,7 +350,7 @@ class ZCtx : public AsyncWrap { Local args[2] = { avail_in, avail_out }; ctx->MakeCallback(env->callback_string(), ARRAY_SIZE(args), args); - if (error == WRITE_PENDING) { + if (error == kWritePending) { ZCtx::Error(ctx, "Zlib error"); return; } From 91586661c983f45d650644451df73c8649a8d459 Mon Sep 17 00:00:00 2001 From: Chris Dickinson Date: Thu, 4 Dec 2014 12:00:23 -0800 Subject: [PATCH 10/22] stream: switch _writableState.buffer to queue In cases where many small writes are made to a stream lacking _writev, the array data structure backing the WriteReq buffer would greatly increase GC pressure. Specifically, in the fs.WriteStream case, the clearBuffer routine would only clear a single WriteReq from the buffer before exiting, but would cause the entire backing array to be GC'd. Switching to [].shift lessened pressure, but still the bulk of the time was spent in memcpy. This replaces that structure with a linked list-backed queue so that adding and removing from the queue is O(1). In the _writev case, collecting the buffer requires an O(N) loop over the buffer, but that was already being performed to collect callbacks, so slowdown should be neglible. PR-URL: https://github.com/joyent/node/pull/8826 Reviewed-by: Timothy J Fontaine Reviewed-by: Trevor Norris --- lib/_stream_writable.js | 68 +++++++++++++++++++-------- lib/net.js | 2 +- test/simple/test-stream2-transform.js | 2 +- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 92984eb08eb24b..39eee61460fe61 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -28,6 +28,7 @@ Writable.WritableState = WritableState; var util = require('util'); var Stream = require('stream'); +var debug = util.debuglog('stream'); util.inherits(Writable, Stream); @@ -35,6 +36,7 @@ function WriteReq(chunk, encoding, cb) { this.chunk = chunk; this.encoding = encoding; this.callback = cb; + this.next = null; } function WritableState(options, stream) { @@ -109,7 +111,8 @@ function WritableState(options, stream) { // the amount that is being written when _write is called. this.writelen = 0; - this.buffer = []; + this.bufferedRequest = null; + this.lastBufferedRequest = null; // number of pending user-supplied write callbacks // this must be 0 before 'finish' can be emitted @@ -123,6 +126,23 @@ function WritableState(options, stream) { this.errorEmitted = false; } +WritableState.prototype.getBuffer = function writableStateGetBuffer() { + var current = this.bufferedRequest; + var out = []; + while (current) { + out.push(current); + current = current.next; + } + return out; +}; + +Object.defineProperty(WritableState.prototype, 'buffer', { + get: util.deprecate(function() { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use ' + + '_writableState.getBuffer() instead.') +}); + function Writable(options) { // Writable ctor is applied to Duplexes, though they're not // instanceof Writable, they're instanceof Readable. @@ -216,7 +236,7 @@ Writable.prototype.uncork = function() { !state.corked && !state.finished && !state.bufferProcessing && - state.buffer.length) + state.bufferedRequest) clearBuffer(this, state); } }; @@ -255,8 +275,15 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) { if (!ret) state.needDrain = true; - if (state.writing || state.corked) - state.buffer.push(new WriteReq(chunk, encoding, cb)); + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = new WriteReq(chunk, encoding, cb); + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; + } + } else doWrite(stream, state, false, len, chunk, encoding, cb); @@ -313,7 +340,7 @@ function onwrite(stream, er) { if (!finished && !state.corked && !state.bufferProcessing && - state.buffer.length) { + state.bufferedRequest) { clearBuffer(stream, state); } @@ -349,17 +376,23 @@ function onwriteDrain(stream, state) { // if there's something in the buffer waiting, then process it function clearBuffer(stream, state) { state.bufferProcessing = true; + var entry = state.bufferedRequest; - if (stream._writev && state.buffer.length > 1) { + if (stream._writev && entry && entry.next) { // Fast case, write everything using _writev() + var buffer = []; var cbs = []; - for (var c = 0; c < state.buffer.length; c++) - cbs.push(state.buffer[c].callback); + while (entry) { + cbs.push(entry.callback); + buffer.push(entry); + entry = entry.next; + } // count the one we are adding, as well. // TODO(isaacs) clean this up state.pendingcb++; - doWrite(stream, state, true, state.length, state.buffer, '', function(err) { + state.lastBufferedRequest = null; + doWrite(stream, state, true, state.length, buffer, '', function(err) { for (var i = 0; i < cbs.length; i++) { state.pendingcb--; cbs[i](err); @@ -367,34 +400,29 @@ function clearBuffer(stream, state) { }); // Clear buffer - state.buffer = []; } else { // Slow case, write chunks one-by-one - for (var c = 0; c < state.buffer.length; c++) { - var entry = state.buffer[c]; + while (entry) { var chunk = entry.chunk; var encoding = entry.encoding; var cb = entry.callback; var len = state.objectMode ? 1 : chunk.length; doWrite(stream, state, false, len, chunk, encoding, cb); - + entry = entry.next; // if we didn't call the onwrite immediately, then // it means that we need to wait until it does. // also, that means that the chunk and cb are currently // being processed, so move the buffer counter past them. if (state.writing) { - c++; break; } } - if (c < state.buffer.length) - state.buffer = state.buffer.slice(c); - else - state.buffer.length = 0; + if (entry === null) + state.lastBufferedRequest = null; } - + state.bufferedRequest = entry; state.bufferProcessing = false; } @@ -435,7 +463,7 @@ Writable.prototype.end = function(chunk, encoding, cb) { function needFinish(stream, state) { return (state.ending && state.length === 0 && - state.buffer.length === 0 && + state.bufferedRequest === null && !state.finished && !state.writing); } diff --git a/lib/net.js b/lib/net.js index fac78f8c04dcbc..f0075b5a33e5b4 100644 --- a/lib/net.js +++ b/lib/net.js @@ -732,7 +732,7 @@ Socket.prototype.__defineGetter__('bytesWritten', function() { data = this._pendingData, encoding = this._pendingEncoding; - state.buffer.forEach(function(el) { + state.getBuffer().forEach(function(el) { if (util.isBuffer(el.chunk)) bytes += el.chunk.length; else diff --git a/test/simple/test-stream2-transform.js b/test/simple/test-stream2-transform.js index 9c9ddd8efc3141..6064565be0a124 100644 --- a/test/simple/test-stream2-transform.js +++ b/test/simple/test-stream2-transform.js @@ -81,7 +81,7 @@ test('writable side consumption', function(t) { t.equal(tx._readableState.length, 10); t.equal(transformed, 10); t.equal(tx._transformState.writechunk.length, 5); - t.same(tx._writableState.buffer.map(function(c) { + t.same(tx._writableState.getBuffer().map(function(c) { return c.chunk.length; }), [6, 7, 8, 9, 10]); From 890baa03a86de0bf8eb415126b4400195ad61750 Mon Sep 17 00:00:00 2001 From: Jackson Tian Date: Wed, 10 Dec 2014 11:20:11 +0800 Subject: [PATCH 11/22] doc: add details for http res/req end callback Add documentation for the callback parameter of http.ClientRequest's and http.ServerResponse's end methods. Signed-off-by: Julien Gilli --- doc/api/http.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index c639bdfd5d9794..3d482b441c80d3 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -444,6 +444,8 @@ response. If `data` is specified, it is equivalent to calling `response.write(data, encoding)` followed by `response.end(callback)`. +If `callback` is specified, it will be called when the response stream +is finished. ## http.request(options[, callback]) @@ -890,6 +892,9 @@ chunked, this will send the terminating `'0\r\n\r\n'`. If `data` is specified, it is equivalent to calling `request.write(data, encoding)` followed by `request.end(callback)`. +If `callback` is specified, it will be called when the request stream +is finished. + ### request.abort() Aborts a request. (New since v0.3.8.) From 6a03fce16eaa4ec1085463d94734d40b370f3ea4 Mon Sep 17 00:00:00 2001 From: CGavrila Date: Tue, 28 Oct 2014 12:08:37 +0000 Subject: [PATCH 12/22] url: improve parsing speed The url.parse() function now checks whether an escapable character is in the URL before trying to escape it. PR-URL: https://github.com/joyent/node/pull/8638 [trev.norris@gmail.com: Switch to use continue instead of if] Signed-off-by: Trevor Norris --- lib/url.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/url.js b/lib/url.js index 0302fda1427181..ac82d2511798ad 100644 --- a/lib/url.js +++ b/lib/url.js @@ -318,6 +318,8 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { // need to be. for (var i = 0, l = autoEscape.length; i < l; i++) { var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) + continue; var esc = encodeURIComponent(ae); if (esc === ae) { esc = escape(ae); From d8586eab7e62304f6087fd1b531aa525a5f14c2c Mon Sep 17 00:00:00 2001 From: Aleksey Smolenchuk Date: Tue, 30 Dec 2014 14:25:52 -0800 Subject: [PATCH 13/22] lib: introduce process module This makes require('process') always return a reference to the global process object. PR-URL: https://github.com/iojs/io.js/pull/206 Reviewed-By: Ben Noordhuis --- lib/process.js | 25 +++++++++++++++++++++++++ node.gyp | 1 + test/parallel/test-require-process.js | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 lib/process.js create mode 100644 test/parallel/test-require-process.js diff --git a/lib/process.js b/lib/process.js new file mode 100644 index 00000000000000..288e313726fcb9 --- /dev/null +++ b/lib/process.js @@ -0,0 +1,25 @@ +// Copyright io.js contributors +// +// 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. + +'use strict'; + +// Re-export process as a native module +module.exports = process; diff --git a/node.gyp b/node.gyp index be266825bf7293..5b97d580d53767 100644 --- a/node.gyp +++ b/node.gyp @@ -43,6 +43,7 @@ 'lib/net.js', 'lib/os.js', 'lib/path.js', + 'lib/process.js', 'lib/punycode.js', 'lib/querystring.js', 'lib/readline.js', diff --git a/test/parallel/test-require-process.js b/test/parallel/test-require-process.js new file mode 100644 index 00000000000000..2820c22eea92ec --- /dev/null +++ b/test/parallel/test-require-process.js @@ -0,0 +1,26 @@ +// Copyright io.js contributors +// +// 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. + +var assert = require('assert'); + +var nativeProcess = require('process'); +assert.strictEqual(nativeProcess, process, + 'require("process") should return a reference to global process'); From 8b041613420f27bc26f60287386efbdf69e4b8b1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 21 Dec 2014 02:06:19 +0100 Subject: [PATCH 14/22] doc: util: document --trace-deprecation Document the --trace-deprecation flag and the `process` properties that affect util.deprecate(). Fixes: https://github.com/iojs/io.js/issues/190 PR-URL: https://github.com/iojs/io.js/pull/191 Reviewed-By: Jonathan Ong --- doc/api/util.markdown | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/api/util.markdown b/doc/api/util.markdown index cc639ddb49434b..416606267d9ae2 100644 --- a/doc/api/util.markdown +++ b/doc/api/util.markdown @@ -267,10 +267,21 @@ Marks that a method should not be used any more. } }, 'util.puts: Use console.log instead') -It returns a modified function which warns once by default. If -`--no-deprecation` is set then this function is a NO-OP. If -`--throw-deprecation` is set then the application will throw an exception -if the deprecated API is used. +It returns a modified function which warns once by default. + +If `--no-deprecation` is set then this function is a NO-OP. Configurable +at run-time through the `process.noDeprecation` boolean (only effective +when set before a module is loaded.) + +If `--trace-deprecation` is set, a warning and a stack trace are logged +to the console the first time the deprecated API is used. Configurable +at run-time through the `process.traceDeprecation` boolean. + +If `--throw-deprecation` is set then the application throws an exception +when the deprecated API is used. Configurable at run-time through the +`process.throwDeprecation` boolean. + +`process.throwDeprecation` takes precedence over `process.traceDeprecation`. ## util.debug(string) From d5c7a9737a787c3605bb6996653a36a988742e15 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 18 Dec 2014 06:48:49 +1000 Subject: [PATCH 15/22] doc: added TC meeting minutes 2014-12-17 Closes #163 PR-URL: https://github.com/iojs/io.js/pull/178 Reviewed-By: Ben Noordhuis Reviewed-By: Bert Belder --- doc/tc-meetings/2014-12-17.md | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 doc/tc-meetings/2014-12-17.md diff --git a/doc/tc-meetings/2014-12-17.md b/doc/tc-meetings/2014-12-17.md new file mode 100644 index 00000000000000..4208f99c619299 --- /dev/null +++ b/doc/tc-meetings/2014-12-17.md @@ -0,0 +1,91 @@ +# io.js TC Meeting 2014-12-17 + +## Links + +* **Google Hangouts Video**: https://www.youtube.com/watch?v=7s-VJLQEWXg +* **GitHub Issue**: https://github.com/iojs/io.js/issues/163 +* **Original Minutes Google Doc**: https://docs.google.com/document/d/1PoqGfxpfTFKv5GcKmhMM2siZpPjT9Ba-ooBi-ZbYNi0 + +## Agenda + +Extracted from https://github.com/iojs/io.js/labels/tc-agenda prior to meeting. + +* Bundle tick processor with iojs #158 https://github.com/iojs/io.js/issues/158 +* Release Cycle Proposal #168 https://github.com/iojs/io.js/issues/168 +* Module search security #176 https://github.com/iojs/io.js/pull/176 +* Dealing with feature requests + +## Review of last meeting + +* Move readable-stream to io.js and flip authoritative flow of code, docs and issues +* Soft deprecation of domains, accept PR #15 as last feature addition +* Caine, discussion continued on GitHub +* Project name is “io.js”, binary name is “iojs” +* Extending options from prototype, discussion continued on GitHub +* Promises statement for issue #11 +* Working with nvm, etc. + +## Minutes + +### Present + +* Bert (TC) +* Chris (TC) +* Trevor (TC) +* Isaac (TC) +* Rod (build, facilitator) + +### Bundle tick processor with iojs #158 + +https://github.com/iojs/io.js/issues/158 + +* Bert: important because it’s tied to the version of V8, not practical to put it in npm because one is needed for each version +* Isaac: this is minimal and shouldn’t set a standard for just adding more stuff to core (i.e. keep core minimal), so +1 + ++1 from Isaac, +1 from Bert, **no disagreement amongst group, consensus has been reached on bundling a tick processor with releases.** + +### Release Cycle Proposal #168 + +https://github.com/iojs/io.js/issues/168 + +* Bert & Isaac discussed how this feeds into the ability to have frequent releases. Discussed semver plays into this. +* Rod: consensus seems to be around having stability, predictability, lead-time but more frequent releases. +* **Bert: Move discussion to #168. Still premature to discuss here.** + +### Module search security #176 + +https://github.com/iojs/io.js/pull/176 + +* Limiting node_modules search path to $HOME as a top-level +* Isaac ~ -1 on this because EACCES already happens when you don’t have permission +* Isaac and Bert bikeshedded Windows C:\ writability and security on Windows. i.e. if someone can install code on a shared system above where a node application is running (e.g. C:\) then you could have untrusted code run by your application. +* Isaac: this PR is only addressing projects running in the home directory. +* Rod: module system is locked-down, TC needs to come to consensus that this is a _security_ issue and therefore warrants breaking it. +* Chris: `useradd node_modules` is a situation this could be a problem +* Isaac: not convinced this is a security problem, even the `useradd` situation requires root access on a system. +* Bert: this is an academic issue, it may _feel_ wrong but that doesn’t mean it’s strictly a security issue. +* Isaac: proposed the issue be closed as not a security issue. +* **No consensus that this is a security issue. Move discussion back to GitHub, potentially close issue, potentially bringing discussion back here. Encourage users to bring examples of real problems.** + + +### Dealing with feature requests + +* Bert: asking for discussion about what to do with feature requests that come up but aren’t clearly something that are wanted. +* Bert: should we put a time limit on feature requests? Would like some guidelines for how to deal with these. +* Chris: have already been putting a 4-6 day window before closing them. If there is no code then it’s easier to close. If there is code then there could be more discussion. +* Isaac: this is a broader problem about the roadmap-setting process. +* Rod & Isaac: It’s up to someone on TC (or elsewhere) to start coming up with a roadmap, or at least start the discussion. +* **Agreed to start a GitHub discussion on roadmap and soliciting feedback from the community.** +* Rod: in an open model, it’s up to TC and those with commit access to take the initiative to just close things, given enough warning and chance for discussion and better arguments. +* Isaac: builtins (like Blog of FileReader) are TC39 / WhatWG groups out there that are doing this at the language & V8 level and we pull from there. It should be straightforward to close those issues. +* Bert: the roadmap shouldn’t be about locking down the dev process and tightly limiting scope of what’s added. +* **Agreed that feedback to all contributors (including TC), regarding closing issues: close issues that are instinctively bad and worth closing (close can be undone), anything potentially controversial can be flagged with a “will close” but give ~ 1 week for discussion, disagreement, lobbying etc.** + + +### Logos + +* **Agreed that the release is the only _technical_ blocker from the TC’s perspective to a logo, so deferring discussion till then. Encourage interested parties from discussing this further on GitHub issue #37.** + +### Next meeting + +* Bert proposed 2014-12-30 as next meeting time From a30839576c65b88e93bc915ae97b59874afde8ac Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Wed, 12 Nov 2014 17:13:14 -0800 Subject: [PATCH 16/22] build: i18n: add icu config options Make "--with-intl=none" the default and add "intl-none" option to vcbuild.bat. If icu data is missing print a warning unless either --download=all or --download=icu is set. If set then automatically download, verify (MD5) and unpack the ICU data if not already available. There's a "list" of URLs being used, but right now only the first is picked up. The logic works something like this: * If there is no directory deps/icu, * If no zip file (currently icu4c-54_1-src.zip), * Download zip file (icu-project.org -> sf.net) * Verify the MD5 sum of the zipfile * If bad, print error and exit * Unpack the zipfile into deps/icu * If deps/icu now exists, use it, else fail with help text Add the configuration option "--with-icu-source=..." Usage: * --with-icu-source=/path/to/my/other/icu * --with-icu-source=/path/to/icu54.zip * --with-icu-source=/path/to/icu54.tgz * --with-icu-source=http://example.com/icu54.tar.bz2 Add the configuration option "--with-icu-locals=...". Allows choosing which locales are used in the "small-icu" case. Example: configure --with-intl=small-icu --with-icu-locales=tlh,grc,nl (Also note that as of this writing, neither Klingon nor Ancient Greek are in upstream CLDR data. Serving suggestion only.) Don't use hard coded ../../out paths on windows. This was suggested by @misterdjules as it causes test failures. With this fix, "out" is no longer created on windows and the following can run properly: python tools/test.py simple Reduce space by about 1MB with ICU 54 (over without this patch). Also trims a few other source files, but only conditional on the exact ICU version used. This is to future-proof - a file that is unneeded now may be needed in future ICUs. Also: * Update distclean to remove icu related files * Refactor some code into tools/configure.d/nodedownload.py * Update docs * Add test PR-URL: https://github.com/joyent/node/pull/8719 Fixes: https://github.com/joyent/node/issues/7676#issuecomment-64704230 [trev.norris@gmail.com small change to test's whitespace and logic] Signed-off-by: Trevor Norris --- .gitignore | 3 + Makefile | 4 +- README.md | 91 ++++++++++++++-- configure | 137 +++++++++++++++++++++-- test/simple/test-intl.js | 103 ++++++++++++++++++ tools/configure.d/nodedownload.py | 127 ++++++++++++++++++++++ tools/icu/icu-generic.gyp | 174 ++++++++++++++++++++++++------ tools/icu/icu_small.json | 15 +-- tools/icu/icutrim.py | 13 +++ vcbuild.bat | 8 +- 10 files changed, 616 insertions(+), 59 deletions(-) create mode 100644 test/simple/test-intl.js create mode 100644 tools/configure.d/nodedownload.py diff --git a/.gitignore b/.gitignore index 6581dee9d1f8db..9dda73b2e4d520 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,9 @@ ipch/ email.md deps/v8-* deps/icu +deps/icu*.zip +deps/icu*.tgz +deps/icu-tmp ./node_modules .svn/ diff --git a/Makefile b/Makefile index f84c2134499944..e463280ac4efad 100644 --- a/Makefile +++ b/Makefile @@ -78,10 +78,12 @@ clean: distclean: -rm -rf out - -rm -f config.gypi + -rm -f config.gypi icu_config.gypi -rm -f config.mk -rm -rf node node_g blog.html email.md -rm -rf node_modules + -rm -rf deps/icu + -rm -rf deps/icu4c*.tgz deps/icu4c*.zip deps/icu-tmp test: all $(PYTHON) tools/test.py --mode=release simple message diff --git a/README.md b/README.md index 0032c63c0730c9..acaf24b372cb30 100644 --- a/README.md +++ b/README.md @@ -83,31 +83,104 @@ make doc man doc/node.1 ``` -### To build `Intl` (ECMA-402) support: +### `Intl` (ECMA-402) support: -*Note:* more docs, including how to reduce disk footprint, are on +[Intl](https://github.com/joyent/node/wiki/Intl) support is not +enabled by default. + +#### "small" (English only) support + +This option will build with "small" (English only) support, but +the full `Intl` (ECMA-402) APIs. With `--download=all` it will +download the ICU library as needed. + +Unix/Macintosh: + +```sh +./configure --with-intl=small-icu --download=all +``` + +Windows: + +```sh +vcbuild small-icu download-all +``` + +The `small-icu` mode builds +with English-only data. You can add full data at runtime. + +*Note:* more docs are on [the wiki](https://github.com/joyent/node/wiki/Intl). -#### Use existing installed ICU (Unix/Macintosh only): +#### Build with full ICU support (all locales supported by ICU): + +With the `--download=all`, this may download ICU if you don't +have an ICU in `deps/icu`. + +Unix/Macintosh: ```sh -pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu +./configure --with-intl=full-icu --download=all ``` -#### Build ICU from source: +Windows: -First: Unpack latest ICU - [icu4c-**##.#**-src.tgz](http://icu-project.org/download) (or `.zip`) - as `deps/icu` (You'll have: `deps/icu/source/...`) +```sh +vcbuild full-icu download-all +``` + +#### Build with no Intl support `:-(` + +The `Intl` object will not be available. +This is the default at present, so this option is not normally needed. Unix/Macintosh: ```sh -./configure --with-intl=full-icu +./configure --with-intl=none ``` Windows: +```sh +vcbuild intl-none +``` + +#### Use existing installed ICU (Unix/Macintosh only): + +```sh +pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu +``` + +#### Build with a specific ICU: + +You can find other ICU releases at +[the ICU homepage](http://icu-project.org/download). +Download the file named something like `icu4c-**##.#**-src.tgz` (or +`.zip`). + +Unix/Macintosh: from an already-unpacked ICU + +```sh +./configure --with-intl=[small-icu,full-icu] --with-icu-source=/path/to/icu +``` + +Unix/Macintosh: from a local ICU tarball + +```sh +./configure --with-intl=[small-icu,full-icu] --with-icu-source=/path/to/icu.tgz +``` + +Unix/Macintosh: from a tarball URL + +```sh +./configure --with-intl=full-icu --with-icu-source=http://url/to/icu.tgz +``` + +Windows: first unpack latest ICU to `deps/icu` + [icu4c-**##.#**-src.tgz](http://icu-project.org/download) (or `.zip`) + as `deps/icu` (You'll have: `deps/icu/source/...`) + ```sh vcbuild full-icu ``` diff --git a/configure b/configure index c558f7f8dd797d..51475f03575f6b 100755 --- a/configure +++ b/configure @@ -6,6 +6,8 @@ import re import shlex import subprocess import sys +import shutil +import string CC = os.environ.get('CC', 'cc') @@ -13,6 +15,10 @@ root_dir = os.path.dirname(__file__) sys.path.insert(0, os.path.join(root_dir, 'tools', 'gyp', 'pylib')) from gyp.common import GetFlavor +# imports in tools/configure.d +sys.path.insert(0, os.path.join(root_dir, 'tools', 'configure.d')) +import nodedownload + # parse our options parser = optparse.OptionParser() @@ -236,16 +242,31 @@ parser.add_option('--with-etw', dest='with_etw', help='build with ETW (default is true on Windows)') +parser.add_option('--download', + action='store', + dest='download_list', + help=nodedownload.help()) + parser.add_option('--with-icu-path', action='store', dest='with_icu_path', help='Path to icu.gyp (ICU i18n, Chromium version only.)') +parser.add_option('--with-icu-locales', + action='store', + dest='with_icu_locales', + help='Comma-separated list of locales for "small-icu". Default: "root,en". "root" is assumed.') + parser.add_option('--with-intl', action='store', dest='with_intl', help='Intl mode: none, full-icu, small-icu (default is none)') +parser.add_option('--with-icu-source', + action='store', + dest='with_icu_source', + help='Intl mode: optional local path to icu/ dir, or path/URL of icu source archive.') + parser.add_option('--with-perfctr', action='store_true', dest='with_perfctr', @@ -294,6 +315,8 @@ parser.add_option('--xcode', (options, args) = parser.parse_args() +# set up auto-download list +auto_downloads = nodedownload.parse(options.download_list) def b(value): """Returns the string 'true' if value is truthy, 'false' otherwise.""" @@ -712,6 +735,35 @@ def glob_to_var(dir_base, dir_sub): return list def configure_intl(o): + icus = [ + { + 'url': 'http://download.icu-project.org/files/icu4c/54.1/icu4c-54_1-src.zip', + # from https://ssl.icu-project.org/files/icu4c/54.1/icu4c-src-54_1.md5: + 'md5': '6b89d60e2f0e140898ae4d7f72323bca', + }, + ] + def icu_download(path): + # download ICU, if needed + for icu in icus: + url = icu['url'] + md5 = icu['md5'] + local = url.split('/')[-1] + targetfile = os.path.join(root_dir, 'deps', local) + if not os.path.isfile(targetfile): + if nodedownload.candownload(auto_downloads, "icu"): + nodedownload.retrievefile(url, targetfile) + else: + print ' Re-using existing %s' % targetfile + if os.path.isfile(targetfile): + sys.stdout.write(' Checking file integrity with MD5:\r') + gotmd5 = nodedownload.md5sum(targetfile) + print ' MD5: %s %s' % (gotmd5, targetfile) + if (md5 == gotmd5): + return targetfile + else: + print ' Expected: %s *MISMATCH*' % md5 + print '\n ** Corrupted ZIP? Delete %s to retry download.\n' % targetfile + return None icu_config = { 'variables': {} } @@ -723,11 +775,11 @@ def configure_intl(o): write(icu_config_name, do_not_edit + pprint.pformat(icu_config, indent=2) + '\n') - # small ICU is off by default. # always set icu_small, node.gyp depends on it being defined. o['variables']['icu_small'] = b(False) with_intl = options.with_intl + with_icu_source = options.with_icu_source have_icu_path = bool(options.with_icu_path) if have_icu_path and with_intl: print 'Error: Cannot specify both --with-icu-path and --with-intl' @@ -739,6 +791,13 @@ def configure_intl(o): o['variables']['icu_gyp_path'] = options.with_icu_path return # --with-intl= + # set the default + if with_intl is None: + with_intl = 'none' # The default mode of Intl + # sanity check localelist + if options.with_icu_locales and (with_intl != 'small-icu'): + print 'Error: --with-icu-locales only makes sense with --with-intl=small-icu' + sys.exit(1) if with_intl == 'none' or with_intl is None: o['variables']['v8_enable_i18n_support'] = 0 return # no Intl @@ -746,6 +805,12 @@ def configure_intl(o): # small ICU (English only) o['variables']['v8_enable_i18n_support'] = 1 o['variables']['icu_small'] = b(True) + with_icu_locales = options.with_icu_locales + if not with_icu_locales: + with_icu_locales = 'root,en' + locs = set(with_icu_locales.split(',')) + locs.add('root') # must have root + o['variables']['icu_locales'] = string.join(locs,',') elif with_intl == 'full-icu': # full ICU o['variables']['v8_enable_i18n_support'] = 1 @@ -769,20 +834,78 @@ def configure_intl(o): # Note: non-ICU implementations could use other 'with_intl' # values. + # this is just the 'deps' dir. Used for unpacking. + icu_parent_path = os.path.join(root_dir, 'deps') + + # The full path to the ICU source directory. + icu_full_path = os.path.join(icu_parent_path, 'icu') + + # icu-tmp is used to download and unpack the ICU tarball. + icu_tmp_path = os.path.join(icu_parent_path, 'icu-tmp') + + # --with-icu-source processing + # first, check that they didn't pass --with-icu-source=deps/icu + if with_icu_source and os.path.abspath(icu_full_path) == os.path.abspath(with_icu_source): + print 'Ignoring redundant --with-icu-source=%s' % (with_icu_source) + with_icu_source = None + # if with_icu_source is still set, try to use it. + if with_icu_source: + if os.path.isdir(icu_full_path): + print 'Deleting old ICU source: %s' % (icu_full_path) + shutil.rmtree(icu_full_path) + # now, what path was given? + if os.path.isdir(with_icu_source): + # it's a path. Copy it. + print '%s -> %s' % (with_icu_source, icu_full_path) + shutil.copytree(with_icu_source, icu_full_path) + else: + # could be file or URL. + # Set up temporary area + if os.path.isdir(icu_tmp_path): + shutil.rmtree(icu_tmp_path) + os.mkdir(icu_tmp_path) + icu_tarball = None + if os.path.isfile(with_icu_source): + # it's a file. Try to unpack it. + icu_tarball = with_icu_source + else: + # Can we download it? + local = os.path.join(icu_tmp_path, with_icu_source.split('/')[-1]) # local part + icu_tarball = nodedownload.retrievefile(with_icu_source, local) + # continue with "icu_tarball" + nodedownload.unpack(icu_tarball, icu_tmp_path) + # Did it unpack correctly? Should contain 'icu' + tmp_icu = os.path.join(icu_tmp_path, 'icu') + if os.path.isdir(tmp_icu): + os.rename(tmp_icu, icu_full_path) + shutil.rmtree(icu_tmp_path) + else: + print ' Error: --with-icu-source=%s did not result in an "icu" dir.' % with_icu_source + shutil.rmtree(icu_tmp_path) + sys.exit(1) + # ICU mode. (icu-generic.gyp) byteorder = sys.byteorder o['variables']['icu_gyp_path'] = 'tools/icu/icu-generic.gyp' # ICU source dir relative to root - icu_full_path = os.path.join(root_dir, 'deps/icu') o['variables']['icu_path'] = icu_full_path if not os.path.isdir(icu_full_path): - print 'Error: ICU path is not a directory: %s' % (icu_full_path) + print '* ECMA-402 (Intl) support didn\'t find ICU in %s..' % (icu_full_path) + # can we download (or find) a zipfile? + localzip = icu_download(icu_full_path) + if localzip: + nodedownload.unpack(localzip, icu_parent_path) + if not os.path.isdir(icu_full_path): + print ' Cannot build Intl without ICU in %s.' % (icu_full_path) + print ' (Fix, or disable with "--with-intl=none" )' sys.exit(1) + else: + print '* Using ICU in %s' % (icu_full_path) # Now, what version of ICU is it? We just need the "major", such as 54. # uvernum.h contains it as a #define. uvernum_h = os.path.join(icu_full_path, 'source/common/unicode/uvernum.h') if not os.path.isfile(uvernum_h): - print 'Error: could not load %s - is ICU installed?' % uvernum_h + print ' Error: could not load %s - is ICU installed?' % uvernum_h sys.exit(1) icu_ver_major = None matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*' @@ -792,7 +915,7 @@ def configure_intl(o): if m: icu_ver_major = m.group(1) if not icu_ver_major: - print 'Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h + print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h sys.exit(1) icu_endianness = sys.byteorder[0]; # TODO(srl295): EBCDIC should be 'e' o['variables']['icu_ver_major'] = icu_ver_major @@ -819,8 +942,8 @@ def configure_intl(o): # this is the icudt*.dat file which node will be using (platform endianness) o['variables']['icu_data_file'] = icu_data_file if not os.path.isfile(icu_data_path): - print 'Error: ICU prebuilt data file %s does not exist.' % icu_data_path - print 'See the README.md.' + print ' Error: ICU prebuilt data file %s does not exist.' % icu_data_path + print ' See the README.md.' # .. and we're not about to build it from .gyp! sys.exit(1) # map from variable name to subdirs diff --git a/test/simple/test-intl.js b/test/simple/test-intl.js new file mode 100644 index 00000000000000..841239a8d94ced --- /dev/null +++ b/test/simple/test-intl.js @@ -0,0 +1,103 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +var common = require('../common'); +var assert = require('assert'); + +// does node think that i18n was enabled? +var enablei18n = process.config.variables.v8_enable_i18n_support; +if (enablei18n === undefined) { + enablei18n = false; +} + +// is the Intl object present? +var haveIntl = (global.Intl != undefined); + +// Returns true if no specific locale ids were configured (i.e. "all") +// Else, returns true if loc is in the configured list +// Else, returns false +function haveLocale(loc) { + var locs = process.config.variables.icu_locales.split(','); + return locs.indexOf(loc) !== -1; +} + +if (!haveIntl) { + var erMsg = + '"Intl" object is NOT present but v8_enable_i18n_support is ' + + enablei18n; + assert.equal(enablei18n, false, erMsg); + console.log('Skipping Intl tests because Intl object not present.'); + +} else { + var erMsg = + '"Intl" object is present but v8_enable_i18n_support is ' + + enablei18n + + '. Is this test out of date?'; + assert.equal(enablei18n, true, erMsg); + + // Construct a new date at the beginning of Unix time + var date0 = new Date(0); + + // Use the GMT time zone + var GMT = 'Etc/GMT'; + + // Construct an English formatter. Should format to "Jan 70" + var dtf = + new Intl.DateTimeFormat(['en'], + {timeZone: GMT, month: 'short', year: '2-digit'}); + + // If list is specified and doesn't contain 'en' then return. + if (process.config.variables.icu_locales && !haveLocale('en')) { + console.log('Skipping detailed Intl tests because English is not listed ' + + 'as supported.'); + // Smoke test. Does it format anything, or fail? + console.log('Date(0) formatted to: ' + dtf.format(date0)); + return; + } + + // Check with toLocaleString + var localeString = dtf.format(date0); + assert.equal(localeString, 'Jan 70'); + + // Options to request GMT + var optsGMT = {timeZone: GMT}; + + // Test format + localeString = date0.toLocaleString(['en'], optsGMT); + assert.equal(localeString, '1/1/1970, 12:00:00 AM'); + + // number format + assert.equal(new Intl.NumberFormat(['en']).format(12345.67890), '12,345.679'); + + var collOpts = { sensitivity: 'base', ignorePunctuation: true }; + var coll = new Intl.Collator(['en'], collOpts); + + assert.equal(coll.compare('blackbird', 'black-bird'), 0, + 'ignore punctuation failed'); + assert.equal(coll.compare('blackbird', 'red-bird'), -1, + 'compare less failed'); + assert.equal(coll.compare('bluebird', 'blackbird'), 1, + 'compare greater failed'); + assert.equal(coll.compare('Bluebird', 'bluebird'), 0, + 'ignore case failed'); + assert.equal(coll.compare('\ufb03', 'ffi'), 0, + 'ffi ligature (contraction) failed'); +} diff --git a/tools/configure.d/nodedownload.py b/tools/configure.d/nodedownload.py new file mode 100644 index 00000000000000..e24efd865f3049 --- /dev/null +++ b/tools/configure.d/nodedownload.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# Moved some utilities here from ../../configure + +import urllib +import hashlib +import sys +import zipfile +import tarfile +import fpformat +import contextlib + +def formatSize(amt): + """Format a size as a string in MB""" + return fpformat.fix(amt / 1024000., 1) + +def spin(c): + """print out an ASCII 'spinner' based on the value of counter 'c'""" + spin = ".:|'" + return (spin[c % len(spin)]) + +class ConfigOpener(urllib.FancyURLopener): + """fancy opener used by retrievefile. Set a UA""" + # append to existing version (UA) + version = '%s node.js/configure' % urllib.URLopener.version + +def reporthook(count, size, total): + """internal hook used by retrievefile""" + sys.stdout.write(' Fetch: %c %sMB total, %sMB downloaded \r' % + (spin(count), + formatSize(total), + formatSize(count*size))) + +def retrievefile(url, targetfile): + """fetch file 'url' as 'targetfile'. Return targetfile or throw.""" + try: + sys.stdout.write(' <%s>\nConnecting...\r' % url) + sys.stdout.flush() + msg = ConfigOpener().retrieve(url, targetfile, reporthook=reporthook) + print '' # clear the line + return targetfile + except: + print ' ** Error occurred while downloading\n <%s>' % url + raise + +def md5sum(targetfile): + """md5sum a file. Return the hex digest.""" + digest = hashlib.md5() + with open(targetfile, 'rb') as f: + chunk = f.read(1024) + while chunk != "": + digest.update(chunk) + chunk = f.read(1024) + return digest.hexdigest() + +def unpack(packedfile, parent_path): + """Unpacks packedfile into parent_path. Assumes .zip. Returns parent_path""" + if zipfile.is_zipfile(packedfile): + with contextlib.closing(zipfile.ZipFile(packedfile, 'r')) as icuzip: + print ' Extracting zipfile: %s' % packedfile + icuzip.extractall(parent_path) + return parent_path + elif tarfile.is_tarfile(packedfile): + with tarfile.TarFile.open(packedfile, 'r') as icuzip: + print ' Extracting tarfile: %s' % packedfile + icuzip.extractall(parent_path) + return parent_path + else: + packedsuffix = packedfile.lower().split('.')[-1] # .zip, .tgz etc + raise Exception('Error: Don\'t know how to unpack %s with extension %s' % (packedfile, packedsuffix)) + +# List of possible "--download=" types. +download_types = set(['icu']) + +# Default options for --download. +download_default = "none" + +def help(): + """This function calculates the '--help' text for '--download'.""" + return """Select which packages may be auto-downloaded. +valid values are: none, all, %s. (default is "%s").""" % (", ".join(download_types), download_default) + +def set2dict(keys, value=None): + """Convert some keys (iterable) to a dict.""" + return dict((key, value) for (key) in keys) + +def parse(opt): + """This function parses the options to --download and returns a set such as { icu: true }, etc. """ + if not opt: + opt = download_default + + theOpts = set(opt.split(',')) + + if 'all' in theOpts: + # all on + return set2dict(download_types, True) + elif 'none' in theOpts: + # all off + return set2dict(download_types, False) + + # OK. Now, process each of the opts. + theRet = set2dict(download_types, False) + for anOpt in opt.split(','): + if not anOpt or anOpt == "": + # ignore stray commas, etc. + continue + elif anOpt is 'all': + # all on + theRet = dict((key, True) for (key) in download_types) + else: + # turn this one on + if anOpt in download_types: + theRet[anOpt] = True + else: + # future proof: ignore unknown types + print 'Warning: ignoring unknown --download= type "%s"' % anOpt + # all done + return theRet + +def candownload(auto_downloads, package): + if not (package in auto_downloads.keys()): + raise Exception('Internal error: "%s" is not in the --downloads list. Check nodedownload.py' % package) + if auto_downloads[package]: + return True + else: + print """Warning: Not downloading package "%s". You could pass "--download=all" + (Windows: "download-all") to try auto-downloading it.""" % package + return False diff --git a/tools/icu/icu-generic.gyp b/tools/icu/icu-generic.gyp index 220d2c16a664c2..bb2b5e5e4d5ec4 100644 --- a/tools/icu/icu-generic.gyp +++ b/tools/icu/icu-generic.gyp @@ -11,6 +11,17 @@ }, 'includes': [ '../../icu_config.gypi' ], 'targets': [ + { + # a target for additional uconfig defines, target only + 'target_name': 'icu_uconfig_target', + 'type': 'none', + 'toolsets': [ 'target' ], + 'direct_dependent_settings': { + 'defines': [ + 'UCONFIG_NO_CONVERSION=1', + ] + }, + }, { # a target to hold uconfig defines. # for now these are hard coded, but could be defined. @@ -92,24 +103,74 @@ }, { 'target_name': 'icui18n', - 'type': '<(library)', - 'toolsets': [ 'target' ], - 'sources': [ - '<@(icu_src_i18n)' - ], - 'include_dirs': [ - '../../deps/icu/source/i18n', - ], - 'defines': [ - 'U_I18N_IMPLEMENTATION=1', + 'toolsets': [ 'target', 'host' ], + 'conditions' : [ + ['_toolset=="target"', { + 'type': '<(library)', + 'sources': [ + '<@(icu_src_i18n)' + ], + 'conditions': [ + [ 'icu_ver_major == 54', { 'sources!': [ + ## Strip out the following for ICU 54 only. + ## add more conditions in the future? + ## if your compiler can dead-strip, this will + ## make ZERO difference to binary size. + ## Made ICU-specific for future-proofing. + + # alphabetic index + '../../deps/icu/source/i18n/alphaindex.cpp', + # BOCSU + # misc + '../../deps/icu/source/i18n/regexcmp.cpp', + '../../deps/icu/source/i18n/regexcmp.h', + '../../deps/icu/source/i18n/regexcst.h', + '../../deps/icu/source/i18n/regeximp.cpp', + '../../deps/icu/source/i18n/regeximp.h', + '../../deps/icu/source/i18n/regexst.cpp', + '../../deps/icu/source/i18n/regexst.h', + '../../deps/icu/source/i18n/regextxt.cpp', + '../../deps/icu/source/i18n/regextxt.h', + '../../deps/icu/source/i18n/region.cpp', + '../../deps/icu/source/i18n/region_impl.h', + '../../deps/icu/source/i18n/reldatefmt.cpp', + '../../deps/icu/source/i18n/reldatefmt.h' + '../../deps/icu/source/i18n/scientificformathelper.cpp', + '../../deps/icu/source/i18n/tmunit.cpp', + '../../deps/icu/source/i18n/tmutamt.cpp', + '../../deps/icu/source/i18n/tmutfmt.cpp', + '../../deps/icu/source/i18n/uregex.cpp', + '../../deps/icu/source/i18n/uregexc.cpp', + '../../deps/icu/source/i18n/uregion.cpp', + '../../deps/icu/source/i18n/uspoof.cpp', + '../../deps/icu/source/i18n/uspoof_build.cpp', + '../../deps/icu/source/i18n/uspoof_conf.cpp', + '../../deps/icu/source/i18n/uspoof_conf.h', + '../../deps/icu/source/i18n/uspoof_impl.cpp', + '../../deps/icu/source/i18n/uspoof_impl.h', + '../../deps/icu/source/i18n/uspoof_wsconf.cpp', + '../../deps/icu/source/i18n/uspoof_wsconf.h', + ]}]], + 'include_dirs': [ + '../../deps/icu/source/i18n', + ], + 'defines': [ + 'U_I18N_IMPLEMENTATION=1', + ], + 'dependencies': [ 'icuucx', 'icu_implementation', 'icu_uconfig', 'icu_uconfig_target' ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../../deps/icu/source/i18n', + ], + }, + 'export_dependent_settings': [ 'icuucx', 'icu_uconfig_target' ], + }], + ['_toolset=="host"', { + 'type': 'none', + 'dependencies': [ 'icutools' ], + 'export_dependent_settings': [ 'icutools' ], + }], ], - 'dependencies': [ 'icuucx', 'icu_implementation', 'icu_uconfig' ], - 'direct_dependent_settings': { - 'include_dirs': [ - '../../deps/icu/source/i18n', - ], - }, - 'export_dependent_settings': [ 'icuucx' ], }, # This exports actual ICU data { @@ -146,32 +207,33 @@ # trim down ICU 'action_name': 'icutrim', 'inputs': [ '<(icu_data_in)', 'icu_small.json' ], - 'outputs': [ '../../out/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], 'action': [ 'python', 'icutrim.py', '-P', '../../<(CONFIGURATION_NAME)', '-D', '<(icu_data_in)', '--delete-tmp', - '-T', '../../out/icutmp', + '-T', '<(SHARED_INTERMEDIATE_DIR)/icutmp', '-F', 'icu_small.json', '-O', 'icudt<(icu_ver_major)<(icu_endianness).dat', - '-v' ], + '-v', + '-L', '<(icu_locales)'], }, { # build final .dat -> .obj 'action_name': 'genccode', - 'inputs': [ '../../out/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], - 'outputs': [ '../../out/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], + 'inputs': [ '<(SHARED_INTERMEDIATE_DIR)/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], 'action': [ '../../<(CONFIGURATION_NAME)/genccode', '-o', - '-d', '../../out/', + '-d', '<(SHARED_INTERMEDIATE_DIR)/', '-n', 'icudata', '-e', 'icusmdt<(icu_ver_major)', '<@(_inputs)' ], }, ], # This file contains the small ICU data. - 'sources': [ '../../out/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], + 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], } ] ], #end of OS==win and icu_small == true }, { # OS != win 'conditions': [ @@ -235,7 +297,8 @@ '-T', '<(SHARED_INTERMEDIATE_DIR)/icutmp', '-F', 'icu_small.json', '-O', 'icudt<(icu_ver_major)<(icu_endianness).dat', - '-v' ], + '-v', + '-L', '<(icu_locales)'], }, { # rename to get the final entrypoint name right 'action_name': 'rename', @@ -284,19 +347,51 @@ { 'target_name': 'icuuc', 'type': 'none', - 'toolsets': [ 'target' ], - 'dependencies': [ 'icuucx', 'icudata' ], - 'export_dependent_settings': [ 'icuucx', 'icudata' ], + 'toolsets': [ 'target', 'host' ], + 'conditions' : [ + ['_toolset=="host"', { + 'dependencies': [ 'icutools' ], + 'export_dependent_settings': [ 'icutools' ], + }], + ['_toolset=="target"', { + 'dependencies': [ 'icuucx', 'icudata' ], + 'export_dependent_settings': [ 'icuucx', 'icudata' ], + }], + ], }, # This is the 'real' icuuc. - # tools can depend on 'icuuc + stubdata' { 'target_name': 'icuucx', 'type': '<(library)', - 'dependencies': [ 'icu_implementation', 'icu_uconfig' ], + 'dependencies': [ 'icu_implementation', 'icu_uconfig', 'icu_uconfig_target' ], 'toolsets': [ 'target' ], 'sources': [ - '<@(icu_src_common)' + '<@(icu_src_common)', + ], + 'conditions': [ + [ 'icu_ver_major == 54', { 'sources!': [ + ## Strip out the following for ICU 54 only. + ## add more conditions in the future? + ## if your compiler can dead-strip, this will + ## make ZERO difference to binary size. + ## Made ICU-specific for future-proofing. + + # bidi- not needed (yet!) + '../../deps/icu/source/common/ubidi.c', + '../../deps/icu/source/common/ubidiimp.h', + '../../deps/icu/source/common/ubidiln.c', + '../../deps/icu/source/common/ubidiwrt.c', + #'../../deps/icu/source/common/ubidi_props.c', + #'../../deps/icu/source/common/ubidi_props.h', + #'../../deps/icu/source/common/ubidi_props_data.h', + # and the callers + '../../deps/icu/source/common/ushape.cpp', + '../../deps/icu/source/common/usprep.cpp', + '../../deps/icu/source/common/uts46.cpp', + ]}], + [ 'OS == "solaris"', { 'defines': [ + '_XOPEN_SOURCE_EXTENDED=0', + ]}], ], 'include_dirs': [ '../../deps/icu/source/common', @@ -304,7 +399,8 @@ 'defines': [ 'U_COMMON_IMPLEMENTATION=1', ], - 'export_dependent_settings': [ 'icu_uconfig' ], + 'cflags_c': ['-std=c99'], + 'export_dependent_settings': [ 'icu_uconfig', 'icu_uconfig_target' ], 'direct_dependent_settings': { 'include_dirs': [ '../../deps/icu/source/common', @@ -331,6 +427,12 @@ '<@(icu_src_io)', '<@(icu_src_stubdata)', ], + 'sources!': [ + '../../deps/icu/source/tools/toolutil/udbgutil.cpp', + '../../deps/icu/source/tools/toolutil/udbgutil.h', + '../../deps/icu/source/tools/toolutil/dbgutil.cpp', + '../../deps/icu/source/tools/toolutil/dbgutil.h', + ], 'include_dirs': [ '../../deps/icu/source/common', '../../deps/icu/source/i18n', @@ -344,6 +446,12 @@ 'U_TOOLUTIL_IMPLEMENTATION=1', #'DEBUG=0', # http://bugs.icu-project.org/trac/ticket/10977 ], + 'cflags_c': ['-std=c99'], + 'conditions': [ + ['OS == "solaris"', { + 'defines': [ '_XOPEN_SOURCE_EXTENDED=0' ] + }] + ], 'direct_dependent_settings': { 'include_dirs': [ '../../deps/icu/source/common', @@ -359,7 +467,7 @@ }], ], }, - 'export_dependent_settings': [ 'icu_implementation', 'icu_uconfig' ], + 'export_dependent_settings': [ 'icu_uconfig' ], }, # This tool is needed to rebuild .res files from .txt, # or to build index (res_index.txt) files for small-icu diff --git a/tools/icu/icu_small.json b/tools/icu/icu_small.json index ddf7d1204e814a..e434794e91c16b 100644 --- a/tools/icu/icu_small.json +++ b/tools/icu/icu_small.json @@ -1,11 +1,11 @@ { "copyright": "Copyright (c) 2014 IBM Corporation and Others. All Rights Reserved.", - "comment": "icutrim.py config: Trim down ICU to just English, needed for node.js use.", + "comment": "icutrim.py config: Trim down ICU to just a certain locale set, needed for node.js use.", "variables": { "none": { "only": [] }, - "en_only": { + "locales": { "only": [ "root", "en" @@ -15,20 +15,21 @@ } }, "trees": { - "ROOT": "en_only", + "ROOT": "locales", "brkitr": "none", - "coll": "en_only", - "curr": "en_only", + "coll": "locales", + "curr": "locales", "lang": "none", "rbnf": "none", "region": "none", - "zone": "en_only", + "zone": "locales", "converters": "none", "stringprep": "none", "translit": "none", "brkfiles": "none", "brkdict": "none", - "confusables": "none" + "confusables": "none", + "unit": "none" }, "remove": [ "cnvalias.icu", diff --git a/tools/icu/icutrim.py b/tools/icu/icutrim.py index 7f0fb3752e40e9..517bf39bad323d 100755 --- a/tools/icu/icutrim.py +++ b/tools/icu/icutrim.py @@ -65,6 +65,12 @@ action="count", default=0) +parser.add_option('-L',"--locales", + action="store", + dest="locales", + help="sets the 'locales.only' variable", + default=None) + parser.add_option('-e', '--endian', action='store', dest='endian', help='endian, big, little or host, your default is "%s".' % endian, default=endian, metavar='endianness') (options, args) = parser.parse_args() @@ -147,6 +153,13 @@ def runcmd(tool, cmd, doContinue=False): config=json.load(fi) fi.close() +if (options.locales): + if not config.has_key("variables"): + config["variables"] = {} + if not config["variables"].has_key("locales"): + config["variables"]["locales"] = {} + config["variables"]["locales"]["only"] = options.locales.split(',') + if (options.verbose > 6): print config diff --git a/vcbuild.bat b/vcbuild.bat index 616b5bb114569f..39c656f187890e 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -36,6 +36,7 @@ set noperfctr= set noperfctr_arg= set noperfctr_msi_arg= set i18n_arg= +set download_arg= :next-arg if "%1"=="" goto args-done @@ -65,6 +66,8 @@ if /i "%1"=="upload" set upload=1&goto arg-ok if /i "%1"=="jslint" set jslint=1&goto arg-ok if /i "%1"=="small-icu" set i18n_arg=%1&goto arg-ok if /i "%1"=="full-icu" set i18n_arg=%1&goto arg-ok +if /i "%1"=="intl-none" set i18n_arg=%1&goto arg-ok +if /i "%1"=="download-all" set download_arg="--download=all"&goto arg-ok echo Warning: ignoring invalid command line option `%1`. @@ -85,6 +88,7 @@ if defined noperfctr set noperfctr_arg=--without-perfctr& set noperfctr_msi_arg= if "%i18n_arg%"=="full-icu" set i18n_arg=--with-intl=full-icu if "%i18n_arg%"=="small-icu" set i18n_arg=--with-intl=small-icu +if "%i18n_arg%"=="intl-none" set i18n_arg=--with-intl=none :project-gen @rem Skip project generation if requested. @@ -95,7 +99,7 @@ if defined NIGHTLY set TAG=nightly-%NIGHTLY% @rem Generate the VS project. SETLOCAL if defined VS100COMNTOOLS call "%VS100COMNTOOLS%\VCVarsQueryRegistry.bat" - python configure %i18n_arg% %debug_arg% %nosnapshot_arg% %noetw_arg% %noperfctr_arg% --dest-cpu=%target_arch% --tag=%TAG% + python configure %download_arg% %i18n_arg% %debug_arg% %nosnapshot_arg% %noetw_arg% %noperfctr_arg% --dest-cpu=%target_arch% --tag=%TAG% if errorlevel 1 goto create-msvs-files-failed if not exist node.sln goto create-msvs-files-failed echo Project files generated. @@ -232,7 +236,7 @@ python tools/closure_linter/closure_linter/gjslint.py --unix_mode --strict --noj goto exit :help -echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [nobuild] [nosign] [x86/x64] +echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [small-icu/full-icu/intl-none] [nobuild] [nosign] [x86/x64] [download-all] echo Examples: echo vcbuild.bat : builds release build echo vcbuild.bat debug : builds debug build From 261706e2ef9f12131ddcf8ff40fd4c7823693e8d Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Fri, 2 Jan 2015 14:14:51 +1100 Subject: [PATCH 17/22] doc: added TC meeting minutes 2014-12-30 closes #211 PR-URL: https://github.com/iojs/io.js/pull/229 Reviewed-By: Colin Ihrig --- doc/tc-meetings/2014-12-30.md | 95 +++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 doc/tc-meetings/2014-12-30.md diff --git a/doc/tc-meetings/2014-12-30.md b/doc/tc-meetings/2014-12-30.md new file mode 100644 index 00000000000000..013376cd93cded --- /dev/null +++ b/doc/tc-meetings/2014-12-30.md @@ -0,0 +1,95 @@ +# io.js TC Meeting 2014-12-30 + +## Links + +* **Google Hangouts Video**: http://www.youtube.com/watch?v=O60sOsesjOo +* **GitHub Issue**: https://github.com/iojs/io.js/issues/211 +* **Original Minutes Google Doc**: https://docs.google.com/document/d/1KLfX2MZQbVSIaD2lBVqOFK0Kap4uFz9cTGihnpTuvPE + +## Agenda + +Extracted from https://github.com/iojs/io.js/labels/tc-agenda prior to meeting. + +* sys: Remove after 3 years of deprecation #182 https://github.com/iojs/io.js/pull/182 +* module: force require('process') to return a reference to process #206 https://github.com/iojs/io.js/pull/206 +* File copyright policy #216 https://github.com/iojs/io.js/pull/216 +* Rename v0.12 to v1.0.0 https://github.com/iojs/io.js/issues/218 +* Merge strategy (v0.10 and joyent/node) + +## Minutes + +### Present + +* Rod (build, facilitator) +* Ben (TC) +* Bert (TC) +* Chris (TC) +* Fedor (TC) +* Trevor (TC) + +### sys: Remove after 3 years of deprecation #182 + +https://github.com/iojs/io.js/pull/182 + +* Ben: what sort of strategy to take? Deprecated only in the docs but no warning. Looking for an official deprecation policy. +* Bert: suggest we could properly deprecate but not a good case for removing it completely, Chris agreed +* Fedor: suggested a policy that removal of deprecated features should be done where there is a maintenance overhead, but otherwise if there is little/no cost then "who cares" +* Discussed a deprecation message on `require(‘sys’)` + * Ben: -0 + * Fedor: +1 + * Chris: +1 + * Trevor: -0 + * Bert: +1 +* No disagreement to adding a deprecation message, **ask initial PR submitter to change to just adding a message** + +### module: force require('process') to return a reference to process #206 + +https://github.com/iojs/io.js/pull/206 + +* #157 has a long discussion on this: https://github.com/iojs/io.js/issues/157 +* Chris: +1 on a PR adding this +* Trevor: it just returns a global, no point +* Bert: not the way that JS adds new features; discussed the new Intl addition to joyent/node, in favor of making more things requirable rather than adding new globals all the time +* Tangential discussion on the Intl object being added in joyent/node +* Collected votes: + * Bert: +0 + * Ben: +0.5 + * Trevor: -0 + * Fedor: +1 + * Chris: +1 +* **Ben to handle the merge / resolution** + + +### File copyright policy #216 + +https://github.com/iojs/io.js/pull/216 + +* Rod asked if there are any strong opinions about how to handle this +* **Group agreed that Rod will take this issue and seek legal advice to find a way forward** + +### Rename v0.12 to v1.0.0 + +https://github.com/iojs/io.js/issues/218 + +* Trevor: concerns about 1.0 vs 1.x branch naming with maintaining semver releases while also doing LTS, 1.x effectively becomes master until a 2.0 comes along. +* Bert: -1 +* Ben: +1 +* Chris: +1 +* Fedor: +1 +* Trevor: 0 + +Action: **Rename to "v1.x", Ben agreed to make the change** + + +### Merge strategy (v0.10 and joyent/node) + +* _Much_ discussion about merge strategies, patches, branches, etc. +* Agreed to merge regularly +* **Bert agreed to monitor the situation and propose a merge strategy when the time is right** + +### Next meeting + +* Agreed to meet again on the 7th of January UTC +* Agreed to have mini-stand-up at the beginning of each meeting + + From 8cfbeed27ab98dffff68c13188d4f3dc1a506c3c Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 2 Jan 2015 17:16:47 -0800 Subject: [PATCH 18/22] docs: update to authors file PR-URL: https://github.com/joyent/node/pull/8964 Reviewed-by: Trevor Norris --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 5aa6137928e6e6..ce538de7b5c6e2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -568,3 +568,4 @@ Kevin Simper Jackson Tian Tristan Berger Mathias Schreck +Steven R. Loomis From b636ba8186d191c52ee36f2f2b1aebbbb4d95575 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 3 Jan 2015 18:26:26 -0500 Subject: [PATCH 19/22] net: make connect() input validation synchronous Socket.prototype.connect() sometimes throws on bad inputs after an asynchronous operation. This commit makes the input validation synchronous. This commit also removes some hard coded IP addresses. PR-URL: https://github.com/joyent/node/pull/8180 Fixes: https://github.com/joyent/node/issues/8140 Reviewed-By: Trevor Norris Reviewed-By: Fedor Indutny Reviewed-By: Timothy J Fontaine --- lib/net.js | 77 +++++++++--------------- test/simple/test-net-localerror.js | 53 +++++++--------- test/simple/test-process-active-wraps.js | 16 ++++- 3 files changed, 65 insertions(+), 81 deletions(-) diff --git a/lib/net.js b/lib/net.js index f0075b5a33e5b4..0ece1b0f97c3ee 100644 --- a/lib/net.js +++ b/lib/net.js @@ -785,34 +785,18 @@ function connect(self, address, port, addressType, localAddress, localPort) { assert.ok(self._connecting); var err; - if (localAddress || localPort) { - if (localAddress && !exports.isIP(localAddress)) - err = new TypeError( - 'localAddress should be a valid IP: ' + localAddress); - - if (localPort && !util.isNumber(localPort)) - err = new TypeError('localPort should be a number: ' + localPort); + if (localAddress || localPort) { var bind; - switch (addressType) { - case 4: - if (!localAddress) - localAddress = '0.0.0.0'; - bind = self._handle.bind; - break; - case 6: - if (!localAddress) - localAddress = '::'; - bind = self._handle.bind6; - break; - default: - err = new TypeError('Invalid addressType: ' + addressType); - break; - } - - if (err) { - self._destroy(err); + if (addressType === 4) { + localAddress = localAddress || '0.0.0.0'; + bind = self._handle.bind; + } else if (addressType === 6) { + localAddress = localAddress || '::'; + bind = self._handle.bind6; + } else { + self._destroy(new TypeError('Invalid addressType: ' + addressType)); return; } @@ -832,15 +816,12 @@ function connect(self, address, port, addressType, localAddress, localPort) { if (addressType === 6 || addressType === 4) { var req = new TCPConnectWrap(); req.oncomplete = afterConnect; - port = port | 0; - if (port <= 0 || port > 65535) - throw new RangeError('Port should be > 0 and < 65536'); - if (addressType === 6) { - err = self._handle.connect6(req, address, port); - } else if (addressType === 4) { + if (addressType === 4) err = self._handle.connect(req, address, port); - } + else + err = self._handle.connect6(req, address, port); + } else { var req = new PipeConnectWrap(); req.oncomplete = afterConnect; @@ -898,19 +879,26 @@ Socket.prototype.connect = function(options, cb) { if (pipe) { connect(self, options.path); - } else if (!options.host) { - debug('connect: missing host'); - self._host = '127.0.0.1'; - connect(self, self._host, options.port, 4); - } else { var dns = require('dns'); - var host = options.host; + var host = options.host || 'localhost'; + var port = options.port | 0; + var localAddress = options.localAddress; + var localPort = options.localPort; var dnsopts = { family: options.family, hints: 0 }; + if (localAddress && !exports.isIP(localAddress)) + throw new TypeError('localAddress must be a valid IP: ' + localAddress); + + if (localPort && !util.isNumber(localPort)) + throw new TypeError('localPort should be a number: ' + localPort); + + if (port <= 0 || port > 65535) + throw new RangeError('port should be > 0 and < 65536: ' + port); + if (dnsopts.family !== 4 && dnsopts.family !== 6) dnsopts.hints = dns.ADDRCONFIG | dns.V4MAPPED; @@ -936,19 +924,12 @@ Socket.prototype.connect = function(options, cb) { }); } else { timers._unrefActive(self); - - addressType = addressType || 4; - - // node_net.cc handles null host names graciously but user land - // expects remoteAddress to have a meaningful value - ip = ip || (addressType === 4 ? '127.0.0.1' : '0:0:0:0:0:0:0:1'); - connect(self, ip, - options.port, + port, addressType, - options.localAddress, - options.localPort); + localAddress, + localPort); } }); } diff --git a/test/simple/test-net-localerror.js b/test/simple/test-net-localerror.js index c4d04aa921acc2..d04d9c70720424 100644 --- a/test/simple/test-net-localerror.js +++ b/test/simple/test-net-localerror.js @@ -23,39 +23,30 @@ var common = require('../common'); var assert = require('assert'); var net = require('net'); -var server = net.createServer(function(socket) { - assert.ok(false, 'no clients should connect'); -}).listen(common.PORT).on('listening', function() { - server.unref(); + connect({ + host: 'localhost', + port: common.PORT, + localPort: 'foobar', + }, 'localPort should be a number: foobar'); - function test1(next) { - connect({ - host: '127.0.0.1', - port: common.PORT, - localPort: 'foobar', - }, - 'localPort should be a number: foobar', - next); - } + connect({ + host: 'localhost', + port: common.PORT, + localAddress: 'foobar', + }, 'localAddress should be a valid IP: foobar'); - function test2(next) { - connect({ - host: '127.0.0.1', - port: common.PORT, - localAddress: 'foobar', - }, - 'localAddress should be a valid IP: foobar', - next) - } + connect({ + host: 'localhost', + port: 65536 + }, 'port should be > 0 and < 65536: 65536'); - test1(test2); -}) + connect({ + host: 'localhost', + port: 0 + }, 'port should be > 0 and < 65536: 0'); -function connect(opts, msg, cb) { - var client = net.connect(opts).on('connect', function() { - assert.ok(false, 'we should never connect'); - }).on('error', function(err) { - assert.strictEqual(err.message, msg); - if (cb) cb(); - }); +function connect(opts, msg) { + assert.throws(function() { + var client = net.connect(opts); + }, msg); } diff --git a/test/simple/test-process-active-wraps.js b/test/simple/test-process-active-wraps.js index 63fc218debc480..bd4941b786e735 100644 --- a/test/simple/test-process-active-wraps.js +++ b/test/simple/test-process-active-wraps.js @@ -41,9 +41,16 @@ var handles = []; })(); (function() { + function onlookup() { + setImmediate(function() { + assert.equal(process._getActiveRequests().length, 0); + }); + }; + expect(1, 0); var conn = net.createConnection(common.PORT); - conn.on('error', function() { /* ignore */ }); + conn.on('lookup', onlookup); + conn.on('error', function() { assert(false); }); expect(2, 1); conn.destroy(); expect(2, 1); // client handle doesn't shut down until next tick @@ -52,10 +59,15 @@ var handles = []; (function() { var n = 0; + handles.forEach(function(handle) { handle.once('close', onclose); }); function onclose() { - if (++n === handles.length) setImmediate(expect, 0, 0); + if (++n === handles.length) { + setImmediate(function() { + assert.equal(process._getActiveHandles().length, 0); + }); + } } })(); From 372a2f56bed341a23c435c5a94fbb77dbbd6c600 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 5 Jan 2015 02:20:31 -0800 Subject: [PATCH 20/22] smalloc: fix bad assert for zero length data If the data length passed to smalloc.alloc() the array_length will be zero, causing an overflow check to fail. This prevents that from happening. Signed-off-by: Trevor Norris --- src/smalloc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smalloc.cc b/src/smalloc.cc index 7dc3510a0bf540..0cd8f3eb9e4641 100644 --- a/src/smalloc.cc +++ b/src/smalloc.cc @@ -132,7 +132,7 @@ void CallbackInfo::WeakCallback(Isolate* isolate, Local object) { object->GetIndexedPropertiesExternalArrayDataType(); size_t array_size = ExternalArraySize(array_type); CHECK_GT(array_size, 0); - if (array_size > 1) { + if (array_size > 1 && array_data != NULL) { CHECK_GT(array_length * array_size, array_length); // Overflow check. array_length *= array_size; } From eaed2a11ecf8d4f8a309f42d6bbc72306c01b755 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 5 Jan 2015 20:44:25 +0100 Subject: [PATCH 21/22] deps: update libuv to 1.2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/iojs/io.js/pull/237 Reviewed-By: Bert Belder Reviewed-By: Saúl Ibarra Corretgé --- deps/uv/.gitignore | 6 +- deps/uv/.mailmap | 6 +- deps/uv/AUTHORS | 4 + deps/uv/ChangeLog | 149 ++++++ deps/uv/Makefile.am | 6 +- deps/uv/autogen.sh | 2 +- deps/uv/common.gypi | 4 +- deps/uv/configure.ac | 11 +- deps/uv/docs/make.bat | 486 +++++++++--------- deps/uv/docs/src/loop.rst | 2 + deps/uv/docs/src/misc.rst | 6 +- deps/uv/docs/src/tty.rst | 25 +- deps/uv/gyp_uv.py | 17 +- deps/uv/include/uv-version.h | 4 +- deps/uv/include/uv-win.h | 5 +- deps/uv/include/uv.h | 21 +- deps/uv/m4/dtrace.m4 | 66 --- deps/uv/src/unix/aix.c | 2 +- deps/uv/src/unix/core.c | 22 +- deps/uv/src/unix/darwin.c | 37 +- deps/uv/src/unix/freebsd.c | 2 +- deps/uv/src/unix/fs.c | 38 +- deps/uv/src/unix/internal.h | 3 - deps/uv/src/unix/linux-core.c | 24 +- deps/uv/src/unix/linux-syscalls.c | 6 +- deps/uv/src/unix/linux-syscalls.h | 2 +- deps/uv/src/unix/netbsd.c | 2 +- deps/uv/src/unix/openbsd.c | 16 +- deps/uv/src/unix/pipe.c | 17 +- deps/uv/src/unix/sunos.c | 8 +- deps/uv/src/unix/tty.c | 47 +- deps/uv/src/unix/udp.c | 39 +- deps/uv/src/uv-common.h | 3 + deps/uv/src/win/core.c | 7 +- deps/uv/src/win/dl.c | 35 +- deps/uv/src/win/fs.c | 288 +++++++---- deps/uv/src/win/internal.h | 4 +- deps/uv/src/win/poll.c | 44 +- deps/uv/src/win/req-inl.h | 9 +- deps/uv/src/win/thread.c | 24 +- deps/uv/src/win/tty.c | 17 +- deps/uv/src/win/winapi.c | 7 + deps/uv/src/win/winapi.h | 84 ++- deps/uv/src/win/winsock.c | 12 +- deps/uv/test/runner-unix.c | 25 +- deps/uv/test/task.h | 22 + deps/uv/test/test-cwd-and-chdir.c | 27 +- deps/uv/test/test-dlerror.c | 19 +- deps/uv/test/test-fs.c | 12 +- deps/uv/test/test-get-currentexe.c | 21 + deps/uv/test/test-list.h | 6 + deps/uv/test/test-loop-configure.c | 38 ++ deps/uv/test/test-osx-select.c | 2 +- deps/uv/test/test-ping-pong.c | 3 + .../test/test-pipe-close-stdout-read-stdin.c | 3 +- deps/uv/test/test-platform-output.c | 6 + .../test-poll-close-doesnt-corrupt-stack.c | 114 ++++ deps/uv/test/test-spawn.c | 26 +- deps/uv/test/test-tcp-bind6-error.c | 15 + deps/uv/test/test-udp-ipv6.c | 13 +- deps/uv/test/test-udp-multicast-interface6.c | 3 + deps/uv/test/test-udp-multicast-join6.c | 3 + deps/uv/test/test-udp-options.c | 26 +- deps/uv/uv.gyp | 26 +- 64 files changed, 1313 insertions(+), 716 deletions(-) delete mode 100644 deps/uv/m4/dtrace.m4 create mode 100644 deps/uv/test/test-loop-configure.c create mode 100644 deps/uv/test/test-poll-close-doesnt-corrupt-stack.c diff --git a/deps/uv/.gitignore b/deps/uv/.gitignore index 14a174adf63de7..e7f8f3f59fa7ee 100644 --- a/deps/uv/.gitignore +++ b/deps/uv/.gitignore @@ -34,9 +34,6 @@ vgcore.* Makefile Makefile.in -# Generated by dtrace(1) when doing an in-tree build. -/include/uv-dtrace.h - # Generated by gyp for android *.target.mk @@ -52,7 +49,10 @@ Makefile.in /test/run-benchmarks.dSYM *.sln +*.sln.cache +*.ncb *.vcproj +*.vcproj*.user *.vcxproj *.vcxproj.filters *.vcxproj.user diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 34f5e4daf35007..3a350a4b9ac0b4 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -17,12 +17,8 @@ Keno Fischer Leonard Hecker Maciej Małecki Marc Schlaich -Rasmus Christian Pedersen -Rasmus Christian Pedersen -Rasmus Christian Pedersen -Rasmus Christian Pedersen +Rasmus Christian Pedersen Rasmus Christian Pedersen -Rasmus Pedersen Robert Mustacchi Ryan Dahl Ryan Emery diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index d4c18cf532f8ec..7e455f6736ab98 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -173,3 +173,7 @@ Michael Ira Krufky Helge Deller Joey Geralnik Tim Caswell +Logan Rosen +Kenneth Perry +John Marino +Alexey Melnichuk diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index e2169998429ec5..0f3fce81ebe184 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,152 @@ +2015.01.06, Version 1.2.0 (Stable) + +Changes since version 1.1.0: + +* linux: fix epoll_pwait() sigmask size calculation (Ben Noordhuis) + +* tty: implement binary I/O terminal mode (Yuri D'Elia) + +* test: fix spawn test with autotools build (Ben Noordhuis) + +* test: skip ipv6 tests when ipv6 is not supported (Ben Noordhuis) + +* common: move STATIC_ASSERT to uv-common.h (Alexey Melnichuk) + +* win/thread: store thread handle in a TLS slot (Alexey Melnichuk) + +* unix: fix ttl, multicast ttl and loop options on IPv6 (Saúl Ibarra Corretgé) + +* linux: fix support for preadv/pwritev-less kernels (Ben Noordhuis) + +* unix: make uv_exepath(size=0) return UV_EINVAL (Ben Noordhuis) + +* darwin: fix uv_exepath(smallbuf) UV_EPERM error (Ben Noordhuis) + +* openbsd: fix uv_exepath(smallbuf) UV_EINVAL error (Ben Noordhuis) + +* linux: fix uv_exepath(size=1) UV_EINVAL error (Ben Noordhuis) + +* sunos: preemptively fix uv_exepath(size=1) (Ben Noordhuis) + +* win: fix and clarify comments in winapi.h (Bert Belder) + +* win: make available NtQueryDirectoryFile (Bert Belder) + +* win: add definitions for directory information types (Bert Belder) + +* win: use NtQueryDirectoryFile to implement uv_fs_scandir (Bert Belder) + +* unix: don't unlink unix socket on bind error (Ben Noordhuis) + +* build: fix bad comment in autogen.sh (Ben Noordhuis) + +* build: add AC_PROG_LIBTOOL to configure.ac (Ben Noordhuis) + +* test: skip udp_options6 if there no IPv6 support (Saúl Ibarra Corretgé) + +* win: add definitions for MUI errors mingw lacks (Bert Belder) + +* build: enable warnings in autotools build (Ben Noordhuis) + +* build: remove -Wno-dollar-in-identifier-extension (Ben Noordhuis) + +* build: move flags from Makefile.am to configure.ac (Ben Noordhuis) + + +2015.01.06, Version 0.10.32 (Stable), 378de30c59aef5fdb6d130fa5cfcb0a68fce571c + +Changes since version 0.10.31: + +* linux: fix epoll_pwait() sigmask size calculation (Ben Noordhuis) + + +2014.12.25, Version 1.1.0 (Stable), 9572f3e74a167f59a8017e57ca3ebe91ffd88e18 + +Changes since version 1.0.2: + +* test: test that closing a poll handle doesn't corrupt the stack (Bert Belder) + +* win: fix compilation of tests (Marc Schlaich) + +* Revert "win: keep a reference to AFD_POLL_INFO in cancel poll" (Bert Belder) + +* win: avoid stack corruption when closing a poll handle (Bert Belder) + +* test: fix test-fs-file-loop on Windows (Bert Belder) + +* test: fix test-cwd-and-chdir (Bert Belder) + +* doc: indicate what version uv_loop_configure was added on (Saúl Ibarra + Corretgé) + +* doc: fix sphinx warning (Saúl Ibarra Corretgé) + +* test: skip spawn_setuid_setgid if we get EACCES (Saúl Ibarra Corretgé) + +* test: silence some Clang warnings (Saúl Ibarra Corretgé) + +* test: relax osx_select_many_fds (Saúl Ibarra Corretgé) + +* test: fix compilation warnings when building with Clang (Saúl Ibarra + Corretgé) + +* win: fix autotools build of tests (Luis Lavena) + +* gitignore: ignore Visual Studio files (Marc Schlaich) + +* win: set fallback message if FormatMessage fails (Marc Schlaich) + +* win: fall back to default language in uv_dlerror (Marc Schlaich) + +* test: improve compatibility for dlerror test (Marc Schlaich) + +* test: check dlerror is "no error" in no error case (Marc Schlaich) + +* unix: change uv_cwd not to return a trailing slash (Saúl Ibarra Corretgé) + +* test: fix cwd_and_chdir test on Unix (Saúl Ibarra Corretgé) + +* test: add uv_cwd output to platform_output test (Saúl Ibarra Corretgé) + +* build: fix dragonflybsd autotools build (John Marino) + +* win: scandir use 'ls' for formatting long strings (Kenneth Perry) + +* build: remove clang and gcc_version gyp defines (Ben Noordhuis) + +* unix, windows: don't treat uv_run_mode as a bitmask (Saúl Ibarra Corretgé) + +* unix, windows: fix UV_RUN_ONCE mode if progress was made (Saúl Ibarra + Corretgé) + + +2014.12.25, Version 0.10.31 (Stable), 4dbd27e2219069a6daa769fb37f98673b77b4261 + +Changes since version 0.10.30: + +* test: test that closing a poll handle doesn't corrupt the stack (Bert Belder) + +* win: fix compilation of tests (Marc Schlaich) + +* Revert "win: keep a reference to AFD_POLL_INFO in cancel poll" (Bert Belder) + +* win: avoid stack corruption when closing a poll handle (Bert Belder) + +* gitignore: ignore Visual Studio files (Marc Schlaich) + +* win: set fallback message if FormatMessage fails (Marc Schlaich) + +* win: fall back to default language in uv_dlerror (Marc Schlaich) + +* test: improve compatibility for dlerror test (Marc Schlaich) + +* test: check dlerror is "no error" in no error case (Marc Schlaich) + +* build: link against -pthread (Logan Rosen) + +* win: scandir use 'ls' for formatting long strings (Kenneth Perry) + + 2014.12.10, Version 1.0.2 (Stable), eec671f0059953505f9a3c9aeb7f9f31466dd7cd Changes since version 1.0.1: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 371df711d65633..c5b8a1fa870092 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -34,6 +34,8 @@ libuv_la_SOURCES = src/fs-poll.c \ src/version.c if SUNOS +# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers +# on other platforms complain that the argument is unused during compilation. libuv_la_CFLAGS += -pthread endif @@ -81,7 +83,6 @@ else # WINNT include_HEADERS += include/uv-unix.h AM_CPPFLAGS += -I$(top_srcdir)/src/unix -libuv_la_CFLAGS += -g --std=gnu89 -pedantic -Wall -Wextra -Wno-unused-parameter libuv_la_SOURCES += src/unix/async.c \ src/unix/atomic-ops.h \ src/unix/core.c \ @@ -159,6 +160,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-loop-close.c \ test/test-loop-stop.c \ test/test-loop-time.c \ + test/test-loop-configure.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ test/test-osx-select.c \ @@ -172,6 +174,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-close-stdout-read-stdin.c \ test/test-platform-output.c \ test/test-poll-close.c \ + test/test-poll-close-doesnt-corrupt-stack.c \ test/test-poll-closesocket.c \ test/test-poll.c \ test/test-process-title.c \ @@ -274,7 +277,6 @@ endif if DRAGONFLY include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/kqueue.c src/unix/freebsd.c endif if FREEBSD diff --git a/deps/uv/autogen.sh b/deps/uv/autogen.sh index 751b4f5562493a..0574778a4e1040 100755 --- a/deps/uv/autogen.sh +++ b/deps/uv/autogen.sh @@ -33,7 +33,7 @@ UV_EXTRA_AUTOMAKE_FLAGS= if test "$automake_version_major" -gt 1 || \ test "$automake_version_major" -eq 1 && \ test "$automake_version_minor" -gt 11; then - # serial-tests is available in v0.12 and newer. + # serial-tests is available in v1.12 and newer. UV_EXTRA_AUTOMAKE_FLAGS="$UV_EXTRA_AUTOMAKE_FLAGS serial-tests" fi echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index a8e2ef44c6131d..ecf9475234f3da 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -6,8 +6,6 @@ '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', - 'clang%': 0, }, 'target_defaults': { @@ -158,7 +156,7 @@ 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'visibility=="hidden" and (clang==1 or gcc_version >= 40)', { + [ 'visibility=="hidden"', { 'cflags': [ '-fvisibility=hidden' ], }], ], diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 6ae53cc9164f19..56e97abf37880b 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], [1.0.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.2.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -24,9 +24,16 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O -CC_CHECK_CFLAGS_APPEND([-Wno-dollar-in-identifier-extension]) +CC_CHECK_CFLAGS_APPEND([-g]) +CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-pedantic]) +CC_CHECK_CFLAGS_APPEND([-Wall]) +CC_CHECK_CFLAGS_APPEND([-Wextra]) +CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) # AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +# autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR. +AC_PROG_LIBTOOL m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) LT_INIT # TODO(bnoordhuis) Check for -pthread vs. -pthreads diff --git a/deps/uv/docs/make.bat b/deps/uv/docs/make.bat index 10eb94b013b791..aa7089ab5cf26a 100644 --- a/deps/uv/docs/make.bat +++ b/deps/uv/docs/make.bat @@ -1,243 +1,243 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set SRCDIR=src -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SRCDIR% -set I18NSPHINXOPTS=%SPHINXOPTS% %SRCDIR% -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libuv.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libuv.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set SRCDIR=src +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SRCDIR% +set I18NSPHINXOPTS=%SPHINXOPTS% %SRCDIR% +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libuv.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libuv.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index 0a9e8a60869956..d347534bfc77cc 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -52,6 +52,8 @@ API .. c:function:: int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) + .. versionadded:: 1.0.2 + Set additional loop options. You should normally call this before the first call to :c:func:`uv_run` unless mentioned otherwise. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 4b810fe08475e8..10c349e9b736f3 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -2,7 +2,7 @@ .. _misc: Miscellaneous utilities -====================== +======================= This section contains miscellaneous functions that don't really belong in any other section. @@ -207,6 +207,10 @@ API Gets the current working directory. + .. versionchanged:: 1.1.0 + + On Unix the path no longer ends in a slash. + .. c:function:: int uv_chdir(const char* dir) Changes the current working directory. diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 8cb006632038ba..74b485941c07ab 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -16,6 +16,24 @@ Data types TTY handle type. +.. c:type:: uv_tty_mode_t + + .. versionadded:: 1.2.0 + + TTY mode type: + + :: + + typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO + } uv_tty_mode_t; + + Public members ^^^^^^^^^^^^^^ @@ -43,9 +61,12 @@ API .. note:: TTY streams which are not readable have blocking writes. -.. c:function:: int uv_tty_set_mode(uv_tty_t*, int mode) +.. c:function:: int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode) + + .. versionchanged:: 1.2.0: the mode is specified as a :c:type:`uv_tty_mode_t` + value. - Set the TTY mode. 0 for normal, 1 for raw. + Set the TTY using the specified terminal mode. .. c:function:: int uv_tty_reset_mode(void) diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index f5afc6da2d6b0b..0491ff873f1af1 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -1,9 +1,7 @@ #!/usr/bin/env python -import glob -import platform import os -import subprocess +import platform import sys try: @@ -35,16 +33,6 @@ def host_arch(): return machine # Return as-is and hope for the best. -def compiler_version(): - proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE) - is_clang = 'clang' in proc.communicate()[0].split('\n')[0] - proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE) - version = proc.communicate()[0].split('.') - version = map(int, version[:2]) - version = tuple(version) - return (version, is_clang) - - def run_gyp(args): rc = gyp.main(args) if rc != 0: @@ -85,9 +73,6 @@ def run_gyp(args): if 'eclipse' not in args and 'ninja' not in args: args.extend(['-Goutput_dir=' + output_dir]) args.extend(['--generator-output', output_dir]) - (major, minor), is_clang = compiler_version() - args.append('-Dgcc_version=%d' % (10 * major + minor)) - args.append('-Dclang=%d' % int(is_clang)) if not any(a.startswith('-Dhost_arch=') for a in args): args.append('-Dhost_arch=%s' % host_arch()) diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 25c31ab5e1093d..85d74723af1727 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 0 -#define UV_VERSION_PATCH 2 +#define UV_VERSION_MINOR 2 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 0c188e7e22af85..4abb294c0517db 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -517,10 +517,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); /* Used in fast mode */ \ SOCKET peer_socket; \ AFD_POLL_INFO afd_poll_info_1; \ - union { \ - AFD_POLL_INFO* afd_poll_info_ptr; \ - AFD_POLL_INFO afd_poll_info; \ - } afd_poll_info_2; \ + AFD_POLL_INFO afd_poll_info_2; \ /* Used in fast and slow mode. */ \ uv_req_t poll_req_1; \ uv_req_t poll_req_2; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 7b3c25223b29ed..a2332504ca9551 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -628,11 +628,30 @@ struct uv_tty_s { UV_TTY_PRIVATE_FIELDS }; +typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO +} uv_tty_mode_t; + UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); -UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode); +UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode); UV_EXTERN int uv_tty_reset_mode(void); UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); +#ifdef __cplusplus +} /* extern "C" */ + +inline int uv_tty_set_mode(uv_tty_t* handle, int mode) { + return uv_tty_set_mode(handle, static_cast(mode)); +} + +extern "C" { +#endif + UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); /* diff --git a/deps/uv/m4/dtrace.m4 b/deps/uv/m4/dtrace.m4 deleted file mode 100644 index 09f7dc89cf5620..00000000000000 --- a/deps/uv/m4/dtrace.m4 +++ /dev/null @@ -1,66 +0,0 @@ -dnl Copyright (C) 2009 Sun Microsystems -dnl This file is free software; Sun Microsystems -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl --------------------------------------------------------------------------- -dnl Macro: PANDORA_ENABLE_DTRACE -dnl --------------------------------------------------------------------------- -AC_DEFUN([PANDORA_ENABLE_DTRACE],[ - AC_ARG_ENABLE([dtrace], - [AS_HELP_STRING([--disable-dtrace], - [enable DTrace USDT probes. @<:@default=yes@:>@])], - [ac_cv_enable_dtrace="$enableval"], - [ac_cv_enable_dtrace="yes"]) - - AS_IF([test "$ac_cv_enable_dtrace" = "yes"],[ - AC_CHECK_PROGS([DTRACE], [dtrace]) - AS_IF([test "x$ac_cv_prog_DTRACE" = "xdtrace"],[ - - AC_CACHE_CHECK([if dtrace works],[ac_cv_dtrace_works],[ - cat >conftest.d <<_ACEOF -provider Example { - probe increment(int); -}; -_ACEOF - $DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero - AS_IF([test $? -eq 0],[ac_cv_dtrace_works=yes], - [ac_cv_dtrace_works=no]) - rm -f conftest.h conftest.d - ]) - AS_IF([test "x$ac_cv_dtrace_works" = "xyes"],[ - AC_DEFINE([HAVE_DTRACE], [1], [Enables DTRACE Support]) - AC_CACHE_CHECK([if dtrace should instrument object files], - [ac_cv_dtrace_needs_objects],[ - dnl DTrace on MacOSX does not use -G option - cat >conftest.d <<_ACEOF -provider Example { - probe increment(int); -}; -_ACEOF - cat > conftest.c <<_ACEOF -#include "conftest.h" -void foo() { - EXAMPLE_INCREMENT(1); -} -_ACEOF - $DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero - $CC -c -o conftest.o conftest.c - $DTRACE -G -o conftest.d.o -s conftest.d conftest.o 2>/dev/zero - AS_IF([test $? -eq 0],[ac_cv_dtrace_needs_objects=yes], - [ac_cv_dtrace_needs_objects=no]) - rm -f conftest.d.o conftest.d conftest.h conftest.o conftest.c - ]) - ]) - AC_SUBST(DTRACEFLAGS) dnl TODO: test for -G on OSX - ac_cv_have_dtrace=yes - ])]) - -AM_CONDITIONAL([HAVE_DTRACE], [test "x$ac_cv_dtrace_works" = "xyes"]) -AM_CONDITIONAL([DTRACE_NEEDS_OBJECTS], - [test "x$ac_cv_dtrace_needs_objects" = "xyes"]) - -]) -dnl --------------------------------------------------------------------------- -dnl End Macro: PANDORA_ENABLE_DTRACE -dnl --------------------------------------------------------------------------- diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 349c2b558e4fac..0c5d1f4b508453 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -294,7 +294,7 @@ int uv_exepath(char* buffer, size_t* size) { int fd; char **argv; - if ((buffer == NULL) || (size == NULL)) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index c08040e5378f5f..6f284ffa7aea31 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -74,7 +74,7 @@ #include #endif -static void uv__run_pending(uv_loop_t* loop); +static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); @@ -304,6 +304,7 @@ int uv_loop_alive(const uv_loop_t* loop) { int uv_run(uv_loop_t* loop, uv_run_mode mode) { int timeout; int r; + int ran_pending; r = uv__loop_alive(loop); if (!r) @@ -312,12 +313,12 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); uv__run_timers(loop); - uv__run_pending(loop); + ran_pending = uv__run_pending(loop); uv__run_idle(loop); uv__run_prepare(loop); timeout = 0; - if ((mode & UV_RUN_NOWAIT) == 0) + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); uv__io_poll(loop, timeout); @@ -338,8 +339,7 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { } r = uv__loop_alive(loop); - - if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) break; } @@ -635,6 +635,11 @@ int uv_cwd(char* buffer, size_t* size) { return -errno; *size = strlen(buffer); + if (*size > 1 && buffer[*size - 1] == '/') { + buffer[*size-1] = '\0'; + (*size)--; + } + return 0; } @@ -689,10 +694,13 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { } -static void uv__run_pending(uv_loop_t* loop) { +static int uv__run_pending(uv_loop_t* loop) { QUEUE* q; uv__io_t* w; + if (QUEUE_EMPTY(&loop->pending_queue)) + return 0; + while (!QUEUE_EMPTY(&loop->pending_queue)) { q = QUEUE_HEAD(&loop->pending_queue); QUEUE_REMOVE(q); @@ -701,6 +709,8 @@ static void uv__run_pending(uv_loop_t* loop) { w = QUEUE_DATA(q, uv__io_t, pending_queue); w->cb(loop, w, UV__POLLOUT); } + + return 1; } diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index c9a45edee42520..651545f85ee3d1 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -65,28 +65,33 @@ uint64_t uv__hrtime(uv_clocktype_t type) { int uv_exepath(char* buffer, size_t* size) { - uint32_t usize; - int result; - char* path; - char* fullpath; + /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */ + char abspath[PATH_MAX * 2 + 1]; + char exepath[PATH_MAX + 1]; + uint32_t exepath_size; + size_t abspath_size; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; - usize = *size; - result = _NSGetExecutablePath(buffer, &usize); - if (result) return result; + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return -EIO; - path = malloc(2 * PATH_MAX); - fullpath = realpath(buffer, path); - if (fullpath == NULL) { - SAVE_ERRNO(free(path)); + if (realpath(exepath, abspath) != abspath) return -errno; - } - strncpy(buffer, fullpath, *size); - free(fullpath); - *size = strlen(buffer); + abspath_size = strlen(abspath); + if (abspath_size == 0) + return -EIO; + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index d59e3773a557ca..55492adc4801e6 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -78,7 +78,7 @@ int uv_exepath(char* buffer, size_t* size) { int mib[4]; size_t cb; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; #ifdef __DragonFly__ diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 65fd01230b3e09..e7eee2f9abc4ed 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -35,8 +35,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -48,30 +50,12 @@ 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 #define INIT(type) \ @@ -219,6 +203,9 @@ static ssize_t uv__fs_mkdtemp(uv_fs_t* req) { static ssize_t uv__fs_read(uv_fs_t* req) { +#if defined(__linux__) + static int no_preadv; +#endif ssize_t result; #if defined(_AIX) @@ -245,16 +232,12 @@ static ssize_t uv__fs_read(uv_fs_t* req) { result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) - static int no_preadv; - if (no_preadv) + if (no_preadv) retry: # endif { off_t nread; size_t index; -# if defined(__linux__) - retry: -# endif nread = 0; index = 0; result = 1; @@ -578,6 +561,9 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_write(uv_fs_t* req) { +#if defined(__linux__) + static int no_pwritev; +#endif ssize_t r; /* Serialize writes on OS X, concurrent write() and pwrite() calls result in @@ -603,16 +589,12 @@ static ssize_t uv__fs_write(uv_fs_t* req) { r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) - static int no_pwritev; - if (no_pwritev) + if (no_pwritev) retry: # endif { off_t written; size_t index; -# if defined(__linux__) - retry: -# endif written = 0; index = 0; r = 0; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index daad61b782f17f..03a9226101dd7b 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -52,9 +52,6 @@ # include #endif -#define STATIC_ASSERT(expr) \ - void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) - #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index a2145b0f369eee..d77b13fd6fddb5 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -142,8 +141,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event e; QUEUE* q; uv__io_t* w; - sigset_t* pset; - sigset_t set; + uint64_t sigmask; uint64_t base; uint64_t diff; int nevents; @@ -194,24 +192,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; } - pset = NULL; - if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { - pset = &set; - sigemptyset(pset); - sigaddset(pset, SIGPROF); - } + sigmask = 0; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) + sigmask |= 1 << (SIGPROF - 1); assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { - if (no_epoll_wait || pset != NULL) { + if (no_epoll_wait || sigmask) { nfds = uv__epoll_pwait(loop->backend_fd, events, ARRAY_SIZE(events), timeout, - pset); + sigmask); } else { nfds = uv__epoll_wait(loop->backend_fd, events, @@ -383,10 +378,13 @@ void uv_loadavg(double avg[3]) { int uv_exepath(char* buffer, size_t* size) { ssize_t n; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; - n = readlink("/proc/self/exe", buffer, *size - 1); + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + if (n == -1) return -errno; diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index e036fad5ef6427..7bf2c0f87dbea4 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -321,15 +321,15 @@ int uv__epoll_pwait(int epfd, struct uv__epoll_event* events, int nevents, int timeout, - const sigset_t* sigmask) { + uint64_t sigmask) { #if defined(__NR_epoll_pwait) return syscall(__NR_epoll_pwait, epfd, events, nevents, timeout, - sigmask, - _NSIG / 8); + &sigmask, + sizeof(sigmask)); #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 fd6bb48665fb9c..6f249b72453675 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -131,7 +131,7 @@ int uv__epoll_pwait(int epfd, struct uv__epoll_event* events, int nevents, int timeout, - const sigset_t* sigmask); + uint64_t sigmask); int uv__eventfd2(unsigned int count, int flags); int uv__inotify_init(void); int uv__inotify_init1(int flags); diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index 5f1182f8b43edc..de99d135f7aa60 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -83,7 +83,7 @@ int uv_exepath(char* buffer, size_t* size) { size_t cb; pid_t mypid; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; mypid = getpid(); diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index cde8d4d0c962ad..3e7ae848eec7d2 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -85,7 +85,7 @@ int uv_exepath(char* buffer, size_t* size) { pid_t mypid; int err; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; mypid = getpid(); @@ -108,17 +108,19 @@ int uv_exepath(char* buffer, size_t* size) { } argsbuf_size *= 2U; } + if (argsbuf[0] == NULL) { err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ goto out; } + + *size -= 1; exepath_size = strlen(argsbuf[0]); - if (exepath_size >= *size) { - err = -EINVAL; - goto out; - } - memcpy(buffer, argsbuf[0], exepath_size + 1U); - *size = exepath_size; + if (*size > exepath_size) + *size = exepath_size; + + memcpy(buffer, argsbuf[0], *size); + buffer[*size] = '\0'; err = 0; out: diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index b20fb9210c074b..ef47700b7a1635 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -55,17 +55,15 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = strdup(name); - if (pipe_fname == NULL) { - err = -ENOMEM; - goto out; - } + if (pipe_fname == NULL) + return -ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) - goto out; + goto err_socket; sockfd = err; memset(&saddr, 0, sizeof saddr); @@ -78,7 +76,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == -ENOENT) err = -EACCES; - goto out; + goto err_bind; } /* Success. */ @@ -86,11 +84,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { handle->io_watcher.fd = sockfd; return 0; -out: - /* unlink() before uv__close() to avoid races. */ - assert(pipe_fname != NULL); - unlink(pipe_fname); +err_bind: uv__close(sockfd); + +err_socket: free((void*)pipe_fname); return err; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index d6fb7f49509185..ca183a62279a5e 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -300,11 +300,15 @@ int uv_exepath(char* buffer, size_t* size) { ssize_t res; char buf[128]; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); - res = readlink(buf, buffer, *size - 1); + + res = *size - 1; + if (res > 0) + res = readlink(buf, buffer, res); + if (res == -1) return -errno; diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7ae19905fbffcb..068025eaf59cea 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -98,19 +98,19 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv__nonblock(fd, 1); uv__stream_open((uv_stream_t*) tty, fd, flags); - tty->mode = 0; + tty->mode = UV_TTY_MODE_NORMAL; return 0; } -int uv_tty_set_mode(uv_tty_t* tty, int mode) { - struct termios raw; +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + struct termios tmp; int fd; fd = uv__stream_fd(tty); - if (mode && tty->mode == 0) { /* on */ + if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { if (tcgetattr(fd, &tty->orig_termios)) return -errno; @@ -121,27 +121,30 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { orig_termios_fd = fd; } uv_spinlock_unlock(&termios_spinlock); + } - raw = tty->orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag |= (ONLCR); - raw.c_cflag |= (CS8); - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - raw.c_cc[VMIN] = 1; - raw.c_cc[VTIME] = 0; - - /* Put terminal in raw mode after draining */ - if (tcsetattr(fd, TCSADRAIN, &raw)) - return -errno; - - tty->mode = 1; - } else if (mode == 0 && tty->mode) { /* off */ - /* Put terminal in original mode after flushing */ - if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) - return -errno; - tty->mode = 0; + tmp = tty->orig_termios; + switch (mode) { + case UV_TTY_MODE_NORMAL: + break; + case UV_TTY_MODE_RAW: + tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tmp.c_oflag |= (ONLCR); + tmp.c_cflag |= (CS8); + tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME] = 0; + break; + case UV_TTY_MODE_IO: + cfmakeraw(&tmp); + break; } + /* Apply changes after draining */ + if (tcsetattr(fd, TCSADRAIN, &tmp)) + return -errno; + + tty->mode = mode; return 0; } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 71a0e41f1f743e..2e1824c358ae91 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -598,7 +598,11 @@ int uv_udp_set_membership(uv_udp_t* handle, } -static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { +static int uv__setsockopt_maybe_char(uv_udp_t* handle, + int option4, + int option6, + int val) { + int r; #if defined(__sun) || defined(_AIX) char arg = val; #else @@ -608,7 +612,20 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { if (val < 0 || val > 255) return -EINVAL; - if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, option, &arg, sizeof(arg))) + if (handle->flags & UV_HANDLE_IPV6) + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + option6, + &arg, + sizeof(arg)); + else + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + option4, + &arg, + sizeof(arg)); + + if (r) return -errno; return 0; @@ -632,20 +649,26 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { if (ttl < 1 || ttl > 255) return -EINVAL; - if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) - return -errno; - - return 0; + return uv__setsockopt_maybe_char(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + ttl); } int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { - return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, ttl); + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + ttl); } int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { - return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on); + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + on); } int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 7d3c58f1218501..11e7fc395c43eb 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -46,6 +46,9 @@ #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) +#define STATIC_ASSERT(expr) \ + void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) + #ifndef _WIN32 enum { UV__HANDLE_INTERNAL = 0x8000, diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 48897cf29bc735..2bef8b7f332062 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -387,6 +387,7 @@ int uv_loop_alive(const uv_loop_t* loop) { int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; + int ran_pending; void (*poll)(uv_loop_t* loop, DWORD timeout); if (pGetQueuedCompletionStatusEx) @@ -402,12 +403,12 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv_update_time(loop); uv_process_timers(loop); - uv_process_reqs(loop); + ran_pending = uv_process_reqs(loop); uv_idle_invoke(loop); uv_prepare_invoke(loop); timeout = 0; - if ((mode & UV_RUN_NOWAIT) == 0) + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); (*poll)(loop, timeout); @@ -428,7 +429,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { } r = uv__loop_alive(loop); - if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) break; } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index 2ef1f6c54f2fa7..e5f3407f8eb27e 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -69,17 +69,44 @@ const char* uv_dlerror(const uv_lib_t* lib) { } +static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ + DWORD_PTR args[1] = { (DWORD_PTR) errorno }; + LPSTR fallback_error = "error: %1!d!"; + + FormatMessageA(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + fallback_error, 0, 0, + (LPSTR) &lib->errmsg, + 0, (va_list*) args); +} + + + static int uv__dlerror(uv_lib_t* lib, int errorno) { + DWORD res; + if (lib->errmsg) { LocalFree((void*)lib->errmsg); lib->errmsg = NULL; } if (errorno) { - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - (LPSTR)&lib->errmsg, 0, NULL); + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR) &lib->errmsg, 0, NULL); + if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + 0, (LPSTR) &lib->errmsg, 0, NULL); + } + + if (!res) { + uv__format_fallback_error(lib, errorno); + } } return errorno ? -1 : 0; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 30a457a023b490..33bc9da304054f 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -43,8 +43,6 @@ #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 -static const int uv__fs_dirent_slide = 0x20; - #define QUEUE_FS_TP_JOB(loop, req) \ do { \ @@ -788,123 +786,203 @@ void fs__mkdtemp(uv_fs_t* req) { void fs__scandir(uv_fs_t* req) { - WCHAR* pathw = req->pathw; - size_t len = wcslen(pathw); - int result; - WCHAR* name; - HANDLE dir; - WIN32_FIND_DATAW ent = { 0 }; - WCHAR* path2; - const WCHAR* fmt; - uv__dirent_t** dents; - int dent_size; - - if (len == 0) { - fmt = L"./*"; - } else if (pathw[len - 1] == L'/' || pathw[len - 1] == L'\\') { - fmt = L"%s*"; - } else { - fmt = L"%s\\*"; - } + static const size_t dirents_initial_size = 32; - /* Figure out whether path is a file or a directory. */ - if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) { - req->result = UV_ENOTDIR; - req->sys_errno_ = ERROR_SUCCESS; - return; - } - - path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4)); - if (!path2) { - SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); - return; - } + HANDLE dir_handle = INVALID_HANDLE_VALUE; - _snwprintf(path2, len + 3, fmt, pathw); - dir = FindFirstFileW(path2, &ent); - free(path2); - - if(dir == INVALID_HANDLE_VALUE) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - return; - } - - result = 0; - dents = NULL; - dent_size = 0; - - do { - uv__dirent_t* dent; - int utf8_len; - - name = ent.cFileName; - - if (!(name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2])))) - continue; + uv__dirent_t** dirents = NULL; + size_t dirents_size = 0; + size_t dirents_used = 0; - /* Grow dents buffer, if needed */ - if (result >= dent_size) { - uv__dirent_t** tmp; + IO_STATUS_BLOCK iosb; + NTSTATUS status; - dent_size += uv__fs_dirent_slide; - tmp = realloc(dents, dent_size * sizeof(*dents)); - if (tmp == NULL) { - SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); - goto fatal; + /* Buffer to hold directory entries returned by NtQueryDirectoryFile. + * It's important that this buffer can hold at least one entry, regardless + * of the length of the file names present in the enumerated directory. + * A file name is at most 256 WCHARs long. + * According to MSDN, the buffer must be aligned at an 8-byte boundary. + */ + __declspec(align(8)) char buffer[8192]; + + STATIC_ASSERT(sizeof buffer >= + sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR)); + + /* Open the directory. */ + dir_handle = + CreateFileW(req->pathw, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (dir_handle == INVALID_HANDLE_VALUE) + goto win32_error; + + /* Read the first chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + TRUE); + + /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER. + * This should be reported back as UV_ENOTDIR. + */ + if (status == STATUS_INVALID_PARAMETER) + goto not_a_directory_error; + + while (NT_SUCCESS(status)) { + char* position = buffer; + size_t next_entry_offset = 0; + + do { + FILE_DIRECTORY_INFORMATION* info; + uv__dirent_t* dirent; + + size_t wchar_len; + size_t utf8_len; + + /* Obtain a pointer to the current directory entry. */ + position += next_entry_offset; + info = (FILE_DIRECTORY_INFORMATION*) position; + + /* Fetch the offset to the next directory entry. */ + next_entry_offset = info->NextEntryOffset; + + /* Compute the length of the filename in WCHARs. */ + wchar_len = info->FileNameLength / sizeof info->FileName[0]; + + /* Skip over '.' and '..' entries. */ + if (wchar_len == 1 && info->FileName[0] == L'.') + continue; + if (wchar_len == 2 && info->FileName[0] == L'.' && + info->FileName[1] == L'.') + continue; + + /* Compute the space required to store the filename as UTF-8. */ + utf8_len = WideCharToMultiByte( + CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL); + if (utf8_len == 0) + goto win32_error; + + /* Resize the dirent array if needed. */ + if (dirents_used >= dirents_size) { + size_t new_dirents_size = + dirents_size == 0 ? dirents_initial_size : dirents_size << 1; + uv__dirent_t** new_dirents = + realloc(dirents, new_dirents_size * sizeof *dirents); + + if (new_dirents == NULL) + goto out_of_memory_error; + + dirents_size = new_dirents_size; + dirents = new_dirents; } - dents = tmp; - } - - /* Allocate enough space to fit utf8 encoding of file name */ - len = wcslen(name); - utf8_len = uv_utf16_to_utf8(name, len, NULL, 0); - if (!utf8_len) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - goto fatal; - } - - dent = malloc(sizeof(*dent) + utf8_len + 1); - if (dent == NULL) { - SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); - goto fatal; - } - /* Copy file name */ - utf8_len = uv_utf16_to_utf8(name, len, dent->d_name, utf8_len); - if (!utf8_len) { - free(dent); - SET_REQ_WIN32_ERROR(req, GetLastError()); - goto fatal; - } - dent->d_name[utf8_len] = '\0'; - - /* Copy file type */ - if ((ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) - dent->d_type = UV__DT_DIR; - else if ((ent.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) - dent->d_type = UV__DT_LINK; - else - dent->d_type = UV__DT_FILE; + /* Allocate space for the uv dirent structure. The dirent structure + * includes room for the first character of the filename, but `utf8_len` + * doesn't count the NULL terminator at this point. + */ + dirent = malloc(sizeof *dirent + utf8_len); + if (dirent == NULL) + goto out_of_memory_error; + + dirents[dirents_used++] = dirent; + + /* Convert file name to UTF-8. */ + if (WideCharToMultiByte(CP_UTF8, + 0, + &info->FileName[0], + wchar_len, + &dirent->d_name[0], + utf8_len, + NULL, + NULL) == 0) + goto win32_error; + + /* Add a null terminator to the filename. */ + dirent->d_name[utf8_len] = '\0'; + + /* Fill out the type field. */ + if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) + dirent->d_type = UV__DT_CHAR; + else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + dirent->d_type = UV__DT_LINK; + else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dirent->d_type = UV__DT_DIR; + else + dirent->d_type = UV__DT_FILE; + } while (next_entry_offset != 0); + + /* Read the next chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + FALSE); + + /* After the first pNtQueryDirectoryFile call, the function may return + * STATUS_SUCCESS even if the buffer was too small to hold at least one + * directory entry. + */ + if (status == STATUS_SUCCESS && iosb.Information == 0) + status = STATUS_BUFFER_OVERFLOW; + } - dents[result++] = dent; - } while(FindNextFileW(dir, &ent)); + if (status != STATUS_NO_MORE_FILES) + goto nt_error; - FindClose(dir); + CloseHandle(dir_handle); - if (dents != NULL) + /* Store the result in the request object. */ + req->ptr = dirents; + if (dirents != NULL) req->flags |= UV_FS_FREE_PTR; - /* NOTE: nbufs will be used as index */ + SET_REQ_RESULT(req, dirents_used); + + /* `nbufs` will be used as index by uv_fs_scandir_next. */ req->nbufs = 0; - req->ptr = dents; - SET_REQ_RESULT(req, result); + return; -fatal: - /* Deallocate dents */ - for (result--; result >= 0; result--) - free(dents[result]); - free(dents); +nt_error: + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + goto cleanup; + +win32_error: + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto cleanup; + +not_a_directory_error: + SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + goto cleanup; + +out_of_memory_error: + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto cleanup; + +cleanup: + if (dir_handle != INVALID_HANDLE_VALUE) + CloseHandle(dir_handle); + while (dirents_used > 0) + free(dirents[--dirents_used]); + if (dirents != NULL) + free(dirents); } diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index d87402b73a0952..89290aea3277e0 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -364,8 +364,8 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, int* addr_len, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); -int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, - OVERLAPPED* overlapped); +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped); /* Whether there are any non-IFS LSPs stacked on TCP */ extern int uv_tcp_non_ifs_lsp_ipv4; diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 622cbabe399eb2..578d9fff17fd7a 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -46,6 +46,8 @@ typedef struct uv_single_fd_set_s { static OVERLAPPED overlapped_dummy_; static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT; +static AFD_POLL_INFO afd_poll_info_dummy_; + static void uv__init_overlapped_dummy(void) { HANDLE event; @@ -65,6 +67,11 @@ static OVERLAPPED* uv__get_overlapped_dummy() { } +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() { + return &afd_poll_info_dummy_; +} + + static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { uv_req_t* req; AFD_POLL_INFO* afd_poll_info; @@ -79,7 +86,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_2 = handle->events; } else if (handle->submitted_events_2 == 0) { req = &handle->poll_req_2; - afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0]; + afd_poll_info = &handle->afd_poll_info_2; handle->submitted_events_2 = handle->events; handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; @@ -108,6 +115,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { memset(&req->overlapped, 0, sizeof req->overlapped); result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, afd_poll_info, &req->overlapped); if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { @@ -119,26 +127,25 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { - AFD_POLL_INFO* afd_poll_info; + AFD_POLL_INFO afd_poll_info; DWORD result; - afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[1]; - afd_poll_info->Exclusive = TRUE; - afd_poll_info->NumberOfHandles = 1; - afd_poll_info->Timeout.QuadPart = INT64_MAX; - afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; - afd_poll_info->Handles[0].Status = 0; - afd_poll_info->Handles[0].Events = AFD_POLL_ALL; + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; result = uv_msafd_poll(handle->socket, - afd_poll_info, + &afd_poll_info, + uv__get_afd_poll_info_dummy(), uv__get_overlapped_dummy()); if (result == SOCKET_ERROR) { DWORD error = WSAGetLastError(); - if (error != WSA_IO_PENDING) { - return WSAGetLastError(); - } + if (error != WSA_IO_PENDING) + return error; } return 0; @@ -155,7 +162,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, handle->submitted_events_1 = 0; mask_events = handle->mask_events_1; } else if (req == &handle->poll_req_2) { - afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0]; + afd_poll_info = &handle->afd_poll_info_2; handle->submitted_events_2 = 0; mask_events = handle->mask_events_2; } else { @@ -558,11 +565,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, handle->poll_req_2.type = UV_POLL_REQ; handle->poll_req_2.data = handle; - handle->afd_poll_info_2.afd_poll_info_ptr = malloc(sizeof(*handle->afd_poll_info_2.afd_poll_info_ptr) * 2); - if (handle->afd_poll_info_2.afd_poll_info_ptr == NULL) { - return UV_ENOMEM; - } - return 0; } @@ -624,9 +626,5 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { assert(handle->submitted_events_1 == 0); assert(handle->submitted_events_2 == 0); - if (handle->afd_poll_info_2.afd_poll_info_ptr) { - free(handle->afd_poll_info_2.afd_poll_info_ptr); - handle->afd_poll_info_2.afd_poll_info_ptr = NULL; - } uv__handle_close(handle); } diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h index 97342e5c7e0017..46c7d9b106a869 100644 --- a/deps/uv/src/win/req-inl.h +++ b/deps/uv/src/win/req-inl.h @@ -130,14 +130,13 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { } while (0) -INLINE static void uv_process_reqs(uv_loop_t* loop) { +INLINE static int uv_process_reqs(uv_loop_t* loop) { uv_req_t* req; uv_req_t* first; uv_req_t* next; - if (loop->pending_reqs_tail == NULL) { - return; - } + if (loop->pending_reqs_tail == NULL) + return 0; first = loop->pending_reqs_tail->next_req; next = first; @@ -207,6 +206,8 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) { assert(0); } } + + return 1; } #endif /* UV_WIN_REQ_INL_H_ */ diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index a697d7ae74456b..993d66162c40fa 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -117,7 +117,19 @@ void uv_once(uv_once_t* guard, void (*callback)(void)) { uv__once_inner(guard, callback); } -static UV_THREAD_LOCAL uv_thread_t uv__current_thread = NULL; + +/* Verify that uv_thread_t can be stored in a TLS slot. */ +STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); + +static uv_key_t uv__current_thread_key; +static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; + + +static void uv__init_current_thread_key(void) { + if (uv_key_create(&uv__current_thread_key)) + abort(); +} + struct thread_ctx { void (*entry)(void* arg); @@ -126,8 +138,7 @@ struct thread_ctx { }; -static UINT __stdcall uv__thread_start(void* arg) -{ +static UINT __stdcall uv__thread_start(void* arg) { struct thread_ctx *ctx_p; struct thread_ctx ctx; @@ -135,7 +146,9 @@ static UINT __stdcall uv__thread_start(void* arg) ctx = *ctx_p; free(ctx_p); - uv__current_thread = ctx.self; + uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); + uv_key_set(&uv__current_thread_key, (void*) ctx.self); + ctx.entry(ctx.arg); return 0; @@ -177,9 +190,10 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { uv_thread_t uv_thread_self(void) { - return uv__current_thread; + return (uv_thread_t) uv_key_get(&uv__current_thread_key); } + int uv_thread_join(uv_thread_t *tid) { if (WaitForSingleObject(*tid, INFINITE)) return uv_translate_sys_error(GetLastError()); diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 6d6709f79e1170..be4a8b81e40de2 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -170,7 +170,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { } -int uv_tty_set_mode(uv_tty_t* tty, int mode) { +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; unsigned char was_reading; uv_alloc_cb alloc_cb; @@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { return 0; } - if (mode) { - /* Raw input */ - flags = ENABLE_WINDOW_INPUT; - } else { - /* Line-buffered mode. */ - flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + switch (mode) { + case UV_TTY_MODE_NORMAL: + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_RAW: + flags = ENABLE_WINDOW_INPUT; + break; + case UV_TTY_MODE_IO: + return UV_ENOTSUP; } if (!SetConsoleMode(tty->handle, flags)) { diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 84ce73e3a023b6..f3f27f77c15a4e 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -31,6 +31,7 @@ sNtDeviceIoControlFile pNtDeviceIoControlFile; sNtQueryInformationFile pNtQueryInformationFile; sNtSetInformationFile pNtSetInformationFile; sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; @@ -97,6 +98,12 @@ void uv_winapi_init() { uv_fatal_error(GetLastError(), "GetProcAddress"); } + pNtQueryDirectoryFile = (sNtQueryDirectoryFile) + GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( ntdll_module, "NtQuerySystemInformation"); diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 1bb0e9aae1eed9..f4f9145b388f00 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4104,12 +4104,23 @@ # define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 #endif +/* from winternl.h */ +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef const UNICODE_STRING *PCUNICODE_STRING; + +/* from ntifs.h */ #ifndef DEVICE_TYPE # define DEVICE_TYPE DWORD #endif -/* from ntifs.h */ -/* MinGW already has it, mingw-w64 does not. */ +/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does + * not. + */ #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; @@ -4205,6 +4216,37 @@ typedef enum _FILE_INFORMATION_CLASS { FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + typedef struct _FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; @@ -4512,6 +4554,19 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) ULONG SystemInformationLength, PULONG ReturnLength); +typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, + BOOLEAN RestartScan + ); /* * Kernel32 headers @@ -4555,6 +4610,30 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) # define ERROR_SYMLINK_NOT_SUPPORTED 1464 #endif +#ifndef ERROR_MUI_FILE_NOT_FOUND +# define ERROR_MUI_FILE_NOT_FOUND 15100 +#endif + +#ifndef ERROR_MUI_INVALID_FILE +# define ERROR_MUI_INVALID_FILE 15101 +#endif + +#ifndef ERROR_MUI_INVALID_RC_CONFIG +# define ERROR_MUI_INVALID_RC_CONFIG 15102 +#endif + +#ifndef ERROR_MUI_INVALID_LOCALE_NAME +# define ERROR_MUI_INVALID_LOCALE_NAME 15103 +#endif + +#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME +# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104 +#endif + +#ifndef ERROR_MUI_FILE_NOT_LOADED +# define ERROR_MUI_FILE_NOT_LOADED 15105 +#endif + typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) (HANDLE CompletionPort, LPOVERLAPPED_ENTRY lpCompletionPortEntries, @@ -4626,6 +4705,7 @@ extern sNtDeviceIoControlFile pNtDeviceIoControlFile; extern sNtQueryInformationFile pNtQueryInformationFile; extern sNtSetInformationFile pNtSetInformationFile; extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 3711ee9cb6735a..d2e667e9f7546a 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -474,8 +474,8 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, } -int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, - OVERLAPPED* overlapped) { +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK* iosb_ptr; HANDLE event = NULL; @@ -513,10 +513,10 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, apc_context, iosb_ptr, IOCTL_AFD_POLL, - info, - sizeof *info, - info, - sizeof *info); + info_in, + sizeof *info_in, + info_out, + sizeof *info_out); if (overlapped == NULL) { /* If this is a blocking operation, wait for the event to become */ diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 1f12c6f12d91b0..5da720fad43a9d 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -68,6 +68,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) { const char* arg; char* args[16]; int n; + pid_t pid; stdout_file = tmpfile(); if (!stdout_file) { @@ -78,7 +79,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) { p->terminated = 0; p->status = 0; - pid_t pid = fork(); + pid = fork(); if (pid < 0) { perror("fork"); @@ -167,8 +168,14 @@ static void* dowait(void* data) { /* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ int process_wait(process_info_t* vec, int n, int timeout) { int i; + int r; + int retval; process_info_t* p; dowait_args args; + pthread_t tid; + struct timeval tv; + fd_set fds; + args.vec = vec; args.n = n; args.pipe[0] = -1; @@ -186,10 +193,7 @@ int process_wait(process_info_t* vec, int n, int timeout) { * we'd need to lock vec. */ - pthread_t tid; - int retval; - - int r = pipe((int*)&(args.pipe)); + r = pipe((int*)&(args.pipe)); if (r) { perror("pipe()"); return -1; @@ -202,11 +206,9 @@ int process_wait(process_info_t* vec, int n, int timeout) { goto terminate; } - struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = 0; - fd_set fds; FD_ZERO(&fds); FD_SET(args.pipe[0], &fds); @@ -259,15 +261,16 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t *p, int fd) { - int r = fseek(p->stdout_file, 0, SEEK_SET); + ssize_t nwritten; + char buf[1024]; + int r; + + r = fseek(p->stdout_file, 0, SEEK_SET); if (r < 0) { perror("fseek"); return -1; } - ssize_t nwritten; - char buf[1024]; - /* TODO: what if the line is longer than buf */ while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) { /* TODO: what if write doesn't write the whole buffer... */ diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index e890c77fe177d5..07584c52996f8c 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -39,6 +39,11 @@ # include /* setrlimit() */ #endif +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +#endif + #define TEST_PORT 9123 #define TEST_PORT_2 9124 @@ -229,4 +234,21 @@ UNUSED static void close_loop(uv_loop_t* loop) { uv_run(loop, UV_RUN_DEFAULT); } +UNUSED static int can_ipv6(void) { + uv_interface_address_t* addr; + int supported; + int count; + int i; + + if (uv_interface_addresses(&addr, &count)) + return 1; /* Assume IPv6 support on failure. */ + + supported = 0; + for (i = 0; supported == 0 && i < count; i += 1) + supported = (AF_INET6 == addr[i].address.address6.sin6_family); + + uv_free_interface_addresses(addr, count); + return supported; +} + #endif /* TASK_H_ */ diff --git a/deps/uv/test/test-cwd-and-chdir.c b/deps/uv/test/test-cwd-and-chdir.c index 6f6173192dbb3c..1e95043c1775a9 100644 --- a/deps/uv/test/test-cwd-and-chdir.c +++ b/deps/uv/test/test-cwd-and-chdir.c @@ -29,35 +29,22 @@ extern char executable_path[]; TEST_IMPL(cwd_and_chdir) { char buffer_orig[PATHMAX]; char buffer_new[PATHMAX]; - size_t size; - char* last_slash; + size_t size1; + size_t size2; int err; - size = sizeof(buffer_orig); - err = uv_cwd(buffer_orig, &size); + size1 = sizeof buffer_orig; + err = uv_cwd(buffer_orig, &size1); ASSERT(err == 0); - /* Remove trailing slash unless at a root directory. */ -#ifdef _WIN32 - last_slash = strrchr(buffer_orig, '\\'); - ASSERT(last_slash); - if (last_slash > buffer_orig && *(last_slash - 1) != ':') { - *last_slash = '\0'; - } -#else /* Unix */ - last_slash = strrchr(buffer_orig, '/'); - ASSERT(last_slash); - if (last_slash != buffer_orig) { - *last_slash = '\0'; - } -#endif - err = uv_chdir(buffer_orig); ASSERT(err == 0); - err = uv_cwd(buffer_new, &size); + size2 = sizeof buffer_new; + err = uv_cwd(buffer_new, &size2); ASSERT(err == 0); + ASSERT(size1 == size2); ASSERT(strcmp(buffer_orig, buffer_new) == 0); return 0; diff --git a/deps/uv/test/test-dlerror.c b/deps/uv/test/test-dlerror.c index 877ebf3712a213..091200edbed591 100644 --- a/deps/uv/test/test-dlerror.c +++ b/deps/uv/test/test-dlerror.c @@ -26,31 +26,28 @@ TEST_IMPL(dlerror) { const char* path = "test/fixtures/load_error.node"; + const char* dlerror_no_error = "no error"; const char* msg; uv_lib_t lib; int r; -#ifdef __linux__ - const char* dlerror_desc = "file too short"; -#elif defined (__sun__) - const char* dlerror_desc = "unknown file type"; -#elif defined (_WIN32) - const char* dlerror_desc = "%1 is not a valid Win32 application"; -#else - const char* dlerror_desc = ""; -#endif + lib.errmsg = NULL; + lib.handle = NULL; + msg = uv_dlerror(&lib); + ASSERT(msg != NULL); + ASSERT(strstr(msg, dlerror_no_error) != NULL); r = uv_dlopen(path, &lib); ASSERT(r == -1); msg = uv_dlerror(&lib); ASSERT(msg != NULL); - ASSERT(strstr(msg, dlerror_desc) != NULL); + ASSERT(strstr(msg, dlerror_no_error) == NULL); /* Should return the same error twice in a row. */ msg = uv_dlerror(&lib); ASSERT(msg != NULL); - ASSERT(strstr(msg, dlerror_desc) != NULL); + ASSERT(strstr(msg, dlerror_no_error) == NULL); uv_dlclose(&lib); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 471860a76c4c0e..2c392251f03ce5 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -568,7 +568,17 @@ TEST_IMPL(fs_file_loop) { loop = uv_default_loop(); unlink("test_symlink"); - uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL); + r = uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP. + * Starting with vista they are supported, but only when elevated, otherwise + * we'll see UV_EPERM. + */ + if (r == UV_ENOTSUP || r == UV_EPERM) + return 0; +#endif + ASSERT(r == 0); uv_fs_req_cleanup(&req); r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL); diff --git a/deps/uv/test/test-get-currentexe.c b/deps/uv/test/test-get-currentexe.c index be578db75d48bf..0e9d6965402daf 100644 --- a/deps/uv/test/test-get-currentexe.c +++ b/deps/uv/test/test-get-currentexe.c @@ -61,5 +61,26 @@ TEST_IMPL(get_currentexe) { r = uv_exepath(buffer, NULL); ASSERT(r == UV_EINVAL); + size = 0; + r = uv_exepath(buffer, &size); + ASSERT(r == UV_EINVAL); + + memset(buffer, -1, sizeof(buffer)); + + size = 1; + r = uv_exepath(buffer, &size); + ASSERT(r == 0); + ASSERT(size == 0); + ASSERT(buffer[0] == '\0'); + + memset(buffer, -1, sizeof(buffer)); + + size = 2; + r = uv_exepath(buffer, &size); + ASSERT(r == 0); + ASSERT(size == 1); + ASSERT(buffer[0] != '\0'); + ASSERT(buffer[1] == '\0'); + return 0; } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 85ddac82ae123a..eb78a43cc79787 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -29,6 +29,7 @@ TEST_DECLARE (loop_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) +TEST_DECLARE (loop_configure) TEST_DECLARE (default_loop_close) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) @@ -103,6 +104,7 @@ TEST_DECLARE (udp_dgram_too_big) TEST_DECLARE (udp_dual_stack) TEST_DECLARE (udp_ipv6_only) TEST_DECLARE (udp_options) +TEST_DECLARE (udp_options6) TEST_DECLARE (udp_no_autobind) TEST_DECLARE (udp_open) TEST_DECLARE (udp_try_send) @@ -269,6 +271,7 @@ TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) #ifdef _WIN32 +TEST_DECLARE (poll_close_doesnt_corrupt_stack) TEST_DECLARE (poll_closesocket) TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -312,6 +315,7 @@ TASK_LIST_START TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) + TEST_ENTRY (loop_configure) TEST_ENTRY (default_loop_close) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) @@ -410,6 +414,7 @@ TASK_LIST_START TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_ipv6_only) TEST_ENTRY (udp_options) + TEST_ENTRY (udp_options6) TEST_ENTRY (udp_no_autobind) TEST_ENTRY (udp_multicast_interface) TEST_ENTRY (udp_multicast_interface6) @@ -558,6 +563,7 @@ TASK_LIST_START TEST_ENTRY (kill) #ifdef _WIN32 + TEST_ENTRY (poll_close_doesnt_corrupt_stack) TEST_ENTRY (poll_closesocket) TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) diff --git a/deps/uv/test/test-loop-configure.c b/deps/uv/test/test-loop-configure.c new file mode 100644 index 00000000000000..d057c1ed8a7bf8 --- /dev/null +++ b/deps/uv/test/test-loop-configure.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2014, 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. + */ + +#include "uv.h" +#include "task.h" + +static void timer_cb(uv_timer_t* handle) { + uv_close((uv_handle_t*) handle, NULL); +} + + +TEST_IMPL(loop_configure) { + uv_timer_t timer_handle; + uv_loop_t loop; + ASSERT(0 == uv_loop_init(&loop)); +#ifdef _WIN32 + ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0)); +#else + ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF)); +#endif + ASSERT(0 == uv_timer_init(&loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0)); + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_loop_close(&loop)); + return 0; +} diff --git a/deps/uv/test/test-osx-select.c b/deps/uv/test/test-osx-select.c index 49b1bb8229aeb8..ef551eaf2fcc8d 100644 --- a/deps/uv/test/test-osx-select.c +++ b/deps/uv/test/test-osx-select.c @@ -90,7 +90,7 @@ TEST_IMPL(osx_select_many_fds) { uv_tty_t tty; uv_tcp_t tcps[1500]; - TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 2); + TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100); r = uv_ip4_addr("127.0.0.1", 0, &addr); ASSERT(r == 0); diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index 81941ab83db3b6..c074178541b0a3 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -246,6 +246,9 @@ TEST_IMPL(tcp_ping_pong) { TEST_IMPL(tcp_ping_pong_v6) { + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + tcp_pinger_v6_new(); uv_run(uv_default_loop(), UV_RUN_DEFAULT); diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c index 3064babf98c05f..ee8bb2a9a8bc38 100644 --- a/deps/uv/test/test-pipe-close-stdout-read-stdin.c +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { int pid; int fd[2]; int status; + uv_pipe_t stdin_pipe; r = pipe(fd); ASSERT(r == 0); @@ -68,8 +69,6 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { ASSERT(r != -1); /* Create a stream that reads from the pipe. */ - uv_pipe_t stdin_pipe; - r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0); ASSERT(r == 0); diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 931311985bbdf7..dc6fa32b0d115f 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -27,6 +27,7 @@ TEST_IMPL(platform_output) { char buffer[512]; size_t rss; + size_t size; double uptime; uv_rusage_t rusage; uv_cpu_info_t* cpus; @@ -39,6 +40,11 @@ TEST_IMPL(platform_output) { ASSERT(err == 0); printf("uv_get_process_title: %s\n", buffer); + size = sizeof(buffer); + err = uv_cwd(buffer, &size); + ASSERT(err == 0); + printf("uv_cwd: %s\n", buffer); + err = uv_resident_set_memory(&rss); ASSERT(err == 0); printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); diff --git a/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c b/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c new file mode 100644 index 00000000000000..fc2cc004f16ae7 --- /dev/null +++ b/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c @@ -0,0 +1,114 @@ +/* Copyright Bert Belder, and other libuv 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. + */ + +#ifdef _WIN32 + +#include +#include + +#include "uv.h" +#include "task.h" + +#ifdef _MSC_VER /* msvc */ +# define NO_INLINE __declspec(noinline) +#else /* gcc */ +# define NO_INLINE __attribute__ ((noinline)) +#endif + + +uv_os_sock_t sock; +uv_poll_t handle; + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* h) { + close_cb_called++; +} + + +static void poll_cb(uv_poll_t* h, int status, int events) { + ASSERT(0 && "should never get here"); +} + + +static void NO_INLINE close_socket_and_verify_stack() { + const uint32_t MARKER = 0xDEADBEEF; + const int VERIFY_AFTER = 10; /* ms */ + int r; + + volatile uint32_t data[65536]; + size_t i; + + for (i = 0; i < ARRAY_SIZE(data); i++) + data[i] = MARKER; + + r = closesocket(sock); + ASSERT(r == 0); + + uv_sleep(VERIFY_AFTER); + + for (i = 0; i < ARRAY_SIZE(data); i++) + ASSERT(data[i] == MARKER); +} + + +TEST_IMPL(poll_close_doesnt_corrupt_stack) { + struct WSAData wsa_data; + int r; + unsigned long on; + struct sockaddr_in addr; + + r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); + + sock = socket(AF_INET, SOCK_STREAM, 0); + ASSERT(sock != INVALID_SOCKET); + on = 1; + r = ioctlsocket(sock, FIONBIO, &on); + ASSERT(r == 0); + + r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr); + ASSERT(r == 0); + + r = connect(sock, (const struct sockaddr*) &addr, sizeof addr); + ASSERT(r != 0); + ASSERT(WSAGetLastError() == WSAEWOULDBLOCK); + + r = uv_poll_init_socket(uv_default_loop(), &handle, sock); + ASSERT(r == 0); + r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &handle, close_cb); + + close_socket_and_verify_stack(); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* _WIN32 */ diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 11f43bdf1341a7..5c25f81926b6e6 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1032,6 +1032,7 @@ TEST_IMPL(spawn_with_an_odd_path) { #ifndef _WIN32 TEST_IMPL(spawn_setuid_setgid) { int r; + struct passwd* pw; /* if not root, then this will fail. */ uv_uid_t uid = getuid(); @@ -1043,7 +1044,6 @@ TEST_IMPL(spawn_setuid_setgid) { init_process_options("spawn_helper1", exit_cb); /* become the "nobody" user. */ - struct passwd* pw; pw = getpwnam("nobody"); ASSERT(pw != NULL); options.uid = pw->pw_uid; @@ -1051,6 +1051,9 @@ TEST_IMPL(spawn_setuid_setgid) { options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID; r = uv_spawn(uv_default_loop(), &process, &options); + if (r == UV_EACCES) + RETURN_SKIP("user 'nobody' cannot access the test runner"); + ASSERT(r == 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -1297,7 +1300,16 @@ TEST_IMPL(spawn_reads_child_path) { int len; char file[64]; char path[1024]; - char *env[2] = {path, NULL}; + char* env[3]; + + /* Need to carry over the dynamic linker path when the test runner is + * linked against libuv.so, see https://github.com/libuv/libuv/issues/85. + */ +#if defined(__APPLE__) + static const char dyld_path_var[] = "DYLD_LIBRARY_PATH"; +#else + static const char dyld_path_var[] = "LD_LIBRARY_PATH"; +#endif /* Set up the process, but make sure that the file to run is relative and */ /* requires a lookup into PATH */ @@ -1312,6 +1324,16 @@ TEST_IMPL(spawn_reads_child_path) { strcpy(path, "PATH="); strcpy(path + 5, exepath); + env[0] = path; + env[1] = getenv(dyld_path_var); + env[2] = NULL; + + if (env[1] != NULL) { + static char buf[1024 + sizeof(dyld_path_var)]; + snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]); + env[1] = buf; + } + options.file = file; options.args[0] = file; options.env = env; diff --git a/deps/uv/test/test-tcp-bind6-error.c b/deps/uv/test/test-tcp-bind6-error.c index 1d65f3de3e6eec..b762bcb3d1b8d0 100644 --- a/deps/uv/test/test-tcp-bind6-error.c +++ b/deps/uv/test/test-tcp-bind6-error.c @@ -39,6 +39,9 @@ TEST_IMPL(tcp_bind6_error_addrinuse) { uv_tcp_t server1, server2; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server1); @@ -73,6 +76,9 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) { uv_tcp_t server; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); @@ -98,6 +104,9 @@ TEST_IMPL(tcp_bind6_error_fault) { uv_tcp_t server; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + garbage_addr = (struct sockaddr_in6*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); @@ -123,6 +132,9 @@ TEST_IMPL(tcp_bind6_error_inval) { uv_tcp_t server; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1)); ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2)); @@ -149,6 +161,9 @@ TEST_IMPL(tcp_bind6_localhost_ok) { uv_tcp_t server; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 0ca9f4dcff6a6e..1d5720ce73162a 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -147,23 +147,22 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { TEST_IMPL(udp_dual_stack) { -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) - RETURN_SKIP("dual stack not enabled by default in this OS."); -#else + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + do_test(ipv6_recv_ok, 0); ASSERT(recv_cb_called == 1); ASSERT(send_cb_called == 1); return 0; -#endif } TEST_IMPL(udp_ipv6_only) { + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY); ASSERT(recv_cb_called == 0); diff --git a/deps/uv/test/test-udp-multicast-interface6.c b/deps/uv/test/test-udp-multicast-interface6.c index e54e738b0be301..d3881e83bb1565 100644 --- a/deps/uv/test/test-udp-multicast-interface6.c +++ b/deps/uv/test/test-udp-multicast-interface6.c @@ -60,6 +60,9 @@ TEST_IMPL(udp_multicast_interface6) { struct sockaddr_in6 addr; struct sockaddr_in6 baddr; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index babf61e2bf7dc3..9ba201ab9eba98 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -103,6 +103,9 @@ TEST_IMPL(udp_multicast_join6) { uv_buf_t buf; struct sockaddr_in6 addr; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); diff --git a/deps/uv/test/test-udp-options.c b/deps/uv/test/test-udp-options.c index 19c45c2e31976d..0da1786f506fc4 100644 --- a/deps/uv/test/test-udp-options.c +++ b/deps/uv/test/test-udp-options.c @@ -27,15 +27,12 @@ #include -TEST_IMPL(udp_options) { +static int udp_options_test(const struct sockaddr* addr) { static int invalid_ttls[] = { -1, 0, 256 }; - struct sockaddr_in addr; uv_loop_t* loop; uv_udp_t h; int i, r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - loop = uv_default_loop(); r = uv_udp_init(loop, &h); @@ -43,7 +40,7 @@ TEST_IMPL(udp_options) { uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */ - r = uv_udp_bind(&h, (const struct sockaddr*) &addr, 0); + r = uv_udp_bind(&h, addr, 0); ASSERT(r == 0); r = uv_udp_set_broadcast(&h, 1); @@ -88,6 +85,25 @@ TEST_IMPL(udp_options) { } +TEST_IMPL(udp_options) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + return udp_options_test((const struct sockaddr*) &addr); +} + + +TEST_IMPL(udp_options6) { + struct sockaddr_in6 addr; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); + return udp_options_test((const struct sockaddr*) &addr); +} + + TEST_IMPL(udp_no_autobind) { uv_loop_t* loop; uv_udp_t h; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index a5ba14c315a14a..45af6a1f96aa63 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -17,28 +17,8 @@ }], ], 'xcode_settings': { - 'conditions': [ - [ 'clang==1', { - 'WARNING_CFLAGS': [ - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - '-Wno-dollar-in-identifier-extension' - ]}, { - 'WARNING_CFLAGS': [ - '-Wall', - '-Wextra', - '-Wno-unused-parameter' - ]} - ] - ], - 'OTHER_LDFLAGS': [ - ], - 'OTHER_CFLAGS': [ - '-g', - '--std=gnu89', - '-pedantic' - ], + 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], } }, @@ -335,6 +315,7 @@ 'test/test-loop-close.c', 'test/test-loop-stop.c', 'test/test-loop-time.c', + 'test/test-loop-configure.c', 'test/test-walk-handles.c', 'test/test-watcher-cross-stop.c', 'test/test-multiple-listen.c', @@ -350,6 +331,7 @@ 'test/test-platform-output.c', 'test/test-poll.c', 'test/test-poll-close.c', + 'test/test-poll-close-doesnt-corrupt-stack.c', 'test/test-poll-closesocket.c', 'test/test-process-title.c', 'test/test-ref.c', From 52e600a9c8655f578fae55d85e778b58d731201a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 29 Dec 2014 17:35:51 +0100 Subject: [PATCH 22/22] test: don't assume broadcast traffic is unfiltered parallel/test-dgram-broadcast-multi-process assumes non-local broadcast traffic is unfiltered, an assumption that fails with, for example, the default Fedora firewall rules. Use a loopback interface instead. Fixes: https://github.com/iojs/io.js/issues/219 PR-URL: https://github.com/iojs/io.js/pull/220 Reviewed-By: Fedor Indutny --- .../test-dgram-broadcast-multi-process.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/test/parallel/test-dgram-broadcast-multi-process.js b/test/parallel/test-dgram-broadcast-multi-process.js index 4d9eebc1012de7..b05abd8d4fb589 100644 --- a/test/parallel/test-dgram-broadcast-multi-process.js +++ b/test/parallel/test-dgram-broadcast-multi-process.js @@ -23,7 +23,6 @@ var common = require('../common'), assert = require('assert'), dgram = require('dgram'), util = require('util'), - networkInterfaces = require('os').networkInterfaces(), Buffer = require('buffer').Buffer, fork = require('child_process').fork, LOCAL_BROADCAST_HOST = '255.255.255.255', @@ -35,19 +34,6 @@ var common = require('../common'), new Buffer('Fourth message to send') ]; -// take the first non-internal interface as the address for binding -get_bindAddress: for (var name in networkInterfaces) { - var interfaces = networkInterfaces[name]; - for(var i = 0; i < interfaces.length; i++) { - var localInterface = interfaces[i]; - if (!localInterface.internal && localInterface.family === 'IPv4') { - var bindAddress = localInterface.address; - break get_bindAddress; - } - } -} -assert.ok(bindAddress); - if (process.argv[2] !== 'child') { var workers = {}, listeners = 3, @@ -164,7 +150,7 @@ if (process.argv[2] !== 'child') { // bind the address explicitly for sending // INADDR_BROADCAST to only one interface - sendSocket.bind(common.PORT, bindAddress); + sendSocket.bind(common.PORT, '127.0.0.1'); sendSocket.on('listening', function () { sendSocket.setBroadcast(true); }); @@ -211,7 +197,7 @@ if (process.argv[2] === 'child') { listenSocket.on('message', function(buf, rinfo) { // receive udp messages only sent from parent - if (rinfo.address !== bindAddress) return; + if (rinfo.address !== '127.0.0.1') return; console.error('[CHILD] %s received %s from %j', process.pid,