summaryrefslogtreecommitdiff
path: root/deps/uv
diff options
context:
space:
mode:
authorSaúl Ibarra Corretgé <saghul@gmail.com>2015-12-13 12:07:04 +0100
committerSaúl Ibarra Corretgé <saghul@gmail.com>2015-12-14 21:53:42 +0100
commit69b94ec55cb0f8bd90475b5b7dabd57beb7e7dfe (patch)
treed2afb35396d77e45647e1818357a7e17b2be2244 /deps/uv
parente0bb118a1d5f8b6b1eb2405f2dc19b8118f8ec0e (diff)
downloadandroid-node-v8-69b94ec55cb0f8bd90475b5b7dabd57beb7e7dfe.tar.gz
android-node-v8-69b94ec55cb0f8bd90475b5b7dabd57beb7e7dfe.tar.bz2
android-node-v8-69b94ec55cb0f8bd90475b5b7dabd57beb7e7dfe.zip
deps: upgrade libuv to 1.8.0
Fixes: https://github.com/nodejs/node/issues/3718 PR-URL: https://github.com/nodejs/node/pull/4276 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'deps/uv')
-rw-r--r--deps/uv/AUTHORS15
-rw-r--r--deps/uv/ChangeLog99
-rw-r--r--deps/uv/Makefile.am1
-rw-r--r--deps/uv/README.md2
-rw-r--r--deps/uv/appveyor.yml2
-rw-r--r--deps/uv/common.gypi1
-rw-r--r--deps/uv/configure.ac2
-rw-r--r--deps/uv/docs/src/fs.rst10
-rw-r--r--deps/uv/docs/src/misc.rst38
-rw-r--r--deps/uv/docs/src/tcp.rst2
-rwxr-xr-xdeps/uv/gyp_uv.py3
-rw-r--r--deps/uv/include/uv-version.h4
-rw-r--r--deps/uv/include/uv.h14
-rw-r--r--deps/uv/src/inet.c4
-rw-r--r--deps/uv/src/queue.h14
-rw-r--r--deps/uv/src/threadpool.c7
-rw-r--r--deps/uv/src/unix/android-ifaddrs.c2
-rw-r--r--deps/uv/src/unix/async.c8
-rw-r--r--deps/uv/src/unix/atomic-ops.h5
-rw-r--r--deps/uv/src/unix/core.c39
-rw-r--r--deps/uv/src/unix/darwin.c4
-rw-r--r--deps/uv/src/unix/dl.c9
-rw-r--r--deps/uv/src/unix/freebsd.c6
-rw-r--r--deps/uv/src/unix/fs.c83
-rw-r--r--deps/uv/src/unix/fsevents.c43
-rw-r--r--deps/uv/src/unix/linux-core.c4
-rw-r--r--deps/uv/src/unix/linux-inotify.c42
-rw-r--r--deps/uv/src/unix/linux-syscalls.c8
-rw-r--r--deps/uv/src/unix/linux-syscalls.h4
-rw-r--r--deps/uv/src/unix/loop-watcher.c7
-rw-r--r--deps/uv/src/unix/netbsd.c4
-rw-r--r--deps/uv/src/unix/openbsd.c6
-rw-r--r--deps/uv/src/unix/process.c11
-rw-r--r--deps/uv/src/unix/signal.c2
-rw-r--r--deps/uv/src/unix/stream.c4
-rw-r--r--deps/uv/src/unix/sunos.c4
-rw-r--r--deps/uv/src/unix/tty.c9
-rw-r--r--deps/uv/src/unix/udp.c4
-rw-r--r--deps/uv/src/uv-common.c27
-rw-r--r--deps/uv/src/uv-common.h4
-rw-r--r--deps/uv/src/win/error.c1
-rw-r--r--deps/uv/src/win/fs-event.c23
-rw-r--r--deps/uv/src/win/fs.c215
-rw-r--r--deps/uv/src/win/getaddrinfo.c13
-rw-r--r--deps/uv/src/win/internal.h1
-rw-r--r--deps/uv/src/win/pipe.c8
-rw-r--r--deps/uv/src/win/snprintf.c42
-rw-r--r--deps/uv/src/win/tty.c2
-rw-r--r--deps/uv/src/win/util.c12
-rw-r--r--deps/uv/src/win/winapi.c4
-rw-r--r--deps/uv/src/win/winapi.h7
-rw-r--r--deps/uv/test/runner-win.h10
-rw-r--r--deps/uv/test/runner.c2
-rw-r--r--deps/uv/test/task.h38
-rw-r--r--deps/uv/test/test-emfile.c15
-rw-r--r--deps/uv/test/test-fs-event.c28
-rw-r--r--deps/uv/test/test-fs.c142
-rw-r--r--deps/uv/test/test-get-loadavg.c3
-rw-r--r--deps/uv/test/test-getaddrinfo.c6
-rw-r--r--deps/uv/test/test-getnameinfo.c4
-rw-r--r--deps/uv/test/test-ipc-send-recv.c291
-rw-r--r--deps/uv/test/test-list.h10
-rw-r--r--deps/uv/test/test-mutexes.c104
-rw-r--r--deps/uv/test/test-process-title.c2
-rw-r--r--deps/uv/test/test-queue-foreach-delete.c200
-rw-r--r--deps/uv/test/test-spawn.c10
-rw-r--r--deps/uv/test/test-tcp-try-write.c5
-rw-r--r--deps/uv/test/test-tcp-write-fail.c2
-rw-r--r--deps/uv/test/test-threadpool-cancel.c3
-rw-r--r--deps/uv/test/test-tty.c3
-rw-r--r--deps/uv/test/test-udp-ipv6.c21
-rw-r--r--deps/uv/test/test-udp-multicast-join6.c2
-rw-r--r--deps/uv/uv.gyp8
73 files changed, 1449 insertions, 345 deletions
diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS
index b2397e2df6..8dc3955cad 100644
--- a/deps/uv/AUTHORS
+++ b/deps/uv/AUTHORS
@@ -225,3 +225,18 @@ Colin Snover <github.com@zetafleet.com>
Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Eli Skeggs <skeggse@gmail.com>
nmushell <nmushell@bloomberg.net>
+Gireesh Punathil <gpunathi@in.ibm.com>
+Ryan Johnston <ryan@mediapixel.co.nz>
+Adam Stylinski <stylinae@mail.uc.edu>
+Nathan Corvino <nathan@corvino.com>
+Wink Saville <wink@saville.com>
+Angel Leon <gubatron@gmail.com>
+Louis DeJardin <lodejard@microsoft.com>
+Imran Iqbal <imrani@ca.ibm.com>
+Petka Antonov <petka_antonov@hotmail.com>
+Ian Kronquist <iankronquist@teleport.com>
+kkdaemon <kkdaemon@gmail.com>
+Yuval Brik <yuval@brik.org.il>
+Joran Dirk Greef <joran@ronomon.com>
+Andrey Mazo <andrey.mazo@fidelissecurity.com>
+sztomi <hello.sztomi@gmail.com>
diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog
index 42f10352b1..af0743af72 100644
--- a/deps/uv/ChangeLog
+++ b/deps/uv/ChangeLog
@@ -1,3 +1,102 @@
+2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4
+
+Changes since version 1.7.5:
+
+* unix: fix memory leak in uv_interface_addresses (Jianghua Yang)
+
+* unix: make uv_guess_handle work properly for AIX (Gireesh Punathil)
+
+* fs: undo uv__req_init when uv__malloc failed (Jianghua Yang)
+
+* build: remove unused 'component' GYP option (Saúl Ibarra Corretgé)
+
+* include: remove duplicate extern declaration (Jianghua Yang)
+
+* win: use the MSVC provided snprintf where possible (Jason Williams)
+
+* win, test: fix compilation warning (Saúl Ibarra Corretgé)
+
+* win: fix compilation with VS < 2012 (Ryan Johnston)
+
+* stream: support empty uv_try_write on unix (Fedor Indutny)
+
+* unix: fix request handle leak in uv__udp_send (Jianghua Yang)
+
+* src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis)
+
+* unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis)
+
+* unix: squelch harmless valgrind warning (Ben Noordhuis)
+
+* test: don't abort on setrlimit() failure (Ben Noordhuis)
+
+* unix: only undo fs req registration in async mode (Ben Noordhuis)
+
+* unix: fix uv__getiovmax return value (HungMingWu)
+
+* unix: make work with Solaris Studio. (Adam Stylinski)
+
+* test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno)
+
+* unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino)
+
+* test: use FQDN in getaddrinfo_fail test (Wink Saville)
+
+* docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus)
+
+* win: fix comment (Miodrag Milanovic)
+
+* doc: fix typo in README (Angel Leon)
+
+* darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis)
+
+* pipe: enable inprocess uv_write2 on Windows (Louis DeJardin)
+
+* win: properly return UV_EBADF when _close() fails (Nicholas Vavilov)
+
+* test: skip process_title for AIX (Imran Iqbal)
+
+* misc: expose handle print APIs (Petka Antonov)
+
+* include: add stdio.h to uv.h (Saúl Ibarra Corretgé)
+
+* misc: remove unnecessary null pointer checks (Ian Kronquist)
+
+* test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno)
+
+* linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis)
+
+* unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis)
+
+* test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé)
+
+* win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman)
+
+* test: fix test/test-tty.c for AIX (Imran Iqbal)
+
+* android: support api level less than 21 (kkdaemon)
+
+* fsevents: fix race on simultaneous init+close (Fedor Indutny)
+
+* linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé)
+
+* fs: add uv_fs_realpath() (Yuval Brik)
+
+* win: fix path for removed and renamed fs events (Joran Dirk Greef)
+
+* win: do not read more from stream than available (Jeremy Whitlock)
+
+* test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo)
+
+* unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo)
+
+* test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis)
+
+* src: remove non ascii character (sztomi)
+
+* test: fix test udp_multicast_join6 for AIX (Imran Iqbal)
+
+
2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8
Changes since version 1.7.4:
diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am
index fbf9527ae9..0ef781ff19 100644
--- a/deps/uv/Makefile.am
+++ b/deps/uv/Makefile.am
@@ -200,6 +200,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-poll-closesocket.c \
test/test-poll.c \
test/test-process-title.c \
+ test/test-queue-foreach-delete.c \
test/test-ref.c \
test/test-run-nowait.c \
test/test-run-once.c \
diff --git a/deps/uv/README.md b/deps/uv/README.md
index 0ce2669971..dfd24ba79d 100644
--- a/deps/uv/README.md
+++ b/deps/uv/README.md
@@ -119,7 +119,7 @@ Git tags are signed with the developer's key, they can be verified as follows:
$ git verify-tag v1.6.1
Starting with libuv 1.7.0, the tarballs stored in the
-[downloads site](http://dist.libuv.org/dist/) are signed and an accomanying
+[downloads site](http://dist.libuv.org/dist/) are signed and an accompanying
signature file sit alongside each. Once both the release tarball and the
signature file are downloaded, the file can be verified as follows:
diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml
index c9f55134e5..9aa63c5a5d 100644
--- a/deps/uv/appveyor.yml
+++ b/deps/uv/appveyor.yml
@@ -1,4 +1,4 @@
-version: v1.7.5.build{build}
+version: v1.8.0.build{build}
install:
- cinst -y nsis
diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi
index 392c85951e..7cebcde5f8 100644
--- a/deps/uv/common.gypi
+++ b/deps/uv/common.gypi
@@ -4,7 +4,6 @@
'target_arch%': 'ia32', # set v8's target architecture
'host_arch%': 'ia32', # set v8's host architecture
'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
},
diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac
index c55a11847e..011bee2a89 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.7.5], [https://github.com/libuv/libuv/issues])
+AC_INIT([libuv], [1.8.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])
diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst
index 33c04406f1..69e283f4c6 100644
--- a/deps/uv/docs/src/fs.rst
+++ b/deps/uv/docs/src/fs.rst
@@ -279,6 +279,16 @@ API
Equivalent to :man:`readlink(2)`.
+.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``.
+
+ .. note::
+ This function is not implemented on Windows XP and Windows Server 2003.
+ On these systems, UV_ENOSYS is returned.
+
+ .. versionadded:: 1.8.0
+
.. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
.. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst
index e9ddba3db6..2ce0887db0 100644
--- a/deps/uv/docs/src/misc.rst
+++ b/deps/uv/docs/src/misc.rst
@@ -288,3 +288,41 @@ API
.. note::
Not every platform can support nanosecond resolution; however, this value will always
be in nanoseconds.
+
+.. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream)
+
+ Prints all handles associated with the given `loop` to the given `stream`.
+
+ Example:
+
+ ::
+
+ uv_print_all_handles(uv_default_loop(), stderr);
+ /*
+ [--I] signal 0x1a25ea8
+ [-AI] async 0x1a25cf0
+ [R--] idle 0x1a7a8c8
+ */
+
+ The format is `[flags] handle-type handle-address`. For `flags`:
+
+ - `R` is printed for a handle that is referenced
+ - `A` is printed for a handle that is active
+ - `I` is printed for a handle that is internal
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
+
+.. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream)
+
+ This is the same as :c:func:`uv_print_all_handles` except only active handles
+ are printed.
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst
index dd18522d91..ca0c9b4ac5 100644
--- a/deps/uv/docs/src/tcp.rst
+++ b/deps/uv/docs/src/tcp.rst
@@ -34,7 +34,7 @@ API
.. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags)
- Initialize the handle with the specified flags. At the moment the lower 8 bits
+ Initialize the handle with the specified flags. At the moment only the lower 8 bits
of the `flags` parameter are used as the socket domain. A socket will be created
for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
just like :c:func:`uv_tcp_init`.
diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py
index 0491ff873f..39933f624d 100755
--- a/deps/uv/gyp_uv.py
+++ b/deps/uv/gyp_uv.py
@@ -83,9 +83,6 @@ if __name__ == '__main__':
if not any(a.startswith('-Duv_library=') for a in args):
args.append('-Duv_library=static_library')
- if not any(a.startswith('-Dcomponent=') for a in args):
- args.append('-Dcomponent=static_library')
-
# Some platforms (OpenBSD for example) don't have multiprocessing.synchronize
# so gyp must be run with --no-parallel
if not gyp_parallel_support:
diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h
index e1f26601a1..6e61f55ed2 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 7
-#define UV_VERSION_PATCH 5
+#define UV_VERSION_MINOR 8
+#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index f96026b603..dd3111a960 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -48,6 +48,7 @@ extern "C" {
#include "uv-errno.h"
#include "uv-version.h"
#include <stddef.h>
+#include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "stdint-msvc2008.h"
@@ -424,6 +425,10 @@ UV_EXTERN int uv_is_active(const uv_handle_t* handle);
UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
+/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */
+UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream);
+UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream);
+
UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
@@ -1083,7 +1088,8 @@ typedef enum {
UV_FS_SYMLINK,
UV_FS_READLINK,
UV_FS_CHOWN,
- UV_FS_FCHOWN
+ UV_FS_FCHOWN,
+ UV_FS_REALPATH
} uv_fs_type;
/* uv_fs_t is a subclass of uv_req_t. */
@@ -1235,6 +1241,10 @@ UV_EXTERN int uv_fs_readlink(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
uv_fs_cb cb);
+UV_EXTERN int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop,
uv_fs_t* req,
uv_file file,
@@ -1363,7 +1373,7 @@ UV_EXTERN int uv_chdir(const char* dir);
UV_EXTERN uint64_t uv_get_free_memory(void);
UV_EXTERN uint64_t uv_get_total_memory(void);
-UV_EXTERN extern uint64_t uv_hrtime(void);
+UV_EXTERN uint64_t uv_hrtime(void);
UV_EXTERN void uv_disable_stdio_inheritance(void);
diff --git a/deps/uv/src/inet.c b/deps/uv/src/inet.c
index c948b2e7cf..da63a688c4 100644
--- a/deps/uv/src/inet.c
+++ b/deps/uv/src/inet.c
@@ -55,11 +55,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
char tmp[UV__INET_ADDRSTRLEN];
int l;
-#ifndef _WIN32
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
-#else
- l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
-#endif
if (l <= 0 || (size_t) l >= size) {
return UV_ENOSPC;
}
diff --git a/deps/uv/src/queue.h b/deps/uv/src/queue.h
index 60c8000038..ff3540a0a5 100644
--- a/deps/uv/src/queue.h
+++ b/deps/uv/src/queue.h
@@ -30,6 +30,9 @@ typedef void *QUEUE[2];
#define QUEUE_DATA(ptr, type, field) \
((type *) ((char *) (ptr) - offsetof(type, field)))
+/* Important note: mutating the list while QUEUE_FOREACH is
+ * iterating over its elements results in undefined behavior.
+ */
#define QUEUE_FOREACH(q, h) \
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
@@ -66,6 +69,17 @@ typedef void *QUEUE[2];
} \
while (0)
+#define QUEUE_MOVE(h, n) \
+ do { \
+ if (QUEUE_EMPTY(h)) \
+ QUEUE_INIT(n); \
+ else { \
+ QUEUE* q = QUEUE_HEAD(h); \
+ QUEUE_SPLIT(h, q, n); \
+ } \
+ } \
+ while (0)
+
#define QUEUE_INSERT_HEAD(h, q) \
do { \
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c
index 15d719944f..2c5152b420 100644
--- a/deps/uv/src/threadpool.c
+++ b/deps/uv/src/threadpool.c
@@ -223,13 +223,8 @@ void uv__work_done(uv_async_t* handle) {
int err;
loop = container_of(handle, uv_loop_t, wq_async);
- QUEUE_INIT(&wq);
-
uv_mutex_lock(&loop->wq_mutex);
- if (!QUEUE_EMPTY(&loop->wq)) {
- q = QUEUE_HEAD(&loop->wq);
- QUEUE_SPLIT(&loop->wq, q, &wq);
- }
+ QUEUE_MOVE(&loop->wq, &wq);
uv_mutex_unlock(&loop->wq_mutex);
while (!QUEUE_EMPTY(&wq)) {
diff --git a/deps/uv/src/unix/android-ifaddrs.c b/deps/uv/src/unix/android-ifaddrs.c
index 71f7290b32..30f681b7d0 100644
--- a/deps/uv/src/unix/android-ifaddrs.c
+++ b/deps/uv/src/unix/android-ifaddrs.c
@@ -1,6 +1,6 @@
/*
Copyright (c) 2013, Kenneth MacKay
-Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016)
+Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c
index 9ff24aeb3d..184b598126 100644
--- a/deps/uv/src/unix/async.c
+++ b/deps/uv/src/unix/async.c
@@ -78,12 +78,18 @@ void uv__async_close(uv_async_t* handle) {
static void uv__async_event(uv_loop_t* loop,
struct uv__async* w,
unsigned int nevents) {
+ QUEUE queue;
QUEUE* q;
uv_async_t* h;
- QUEUE_FOREACH(q, &loop->async_handles) {
+ QUEUE_MOVE(&loop->async_handles, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_async_t, queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->async_handles, q);
+
if (cmpxchgi(&h->pending, 1, 0) == 0)
continue;
diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h
index 8fb157dcc6..84e471838b 100644
--- a/deps/uv/src/unix/atomic-ops.h
+++ b/deps/uv/src/unix/atomic-ops.h
@@ -18,6 +18,11 @@
#include "internal.h" /* UV_UNUSED */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#include <atomic.h>
+#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
+#endif
+
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
UV_UNUSED(static void cpu_relax(void));
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index e149357e07..cedd86ed34 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -75,6 +75,10 @@
#include <sys/ioctl.h>
#endif
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+# include <dlfcn.h> /* for dlsym */
+#endif
+
static int uv__run_pending(uv_loop_t* loop);
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
@@ -204,8 +208,14 @@ int uv__getiovmax(void) {
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
static int iovmax = -1;
- if (iovmax == -1)
+ if (iovmax == -1) {
iovmax = sysconf(_SC_IOV_MAX);
+ /* On some embedded devices (arm-linux-uclibc based ip camera),
+ * sysconf(_SC_IOV_MAX) can not get the correct value. The return
+ * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
+ */
+ if (iovmax == -1) iovmax = 1;
+ }
return iovmax;
#else
return 1024;
@@ -721,9 +731,7 @@ static int uv__run_pending(uv_loop_t* loop) {
if (QUEUE_EMPTY(&loop->pending_queue))
return 0;
- QUEUE_INIT(&pq);
- q = QUEUE_HEAD(&loop->pending_queue);
- QUEUE_SPLIT(&loop->pending_queue, q, &pq);
+ QUEUE_MOVE(&loop->pending_queue, &pq);
while (!QUEUE_EMPTY(&pq)) {
q = QUEUE_HEAD(&pq);
@@ -956,16 +964,12 @@ int uv__open_cloexec(const char* path, int flags) {
int uv__dup2_cloexec(int oldfd, int newfd) {
int r;
#if defined(__FreeBSD__) && __FreeBSD__ >= 10
- do
- r = dup3(oldfd, newfd, O_CLOEXEC);
- while (r == -1 && errno == EINTR);
+ r = dup3(oldfd, newfd, O_CLOEXEC);
if (r == -1)
return -errno;
return r;
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
- do
- r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
- while (r == -1 && errno == EINTR);
+ r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
if (r != -1)
return r;
if (errno != EINVAL)
@@ -976,7 +980,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) {
if (!no_dup3) {
do
r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
- while (r == -1 && (errno == EINTR || errno == EBUSY));
+ while (r == -1 && errno == EBUSY);
if (r != -1)
return r;
if (errno != ENOSYS)
@@ -990,9 +994,9 @@ int uv__dup2_cloexec(int oldfd, int newfd) {
do
r = dup2(oldfd, newfd);
#if defined(__linux__)
- while (r == -1 && (errno == EINTR || errno == EBUSY));
+ while (r == -1 && errno == EBUSY);
#else
- while (r == -1 && errno == EINTR);
+ while (0); /* Never retry. */
#endif
if (r == -1)
@@ -1018,6 +1022,9 @@ int uv_os_homedir(char* buffer, size_t* size) {
size_t len;
long initsize;
int r;
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
+#endif
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
@@ -1039,6 +1046,12 @@ int uv_os_homedir(char* buffer, size_t* size) {
return 0;
}
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
+ if (getpwuid_r == NULL)
+ return -ENOSYS;
+#endif
+
/* HOME is not set, so call getpwuid() */
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c
index dab6ca999d..cf95da2169 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -258,8 +258,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/dl.c b/deps/uv/src/unix/dl.c
index 7c6d41c969..fc1c052bb8 100644
--- a/deps/uv/src/unix/dl.c
+++ b/deps/uv/src/unix/dl.c
@@ -39,10 +39,8 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
void uv_dlclose(uv_lib_t* lib) {
- if (lib->errmsg) {
- uv__free(lib->errmsg);
- lib->errmsg = NULL;
- }
+ uv__free(lib->errmsg);
+ lib->errmsg = NULL;
if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
@@ -67,8 +65,7 @@ const char* uv_dlerror(const uv_lib_t* lib) {
static int uv__dlerror(uv_lib_t* lib) {
const char* errmsg;
- if (lib->errmsg)
- uv__free(lib->errmsg);
+ uv__free(lib->errmsg);
errmsg = dlerror();
diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c
index c69608b139..b747abdf5b 100644
--- a/deps/uv/src/unix/freebsd.c
+++ b/deps/uv/src/unix/freebsd.c
@@ -176,7 +176,7 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
int oid[4];
- if (process_title) uv__free(process_title);
+ uv__free(process_title);
process_title = uv__strdup(title);
oid[0] = CTL_KERN;
@@ -373,8 +373,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index d739c28258..57b65be25a 100644
--- a/deps/uv/src/unix/fs.c
+++ b/deps/uv/src/unix/fs.c
@@ -80,8 +80,10 @@
req->path = path; \
} else { \
req->path = uv__strdup(path); \
- if (req->path == NULL) \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
return -ENOMEM; \
+ } \
} \
} \
while (0)
@@ -97,8 +99,10 @@
path_len = strlen(path) + 1; \
new_path_len = strlen(new_path) + 1; \
req->path = uv__malloc(path_len + new_path_len); \
- if (req->path == NULL) \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
return -ENOMEM; \
+ } \
req->new_path = req->path + path_len; \
memcpy((void*) req->path, path, path_len); \
memcpy((void*) req->new_path, new_path, new_path_len); \
@@ -370,20 +374,27 @@ out:
}
-static ssize_t uv__fs_readlink(uv_fs_t* req) {
- ssize_t len;
- char* buf;
+static ssize_t uv__fs_pathmax_size(const char* path) {
+ ssize_t pathmax;
- len = pathconf(req->path, _PC_PATH_MAX);
+ pathmax = pathconf(path, _PC_PATH_MAX);
- if (len == -1) {
+ if (pathmax == -1) {
#if defined(PATH_MAX)
- len = PATH_MAX;
+ return PATH_MAX;
#else
- len = 4096;
+ return 4096;
#endif
}
+ return pathmax;
+}
+
+static ssize_t uv__fs_readlink(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
buf = uv__malloc(len + 1);
if (buf == NULL) {
@@ -404,6 +415,27 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
return 0;
}
+static ssize_t uv__fs_realpath(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (realpath(req->path, buf) == NULL) {
+ uv__free(buf);
+ return -1;
+ }
+
+ req->ptr = buf;
+
+ return 0;
+}
static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
struct pollfd pfd;
@@ -626,7 +658,9 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
*/
#if defined(__APPLE__)
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&lock);
+
+ if (pthread_mutex_lock(&lock))
+ abort();
#endif
if (req->off < 0) {
@@ -683,7 +717,8 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
done:
#if defined(__APPLE__)
- pthread_mutex_unlock(&lock);
+ if (pthread_mutex_unlock(&lock))
+ abort();
#endif
return r;
@@ -867,6 +902,7 @@ static void uv__fs_work(struct uv__work* w) {
X(READ, uv__fs_buf_iter(req, uv__fs_read));
X(SCANDIR, uv__fs_scandir(req));
X(READLINK, uv__fs_readlink(req));
+ X(REALPATH, uv__fs_realpath(req));
X(RENAME, rename(req->path, req->new_path));
X(RMDIR, rmdir(req->path));
X(SENDFILE, uv__fs_sendfile(req));
@@ -1062,8 +1098,11 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(MKDTEMP);
req->path = uv__strdup(tpl);
- if (req->path == NULL)
+ if (req->path == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
return -ENOMEM;
+ }
POST;
}
@@ -1099,8 +1138,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = uv__malloc(nbufs * sizeof(*bufs));
- if (req->bufs == NULL)
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
return -ENOMEM;
+ }
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
@@ -1131,6 +1173,16 @@ int uv_fs_readlink(uv_loop_t* loop,
}
+int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char * path,
+ uv_fs_cb cb) {
+ INIT(REALPATH);
+ PATH;
+ POST;
+}
+
+
int uv_fs_rename(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
@@ -1224,8 +1276,11 @@ int uv_fs_write(uv_loop_t* loop,
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = uv__malloc(nbufs * sizeof(*bufs));
- if (req->bufs == NULL)
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
return -ENOMEM;
+ }
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c
index 8143f7c1f0..d331a13172 100644
--- a/deps/uv/src/unix/fsevents.c
+++ b/deps/uv/src/unix/fsevents.c
@@ -73,9 +73,16 @@ typedef struct uv__fsevents_event_s uv__fsevents_event_t;
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
+enum uv__cf_loop_signal_type_e {
+ kUVCFLoopSignalRegular,
+ kUVCFLoopSignalClosing
+};
+typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
+
struct uv__cf_loop_signal_s {
QUEUE member;
uv_fs_event_t* handle;
+ uv__cf_loop_signal_type_t type;
};
struct uv__fsevents_event_s {
@@ -98,7 +105,9 @@ struct uv__cf_loop_state_s {
/* Forward declarations */
static void uv__cf_loop_cb(void* arg);
static void* uv__cf_loop_runner(void* arg);
-static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle);
+static int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type);
/* Lazy-loaded by uv__fsevents_global_init(). */
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
@@ -149,11 +158,7 @@ static void (*pFSEventStreamStop)(FSEventStreamRef);
int err; \
uv_mutex_lock(&(handle)->cf_mutex); \
/* Split-off all events and empty original queue */ \
- QUEUE_INIT(&events); \
- if (!QUEUE_EMPTY(&(handle)->cf_events)) { \
- q = QUEUE_HEAD(&(handle)->cf_events); \
- QUEUE_SPLIT(&(handle)->cf_events, q, &events); \
- } \
+ QUEUE_MOVE(&(handle)->cf_events, &events); \
/* Get error (if any) and zero original one */ \
err = (handle)->cf_error; \
(handle)->cf_error = 0; \
@@ -387,7 +392,8 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
/* Runs in CF thread, when there're new fsevent handles to add to stream */
-static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
+static void uv__fsevents_reschedule(uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
uv__cf_loop_state_t* state;
QUEUE* q;
uv_fs_event_t* curr;
@@ -486,7 +492,7 @@ final:
*
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
*/
- if (!uv__is_active(handle))
+ if (type == kUVCFLoopSignalClosing)
uv_sem_post(&state->fsevent_sem);
}
@@ -676,7 +682,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) {
if (loop->cf_state == NULL)
return;
- if (uv__cf_loop_signal(loop, NULL) != 0)
+ if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
abort();
uv_thread_join(&loop->cf_thread);
@@ -735,17 +741,14 @@ static void uv__cf_loop_cb(void* arg) {
loop = arg;
state = loop->cf_state;
- QUEUE_INIT(&split_head);
uv_mutex_lock(&loop->cf_mutex);
- if (!QUEUE_EMPTY(&loop->cf_signals)) {
- QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals);
- QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head);
- }
+ QUEUE_MOVE(&loop->cf_signals, &split_head);
uv_mutex_unlock(&loop->cf_mutex);
while (!QUEUE_EMPTY(&split_head)) {
item = QUEUE_HEAD(&split_head);
+ QUEUE_REMOVE(item);
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
@@ -753,16 +756,17 @@ static void uv__cf_loop_cb(void* arg) {
if (s->handle == NULL)
pCFRunLoopStop(state->loop);
else
- uv__fsevents_reschedule(s->handle);
+ uv__fsevents_reschedule(s->handle, s->type);
- QUEUE_REMOVE(item);
uv__free(s);
}
}
/* Runs in UV loop to notify CF thread */
-int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
+int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
uv__cf_loop_signal_t* item;
uv__cf_loop_state_t* state;
@@ -771,6 +775,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
return -ENOMEM;
item->handle = handle;
+ item->type = type;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
@@ -833,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
/* Reschedule FSEventStream */
assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
if (err)
goto fail_loop_signal;
@@ -873,7 +878,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
/* Reschedule FSEventStream */
assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
if (err)
return -err;
diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c
index e6e68283d5..3ff6fb15e9 100644
--- a/deps/uv/src/unix/linux-core.c
+++ b/deps/uv/src/unix/linux-core.c
@@ -814,8 +814,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
return 0;
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c
index d9ed9f4b24..282912115d 100644
--- a/deps/uv/src/unix/linux-inotify.c
+++ b/deps/uv/src/unix/linux-inotify.c
@@ -35,6 +35,7 @@
struct watcher_list {
RB_ENTRY(watcher_list) entry;
QUEUE watchers;
+ int iterating;
char* path;
int wd;
};
@@ -113,6 +114,15 @@ static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
}
+static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
+ /* if the watcher_list->watchers is being iterated over, we can't free it. */
+ if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
+ /* No watchers left for this path. Clean up. */
+ RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
+ uv__inotify_rm_watch(loop->inotify_fd, w->wd);
+ uv__free(w);
+ }
+}
static void uv__inotify_read(uv_loop_t* loop,
uv__io_t* dummy,
@@ -120,6 +130,7 @@ static void uv__inotify_read(uv_loop_t* loop,
const struct uv__inotify_event* e;
struct watcher_list* w;
uv_fs_event_t* h;
+ QUEUE queue;
QUEUE* q;
const char* path;
ssize_t size;
@@ -159,10 +170,31 @@ static void uv__inotify_read(uv_loop_t* loop,
*/
path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
- QUEUE_FOREACH(q, &w->watchers) {
+ /* We're about to iterate over the queue and call user's callbacks.
+ * What can go wrong?
+ * A callback could call uv_fs_event_stop()
+ * and the queue can change under our feet.
+ * So, we use QUEUE_MOVE() trick to safely iterate over the queue.
+ * And we don't free the watcher_list until we're done iterating.
+ *
+ * First,
+ * tell uv_fs_event_stop() (that could be called from a user's callback)
+ * not to free watcher_list.
+ */
+ w->iterating = 1;
+ QUEUE_MOVE(&w->watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_fs_event_t, watchers);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&w->watchers, q);
+
h->cb(h, path, events, 0);
}
+ /* done iterating, time to (maybe) free empty watcher_list */
+ w->iterating = 0;
+ maybe_free_watcher_list(w, loop);
}
}
}
@@ -214,6 +246,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
w->wd = wd;
w->path = strcpy((char*)(w + 1), path);
QUEUE_INIT(&w->watchers);
+ w->iterating = 0;
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
no_insert:
@@ -241,12 +274,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__handle_stop(handle);
QUEUE_REMOVE(&handle->watchers);
- if (QUEUE_EMPTY(&w->watchers)) {
- /* No watchers left for this path. Clean up. */
- RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w);
- uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd);
- uv__free(w);
- }
+ maybe_free_watcher_list(w, handle->loop);
return 0;
}
diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c
index 566e1f37cf..89998ded26 100644
--- a/deps/uv/src/unix/linux-syscalls.c
+++ b/deps/uv/src/unix/linux-syscalls.c
@@ -444,18 +444,18 @@ int uv__utimesat(int dirfd,
}
-ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_preadv)
- return syscall(__NR_preadv, fd, iov, iovcnt, offset);
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#else
return errno = ENOSYS, -1;
#endif
}
-ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_pwritev)
- return syscall(__NR_pwritev, fd, iov, iovcnt, offset);
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#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 6f249b7245..96e79439cf 100644
--- a/deps/uv/src/unix/linux-syscalls.h
+++ b/deps/uv/src/unix/linux-syscalls.h
@@ -151,8 +151,8 @@ int uv__utimesat(int dirfd,
const char* path,
const struct timespec times[2],
int flags);
-ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
-ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
int uv__dup3(int oldfd, int newfd, int flags);
#endif /* UV_LINUX_SYSCALL_H_ */
diff --git a/deps/uv/src/unix/loop-watcher.c b/deps/uv/src/unix/loop-watcher.c
index dc25760bd5..340bb0dfa1 100644
--- a/deps/uv/src/unix/loop-watcher.c
+++ b/deps/uv/src/unix/loop-watcher.c
@@ -47,9 +47,14 @@
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
+ QUEUE queue; \
QUEUE* q; \
- QUEUE_FOREACH(q, &loop->name##_handles) { \
+ QUEUE_MOVE(&loop->name##_handles, &queue); \
+ while (!QUEUE_EMPTY(&queue)) { \
+ q = QUEUE_HEAD(&queue); \
h = QUEUE_DATA(q, uv_##name##_t, queue); \
+ QUEUE_REMOVE(q); \
+ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
h->name##_cb(h); \
} \
} \
diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c
index 29f2a4dec6..ca48550f9d 100644
--- a/deps/uv/src/unix/netbsd.c
+++ b/deps/uv/src/unix/netbsd.c
@@ -298,8 +298,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c
index c8d5459938..6a3909a666 100644
--- a/deps/uv/src/unix/openbsd.c
+++ b/deps/uv/src/unix/openbsd.c
@@ -161,7 +161,7 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
- if (process_title) uv__free(process_title);
+ uv__free(process_title);
process_title = uv__strdup(title);
setproctitle(title);
return 0;
@@ -313,8 +313,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index 9fa061e6bc..571f8cd778 100644
--- a/deps/uv/src/unix/process.c
+++ b/deps/uv/src/unix/process.c
@@ -270,6 +270,11 @@ static void uv__write_int(int fd, int val) {
}
+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
+/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
+ * avoided. Since this isn't called on those targets, the function
+ * doesn't even need to be defined for them.
+ */
static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
@@ -375,11 +380,16 @@ static void uv__process_child_init(const uv_process_options_t* options,
uv__write_int(error_fd, -errno);
_exit(127);
}
+#endif
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
const uv_process_options_t* options) {
+#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
+ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
+ return -ENOSYS;
+#else
int signal_pipe[2] = { -1, -1 };
int (*pipes)[2];
int stdio_count;
@@ -528,6 +538,7 @@ error:
}
return err;
+#endif
}
diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c
index 0b7a405c15..edd9085d3f 100644
--- a/deps/uv/src/unix/signal.c
+++ b/deps/uv/src/unix/signal.c
@@ -234,6 +234,8 @@ void uv__signal_loop_cleanup(uv_loop_t* loop) {
/* Stop all the signal watchers that are still attached to this loop. This
* ensures that the (shared) signal tree doesn't contain any invalid entries
* entries, and that signal handlers are removed when appropriate.
+ * It's safe to use QUEUE_FOREACH here because the handles and the handle
+ * queue are not modified by uv__signal_stop().
*/
QUEUE_FOREACH(q, &loop->handle_queue) {
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 183b68cf71..7d7ab2633b 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -779,9 +779,9 @@ start:
if (req->send_handle) {
struct msghdr msg;
- char scratch[64];
struct cmsghdr *cmsg;
int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+ char scratch[64] = {0};
assert(fd_to_send >= 0);
@@ -1471,7 +1471,7 @@ int uv_try_write(uv_stream_t* stream,
uv__stream_osx_interrupt_select(stream);
}
- if (written == 0)
+ if (written == 0 && req_size != 0)
return -EAGAIN;
else
return written;
diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c
index 05b7a11403..0c46817b44 100644
--- a/deps/uv/src/unix/sunos.c
+++ b/deps/uv/src/unix/sunos.c
@@ -693,8 +693,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
*addresses = uv__malloc(*count * sizeof(**addresses));
- if (!(*addresses))
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
return -ENOMEM;
+ }
address = *addresses;
diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c
index 54c9055a08..7cc5b714ed 100644
--- a/deps/uv/src/unix/tty.c
+++ b/deps/uv/src/unix/tty.c
@@ -236,6 +236,15 @@ uv_handle_type uv_guess_handle(uv_file file) {
return UV_UDP;
if (type == SOCK_STREAM) {
+#if defined(_AIX)
+ /* on AIX the getsockname call returns an empty sa structure
+ * for sockets of type AF_UNIX. For all other types it will
+ * return a properly filled in structure.
+ */
+ if (len == 0)
+ return UV_NAMED_PIPE;
+#endif /* defined(_AIX) */
+
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_TCP;
if (sa.sa_family == AF_UNIX)
diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c
index 66ecc4e341..39ade8de33 100644
--- a/deps/uv/src/unix/udp.c
+++ b/deps/uv/src/unix/udp.c
@@ -410,8 +410,10 @@ int uv__udp_send(uv_udp_send_t* req,
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
- if (req->bufs == NULL)
+ if (req->bufs == NULL) {
+ uv__req_unregister(handle->loop, req);
return -ENOMEM;
+ }
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c
index 675a776bf4..40ed28fec5 100644
--- a/deps/uv/src/uv-common.c
+++ b/deps/uv/src/uv-common.c
@@ -141,11 +141,7 @@ static const char* uv__unknown_err_code(int err) {
char buf[32];
char* copy;
-#ifndef _WIN32
snprintf(buf, sizeof(buf), "Unknown system error %d", err);
-#else
- _snprintf(buf, sizeof(buf), "Unknown system error %d", err);
-#endif
copy = uv__strdup(buf);
return copy != NULL ? copy : "Unknown system error";
@@ -341,19 +337,25 @@ int uv_udp_recv_stop(uv_udp_t* handle) {
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
+ QUEUE queue;
QUEUE* q;
uv_handle_t* h;
- QUEUE_FOREACH(q, &loop->handle_queue) {
+ QUEUE_MOVE(&loop->handle_queue, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->handle_queue, q);
+
if (h->flags & UV__HANDLE_INTERNAL) continue;
walk_cb(h, arg);
}
}
-#ifndef NDEBUG
-static void uv__print_handles(uv_loop_t* loop, int only_active) {
+static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
const char* type;
QUEUE* q;
uv_handle_t* h;
@@ -374,7 +376,7 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) {
default: type = "<unknown>";
}
- fprintf(stderr,
+ fprintf(stream,
"[%c%c%c] %-8s %p\n",
"R-"[!(h->flags & UV__HANDLE_REF)],
"A-"[!(h->flags & UV__HANDLE_ACTIVE)],
@@ -385,15 +387,14 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) {
}
-void uv_print_all_handles(uv_loop_t* loop) {
- uv__print_handles(loop, 0);
+void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 0, stream);
}
-void uv_print_active_handles(uv_loop_t* loop) {
- uv__print_handles(loop, 1);
+void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 1, stream);
}
-#endif
void uv_ref(uv_handle_t* handle) {
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
index b348ec76bd..27902fdf86 100644
--- a/deps/uv/src/uv-common.h
+++ b/deps/uv/src/uv-common.h
@@ -41,6 +41,10 @@
#include "tree.h"
#include "queue.h"
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define container_of(ptr, type, member) \
diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c
index a265a272dc..c512f35af9 100644
--- a/deps/uv/src/win/error.c
+++ b/deps/uv/src/win/error.c
@@ -129,6 +129,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case WSAENOBUFS: return UV_ENOBUFS;
+ case ERROR_BAD_PATHNAME: return UV_ENOENT;
case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT;
diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c
index ba68f78c82..76ecfebaa2 100644
--- a/deps/uv/src/win/fs-event.c
+++ b/deps/uv/src/win/fs-event.c
@@ -381,9 +381,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
if (handle->dirw) {
/*
- * We attempt to convert the file name to its long form for
- * events that still point to valid files on disk.
- * For removed and renamed events, we do not provide the file name.
+ * We attempt to resolve the long form of the file name explicitly.
+ * We only do this for file names that might still exist on disk.
+ * If this fails, we use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
*/
if (file_info->Action != FILE_ACTION_REMOVED &&
file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
@@ -438,16 +439,24 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
}
/*
- * If we couldn't get the long name - just use the name
- * provided by ReadDirectoryChangesW.
+ * We could not resolve the long form explicitly.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
*/
if (!long_filenamew) {
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
- /* Removed or renamed callbacks don't provide filename. */
- filenamew = NULL;
+ /*
+ * Removed or renamed events cannot be resolved to the long form.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (!long_filenamew) {
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
}
} else {
/* We already have the long name of the file, so just use it. */
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 4a17573113..a32b0127f7 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -110,6 +110,9 @@ const WCHAR JUNCTION_PREFIX_LEN = 4;
const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
const WCHAR LONG_PATH_PREFIX_LEN = 4;
+const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
+const WCHAR UNC_PATH_PREFIX_LEN = 8;
+
void uv_fs_init() {
_fmode = _O_BINARY;
@@ -233,14 +236,61 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
}
+static int fs__wide_to_utf8(WCHAR* w_source_ptr,
+ DWORD w_source_len,
+ char** target_ptr,
+ uint64_t* target_len_ptr) {
+ int r;
+ int target_len;
+ char* target;
+ target_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (target_len == 0) {
+ return -1;
+ }
+
+ if (target_len_ptr != NULL) {
+ *target_len_ptr = target_len;
+ }
+
+ if (target_ptr == NULL) {
+ return 0;
+ }
+
+ target = uv__malloc(target_len + 1);
+ if (target == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ target,
+ target_len,
+ NULL,
+ NULL);
+ assert(r == target_len);
+ target[target_len] = '\0';
+ *target_ptr = target;
+ return 0;
+}
+
+
INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
uint64_t* target_len_ptr) {
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
- WCHAR *w_target;
+ WCHAR* w_target;
DWORD w_target_len;
- char* target;
- int target_len;
DWORD bytes;
if (!DeviceIoControl(handle,
@@ -333,50 +383,7 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
return -1;
}
- /* If needed, compute the length of the target. */
- if (target_ptr != NULL || target_len_ptr != NULL) {
- /* Compute the length of the target. */
- target_len = WideCharToMultiByte(CP_UTF8,
- 0,
- w_target,
- w_target_len,
- NULL,
- 0,
- NULL,
- NULL);
- if (target_len == 0) {
- return -1;
- }
- }
-
- /* If requested, allocate memory and convert to UTF8. */
- if (target_ptr != NULL) {
- int r;
- target = (char*) uv__malloc(target_len + 1);
- if (target == NULL) {
- SetLastError(ERROR_OUTOFMEMORY);
- return -1;
- }
-
- r = WideCharToMultiByte(CP_UTF8,
- 0,
- w_target,
- w_target_len,
- target,
- target_len,
- NULL,
- NULL);
- assert(r == target_len);
- target[target_len] = '\0';
-
- *target_ptr = target;
- }
-
- if (target_len_ptr != NULL) {
- *target_len_ptr = target_len;
- }
-
- return 0;
+ return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
}
@@ -533,7 +540,15 @@ void fs__close(uv_fs_t* req) {
else
result = 0;
- SET_REQ_RESULT(req, result);
+ /* _close doesn't set _doserrno on failure, but it does always set errno
+ * to EBADF on failure.
+ */
+ if (result == -1) {
+ assert(errno == EBADF);
+ SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
+ } else {
+ req->result = 0;
+ }
}
@@ -1699,6 +1714,84 @@ static void fs__readlink(uv_fs_t* req) {
}
+static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+ int r;
+ DWORD w_realpath_len;
+ WCHAR* w_realpath_ptr;
+ WCHAR* w_finalpath_ptr = NULL;
+
+ w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+ if (w_realpath_len == 0) {
+ return -1;
+ }
+
+ w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
+ if (w_realpath_ptr == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ if (pGetFinalPathNameByHandleW(handle,
+ w_realpath_ptr,
+ w_realpath_len,
+ VOLUME_NAME_DOS) == 0) {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ /* convert UNC path to long path */
+ if (wcsncmp(w_realpath_ptr,
+ UNC_PATH_PREFIX,
+ UNC_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 6;
+ *w_finalpath_ptr = L'\\';
+ } else if (wcsncmp(w_realpath_ptr,
+ LONG_PATH_PREFIX,
+ LONG_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 4;
+ } else {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL);
+ uv__free(w_realpath_ptr);
+ return r;
+}
+
+static void fs__realpath(uv_fs_t* req) {
+ HANDLE handle;
+
+ if (!pGetFinalPathNameByHandleW) {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
+ CloseHandle(handle);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ CloseHandle(handle);
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
static void fs__chown(uv_fs_t* req) {
req->result = 0;
@@ -1743,6 +1836,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(LINK, link)
XX(SYMLINK, symlink)
XX(READLINK, readlink)
+ XX(REALPATH, realpath)
XX(CHOWN, chown)
XX(FCHOWN, fchown);
default:
@@ -2067,6 +2161,31 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
}
+int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ if (!req || !path) {
+ return UV_EINVAL;
+ }
+
+ uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__realpath(req);
+ return req->result;
+ }
+}
+
+
int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
uv_gid_t gid, uv_fs_cb cb) {
int err;
diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c
index 3d23660e88..ceed3b7638 100644
--- a/deps/uv/src/win/getaddrinfo.c
+++ b/deps/uv/src/win/getaddrinfo.c
@@ -109,10 +109,8 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */
- if (req->alloc != NULL) {
- uv__free(req->alloc);
- req->alloc = NULL;
- }
+ uv__free(req->alloc);
+ req->alloc = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
@@ -219,9 +217,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
char* alloc_ptr = (char*)ai;
/* release copied result memory */
- if (alloc_ptr != NULL) {
- uv__free(alloc_ptr);
- }
+ uv__free(alloc_ptr);
}
@@ -354,8 +350,9 @@ int uv_getaddrinfo(uv_loop_t* loop,
}
error:
- if (req != NULL && req->alloc != NULL) {
+ if (req != NULL) {
uv__free(req->alloc);
+ req->alloc = NULL;
}
return uv_translate_sys_error(err);
}
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
index 8d4081bdb5..783f21af0f 100644
--- a/deps/uv/src/win/internal.h
+++ b/deps/uv/src/win/internal.h
@@ -327,6 +327,7 @@ void uv__util_init();
uint64_t uv__hrtime(double scale);
int uv_parent_pid();
+int uv_current_pid();
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index 8312b1ceb9..bcce80c77e 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle);
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
- _snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
+ snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
}
@@ -1246,6 +1246,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
if (send_handle) {
tcp_send_handle = (uv_tcp_t*)send_handle;
+ if (handle->pipe.conn.ipc_pid == 0) {
+ handle->pipe.conn.ipc_pid = uv_current_pid();
+ }
+
err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
&ipc_frame.socket_info_ex.socket_info);
if (err) {
@@ -1629,7 +1633,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
if (ReadFile(handle->handle,
buf.base,
- buf.len,
+ min(buf.len, avail),
&bytes,
NULL)) {
/* Successful read */
diff --git a/deps/uv/src/win/snprintf.c b/deps/uv/src/win/snprintf.c
new file mode 100644
index 0000000000..776c0e3921
--- /dev/null
+++ b/deps/uv/src/win/snprintf.c
@@ -0,0 +1,42 @@
+/* Copyright the libuv project 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.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
+ * on overflow...
+ */
+int snprintf(char* buf, size_t len, const char* fmt, ...) {
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ n = _vscprintf(fmt, ap);
+ vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
+
+ va_end(ap);
+ return n;
+}
+
+#endif
diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
index b40bb42710..d87cc69909 100644
--- a/deps/uv/src/win/tty.c
+++ b/deps/uv/src/win/tty.c
@@ -208,7 +208,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
static int style_captured = 0;
/* Only do this once.
- /* Assumption: Caller has acquired uv_tty_output_lock. */
+ Assumption: Caller has acquired uv_tty_output_lock. */
if (style_captured)
return;
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
index a0d1307f8a..cb24751304 100644
--- a/deps/uv/src/win/util.c
+++ b/deps/uv/src/win/util.c
@@ -59,6 +59,10 @@
static char *process_title;
static CRITICAL_SECTION process_title_lock;
+/* Cached copy of the process id, written once. */
+static DWORD current_pid = 0;
+
+
/* Interval (in seconds) of the high-resolution clock. */
static double hrtime_interval_ = 0;
@@ -359,6 +363,14 @@ int uv_parent_pid() {
}
+int uv_current_pid() {
+ if (current_pid == 0) {
+ current_pid = GetCurrentProcessId();
+ }
+ return current_pid;
+}
+
+
char** uv_setup_args(int argc, char** argv) {
return argv;
}
diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c
index b0b7fd825f..26bd064866 100644
--- a/deps/uv/src/win/winapi.c
+++ b/deps/uv/src/win/winapi.c
@@ -46,6 +46,7 @@ sSleepConditionVariableSRW pSleepConditionVariableSRW;
sWakeAllConditionVariable pWakeAllConditionVariable;
sWakeConditionVariable pWakeConditionVariable;
sCancelSynchronousIo pCancelSynchronousIo;
+sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
void uv_winapi_init() {
@@ -139,4 +140,7 @@ void uv_winapi_init() {
pCancelSynchronousIo = (sCancelSynchronousIo)
GetProcAddress(kernel32_module, "CancelSynchronousIo");
+
+ pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
+ GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
}
diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h
index 5bc79bcab2..122198a6d4 100644
--- a/deps/uv/src/win/winapi.h
+++ b/deps/uv/src/win/winapi.h
@@ -4678,6 +4678,12 @@ typedef VOID (WINAPI* sWakeConditionVariable)
typedef BOOL (WINAPI* sCancelSynchronousIo)
(HANDLE hThread);
+typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
+ (HANDLE hFile,
+ LPWSTR lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
/* Ntdll function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
@@ -4699,5 +4705,6 @@ extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
extern sWakeAllConditionVariable pWakeAllConditionVariable;
extern sWakeConditionVariable pWakeConditionVariable;
extern sCancelSynchronousIo pCancelSynchronousIo;
+extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
#endif /* UV_WIN_WINAPI_H_ */
diff --git a/deps/uv/test/runner-win.h b/deps/uv/test/runner-win.h
index c94b89bd5e..8cc4c16eb2 100644
--- a/deps/uv/test/runner-win.h
+++ b/deps/uv/test/runner-win.h
@@ -19,9 +19,6 @@
* IN THE SOFTWARE.
*/
-/* Don't complain about _snprintf being insecure. */
-#define _CRT_SECURE_NO_WARNINGS
-
/* Don't complain about write(), fileno() etc. being deprecated. */
#pragma warning(disable : 4996)
@@ -30,10 +27,9 @@
#include <windows.h>
#include <stdio.h>
-
-/* Windows has no snprintf, only _snprintf. */
-#define snprintf _snprintf
-
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
typedef struct {
HANDLE process;
diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c
index e094defc7e..c616d17644 100644
--- a/deps/uv/test/runner.c
+++ b/deps/uv/test/runner.c
@@ -210,6 +210,8 @@ int run_test(const char* test,
#ifndef _WIN32
/* Clean up stale socket from previous run. */
remove(TEST_PIPENAME);
+ remove(TEST_PIPENAME_2);
+ remove(TEST_PIPENAME_3);
#endif
/* If it's a helper the user asks for, start it directly. */
diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h
index e736763802..d18c1daa36 100644
--- a/deps/uv/test/task.h
+++ b/deps/uv/test/task.h
@@ -50,9 +50,11 @@
#ifdef _WIN32
# define TEST_PIPENAME "\\\\?\\pipe\\uv-test"
# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2"
+# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3"
#else
# define TEST_PIPENAME "/tmp/uv-test-sock"
# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
+# define TEST_PIPENAME_3 "/tmp/uv-test-sock3"
#endif
#ifdef _WIN32
@@ -174,40 +176,8 @@ enum test_status {
#endif
-
-#if defined _WIN32 && ! defined __GNUC__
-
-#include <stdarg.h>
-
-/* Define inline for MSVC<2015 */
-# if defined(_MSC_VER) && _MSC_VER < 1900
-# define inline __inline
-# endif
-
-# if defined(_MSC_VER) && _MSC_VER < 1900
-/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
- * on overflow...
- */
-inline int snprintf(char* buf, size_t len, const char* fmt, ...) {
- va_list ap;
- int n;
-
- va_start(ap, fmt);
- n = _vsprintf_p(buf, len, fmt, ap);
- va_end(ap);
-
- /* It's a sad fact of life that no one ever checks the return value of
- * snprintf(). Zero-terminating the buffer hopefully reduces the risk
- * of gaping security holes.
- */
- if (n < 0)
- if (len > 0)
- buf[0] = '\0';
-
- return n;
-}
-# endif
-
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
#endif
#if defined(__clang__) || \
diff --git a/deps/uv/test/test-emfile.c b/deps/uv/test/test-emfile.c
index 453bfe4cf5..dd35f785b4 100644
--- a/deps/uv/test/test-emfile.c
+++ b/deps/uv/test/test-emfile.c
@@ -25,7 +25,6 @@
#include "task.h"
#include <errno.h>
-#include <stdio.h>
#include <sys/resource.h>
#include <unistd.h>
@@ -45,6 +44,13 @@ TEST_IMPL(emfile) {
uv_loop_t* loop;
int first_fd;
+ /* Lower the file descriptor limit and use up all fds save one. */
+ limits.rlim_cur = limits.rlim_max = maxfd + 1;
+ if (setrlimit(RLIMIT_NOFILE, &limits)) {
+ ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */
+ RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?");
+ }
+
loop = uv_default_loop();
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(loop, &server_handle));
@@ -52,13 +58,6 @@ TEST_IMPL(emfile) {
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
- /* Lower the file descriptor limit and use up all fds save one. */
- limits.rlim_cur = limits.rlim_max = maxfd + 1;
- if (setrlimit(RLIMIT_NOFILE, &limits)) {
- perror("setrlimit(RLIMIT_NOFILE)");
- ASSERT(0);
- }
-
/* Remember the first one so we can clean up afterwards. */
do
first_fd = dup(0);
diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c
index a0908ce575..e02ff2fda5 100644
--- a/deps/uv/test/test-fs-event.c
+++ b/deps/uv/test/test-fs-event.c
@@ -115,7 +115,11 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file1") == 0);
+ #else
ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
+ #endif
ASSERT(0 == uv_fs_event_stop(handle));
uv_close((uv_handle_t*)handle, close_cb);
}
@@ -178,8 +182,12 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #else
ASSERT(filename == NULL ||
strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #endif
if (fs_event_created + fs_event_removed == fs_event_file_count) {
/* Once we've processed all create events, delete all files */
@@ -250,8 +258,16 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #else
ASSERT(filename == NULL ||
- strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0);
+ strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #endif
if (fs_event_created + fs_event_removed == fs_event_file_count) {
/* Once we've processed all create events, delete all files */
@@ -270,7 +286,11 @@ static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file2") == 0);
+ #else
ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
+ #endif
ASSERT(0 == uv_fs_event_stop(handle));
uv_close((uv_handle_t*)handle, close_cb);
}
@@ -293,7 +313,11 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "watch_file") == 0);
+ #else
ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
+ #endif
/* Regression test for SunOS: touch should generate just one event. */
{
@@ -487,7 +511,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
- r = uv_timer_start(&timer, timer_cb_touch, 1, 0);
+ r = uv_timer_start(&timer, timer_cb_touch, 10, 0);
ASSERT(r == 0);
ASSERT(timer_cb_touch_called == 0);
diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c
index 90572ca614..cf37ac4909 100644
--- a/deps/uv/test/test-fs.c
+++ b/deps/uv/test/test-fs.c
@@ -83,6 +83,7 @@ static int fchown_cb_count;
static int link_cb_count;
static int symlink_cb_count;
static int readlink_cb_count;
+static int realpath_cb_count;
static int utime_cb_count;
static int futime_cb_count;
@@ -168,6 +169,35 @@ static void readlink_cb(uv_fs_t* req) {
}
+static void realpath_cb(uv_fs_t* req) {
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size = sizeof(test_file_abs_buf);
+ ASSERT(req->fs_type == UV_FS_REALPATH);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req->result == UV_ENOSYS) {
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+ return;
+ }
+#endif
+ ASSERT(req->result == 0);
+
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+#ifdef _WIN32
+ strcat(test_file_abs_buf, "\\test_file");
+ ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0);
+#else
+ strcat(test_file_abs_buf, "/test_file");
+ ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0);
+#endif
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
static void access_cb(uv_fs_t* req) {
ASSERT(req->fs_type == UV_FS_ACCESS);
access_cb_count++;
@@ -1565,11 +1595,43 @@ TEST_IMPL(fs_readlink) {
}
+TEST_IMPL(fs_realpath) {
+ uv_fs_t req;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(dummy_cb_count == 1);
+ ASSERT(req.ptr == NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req.result == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL));
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
TEST_IMPL(fs_symlink) {
int r;
uv_fs_t req;
uv_file file;
uv_file link;
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size;
/* Setup. */
unlink("test_file");
@@ -1577,6 +1639,14 @@ TEST_IMPL(fs_symlink) {
unlink("test_file_symlink2");
unlink("test_file_symlink_symlink");
unlink("test_file_symlink2_symlink");
+ test_file_abs_size = sizeof(test_file_abs_buf);
+#ifdef _WIN32
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "\\test_file");
+#else
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "/test_file");
+#endif
loop = uv_default_loop();
@@ -1647,6 +1717,24 @@ TEST_IMPL(fs_symlink) {
ASSERT(strcmp(req.ptr, "test_file_symlink") == 0);
uv_fs_req_cleanup(&req);
+ r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
/* async link */
r = uv_fs_symlink(loop,
&req,
@@ -1687,6 +1775,20 @@ TEST_IMPL(fs_symlink) {
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(readlink_cb_count == 1);
+ r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(realpath_cb_count == 1);
+
/*
* Run the loop just to check we don't have make any extraneous uv_ref()
* calls. This should drop out immediately.
@@ -1710,12 +1812,15 @@ TEST_IMPL(fs_symlink_dir) {
int r;
char* test_dir;
uv_dirent_t dent;
+ static char test_dir_abs_buf[PATHMAX];
+ size_t test_dir_abs_size;
/* set-up */
unlink("test_dir/file1");
unlink("test_dir/file2");
rmdir("test_dir");
rmdir("test_dir_symlink");
+ test_dir_abs_size = sizeof(test_dir_abs_buf);
loop = uv_default_loop();
@@ -1723,16 +1828,16 @@ TEST_IMPL(fs_symlink_dir) {
uv_fs_req_cleanup(&req);
#ifdef _WIN32
- {
- static char src_path_buf[PATHMAX];
- size_t size;
- size = sizeof(src_path_buf);
- strcpy(src_path_buf, "\\\\?\\");
- uv_cwd(src_path_buf + 4, &size);
- strcat(src_path_buf, "\\test_dir\\");
- test_dir = src_path_buf;
- }
+ strcpy(test_dir_abs_buf, "\\\\?\\");
+ uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
+ test_dir_abs_size += 4;
+ strcat(test_dir_abs_buf, "\\test_dir\\");
+ test_dir_abs_size += strlen("\\test_dir\\");
+ test_dir = test_dir_abs_buf;
#else
+ uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
+ strcat(test_dir_abs_buf, "/test_dir");
+ test_dir_abs_size += strlen("/test_dir");
test_dir = "test_dir";
#endif
@@ -1767,6 +1872,25 @@ TEST_IMPL(fs_symlink_dir) {
#endif
uv_fs_req_cleanup(&req);
+ r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(strlen(req.ptr) == test_dir_abs_size - 5);
+ ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
S_IWUSR | S_IRUSR, NULL);
ASSERT(r >= 0);
diff --git a/deps/uv/test/test-get-loadavg.c b/deps/uv/test/test-get-loadavg.c
index 7465e18b91..4762e47576 100644
--- a/deps/uv/test/test-get-loadavg.c
+++ b/deps/uv/test/test-get-loadavg.c
@@ -24,10 +24,9 @@
TEST_IMPL(get_loadavg) {
- double avg[3];
+ double avg[3] = {-1, -1, -1};
uv_loadavg(avg);
- ASSERT(avg != NULL);
ASSERT(avg[0] >= 0);
ASSERT(avg[1] >= 0);
ASSERT(avg[2] >= 0);
diff --git a/deps/uv/test/test-getaddrinfo.c b/deps/uv/test/test-getaddrinfo.c
index 45813c313a..6b644a8d44 100644
--- a/deps/uv/test/test-getaddrinfo.c
+++ b/deps/uv/test/test-getaddrinfo.c
@@ -83,10 +83,11 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle,
TEST_IMPL(getaddrinfo_fail) {
uv_getaddrinfo_t req;
+ /* Use a FQDN by ending in a period */
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,
getaddrinfo_fail_cb,
- "xyzzy.xyzzy.xyzzy",
+ "xyzzy.xyzzy.xyzzy.",
NULL,
NULL));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
@@ -100,10 +101,11 @@ TEST_IMPL(getaddrinfo_fail) {
TEST_IMPL(getaddrinfo_fail_sync) {
uv_getaddrinfo_t req;
+ /* Use a FQDN by ending in a period */
ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
- "xyzzy.xyzzy.xyzzy",
+ "xyzzy.xyzzy.xyzzy.",
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);
diff --git a/deps/uv/test/test-getnameinfo.c b/deps/uv/test/test-getnameinfo.c
index ebe9246699..b1391616d1 100644
--- a/deps/uv/test/test-getnameinfo.c
+++ b/deps/uv/test/test-getnameinfo.c
@@ -73,8 +73,8 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) {
NULL,
(const struct sockaddr*)&addr4,
0));
- ASSERT(req.host != NULL);
- ASSERT(req.service != NULL);
+ ASSERT(req.host[0] != '\0');
+ ASSERT(req.service[0] != '\0');
MAKE_VALGRIND_HAPPY();
return 0;
diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c
index d9b913339d..c445483fa0 100644
--- a/deps/uv/test/test-ipc-send-recv.c
+++ b/deps/uv/test/test-ipc-send-recv.c
@@ -30,6 +30,8 @@ void spawn_helper(uv_pipe_t* channel,
uv_process_t* process,
const char* helper);
+void ipc_send_recv_helper_threadproc(void* arg);
+
union handles {
uv_handle_t handle;
uv_stream_t stream;
@@ -38,16 +40,37 @@ union handles {
uv_tty_t tty;
};
-struct echo_ctx {
+struct test_ctx {
uv_pipe_t channel;
+ uv_connect_t connect_req;
uv_write_t write_req;
+ uv_write_t write_req2;
uv_handle_type expected_type;
union handles send;
+ union handles send2;
+ union handles recv;
+ union handles recv2;
+};
+
+struct echo_ctx {
+ uv_pipe_t listen;
+ uv_pipe_t channel;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ uv_handle_type expected_type;
union handles recv;
+ union handles recv2;
};
-static struct echo_ctx ctx;
-static int num_recv_handles;
+static struct test_ctx ctx;
+static struct echo_ctx ctx2;
+
+/* Used in write2_cb to decide if we need to cleanup or not */
+static int is_child_process;
+static int is_in_process;
+static int read_cb_called;
+static int recv_cb_called;
+static int write2_cb_called;
static void alloc_cb(uv_handle_t* handle,
@@ -66,39 +89,55 @@ static void recv_cb(uv_stream_t* handle,
uv_handle_type pending;
uv_pipe_t* pipe;
int r;
+ union handles* recv;
+
+ if (++recv_cb_called == 1) {
+ recv = &ctx.recv;
+ } else {
+ recv = &ctx.recv2;
+ }
pipe = (uv_pipe_t*) handle;
ASSERT(pipe == &ctx.channel);
- ASSERT(nread >= 0);
- ASSERT(1 == uv_pipe_pending_count(pipe));
-
- pending = uv_pipe_pending_type(pipe);
- ASSERT(pending == ctx.expected_type);
-
- if (pending == UV_NAMED_PIPE)
- r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
- else if (pending == UV_TCP)
- r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
- else
- abort();
- ASSERT(r == 0);
- r = uv_accept(handle, &ctx.recv.stream);
- ASSERT(r == 0);
-
- uv_close((uv_handle_t*)&ctx.channel, NULL);
- uv_close(&ctx.send.handle, NULL);
- uv_close(&ctx.recv.handle, NULL);
- num_recv_handles++;
+ /* Depending on the OS, the final recv_cb can be called after the child
+ * process has terminated which can result in nread being UV_EOF instead of
+ * the number of bytes read. Since the other end of the pipe has closed this
+ * UV_EOF is an acceptable value. */
+ if (nread == UV_EOF) {
+ /* UV_EOF is only acceptable for the final recv_cb call */
+ ASSERT(recv_cb_called == 2);
+ } else {
+ ASSERT(nread >= 0);
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(pending == ctx.expected_type);
+
+ if (pending == UV_NAMED_PIPE)
+ r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
+ else if (pending == UV_TCP)
+ r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
+ else
+ abort();
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, &recv->stream);
+ ASSERT(r == 0);
+ }
+
+ /* Close after two writes received */
+ if (recv_cb_called == 2) {
+ uv_close((uv_handle_t*)&ctx.channel, NULL);
+ }
}
-
-static int run_test(void) {
- uv_process_t process;
- uv_buf_t buf;
+static void connect_cb(uv_connect_t* req, int status) {
int r;
+ uv_buf_t buf;
- spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
+ ASSERT(req == &ctx.connect_req);
+ ASSERT(status == 0);
buf = uv_buf_init(".", 1);
r = uv_write2(&ctx.write_req,
@@ -108,19 +147,56 @@ static int run_test(void) {
NULL);
ASSERT(r == 0);
+ /* Perform two writes to the same pipe to make sure that on Windows we are
+ * not running into issue 505:
+ * https://github.com/libuv/libuv/issues/505 */
+ buf = uv_buf_init(".", 1);
+ r = uv_write2(&ctx.write_req2,
+ (uv_stream_t*)&ctx.channel,
+ &buf, 1,
+ &ctx.send2.stream,
+ NULL);
+ ASSERT(r == 0);
+
r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
ASSERT(r == 0);
+}
+
+static int run_test(int inprocess) {
+ uv_process_t process;
+ uv_thread_t tid;
+ int r;
+
+ if (inprocess) {
+ r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42);
+ ASSERT(r == 0);
+
+ uv_sleep(1000);
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb);
+ } else {
+ spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
+
+ connect_cb(&ctx.connect_req, 0);
+ }
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
- ASSERT(num_recv_handles == 1);
+ ASSERT(recv_cb_called == 2);
+
+ if (inprocess) {
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+ }
return 0;
}
-
-TEST_IMPL(ipc_send_recv_pipe) {
+static int run_ipc_send_recv_pipe(int inprocess) {
int r;
ctx.expected_type = UV_NAMED_PIPE;
@@ -131,15 +207,28 @@ TEST_IMPL(ipc_send_recv_pipe) {
r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME);
ASSERT(r == 0);
- r = run_test();
+ r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}
+TEST_IMPL(ipc_send_recv_pipe) {
+ return run_ipc_send_recv_pipe(0);
+}
-TEST_IMPL(ipc_send_recv_tcp) {
+TEST_IMPL(ipc_send_recv_pipe_inprocess) {
+ return run_ipc_send_recv_pipe(1);
+}
+
+static int run_ipc_send_recv_tcp(int inprocess) {
struct sockaddr_in addr;
int r;
@@ -150,25 +239,45 @@ TEST_IMPL(ipc_send_recv_tcp) {
r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
ASSERT(r == 0);
+ r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp);
+ ASSERT(r == 0);
+
r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
- r = run_test();
+ r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}
+TEST_IMPL(ipc_send_recv_tcp) {
+ return run_ipc_send_recv_tcp(0);
+}
+
+TEST_IMPL(ipc_send_recv_tcp_inprocess) {
+ return run_ipc_send_recv_tcp(1);
+}
+
-/* Everything here runs in a child process. */
+/* Everything here runs in a child process or second thread. */
static void write2_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
- uv_close(&ctx.recv.handle, NULL);
- uv_close((uv_handle_t*)&ctx.channel, NULL);
-}
+ /* After two successful writes in the child process, allow the child
+ * process to be closed. */
+ if (++write2_cb_called == 2 && (is_child_process || is_in_process)) {
+ uv_close(&ctx2.recv.handle, NULL);
+ uv_close(&ctx2.recv2.handle, NULL);
+ uv_close((uv_handle_t*)&ctx2.channel, NULL);
+ uv_close((uv_handle_t*)&ctx2.listen, NULL);
+ }
+}
static void read_cb(uv_stream_t* handle,
ssize_t nread,
@@ -177,37 +286,102 @@ static void read_cb(uv_stream_t* handle,
uv_pipe_t* pipe;
uv_handle_type pending;
int r;
+ union handles* recv;
+ uv_write_t* write_req;
+
+ if (nread == UV__EOF || nread == UV__ECONNABORTED) {
+ return;
+ }
+
+ if (++read_cb_called == 2) {
+ recv = &ctx2.recv;
+ write_req = &ctx2.write_req;
+ } else {
+ recv = &ctx2.recv2;
+ write_req = &ctx2.write_req2;
+ }
pipe = (uv_pipe_t*) handle;
- ASSERT(pipe == &ctx.channel);
+ ASSERT(pipe == &ctx2.channel);
ASSERT(nread >= 0);
ASSERT(1 == uv_pipe_pending_count(pipe));
pending = uv_pipe_pending_type(pipe);
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
- wrbuf = uv_buf_init(".", 1);
-
if (pending == UV_NAMED_PIPE)
- r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
+ r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
else if (pending == UV_TCP)
- r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
+ r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
else
abort();
ASSERT(r == 0);
- r = uv_accept(handle, &ctx.recv.stream);
+ r = uv_accept(handle, &recv->stream);
ASSERT(r == 0);
- r = uv_write2(&ctx.write_req,
- (uv_stream_t*)&ctx.channel,
+ wrbuf = uv_buf_init(".", 1);
+ r = uv_write2(write_req,
+ (uv_stream_t*)&ctx2.channel,
&wrbuf,
1,
- &ctx.recv.stream,
+ &recv->stream,
write2_cb);
ASSERT(r == 0);
}
+static void send_recv_start() {
+ int r;
+ ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel));
+
+ r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+static void listen_cb(uv_stream_t* handle, int status) {
+ int r;
+ ASSERT(handle == (uv_stream_t*)&ctx2.listen);
+ ASSERT(status == 0);
+
+ r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel);
+ ASSERT(r == 0);
+
+ send_recv_start();
+}
+
+int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) {
+ int r;
+
+ is_in_process = inprocess;
+
+ memset(&ctx2, 0, sizeof(ctx2));
+
+ r = uv_pipe_init(loop, &ctx2.listen, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &ctx2.channel, 1);
+ ASSERT(r == 0);
+
+ if (inprocess) {
+ r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb);
+ ASSERT(r == 0);
+ } else {
+ r = uv_pipe_open(&ctx2.channel, 0);
+ ASSERT(r == 0);
+
+ send_recv_start();
+ }
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ return 0;
+}
/* stdin is a duplex channel over which a handle is sent.
* We receive it and send it back where it came from.
@@ -215,22 +389,23 @@ static void read_cb(uv_stream_t* handle,
int ipc_send_recv_helper(void) {
int r;
- memset(&ctx, 0, sizeof(ctx));
-
- r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
+ r = run_ipc_send_recv_helper(uv_default_loop(), 0);
ASSERT(r == 0);
- uv_pipe_open(&ctx.channel, 0);
- ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel));
- ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel));
- ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
- r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb);
+void ipc_send_recv_helper_threadproc(void* arg) {
+ int r;
+ uv_loop_t loop;
+
+ r = uv_loop_init(&loop);
ASSERT(r == 0);
- r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ r = run_ipc_send_recv_helper(&loop, 1);
ASSERT(r == 0);
- MAKE_VALGRIND_HAPPY();
- return 0;
+ r = uv_loop_close(&loop);
+ ASSERT(r == 0);
}
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 8ee74391af..858a20af49 100644
--- a/deps/uv/test/test-list.h
+++ b/deps/uv/test/test-list.h
@@ -50,8 +50,10 @@ TEST_DECLARE (ipc_listen_before_write)
TEST_DECLARE (ipc_listen_after_write)
#ifndef _WIN32
TEST_DECLARE (ipc_send_recv_pipe)
+TEST_DECLARE (ipc_send_recv_pipe_inprocess)
#endif
TEST_DECLARE (ipc_send_recv_tcp)
+TEST_DECLARE (ipc_send_recv_tcp_inprocess)
TEST_DECLARE (ipc_tcp_connection)
TEST_DECLARE (tcp_ping_pong)
TEST_DECLARE (tcp_ping_pong_v6)
@@ -252,6 +254,7 @@ TEST_DECLARE (fs_unlink_readonly)
TEST_DECLARE (fs_chown)
TEST_DECLARE (fs_link)
TEST_DECLARE (fs_readlink)
+TEST_DECLARE (fs_realpath)
TEST_DECLARE (fs_symlink)
TEST_DECLARE (fs_symlink_dir)
TEST_DECLARE (fs_utime)
@@ -334,6 +337,7 @@ HELPER_DECLARE (tcp6_echo_server)
HELPER_DECLARE (udp4_echo_server)
HELPER_DECLARE (pipe_echo_server)
+TEST_DECLARE (queue_foreach_delete)
TASK_LIST_START
TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)
@@ -380,8 +384,10 @@ TASK_LIST_START
TEST_ENTRY (ipc_listen_after_write)
#ifndef _WIN32
TEST_ENTRY (ipc_send_recv_pipe)
+ TEST_ENTRY (ipc_send_recv_pipe_inprocess)
#endif
TEST_ENTRY (ipc_send_recv_tcp)
+ TEST_ENTRY (ipc_send_recv_tcp_inprocess)
TEST_ENTRY (ipc_tcp_connection)
TEST_ENTRY (tcp_ping_pong)
@@ -671,6 +677,7 @@ TASK_LIST_START
TEST_ENTRY (fs_utime)
TEST_ENTRY (fs_futime)
TEST_ENTRY (fs_readlink)
+ TEST_ENTRY (fs_realpath)
TEST_ENTRY (fs_symlink)
TEST_ENTRY (fs_symlink_dir)
TEST_ENTRY (fs_stat_missing_path)
@@ -714,6 +721,9 @@ TASK_LIST_START
TEST_ENTRY (dlerror)
TEST_ENTRY (ip4_addr)
TEST_ENTRY (ip6_addr_link_local)
+
+ TEST_ENTRY (queue_foreach_delete)
+
#if 0
/* These are for testing the test runner. */
TEST_ENTRY (fail_always)
diff --git a/deps/uv/test/test-mutexes.c b/deps/uv/test/test-mutexes.c
index 4aeac73b4c..af5e4e88a2 100644
--- a/deps/uv/test/test-mutexes.c
+++ b/deps/uv/test/test-mutexes.c
@@ -25,6 +25,10 @@
#include <stdio.h>
#include <stdlib.h>
+static uv_cond_t condvar;
+static uv_mutex_t mutex;
+static uv_rwlock_t rwlock;
+static int step;
/* The mutex and rwlock tests are really poor.
* They're very basic sanity checks and nothing more.
@@ -63,60 +67,96 @@ TEST_IMPL(thread_rwlock) {
}
-TEST_IMPL(thread_rwlock_trylock) {
- uv_rwlock_t rwlock;
- int r;
-
- r = uv_rwlock_init(&rwlock);
- ASSERT(r == 0);
-
- /* No locks held. */
+/* Call when holding |mutex|. */
+static void synchronize_nowait(void) {
+ step += 1;
+ uv_cond_signal(&condvar);
+}
- r = uv_rwlock_trywrlock(&rwlock);
- ASSERT(r == 0);
- /* Write lock held. */
+/* Call when holding |mutex|. */
+static void synchronize(void) {
+ int current;
- r = uv_rwlock_tryrdlock(&rwlock);
- ASSERT(r == UV_EBUSY);
- r = uv_rwlock_trywrlock(&rwlock);
- ASSERT(r == UV_EBUSY);
+ synchronize_nowait();
+ /* Wait for the other thread. Guard against spurious wakeups. */
+ for (current = step; current == step; uv_cond_wait(&condvar, &mutex));
+ ASSERT(step == current + 1);
+}
- uv_rwlock_wrunlock(&rwlock);
- /* No locks held. */
+static void thread_rwlock_trylock_peer(void* unused) {
+ (void) &unused;
- r = uv_rwlock_tryrdlock(&rwlock);
- ASSERT(r == 0);
+ uv_mutex_lock(&mutex);
- /* One read lock held. */
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
- r = uv_rwlock_tryrdlock(&rwlock);
- ASSERT(r == 0);
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
- /* Two read locks held. */
+ /* Acquire write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
- r = uv_rwlock_trywrlock(&rwlock);
- ASSERT(r == UV_EBUSY);
+ /* Release write lock and acquire read lock. */
+ uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
uv_rwlock_rdunlock(&rwlock);
+ synchronize_nowait(); /* Signal main thread we're going away. */
+ uv_mutex_unlock(&mutex);
+}
- /* One read lock held. */
- uv_rwlock_rdunlock(&rwlock);
+TEST_IMPL(thread_rwlock_trylock) {
+ uv_thread_t thread;
- /* No read locks held. */
+ ASSERT(0 == uv_cond_init(&condvar));
+ ASSERT(0 == uv_mutex_init(&mutex));
+ ASSERT(0 == uv_rwlock_init(&rwlock));
- r = uv_rwlock_trywrlock(&rwlock);
- ASSERT(r == 0);
+ uv_mutex_lock(&mutex);
+ ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL));
- /* Write lock held. */
+ /* Hold write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize(); /* Releases the mutex to the other thread. */
+ /* Release write lock and acquire read lock. Pthreads doesn't support
+ * the notion of upgrading or downgrading rwlocks, so neither do we.
+ */
uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
+
+ /* Release read lock. */
+ uv_rwlock_rdunlock(&rwlock);
+ synchronize();
- /* No locks held. */
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ ASSERT(0 == uv_thread_join(&thread));
uv_rwlock_destroy(&rwlock);
+ uv_mutex_unlock(&mutex);
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&condvar);
return 0;
}
diff --git a/deps/uv/test/test-process-title.c b/deps/uv/test/test-process-title.c
index 29be20749b..42ade44160 100644
--- a/deps/uv/test/test-process-title.c
+++ b/deps/uv/test/test-process-title.c
@@ -42,7 +42,7 @@ static void set_title(const char* title) {
TEST_IMPL(process_title) {
-#if defined(__sun)
+#if defined(__sun) || defined(_AIX)
RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
#else
/* Check for format string vulnerabilities. */
diff --git a/deps/uv/test/test-queue-foreach-delete.c b/deps/uv/test/test-queue-foreach-delete.c
new file mode 100644
index 0000000000..45da225381
--- /dev/null
+++ b/deps/uv/test/test-queue-foreach-delete.c
@@ -0,0 +1,200 @@
+/* Copyright The libuv project and contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+
+
+/*
+ * The idea behind the test is as follows.
+ * Certain handle types are stored in a queue internally.
+ * Extra care should be taken for removal of a handle from the queue while iterating over the queue.
+ * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH())
+ * This usually happens when someone closes or stops a handle from within its callback.
+ * So we need to check that we haven't screwed the queue on close/stop.
+ * To do so we do the following (for each handle type):
+ * 1. Create and start 3 handles (#0, #1, and #2).
+ *
+ * The queue after the start() calls:
+ * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=..
+ *
+ * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do).
+ *
+ * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type)
+ * stop the handle and the next one (#1).
+ * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed,
+ * so callback for handle #2 will be called first)
+ *
+ * The queue after the stop() calls:
+ * correct foreach "next" |
+ * \/
+ * ..=> [queue head] <==============================> [handle] <=..
+ * [ ] <- [handle] <=> [handle #1] -> [ ]
+ * /\
+ * wrong foreach "next" |
+ *
+ * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step.
+ * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called.
+ */
+
+static const unsigned first_handle_number_idle = 2;
+static const unsigned first_handle_number_prepare = 2;
+static const unsigned first_handle_number_check = 2;
+#ifdef __linux__
+static const unsigned first_handle_number_fs_event = 0;
+#endif
+
+
+#define DEFINE_GLOBALS_AND_CBS(name) \
+ static uv_##name##_t (name)[3]; \
+ static unsigned name##_cb_calls[3]; \
+ \
+ static void name##2_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[2]); \
+ if (first_handle_number_##name == 2) { \
+ uv_close((uv_handle_t*)&(name)[2], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[2]++; \
+ } \
+ \
+ static void name##1_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[1]); \
+ ASSERT(0 && "Shouldn't be called" && (&name[0])); \
+ } \
+ \
+ static void name##0_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[0]); \
+ if (first_handle_number_##name == 0) { \
+ uv_close((uv_handle_t*)&(name)[0], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[0]++; \
+ } \
+ \
+ static const uv_##name##_cb name##_cbs[] = { \
+ (uv_##name##_cb)name##0_cb, \
+ (uv_##name##_cb)name##1_cb, \
+ (uv_##name##_cb)name##2_cb, \
+ };
+
+#define INIT_AND_START(name, loop) \
+ do { \
+ size_t i; \
+ for (i = 0; i < ARRAY_SIZE(name); i++) { \
+ int r; \
+ r = uv_##name##_init((loop), &(name)[i]); \
+ ASSERT(r == 0); \
+ \
+ r = uv_##name##_start(&(name)[i], name##_cbs[i]); \
+ ASSERT(r == 0); \
+ } \
+ } while (0)
+
+#define END_ASSERTS(name) \
+ do { \
+ ASSERT(name##_cb_calls[0] == 1); \
+ ASSERT(name##_cb_calls[1] == 0); \
+ ASSERT(name##_cb_calls[2] == 1); \
+ } while (0)
+
+DEFINE_GLOBALS_AND_CBS(idle)
+DEFINE_GLOBALS_AND_CBS(prepare)
+DEFINE_GLOBALS_AND_CBS(check)
+
+#ifdef __linux__
+DEFINE_GLOBALS_AND_CBS(fs_event)
+
+static const char watched_dir[] = ".";
+static uv_timer_t timer;
+static unsigned helper_timer_cb_calls;
+
+
+static void init_and_start_fs_events(uv_loop_t* loop) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(fs_event); i++) {
+ int r;
+ r = uv_fs_event_init(loop, &fs_event[i]);
+ ASSERT(r == 0);
+
+ r = uv_fs_event_start(&fs_event[i],
+ (uv_fs_event_cb)fs_event_cbs[i],
+ watched_dir,
+ 0);
+ ASSERT(r == 0);
+ }
+}
+
+static void helper_timer_cb(uv_timer_t* thandle) {
+ int r;
+ uv_fs_t fs_req;
+
+ /* fire all fs_events */
+ r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(fs_req.result == 0);
+ ASSERT(fs_req.fs_type == UV_FS_UTIME);
+ ASSERT(strcmp(fs_req.path, watched_dir) == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ helper_timer_cb_calls++;
+}
+#endif
+
+
+TEST_IMPL(queue_foreach_delete) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ INIT_AND_START(idle, loop);
+ INIT_AND_START(prepare, loop);
+ INIT_AND_START(check, loop);
+
+#ifdef __linux__
+ init_and_start_fs_events(loop);
+
+ /* helper timer to trigger async and fs_event callbacks */
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, helper_timer_cb, 0, 0);
+ ASSERT(r == 0);
+#endif
+
+ r = uv_run(loop, UV_RUN_NOWAIT);
+ ASSERT(r == 1);
+
+ END_ASSERTS(idle);
+ END_ASSERTS(prepare);
+ END_ASSERTS(check);
+
+#ifdef __linux__
+ ASSERT(helper_timer_cb_calls == 1);
+#endif
+
+ MAKE_VALGRIND_HAPPY();
+
+ return 0;
+}
diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c
index e71f0f7d53..eba54ae705 100644
--- a/deps/uv/test/test-spawn.c
+++ b/deps/uv/test/test-spawn.c
@@ -960,11 +960,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
options.stdio_count = 2;
/* Create a pipe that'll cause a collision. */
- _snprintf(name,
- sizeof(name),
- "\\\\.\\pipe\\uv\\%p-%d",
- &out,
- GetCurrentProcessId());
+ snprintf(name,
+ sizeof(name),
+ "\\\\.\\pipe\\uv\\%p-%d",
+ &out,
+ GetCurrentProcessId());
pipe_handle = CreateNamedPipeA(name,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
diff --git a/deps/uv/test/test-tcp-try-write.c b/deps/uv/test/test-tcp-try-write.c
index 8a60136b64..97a1d6e3d5 100644
--- a/deps/uv/test/test-tcp-try-write.c
+++ b/deps/uv/test/test-tcp-try-write.c
@@ -58,6 +58,11 @@ static void connect_cb(uv_connect_t* req, int status) {
break;
}
} while (1);
+
+ do {
+ buf = uv_buf_init("", 0);
+ r = uv_try_write((uv_stream_t*) &client, &buf, 1);
+ } while (r != 0);
uv_close((uv_handle_t*) &client, close_cb);
}
diff --git a/deps/uv/test/test-tcp-write-fail.c b/deps/uv/test/test-tcp-write-fail.c
index 2840d81610..5256a9f4a7 100644
--- a/deps/uv/test/test-tcp-write-fail.c
+++ b/deps/uv/test/test-tcp-write-fail.c
@@ -43,7 +43,7 @@ static void close_socket(uv_tcp_t* sock) {
r = uv_fileno((uv_handle_t*)sock, &fd);
ASSERT(r == 0);
#ifdef _WIN32
- r = closesocket(fd);
+ r = closesocket((uv_os_sock_t)fd);
#else
r = close(fd);
#endif
diff --git a/deps/uv/test/test-threadpool-cancel.c b/deps/uv/test/test-threadpool-cancel.c
index cb45622451..784c1739f6 100644
--- a/deps/uv/test/test-threadpool-cancel.c
+++ b/deps/uv/test/test-threadpool-cancel.c
@@ -276,7 +276,7 @@ TEST_IMPL(threadpool_cancel_work) {
TEST_IMPL(threadpool_cancel_fs) {
struct cancel_info ci;
- uv_fs_t reqs[25];
+ uv_fs_t reqs[26];
uv_loop_t* loop;
unsigned n;
uv_buf_t iov;
@@ -305,6 +305,7 @@ TEST_IMPL(threadpool_cancel_fs) {
ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb));
ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb));
ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb));
ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb));
diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c
index 81e612c1d6..b844959d52 100644
--- a/deps/uv/test/test-tty.c
+++ b/deps/uv/test/test-tty.c
@@ -153,11 +153,14 @@ TEST_IMPL(tty_file) {
ASSERT(0 == close(fd));
}
+/* Bug on AIX where '/dev/random' returns 1 from isatty() */
+#ifndef _AIX
fd = open("/dev/random", O_RDONLY);
if (fd != -1) {
ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
}
+#endif /* _AIX */
fd = open("/dev/zero", O_RDONLY);
if (fd != -1) {
diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c
index 1d5720ce73..1b0db78b8e 100644
--- a/deps/uv/test/test-udp-ipv6.c
+++ b/deps/uv/test/test-udp-ipv6.c
@@ -26,6 +26,10 @@
#include <stdlib.h>
#include <string.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server \
|| (uv_udp_t*)(handle) == &client \
@@ -43,6 +47,18 @@ static int send_cb_called;
static int recv_cb_called;
static int close_cb_called;
+#ifdef __FreeBSD__
+static int can_ipv6_ipv4_dual() {
+ int v6only;
+ size_t size = sizeof(int);
+
+ if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0))
+ return 0;
+
+ return v6only != 1;
+}
+#endif
+
static void alloc_cb(uv_handle_t* handle,
size_t suggested_size,
@@ -150,6 +166,11 @@ TEST_IMPL(udp_dual_stack) {
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");
+#ifdef __FreeBSD__
+ if (!can_ipv6_ipv4_dual())
+ RETURN_SKIP("IPv6-IPv4 dual stack not supported");
+#endif
+
do_test(ipv6_recv_ok, 0);
ASSERT(recv_cb_called == 1);
diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c
index 873cb6d811..f635bdb9e1 100644
--- a/deps/uv/test/test-udp-multicast-join6.c
+++ b/deps/uv/test/test-udp-multicast-join6.c
@@ -119,7 +119,7 @@ TEST_IMPL(udp_multicast_join6) {
ASSERT(r == 0);
/* join the multicast channel */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_AIX)
r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP);
#else
r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP);
diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp
index 8049faa7a6..635a234ea6 100644
--- a/deps/uv/uv.gyp
+++ b/deps/uv/uv.gyp
@@ -104,6 +104,13 @@
'src/win/winsock.c',
'src/win/winsock.h',
],
+ 'conditions': [
+ ['MSVS_VERSION < "2015"', {
+ 'sources': [
+ 'src/win/snprintf.c'
+ ]
+ }]
+ ],
'link_settings': {
'libraries': [
'-ladvapi32',
@@ -340,6 +347,7 @@
'test/test-poll-close-doesnt-corrupt-stack.c',
'test/test-poll-closesocket.c',
'test/test-process-title.c',
+ 'test/test-queue-foreach-delete.c',
'test/test-ref.c',
'test/test-run-nowait.c',
'test/test-run-once.c',