deps: upgrade libuv to 1.7.3
authorSaúl Ibarra Corretgé <saghul@gmail.com>
Wed, 5 Aug 2015 19:17:46 +0000 (21:17 +0200)
committerRod Vagg <rod@vagg.org>
Wed, 2 Sep 2015 11:32:17 +0000 (21:32 +1000)
PR-URL: https://github.com/nodejs/node/pull/2310
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: cjihrig - Colin Ihrig <cjihrig@gmail.com>
78 files changed:
deps/uv/AUTHORS
deps/uv/ChangeLog
deps/uv/MAINTAINERS.md [new file with mode: 0644]
deps/uv/Makefile.am
deps/uv/README.md
deps/uv/android-configure
deps/uv/appveyor.yml [new file with mode: 0644]
deps/uv/common.gypi
deps/uv/configure.ac
deps/uv/docs/src/check.rst
deps/uv/docs/src/errors.rst
deps/uv/docs/src/fs.rst
deps/uv/docs/src/fs_event.rst
deps/uv/docs/src/idle.rst
deps/uv/docs/src/index.rst
deps/uv/docs/src/misc.rst
deps/uv/docs/src/pipe.rst
deps/uv/docs/src/signal.rst
deps/uv/docs/src/stream.rst
deps/uv/docs/src/tcp.rst
deps/uv/docs/src/tty.rst
deps/uv/docs/src/udp.rst
deps/uv/docs/src/version.rst [new file with mode: 0644]
deps/uv/include/uv-version.h
deps/uv/include/uv.h
deps/uv/libuv.nsi [new file with mode: 0644]
deps/uv/src/queue.h
deps/uv/src/threadpool.c
deps/uv/src/unix/aix.c
deps/uv/src/unix/core.c
deps/uv/src/unix/freebsd.c
deps/uv/src/unix/fs.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/kqueue.c
deps/uv/src/unix/loop.c
deps/uv/src/unix/pthread-fixes.c
deps/uv/src/unix/stream.c
deps/uv/src/unix/tcp.c
deps/uv/src/unix/tty.c
deps/uv/src/unix/udp.c
deps/uv/src/uv-common.c
deps/uv/src/uv-common.h
deps/uv/src/version.c
deps/uv/src/win/core.c
deps/uv/src/win/fs-event.c
deps/uv/src/win/fs.c
deps/uv/src/win/internal.h
deps/uv/src/win/pipe.c
deps/uv/src/win/process-stdio.c
deps/uv/src/win/tcp.c
deps/uv/src/win/thread.c
deps/uv/src/win/tty.c
deps/uv/src/win/udp.c
deps/uv/test/benchmark-fs-stat.c
deps/uv/test/echo-server.c
deps/uv/test/run-tests.c
deps/uv/test/runner-unix.c
deps/uv/test/task.h
deps/uv/test/test-fs-event.c
deps/uv/test/test-fs.c
deps/uv/test/test-list.h
deps/uv/test/test-pipe-connect-multiple.c [new file with mode: 0644]
deps/uv/test/test-pipe-pending-instances.c [new file with mode: 0644]
deps/uv/test/test-signal-multiple-loops.c
deps/uv/test/test-spawn.c
deps/uv/test/test-tcp-close-while-connecting.c
deps/uv/test/test-tcp-connect-timeout.c
deps/uv/test/test-tcp-create-socket-early.c [new file with mode: 0644]
deps/uv/test/test-tcp-open.c
deps/uv/test/test-tcp-squelch-connreset.c [new file with mode: 0644]
deps/uv/test/test-threadpool-cancel.c
deps/uv/test/test-udp-create-socket-early.c [new file with mode: 0644]
deps/uv/test/test-udp-multicast-interface.c
deps/uv/test/test-udp-multicast-join.c
deps/uv/test/test-udp-multicast-join6.c
deps/uv/test/test-udp-multicast-ttl.c
deps/uv/test/test-udp-open.c
deps/uv/uv.gyp

index bbb8f4d..2c12c14 100644 (file)
@@ -200,3 +200,22 @@ farblue68 <farblue68@gmail.com>
 Jason Williams <necmon@yahoo.com>
 Igor Soarez <igorsoarez@gmail.com>
 Miodrag Milanovic <mmicko@gmail.com>
+Cheng Zhao <zcbenz@gmail.com>
+Michael Neumann <mneumann@think.localnet>
+Stefano Cristiano <stefanocristiano82@gmail.com>
+heshamsafi <hesham.safi.eldeen@gmail.com>
+A. Hauptmann <andreashauptmann@t-online.de>
+John McNamee <jpm@microwiz.com>
+Yosuke Furukawa <yosuke.furukawa@gmail.com>
+Santiago Gimeno <santiago.gimeno@quantion.es>
+guworks <ground.up.works@gmail.com>
+RossBencina <rossb@audiomulch.com>
+Roger A. Light <roger@atchoo.org>
+chenttuuvv <chenttuuvv@yahoo.com>
+Richard Lau <riclau@uk.ibm.com>
+ronkorving <rkorving@wizcorp.jp>
+Corbin Simpson <MostAwesomeDude@gmail.com>
+Zachary Hamm <zsh@imipolexg.org>
+Karl Skomski <karl@skomski.com>
+Jeremy Whitlock <jwhitlock@apache.org>
+Willem Thiart <himself@willemthiart.com>
index 5d3a4ca..e9ebdec 100644 (file)
@@ -1,3 +1,163 @@
+2015.08.28, Version 1.7.3 (Stable), 93877b11c8b86e0a6befcda83a54555c1e36e4f0
+
+Changes since version 1.7.2:
+
+* threadpool: fix thread starvation bug (Ben Noordhuis)
+
+
+2015.08.25, Version 1.7.2 (Stable), 4d13a013fcfa72311f0102751fdc7951873f466c
+
+Changes since version 1.7.1:
+
+* unix, win: make uv_loop_init return on error (Willem Thiart)
+
+* win: reset pipe handle for pipe servers (Saúl Ibarra Corretgé)
+
+* win: fix replacing pipe handle for pipe servers (Saúl Ibarra Corretgé)
+
+* win: fix setting pipe pending instances after bind (Saúl Ibarra Corretgé)
+
+
+2015.08.20, Version 1.7.1 (Stable), 44f4b6bd82d8ae4583ccc4768a83af778ef69f85
+
+Changes since version 1.7.0:
+
+* doc: document the procedure for verifying releases (Saúl Ibarra Corretgé)
+
+* doc: add note about Windows binaries to the README (Saúl Ibarra Corretgé)
+
+* doc: use long GPG IDs in MAINTAINERS.md (Saúl Ibarra Corretgé)
+
+* Revert "stream: squelch ECONNRESET error if already closed" (Saúl Ibarra
+  Corretgé)
+
+* doc: clarify uv_read_stop() is idempotent (Corbin Simpson)
+
+* unix: OpenBSD's setsockopt needs an unsigned char for multicast (Zachary
+  Hamm)
+
+* test: Fix two memory leaks (Karl Skomski)
+
+* unix,win: return EINVAL on nullptr args in uv_fs_{read,write} (Karl Skomski)
+
+* win: set accepted TCP sockets as non-inheritable (Saúl Ibarra Corretgé)
+
+* unix: remove superfluous parentheses in fs macros (Ben Noordhuis)
+
+* unix: don't copy arguments for sync fs requests (Ben Noordhuis)
+
+* test: plug small memory leak in unix test runner (Ben Noordhuis)
+
+* unix,windows: allow NULL loop for sync fs requests (Ben Noordhuis)
+
+* unix,windows: don't assert on unknown error code (Ben Noordhuis)
+
+* stream: retry write on EPROTOTYPE on OSX (Brian White)
+
+* common: fix use of snprintf on Windows (Saúl Ibarra Corretgé)
+
+* tests: refactored fs watch_dir tests for stability (Jeremy Whitlock)
+
+
+2015.08.06, Version 1.7.0 (Stable), 415a865d6365ba58d02b92b89d46ba5d7744ec8b
+
+Changes since version 1.6.1:
+
+* win,stream: add slot to remember CRT fd (Bert Belder)
+
+* win,pipe: properly close when created from CRT fd (Bert Belder)
+
+* win,pipe: don't close fd 0-2 (Bert Belder)
+
+* win,tty: convert fd -> handle safely (Bert Belder)
+
+* win,tty: properly close when created from CRT fd (Bert Belder)
+
+* win,tty: don't close fd 0-2 (Bert Belder)
+
+* win,fs: don't close fd 0-2 (Bert Belder)
+
+* win: include "malloc.h" (Cheng Zhao)
+
+* windows: MSVC 2015 has C99 inline (Jason Williams)
+
+* dragonflybsd: fixes for nonblocking and cloexec (Michael Neumann)
+
+* dragonflybsd: use sendfile(2) for uv_fs_sendfile (Michael Neumann)
+
+* dragonflybsd: fix uv_exepath (Michael Neumann)
+
+* win,fs: Fixes align(8) directive on mingw (Stefano Cristiano)
+
+* unix, win: prevent replacing fd in uv_{udp,tcp,pipe}_t (Saúl Ibarra Corretgé)
+
+* win: move logic to set socket non-inheritable to uv_tcp_set_socket (Saúl
+  Ibarra Corretgé)
+
+* unix, win: add ability to create tcp/udp sockets early (Saúl Ibarra Corretgé)
+
+* test: retry select() on EINTR, honor milliseconds (Ben Noordhuis)
+
+* unix: consolidate tcp and udp bind error (Saúl Ibarra Corretgé)
+
+* test: conditionally skip udp_ipv6_multicast_join6 (heshamsafi)
+
+* core: add UV_VERSION_HEX macro (Saúl Ibarra Corretgé)
+
+* doc: add section with version-checking macros and functions (Saúl Ibarra
+  Corretgé)
+
+* tty: cleanup handle if uv_tty_init fails (Saúl Ibarra Corretgé)
+
+* darwin: save a fd when FSEvents is used (Saúl Ibarra Corretgé)
+
+* win: fix returning thread id in uv_thread_self (Saúl Ibarra Corretgé)
+
+* common: use offsetof for QUEUE_DATA (Saúl Ibarra Corretgé)
+
+* win: remove UV_HANDLE_CONNECTED (A. Hauptmann)
+
+* docs: add Windows specific note for uv_fs_open (Saúl Ibarra Corretgé)
+
+* doc: add note about uv_fs_scandir (Saúl Ibarra Corretgé)
+
+* test,unix: reduce stack size of watchdog threads (Ben Noordhuis)
+
+* win: add support for recursive file watching (Saúl Ibarra Corretgé)
+
+* win,tty: support consoles with non-default colors (John McNamee)
+
+* doc: add missing variable name (Yosuke Furukawa)
+
+* stream: squelch ECONNRESET error if already closed (Santiago Gimeno)
+
+* build: remove ancient condition from common.gypi (Saúl Ibarra Corretgé)
+
+* tests: skip some tests when network is unreachable (Luca Bruno)
+
+* build: proper support for android cross compilation (guworks)
+
+* android: add missing include to pthread-fixes.c (RossBencina)
+
+* test: fix compilation warning (Saúl Ibarra Corretgé)
+
+* doc: add a note about uv_dirent_t.type (Saúl Ibarra Corretgé)
+
+* win,test: fix shared library build (Saúl Ibarra Corretgé)
+
+* test: fix compilation warning (Santiago Gimeno)
+
+* build: add experimental Windows installer (Roger A. Light)
+
+* threadpool: send signal only when queue is empty (chenttuuvv)
+
+* aix: fix uv_exepath with relative paths (Richard Lau)
+
+* build: fix version syntax in AppVeyor file (Saúl Ibarra Corretgé)
+
+* unix: allow nbufs > IOV_MAX in uv_fs_{read,write} (ronkorving)
+
+
 2015.06.06, Version 1.6.1 (Stable), 30c8be07bb78a66fdee5141626bf53a49a17094a
 
 Changes since version 1.6.0:
diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md
new file mode 100644 (file)
index 0000000..4db2f51
--- /dev/null
@@ -0,0 +1,36 @@
+
+# Project Maintainers
+
+libuv is currently managed by the following individuals:
+
+* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
+  - GPG key: D77B 1E34 243F BAF0 5F8E  9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
+* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
+* **Fedor Indutny** ([@indutny](https://github.com/indutny))
+  - GPG key: AF2E EA41 EC34 47BF DD86  FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
+* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
+  - GPG key: FDF5 1936 4458 319F A823  3DC9 410E 5553 AE9B C059 (pubkey-saghul)
+
+## Storing a maintainer key in Git
+
+It's quite handy to store a maintainer's signature as a git blob, and have
+that object tagged and signed with such key.
+
+Export your public key:
+
+    $ gpg --armor --export saghul@gmail.com > saghul.asc
+
+Store it as a blob on the repo:
+
+    $ git hash-object -w saghul.asc
+
+The previous command returns a hash, copy it. For the sake of this explanation,
+we'll assume it's 'abcd1234'. Storing the blob in git is not enough, it could
+be garbage collected since nothing references it, so we'll create a tag for it:
+
+    $ git tag -s pubkey-saghul abcd1234
+
+Commit the changes and push:
+
+    $ git push origin pubkey-saghul
+
index e9814d7..f0ca6a7 100644 (file)
@@ -186,8 +186,10 @@ test_run_tests_SOURCES = test/blackhole-server.c \
                          test/test-ping-pong.c \
                          test/test-pipe-bind-error.c \
                          test/test-pipe-connect-error.c \
+                         test/test-pipe-connect-multiple.c \
                          test/test-pipe-connect-prepare.c \
                          test/test-pipe-getsockname.c \
+                         test/test-pipe-pending-instances.c \
                          test/test-pipe-sendmsg.c \
                          test/test-pipe-server-close.c \
                          test/test-pipe-close-stdout-read-stdin.c \
@@ -215,6 +217,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
                          test/test-tcp-close-accept.c \
                          test/test-tcp-close-while-connecting.c \
                          test/test-tcp-close.c \
+                         test/test-tcp-create-socket-early.c \
                          test/test-tcp-connect-error-after-write.c \
                          test/test-tcp-connect-error.c \
                          test/test-tcp-connect-timeout.c \
@@ -240,6 +243,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
                          test/test-timer.c \
                          test/test-tty.c \
                          test/test-udp-bind.c \
+                         test/test-udp-create-socket-early.c \
                          test/test-udp-dgram-too-big.c \
                          test/test-udp-ipv6.c \
                          test/test-udp-multicast-interface.c \
index f9a7a1e..0ce2669 100644 (file)
@@ -89,6 +89,42 @@ also serve as API specification and usage examples.
 These resources are not handled by libuv maintainers and might be out of
 date. Please verify it before opening new issues.
 
+## Downloading
+
+libuv can be downloaded either from the
+[GitHub repository](https://github.com/libuv/libuv)
+or from the [downloads site](http://dist.libuv.org/dist/).
+
+Starting with libuv 1.7.0, binaries for Windows are also provided. This is to
+be considered EXPERIMENTAL.
+
+Before verifying the git tags or signature files, importing the relevant keys
+is necessary. Key IDs are listed in the
+[MAINTAINERS](https://github.com/libuv/libuv/blob/master/MAINTAINERS.md)
+file, but are also available as git blob objects for easier use.
+
+Importing a key the usual way:
+
+    $ gpg --keyserver pool.sks-keyservers.net \
+      --recv-keys AE9BC059
+
+Importing a key from a git blob object:
+
+    $ git show pubkey-saghul | gpg --import
+
+### Verifying releases
+
+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
+signature file sit alongside each. Once both the release tarball and the
+signature file are downloaded, the file can be verified as follows:
+
+    $ gpg --verify libuv-1.7.0.tar.gz.sign
+
 ## Build Instructions
 
 For GCC there are two build methods: via autotools or via [GYP][].
index 9750581..e0b250f 100755 (executable)
@@ -6,7 +6,7 @@ $1/build/tools/make-standalone-toolchain.sh \
     --toolchain=arm-linux-androideabi-4.8 \
     --arch=arm \
     --install-dir=$TOOLCHAIN \
-    --platform=android-9
+    --platform=android-21
 export PATH=$TOOLCHAIN/bin:$PATH
 export AR=arm-linux-androideabi-ar
 export CC=arm-linux-androideabi-gcc
@@ -16,5 +16,5 @@ export PLATFORM=android
 
 if [ $2 -a $2 == 'gyp' ]
   then
-    ./gyp_uv.py -Dtarget_arch=arm -DOS=android
+    ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android
 fi
diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml
new file mode 100644 (file)
index 0000000..8790283
--- /dev/null
@@ -0,0 +1,36 @@
+version: v1.7.3.build{build}
+
+install:
+  - cinst -y nsis
+
+matrix:
+  fast_finish: true
+  allow_failures:
+    - platform: x86
+      configuration: Release
+    - platform: x64
+      configuration: Release
+
+platform:
+  - x86
+  - x64
+
+configuration:
+  - Release
+
+build_script:
+  # Fixed tag version number if using a tag.
+  - cmd: if "%APPVEYOR_REPO_TAG%" == "true" set APPVEYOR_BUILD_VERSION=%APPVEYOR_REPO_TAG_NAME%
+  # vcbuild overwrites the platform variable.
+  - cmd: set ARCH=%platform%
+  - cmd: vcbuild.bat release %ARCH% shared
+
+after_build:
+  - '"%PROGRAMFILES(x86)%\NSIS\makensis" /DVERSION=%APPVEYOR_BUILD_VERSION% /DARCH=%ARCH% libuv.nsi'
+
+artifacts:
+  - name: Installer
+    path: 'libuv-*.exe'
+
+cache:
+  - C:\projects\libuv\build\gyp
index ecf9475..c6f6dec 100644 (file)
           'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ],
         },
         'conditions': [
-          ['OS != "win"', {
-            'defines': [ 'EV_VERIFY=2' ],
-          }],
+          ['OS == "android"', {
+            'cflags': [ '-fPIE' ],
+            'ldflags': [ '-fPIE', '-pie' ]
+          }]
         ]
       },
       'Release': {
index fe7228e..ad5cb00 100644 (file)
@@ -13,7 +13,7 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 AC_PREREQ(2.57)
-AC_INIT([libuv], [1.6.1], [https://github.com/libuv/libuv/issues])
+AC_INIT([libuv], [1.7.3], [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])
index 8d48f22..36c93cf 100644 (file)
@@ -31,7 +31,7 @@ N/A
 API
 ---
 
-.. c:function:: int uv_check_init(uv_loop_t*, uv_check_t* check)
+.. c:function:: int uv_check_init(uv_loop_t* loop, uv_check_t* check)
 
     Initialize the handle.
 
index 5d59dc3..cec25f5 100644 (file)
@@ -322,8 +322,10 @@ API
 
 .. c:function:: const char* uv_strerror(int err)
 
-    Returns the error message for the given error code.
+    Returns the error message for the given error code.  Leaks a few bytes
+    of memory when you call it with an unknown error code.
 
 .. c:function:: const char* uv_err_name(int err)
 
-    Returns the error name for the given error code.
+    Returns the error name for the given error code.  Leaks a few bytes
+    of memory when you call it with an unknown error code.
index c2a3fc2..33c0440 100644 (file)
@@ -168,6 +168,11 @@ API
 
     Equivalent to :man:`open(2)`.
 
+    .. note::
+        On Windows libuv uses `CreateFileW` and thus the file is always opened
+        in binary mode. Because of this the O_BINARY and O_TEXT flags are not
+        supported.
+
 .. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
 
     Equivalent to :man:`preadv(2)`.
@@ -206,6 +211,13 @@ API
     get `ent` populated with the next directory entry data. When there are no
     more entries ``UV_EOF`` will be returned.
 
+    .. note::
+        Unlike `scandir(3)`, this function does not return the "." and ".." entries.
+
+    .. note::
+        On Linux, getting the type of an entry is only supported by some filesystems (btrfs, ext2,
+        ext3 and ext4 at the time of this writing), check the :man:`getdents(2)` man page.
+
 .. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
 .. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
 .. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
index 681ae52..c2d7f52 100644 (file)
@@ -88,7 +88,7 @@ API
     `path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`.
 
     .. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and
-              only on OSX.
+              only on OSX and Windows.
 
 .. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle)
 
index 81f51d2..1f51c4a 100644 (file)
@@ -39,7 +39,7 @@ N/A
 API
 ---
 
-.. c:function:: int uv_idle_init(uv_loop_t*, uv_idle_t* idle)
+.. c:function:: int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle)
 
     Initialize the handle.
 
index 9cdc494..fa89c4b 100644 (file)
@@ -68,6 +68,7 @@ Documentation
 
    design
    errors
+   version
    loop
    handle
    request
index 9708c5d..e9ddba3 100644 (file)
@@ -135,17 +135,6 @@ API
     For :man:`isatty(3)` equivalent functionality use this function and test
     for ``UV_TTY``.
 
-.. c:function:: unsigned int uv_version(void)
-
-    Returns the libuv version packed into a single integer. 8 bits are used for
-    each component, with the patch number stored in the 8 least significant
-    bits. E.g. for libuv 1.2.3 this would return 0x010203.
-
-.. c:function:: const char* uv_version_string(void)
-
-    Returns the libuv version number as a string. For non-release versions
-    "-pre" is appended, so the version number could be "1.2.3-pre".
-
 .. c:function:: int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, uv_free_func free_func)
 
     .. versionadded:: 1.6.0
index df896a0..d33b0f2 100644 (file)
@@ -29,12 +29,12 @@ N/A
 API
 ---
 
-.. c:function:: int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc)
+.. c:function:: int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)
 
     Initialize a pipe handle. The `ipc` argument is a boolean to indicate if
     this pipe will be used for handle passing between processes.
 
-.. c:function:: int uv_pipe_open(uv_pipe_t*, uv_file file)
+.. c:function:: int uv_pipe_open(uv_pipe_t* handle, uv_file file)
 
     Open an existing file descriptor or HANDLE as a pipe.
 
index 2167594..dc1223b 100644 (file)
@@ -62,7 +62,7 @@ Public members
 API
 ---
 
-.. c:function:: int uv_signal_init(uv_loop_t*, uv_signal_t* signal)
+.. c:function:: int uv_signal_init(uv_loop_t* loop, uv_signal_t* signal)
 
     Initialize the handle.
 
index 880f0e2..21562b3 100644 (file)
@@ -123,7 +123,7 @@ API
     .. note::
         `server` and `client` must be handles running on the same loop.
 
-.. c:function:: int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
+.. c:function:: int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
 
     Read data from an incoming stream. The callback will be made several
     times until there is no more data to read or :c:func:`uv_read_stop` is called.
@@ -142,6 +142,8 @@ API
     Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
     no longer be called.
 
+    This function is idempotent and may be safely called on a stopped stream.
+
 .. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
 
     Write data to stream. Buffers are written in order. Example:
index dd746fe..dd18522 100644 (file)
@@ -28,9 +28,18 @@ N/A
 API
 ---
 
-.. c:function:: int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle)
+.. c:function:: int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle)
 
-    Initialize the handle.
+    Initialize the handle. No socket is created as of yet.
+
+.. 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
+    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`.
+
+    .. versionadded:: 1.7.0
 
 .. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
 
index 18f34ef..655dca9 100644 (file)
@@ -46,7 +46,7 @@ N/A
 API
 ---
 
-.. c:function:: int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable)
+.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int readable)
 
     Initialize a new TTY stream with the given file descriptor. Usually the
     file descriptor will be:
@@ -70,7 +70,7 @@ API
                         descriptor that refers to a file returns `UV_EINVAL`
                         on UNIX.
 
-.. c:function:: int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode)
+.. c:function:: int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode)
 
     .. versionchanged:: 1.2.0: the mode is specified as a
                         :c:type:`uv_tty_mode_t` value.
@@ -86,7 +86,7 @@ API
     code ``UV_EBUSY`` if you call it when execution is inside
     :c:func:`uv_tty_set_mode`.
 
-.. c:function:: int uv_tty_get_winsize(uv_tty_t*, int* width, int* height)
+.. c:function:: int uv_tty_get_winsize(uv_tty_t* handle, int* width, int* height)
 
     Gets the current Window size. On success it returns 0.
 
index ec7ce56..dd46603 100644 (file)
@@ -105,11 +105,20 @@ Public members
 API
 ---
 
-.. c:function:: int uv_udp_init(uv_loop_t*, uv_udp_t* handle)
+.. c:function:: int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle)
 
     Initialize a new UDP handle. The actual socket is created lazily.
     Returns 0 on success.
 
+.. c:function:: int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
+
+    Initialize the handle with the specified flags. At the moment 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_udp_init`.
+
+    .. versionadded:: 1.7.0
+
 .. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
 
     Opens an existing file descriptor or Windows SOCKET as a UDP handle.
diff --git a/deps/uv/docs/src/version.rst b/deps/uv/docs/src/version.rst
new file mode 100644 (file)
index 0000000..e1715b2
--- /dev/null
@@ -0,0 +1,60 @@
+
+.. _version:
+
+Version-checking macros and functions
+=====================================
+
+Starting with version 1.0.0 libuv follows the `semantic versioning`_
+scheme. This means that new APIs can be introduced throughout the lifetime of
+a major release. In this section you'll find all macros and functions that
+will allow you to write or compile code conditionally, in order to work with
+multiple libuv versions.
+
+.. _semantic versioning: http://semver.org
+
+
+Macros
+------
+
+.. c:macro:: UV_VERSION_MAJOR
+
+    libuv version's major number.
+
+.. c:macro:: UV_VERSION_MINOR
+
+    libuv version's minor number.
+
+.. c:macro:: UV_VERSION_PATCH
+
+    libuv version's patch number.
+
+.. c:macro:: UV_VERSION_IS_RELEASE
+
+    Set to 1 to indicate a release version of libuv, 0 for a development
+    snapshot.
+
+.. c:macro:: UV_VERSION_SUFFIX
+
+    libuv version suffix. Certain development releases such as Release Candidates
+    might have a suffix such as "rc".
+
+.. c:macro:: UV_VERSION_HEX
+
+    Returns the libuv version packed into a single integer. 8 bits are used for
+    each component, with the patch number stored in the 8 least significant
+    bits. E.g. for libuv 1.2.3 this would be 0x010203.
+
+    .. versionadded:: 1.7.0
+
+
+Functions
+---------
+
+.. c:function:: unsigned int uv_version(void)
+
+    Returns :c:macro:`UV_VERSION_HEX`.
+
+.. c:function:: const char* uv_version_string(void)
+
+    Returns the libuv version number as a string. For non-release versions the
+    version suffix is included.
index 3372212..90f2ce1 100644 (file)
  */
 
 #define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 6
-#define UV_VERSION_PATCH 1
+#define UV_VERSION_MINOR 7
+#define UV_VERSION_PATCH 3
 #define UV_VERSION_IS_RELEASE 1
 #define UV_VERSION_SUFFIX ""
 
+#define UV_VERSION_HEX  ((UV_VERSION_MAJOR << 16) | \
+                         (UV_VERSION_MINOR <<  8) | \
+                         (UV_VERSION_PATCH))
+
 #endif /* UV_VERSION_H */
index 564af5f..f96026b 100644 (file)
@@ -406,7 +406,10 @@ struct uv_shutdown_s {
   /* private */                                                               \
   uv_close_cb close_cb;                                                       \
   void* handle_queue[2];                                                      \
-  void* reserved[4];                                                          \
+  union {                                                                     \
+    int fd;                                                                   \
+    void* reserved[4];                                                        \
+  } u;                                                                        \
   UV_HANDLE_PRIVATE_FIELDS                                                    \
 
 /* The abstract base class of all handles. */
@@ -504,6 +507,7 @@ struct uv_tcp_s {
 };
 
 UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
+UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
 UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
 UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
 UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
@@ -594,6 +598,7 @@ struct uv_udp_send_s {
 };
 
 UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
+UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
 UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
 UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
                           const struct sockaddr* addr,
diff --git a/deps/uv/libuv.nsi b/deps/uv/libuv.nsi
new file mode 100644 (file)
index 0000000..159756e
--- /dev/null
@@ -0,0 +1,86 @@
+; NSIS installer script for libuv
+
+!include "MUI2.nsh"
+
+Name "libuv"
+OutFile "libuv-${ARCH}-${VERSION}.exe"
+
+!include "x64.nsh"
+# Default install location, for 32-bit files
+InstallDir "$PROGRAMFILES\libuv"
+
+# Override install and registry locations if this is a 64-bit install.
+function .onInit
+       ${If} ${ARCH} == "x64"
+               SetRegView 64
+               StrCpy $INSTDIR "$PROGRAMFILES64\libuv"
+       ${EndIf}
+functionEnd
+
+;--------------------------------
+; Installer pages
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+
+;--------------------------------
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+; Languages
+!insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+; Installer sections
+
+Section "Files" SecInstall
+       SectionIn RO
+       SetOutPath "$INSTDIR"
+       File "Release\*.dll"
+       File "Release\*.lib"
+       File "LICENSE"
+       File "README.md"
+
+       SetOutPath "$INSTDIR\include"
+       File "include\uv.h"
+       File "include\uv-errno.h"
+       File "include\uv-threadpool.h"
+       File "include\uv-version.h"
+       File "include\uv-win.h"
+       File "include\tree.h"
+
+       WriteUninstaller "$INSTDIR\Uninstall.exe"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayName" "libuv-${ARCH}-${VERSION}"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "HelpLink" "http://libuv.org/"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "URLInfoAbout" "http://libuv.org/"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayVersion" "${VERSION}"
+       WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoModify" "1"
+       WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoRepair" "1"
+SectionEnd
+
+Section "Uninstall"
+       Delete "$INSTDIR\libuv.dll"
+       Delete "$INSTDIR\libuv.lib"
+       Delete "$INSTDIR\LICENSE"
+       Delete "$INSTDIR\README.md"
+
+       Delete "$INSTDIR\include\uv.h"
+       Delete "$INSTDIR\include\uv-errno.h"
+       Delete "$INSTDIR\include\uv-threadpool.h"
+       Delete "$INSTDIR\include\uv-version.h"
+       Delete "$INSTDIR\include\uv-win.h"
+       Delete "$INSTDIR\include\tree.h"
+
+       Delete "$INSTDIR\Uninstall.exe"
+       RMDir "$INSTDIR"
+       DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}"
+SectionEnd
+
index fe02b45..60c8000 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef QUEUE_H_
 #define QUEUE_H_
 
+#include <stddef.h>
+
 typedef void *QUEUE[2];
 
 /* Private macros. */
@@ -26,7 +28,7 @@ typedef void *QUEUE[2];
 
 /* Public macros. */
 #define QUEUE_DATA(ptr, type, field)                                          \
-  ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+  ((type *) ((char *) (ptr) - offsetof(type, field)))
 
 #define QUEUE_FOREACH(q, h)                                                   \
   for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
index debaf5c..15d7199 100644 (file)
@@ -44,6 +44,7 @@ static void uv__req_init(uv_loop_t* loop,
 static uv_once_t once = UV_ONCE_INIT;
 static uv_cond_t cond;
 static uv_mutex_t mutex;
+static unsigned int idle_threads;
 static unsigned int nthreads;
 static uv_thread_t* threads;
 static uv_thread_t default_threads[4];
@@ -69,8 +70,11 @@ static void worker(void* arg) {
   for (;;) {
     uv_mutex_lock(&mutex);
 
-    while (QUEUE_EMPTY(&wq))
+    while (QUEUE_EMPTY(&wq)) {
+      idle_threads += 1;
       uv_cond_wait(&cond, &mutex);
+      idle_threads -= 1;
+    }
 
     q = QUEUE_HEAD(&wq);
 
@@ -103,7 +107,8 @@ static void worker(void* arg) {
 static void post(QUEUE* q) {
   uv_mutex_lock(&mutex);
   QUEUE_INSERT_TAIL(&wq, q);
-  uv_cond_signal(&cond);
+  if (idle_threads > 0)
+    uv_cond_signal(&cond);
   uv_mutex_unlock(&mutex);
 }
 
index a2b0744..c90b7e5 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <sys/protosw.h>
 #include <libperfstat.h>
+#include <procinfo.h>
 #include <sys/proc.h>
 #include <sys/procfs.h>
 
@@ -288,182 +289,80 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
  * and use it in conjunction with PATH environment variable to craft one.
  */
 int uv_exepath(char* buffer, size_t* size) {
-  ssize_t res;
-  char cwd[PATH_MAX], cwdl[PATH_MAX];
-  char symlink[PATH_MAX], temp_buffer[PATH_MAX];
-  char pp[64];
-  struct psinfo ps;
-  int fd;
-  char **argv;
+  int res;
+  char args[PATH_MAX];
+  char abspath[PATH_MAX];
+  size_t abspath_size;
+  struct procsinfo pi;
 
   if (buffer == NULL || size == NULL || *size == 0)
     return -EINVAL;
 
-  snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
-
-  fd = open(pp, O_RDONLY);
-  if (fd < 0)
-    return fd;
-
-  res = read(fd, &ps, sizeof(ps));
-  uv__close(fd);
-  if (res < 0)
-    return res;
-
-  if (ps.pr_argv == 0)
-    return -EINVAL;
-
-  argv = (char **) *((char ***) (intptr_t) ps.pr_argv);
-
-  if ((argv == NULL) || (argv[0] == NULL))
+  pi.pi_pid = getpid();
+  res = getargs(&pi, sizeof(pi), args, sizeof(args));
+  if (res < 0) 
     return -EINVAL;
 
   /*
-   * Three possibilities for argv[0]:
+   * Possibilities for args:
    * i) an absolute path such as: /home/user/myprojects/nodejs/node
-   * ii) a relative path such as: ./node or ./myprojects/nodejs/node
+   * ii) a relative path such as: ./node or ../myprojects/nodejs/node
    * iii) a bare filename such as "node", after exporting PATH variable 
    *     to its location.
    */
 
-  /* case #1, absolute path. */
-  if (argv[0][0] == '/') {
-    snprintf(symlink, PATH_MAX-1, "%s", argv[0]);
-
-    /* This could or could not be a symlink. */
-    res = readlink(symlink, temp_buffer, PATH_MAX-1);
-
-    /* if readlink fails, it is a normal file just copy symlink to the 
-     * output buffer.
-     */
-    if (res < 0) {
-      assert(*size > strlen(symlink));
-      strcpy(buffer, symlink);
-
-    /* If it is a link, the resolved filename is again a relative path,
-     * make it absolute. 
-     */
-    } else {
-      assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
-      snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
-    }
-    *size = strlen(buffer);
-    return 0;
-
-  /* case #2, relative path with usage of '.' */
-  } else if (argv[0][0] == '.') {
-    char *relative = strchr(argv[0], '/');
-    if (relative == NULL)
-      return -EINVAL;
-
-    /* Get the current working directory to resolve the relative path. */
-    snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
-
-    /* This is always a symlink, resolve it. */
-    res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
-    if (res < 0)
+  /* Case i) and ii) absolute or relative paths */
+  if (strchr(args, '/') != NULL) {
+    if (realpath(args, abspath) != abspath) 
       return -errno;
 
-    snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1);
-
-    res = readlink(symlink, temp_buffer, PATH_MAX-1);
-    if (res < 0) {
-      assert(*size > strlen(symlink));
-      strcpy(buffer, symlink);
-    } else {
-      assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
-      snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
-    }
-    *size = strlen(buffer);
-    return 0;
-
-  /* case #3, relative path without usage of '.', such as invocations in Node test suite. */
-  } else if (strchr(argv[0], '/') != NULL) {
-    /* Get the current working directory to resolve the relative path. */
-    snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
+    abspath_size = strlen(abspath);
 
-    /* This is always a symlink, resolve it. */
-    res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
-    if (res < 0)
-      return -errno;
+    *size -= 1;
+    if (*size > abspath_size)
+      *size = abspath_size;
 
-    snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]);
+    memcpy(buffer, abspath, *size);
+    buffer[*size] = '\0';
 
-    res = readlink(symlink, temp_buffer, PATH_MAX-1);
-    if (res < 0) {
-      assert(*size > strlen(symlink));
-      strcpy(buffer, symlink);
-    } else {
-      assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
-      snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
-    }
-    *size = strlen(buffer);
     return 0;
-  /* Usage of absolute filename with location exported in PATH */
   } else {
-    char clonedpath[8192];  /* assume 8k buffer will fit PATH */
+  /* Case iii). Search PATH environment variable */ 
+    char trypath[PATH_MAX];
+    char *clonedpath = NULL;
     char *token = NULL;
-    struct stat statstruct;
-
-    /* Get the paths. */
     char *path = getenv("PATH");
-    if(sizeof(clonedpath) <= strlen(path))
+
+    if (path == NULL)
       return -EINVAL;
 
-    /* Get a local copy. */
-    strcpy(clonedpath, path);
+    clonedpath = uv__strdup(path);
+    if (clonedpath == NULL)
+      return -ENOMEM;
 
-    /* Tokenize. */
     token = strtok(clonedpath, ":");
+    while (token != NULL) {
+      snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+      if (realpath(trypath, abspath) == abspath) { 
+        /* Check the match is executable */
+        if (access(abspath, X_OK) == 0) {
+          abspath_size = strlen(abspath);
 
-    /* Get current working directory. (may be required in the loop). */
-    snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
-    res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
-    if (res < 0)
-      return -errno;
-    /* Run through the tokens, append our executable file name with each,
-     * and see which one succeeds. Exit on first match. */
-    while(token != NULL) {
-      if (token[0] == '.') {
-        /* Path contains a token relative to current directory. */
-        char *relative = strchr(token, '/');
-        if (relative != NULL)
-          /* A path which is not current directory. */
-          snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname);
-        else
-          snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname);
-        if (stat(symlink, &statstruct) != -1) {
-          /* File exists. Resolve if it is a link. */
-          res = readlink(symlink, temp_buffer, PATH_MAX-1);
-          if (res < 0) {
-            assert(*size > strlen(symlink));
-            strcpy(buffer, symlink);
-          } else {
-            assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
-            snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
-          }
-          *size = strlen(buffer);
-          return 0;
-        }
+          *size -= 1;
+          if (*size > abspath_size)
+            *size = abspath_size;
 
-        /* Absolute path names. */
-      } else {
-        snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname);
-        if (stat(symlink, &statstruct) != -1) {
-          res = readlink(symlink, temp_buffer, PATH_MAX-1);
-          if (res < 0) {
-            assert(*size > strlen(symlink));
-            strcpy(buffer, symlink);
-          } else {
-            assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
-            snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
-          }
-          *size = strlen(buffer);
+          memcpy(buffer, abspath, *size);
+          buffer[*size] = '\0';
+
+          uv__free(clonedpath);
           return 0;
         }
       }
       token = strtok(NULL, ":");
     }
+    uv__free(clonedpath);
+
     /* Out of tokens (path entries), and no match found */
     return -EINVAL;
   }
index 826b411..e149357 100644 (file)
@@ -35,7 +35,7 @@
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <limits.h> /* INT_MAX, PATH_MAX */
+#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
 #include <sys/uio.h> /* writev */
 #include <sys/resource.h> /* getrusage */
 #include <pwd.h>
 # include <sys/ioctl.h>
 #endif
 
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__DragonFly__)
 # include <sys/sysctl.h>
 # include <sys/filio.h>
 # include <sys/ioctl.h>
 # include <sys/wait.h>
 # define UV__O_CLOEXEC O_CLOEXEC
-# if __FreeBSD__ >= 10
+# if defined(__FreeBSD__) && __FreeBSD__ >= 10
 #  define uv__accept4 accept4
 #  define UV__SOCK_NONBLOCK SOCK_NONBLOCK
 #  define UV__SOCK_CLOEXEC  SOCK_CLOEXEC
@@ -199,6 +199,19 @@ void uv__make_close_pending(uv_handle_t* handle) {
   handle->loop->closing_handles = handle;
 }
 
+int uv__getiovmax(void) {
+#if defined(IOV_MAX)
+  return IOV_MAX;
+#elif defined(_SC_IOV_MAX)
+  static int iovmax = -1;
+  if (iovmax == -1)
+    iovmax = sysconf(_SC_IOV_MAX);
+  return iovmax;
+#else
+  return 1024;
+#endif
+}
+
 
 static void uv__finish_close(uv_handle_t* handle) {
   /* Note: while the handle is in the UV_CLOSING state now, it's still possible
@@ -477,7 +490,7 @@ int uv__close(int fd) {
 
 
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
-    defined(_AIX)
+    defined(_AIX) || defined(__DragonFly__)
 
 int uv__nonblock(int fd, int set) {
   int r;
@@ -506,7 +519,8 @@ int uv__cloexec(int fd, int set) {
   return 0;
 }
 
-#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) */
+#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+          defined(_AIX) || defined(__DragonFly__)) */
 
 int uv__nonblock(int fd, int set) {
   int flags;
@@ -569,7 +583,8 @@ int uv__cloexec(int fd, int set) {
   return 0;
 }
 
-#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */
+#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+         defined(_AIX) || defined(__DragonFly__) */
 
 
 /* This function is not execve-safe, there is a race window
@@ -907,7 +922,8 @@ int uv__open_cloexec(const char* path, int flags) {
   int err;
   int fd;
 
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9)
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \
+    defined(__DragonFly__)
   static int no_cloexec;
 
   if (!no_cloexec) {
index 44976f7..c838beb 100644 (file)
@@ -74,6 +74,30 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
 }
 
 
+#ifdef __DragonFly__
+int uv_exepath(char* buffer, size_t* size) {
+  char abspath[PATH_MAX * 2 + 1];
+  ssize_t abspath_size;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return -EINVAL;
+
+  abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
+  if (abspath_size < 0)
+    return -errno;
+
+  assert(abspath_size > 0);
+  *size -= 1;
+
+  if (*size > abspath_size)
+    *size = abspath_size;
+
+  memcpy(buffer, abspath, *size);
+  buffer[*size] = '\0';
+
+  return 0;
+}
+#else
 int uv_exepath(char* buffer, size_t* size) {
   char abspath[PATH_MAX * 2 + 1];
   int mib[4];
@@ -82,19 +106,12 @@ int uv_exepath(char* buffer, size_t* size) {
   if (buffer == NULL || size == NULL || *size == 0)
     return -EINVAL;
 
-#ifdef __DragonFly__
-  mib[0] = CTL_KERN;
-  mib[1] = KERN_PROC;
-  mib[2] = KERN_PROC_ARGS;
-  mib[3] = getpid();
-#else
   mib[0] = CTL_KERN;
   mib[1] = KERN_PROC;
   mib[2] = KERN_PROC_PATHNAME;
   mib[3] = -1;
-#endif
 
-  abspath_size = sizeof abspath;;
+  abspath_size = sizeof abspath;
   if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
     return -errno;
 
@@ -110,7 +127,7 @@ int uv_exepath(char* buffer, size_t* size) {
 
   return 0;
 }
-
+#endif
 
 uint64_t uv_get_free_memory(void) {
   int freecount;
index 9dab202..52082e9 100644 (file)
 # include <sys/sendfile.h>
 #endif
 
-#define INIT(type)                                                            \
+#define INIT(subtype)                                                         \
   do {                                                                        \
-    uv__req_init((loop), (req), UV_FS);                                       \
-    (req)->fs_type = UV_FS_ ## type;                                          \
-    (req)->result = 0;                                                        \
-    (req)->ptr = NULL;                                                        \
-    (req)->loop = loop;                                                       \
-    (req)->path = NULL;                                                       \
-    (req)->new_path = NULL;                                                   \
-    (req)->cb = (cb);                                                         \
+    req->type = UV_FS;                                                        \
+    if (cb != NULL)                                                           \
+      uv__req_init(loop, req, UV_FS);                                         \
+    req->fs_type = UV_FS_ ## subtype;                                         \
+    req->result = 0;                                                          \
+    req->ptr = NULL;                                                          \
+    req->loop = loop;                                                         \
+    req->path = NULL;                                                         \
+    req->new_path = NULL;                                                     \
+    req->cb = cb;                                                             \
   }                                                                           \
   while (0)
 
 #define PATH                                                                  \
   do {                                                                        \
-    (req)->path = uv__strdup(path);                                           \
-    if ((req)->path == NULL)                                                  \
-      return -ENOMEM;                                                         \
+    assert(path != NULL);                                                     \
+    if (cb == NULL) {                                                         \
+      req->path = path;                                                       \
+    } else {                                                                  \
+      req->path = uv__strdup(path);                                           \
+      if (req->path == NULL)                                                  \
+        return -ENOMEM;                                                       \
+    }                                                                         \
   }                                                                           \
   while (0)
 
 #define PATH2                                                                 \
   do {                                                                        \
-    size_t path_len;                                                          \
-    size_t new_path_len;                                                      \
-    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)                                                  \
-      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);                \
+    if (cb == NULL) {                                                         \
+      req->path = path;                                                       \
+      req->new_path = new_path;                                               \
+    } else {                                                                  \
+      size_t path_len;                                                        \
+      size_t new_path_len;                                                    \
+      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)                                                  \
+        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);                  \
+    }                                                                         \
   }                                                                           \
   while (0)
 
 #define POST                                                                  \
   do {                                                                        \
-    if ((cb) != NULL) {                                                       \
-      uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done);    \
+    if (cb != NULL) {                                                         \
+      uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done);        \
       return 0;                                                               \
     }                                                                         \
     else {                                                                    \
-      uv__fs_work(&(req)->work_req);                                          \
-      uv__fs_done(&(req)->work_req, 0);                                       \
-      return (req)->result;                                                   \
+      uv__fs_work(&req->work_req);                                            \
+      return req->result;                                                     \
     }                                                                         \
   }                                                                           \
   while (0)
@@ -309,8 +320,6 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
   }
 
 done:
-  if (req->bufs != req->bufsml)
-    uv__free(req->bufs);
   return result;
 }
 
@@ -545,7 +554,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
 
     return -1;
   }
-#elif defined(__FreeBSD__) || defined(__APPLE__)
+#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
   {
     off_t len;
     ssize_t r;
@@ -555,7 +564,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
      * number of bytes have been sent, we don't consider it an error.
      */
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
     len = 0;
     r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
 #else
@@ -670,9 +679,6 @@ done:
   pthread_mutex_unlock(&lock);
 #endif
 
-  if (req->bufs != req->bufsml)
-    uv__free(req->bufs);
-
   return r;
 }
 
@@ -777,6 +783,47 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
 }
 
 
+typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
+static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
+  unsigned int iovmax;
+  unsigned int nbufs;
+  uv_buf_t* bufs;
+  ssize_t total;
+  ssize_t result;
+
+  iovmax = uv__getiovmax();
+  nbufs = req->nbufs;
+  bufs = req->bufs;
+  total = 0;
+
+  while (nbufs > 0) {
+    req->nbufs = nbufs;
+    if (req->nbufs > iovmax)
+      req->nbufs = iovmax;
+
+    result = process(req);
+    if (result <= 0) {
+      if (total == 0)
+        total = result;
+      break;
+    }
+
+    if (req->off >= 0)
+      req->off += result;
+
+    req->bufs += req->nbufs;
+    nbufs -= req->nbufs;
+    total += result;
+  }
+
+  if (bufs != req->bufsml)
+    uv__free(bufs);
+  req->bufs = NULL;
+
+  return total;
+}
+
+
 static void uv__fs_work(struct uv__work* w) {
   int retry_on_eintr;
   uv_fs_t* req;
@@ -810,7 +857,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(MKDIR, mkdir(req->path, req->mode));
     X(MKDTEMP, uv__fs_mkdtemp(req));
     X(OPEN, uv__fs_open(req));
-    X(READ, uv__fs_read(req));
+    X(READ, uv__fs_buf_iter(req, uv__fs_read));
     X(SCANDIR, uv__fs_scandir(req));
     X(READLINK, uv__fs_readlink(req));
     X(RENAME, rename(req->path, req->new_path));
@@ -820,7 +867,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(SYMLINK, symlink(req->path, req->new_path));
     X(UNLINK, unlink(req->path));
     X(UTIME, uv__fs_utime(req));
-    X(WRITE, uv__fs_write(req));
+    X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
     default: abort();
     }
 #undef X
@@ -850,8 +897,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
     req->result = -ECANCELED;
   }
 
-  if (req->cb != NULL)
-    req->cb(req);
+  req->cb(req);
 }
 
 
@@ -1035,6 +1081,9 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
                unsigned int nbufs,
                int64_t off,
                uv_fs_cb cb) {
+  if (bufs == NULL || nbufs == 0)
+    return -EINVAL;
+
   INIT(READ);
   req->file = file;
 
@@ -1157,6 +1206,9 @@ int uv_fs_write(uv_loop_t* loop,
                 unsigned int nbufs,
                 int64_t off,
                 uv_fs_cb cb) {
+  if (bufs == NULL || nbufs == 0)
+    return -EINVAL;
+
   INIT(WRITE);
   req->file = file;
 
@@ -1176,7 +1228,14 @@ int uv_fs_write(uv_loop_t* loop,
 
 
 void uv_fs_req_cleanup(uv_fs_t* req) {
-  uv__free((void*)req->path);
+  /* Only necessary for asychronous requests, i.e., requests with a callback.
+   * Synchronous ones don't copy their arguments and have req->path and
+   * req->new_path pointing to user-owned memory.  UV_FS_MKDTEMP is the
+   * exception to the rule, it always allocates memory.
+   */
+  if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
+    uv__free((void*) req->path);  /* Memory is shared with req->new_path. */
+
   req->path = NULL;
   req->new_path = NULL;
 
index c31e549..741fa57 100644 (file)
@@ -172,6 +172,7 @@ int uv__socket(int domain, int type, int protocol);
 int uv__dup(int fd);
 ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
 void uv__make_close_pending(uv_handle_t* handle);
+int uv__getiovmax(void);
 
 void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
 void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
index 424236a..495f20d 100644 (file)
@@ -379,6 +379,10 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   if (!(statbuf.st_mode & S_IFDIR))
     goto fallback;
 
+  /* The fallback fd is no longer needed */
+  uv__close(fd);
+  handle->event_watcher.fd = -1;
+
   return uv__fsevents_init(handle);
 
 fallback:
@@ -406,8 +410,12 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
   uv__free(handle->path);
   handle->path = NULL;
 
-  uv__close(handle->event_watcher.fd);
-  handle->event_watcher.fd = -1;
+  if (handle->event_watcher.fd != -1) {
+    /* When FSEvents is used, we don't use the event_watcher's fd under certain
+     * confitions. (see uv_fs_event_start) */
+    uv__close(handle->event_watcher.fd);
+    handle->event_watcher.fd = -1;
+  }
 
   return 0;
 }
index aa9146b..92e96f0 100644 (file)
@@ -63,24 +63,44 @@ int uv_loop_init(uv_loop_t* loop) {
   if (err)
     return err;
 
-  uv_signal_init(loop, &loop->child_watcher);
+  err = uv_signal_init(loop, &loop->child_watcher);
+  if (err)
+    goto fail_signal_init;
+
   uv__handle_unref(&loop->child_watcher);
   loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
   QUEUE_INIT(&loop->process_handles);
 
-  if (uv_rwlock_init(&loop->cloexec_lock))
-    abort();
+  err = uv_rwlock_init(&loop->cloexec_lock);
+  if (err)
+    goto fail_rwlock_init;
 
-  if (uv_mutex_init(&loop->wq_mutex))
-    abort();
+  err = uv_mutex_init(&loop->wq_mutex);
+  if (err)
+    goto fail_mutex_init;
 
-  if (uv_async_init(loop, &loop->wq_async, uv__work_done))
-    abort();
+  err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+  if (err)
+    goto fail_async_init;
 
   uv__handle_unref(&loop->wq_async);
   loop->wq_async.flags |= UV__HANDLE_INTERNAL;
 
   return 0;
+
+fail_async_init:
+  uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+  uv_rwlock_destroy(&loop->cloexec_lock);
+
+fail_rwlock_init:
+  uv__signal_loop_cleanup(loop);
+
+fail_signal_init:
+  uv__platform_loop_delete(loop);
+
+  return err;
 }
 
 
index dc54f35..3a71eb5 100644 (file)
@@ -35,6 +35,7 @@
  * */
 #include <errno.h>
 #include <pthread.h>
+#include <signal.h>
 
 int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
   static int workaround;
index 7ad1658..183b68c 100644 (file)
@@ -391,6 +391,9 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
   int enable;
 #endif
 
+  if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd))
+    return -EBUSY;
+
   assert(fd >= 0);
   stream->flags |= flags;
 
@@ -736,19 +739,6 @@ static int uv__handle_fd(uv_handle_t* handle) {
   }
 }
 
-static int uv__getiovmax() {
-#if defined(IOV_MAX)
-  return IOV_MAX;
-#elif defined(_SC_IOV_MAX)
-  static int iovmax = -1;
-  if (iovmax == -1)
-    iovmax = sysconf(_SC_IOV_MAX);
-  return iovmax;
-#else
-  return 1024;
-#endif
-}
-
 static void uv__write(uv_stream_t* stream) {
   struct iovec* iov;
   QUEUE* q;
@@ -819,7 +809,17 @@ start:
     do {
       n = sendmsg(uv__stream_fd(stream), &msg, 0);
     }
+#if defined(__APPLE__)
+    /*
+     * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+     * EPROTOTYPE can be returned while trying to write to a socket that is
+     * shutting down. If we retry the write, we should get the expected EPIPE
+     * instead.
+     */
+    while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
     while (n == -1 && errno == EINTR);
+#endif
   } else {
     do {
       if (iovcnt == 1) {
@@ -828,7 +828,17 @@ start:
         n = writev(uv__stream_fd(stream), iov, iovcnt);
       }
     }
+#if defined(__APPLE__)
+    /*
+     * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+     * EPROTOTYPE can be returned while trying to write to a socket that is
+     * shutting down. If we retry the write, we should get the expected EPIPE
+     * instead.
+     */
+    while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
     while (n == -1 && errno == EINTR);
+#endif
   }
 
   if (n < 0) {
index 4060e7b..6d213a4 100644 (file)
 #include <errno.h>
 
 
-int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
-  uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
-  return 0;
-}
-
-
 static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
   int sockfd;
   int err;
 
-  if (uv__stream_fd(handle) != -1)
+  if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
+    handle->flags |= flags;
     return 0;
+  }
 
   err = uv__socket(domain, SOCK_STREAM, 0);
   if (err < 0)
@@ -56,6 +52,40 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
 }
 
 
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
+  int domain;
+
+  /* Use the lower 8 bits for the domain */
+  domain = flags & 0xFF;
+  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+    return -EINVAL;
+
+  if (flags & ~0xFF)
+    return -EINVAL;
+
+  uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
+
+  /* If anything fails beyond this point we need to remove the handle from
+   * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+   */
+
+  if (domain != AF_UNSPEC) {
+    int err = maybe_new_socket(tcp, domain, 0);
+    if (err) {
+      QUEUE_REMOVE(&tcp->handle_queue);
+      return err;
+    }
+  }
+
+  return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
+  return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
+}
+
+
 int uv__tcp_bind(uv_tcp_t* tcp,
                  const struct sockaddr* addr,
                  unsigned int addrlen,
@@ -91,8 +121,13 @@ int uv__tcp_bind(uv_tcp_t* tcp,
 #endif
 
   errno = 0;
-  if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE)
+  if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
+    if (errno == EAFNOSUPPORT)
+      /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+       * socket created with AF_INET to an AF_INET6 address or vice versa. */
+      return -EINVAL;
     return -errno;
+  }
   tcp->delayed_error = -errno;
 
   if (addr->sa_family == AF_INET6)
index 7783548..54c9055 100644 (file)
@@ -51,8 +51,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
   flags = 0;
   newfd = -1;
 
-  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
-
   /* Reopen the file descriptor when it refers to a tty. This lets us put the
    * tty in non-blocking mode without affecting other processes that share it
    * with us.
@@ -89,11 +87,18 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
   }
 
 skip:
+  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+
+  /* If anything fails beyond this point we need to remove the handle from
+   * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+   */
+
 #if defined(__APPLE__)
   r = uv__stream_try_select((uv_stream_t*) tty, &fd);
   if (r) {
     if (newfd != -1)
       uv__close(newfd);
+    QUEUE_REMOVE(&tty->handle_queue);
     return r;
   }
 #endif
index f85ab14..66ecc4e 100644 (file)
@@ -321,6 +321,10 @@ int uv__udp_bind(uv_udp_t* handle,
 
   if (bind(fd, addr, addrlen)) {
     err = -errno;
+    if (errno == EAFNOSUPPORT)
+      /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+       * socket created with AF_INET to an AF_INET6 address or vice versa. */
+      err = -EINVAL;
     goto out;
   }
 
@@ -551,25 +555,51 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
 }
 
 
-int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+  int domain;
+  int err;
+  int fd;
+
+  /* Use the lower 8 bits for the domain */
+  domain = flags & 0xFF;
+  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+    return -EINVAL;
+
+  if (flags & ~0xFF)
+    return -EINVAL;
+
+  if (domain != AF_UNSPEC) {
+    err = uv__socket(domain, SOCK_DGRAM, 0);
+    if (err < 0)
+      return err;
+    fd = err;
+  } else {
+    fd = -1;
+  }
+
   uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
   handle->alloc_cb = NULL;
   handle->recv_cb = NULL;
   handle->send_queue_size = 0;
   handle->send_queue_count = 0;
-  uv__io_init(&handle->io_watcher, uv__udp_io, -1);
+  uv__io_init(&handle->io_watcher, uv__udp_io, fd);
   QUEUE_INIT(&handle->write_queue);
   QUEUE_INIT(&handle->write_completed_queue);
   return 0;
 }
 
 
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+  return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
 int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
   int err;
 
   /* Check for already active socket. */
   if (handle->io_watcher.fd != -1)
-    return -EALREADY;  /* FIXME(bnoordhuis) Should be -EBUSY. */
+    return -EBUSY;
 
   err = uv__nonblock(sock, 1);
   if (err)
@@ -638,6 +668,8 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle,
                                      int val) {
 #if defined(__sun) || defined(_AIX)
   char arg = val;
+#elif defined(__OpenBSD__)
+  unsigned char arg = val;
 #else
   int arg = val;
 #endif
@@ -672,13 +704,13 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
  * so hardcode the size of these options on this platform,
  * and use the general uv__setsockopt_maybe_char call on other platforms.
  */
-#if defined(__sun) || defined(_AIX)
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__)
   return uv__setsockopt(handle,
                         IP_TTL,
                         IPV6_UNICAST_HOPS,
                         &ttl,
                         sizeof(ttl));
-#endif /* defined(__sun) || defined(_AIX) */
+#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */
 
   return uv__setsockopt_maybe_char(handle,
                                    IP_TTL,
index 77879b9..675a776 100644 (file)
@@ -29,7 +29,9 @@
 #include <stdlib.h> /* malloc */
 #include <string.h> /* memset */
 
-#if !defined(_WIN32)
+#if defined(_WIN32)
+# include <malloc.h> /* malloc */
+#else
 # include <net/if.h> /* if_nametoindex */
 #endif
 
@@ -135,14 +137,27 @@ uv_buf_t uv_buf_init(char* base, unsigned int len) {
 }
 
 
+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";
+}
+
+
 #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
 const char* uv_err_name(int err) {
   switch (err) {
     UV_ERRNO_MAP(UV_ERR_NAME_GEN)
-    default:
-      assert(0);
-      return NULL;
   }
+  return uv__unknown_err_code(err);
 }
 #undef UV_ERR_NAME_GEN
 
@@ -151,9 +166,8 @@ const char* uv_err_name(int err) {
 const char* uv_strerror(int err) {
   switch (err) {
     UV_ERRNO_MAP(UV_STRERROR_GEN)
-    default:
-      return "Unknown system error";
   }
+  return uv__unknown_err_code(err);
 }
 #undef UV_STRERROR_GEN
 
index 8258d7a..b348ec7 100644 (file)
@@ -196,7 +196,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   (((h)->flags & UV__HANDLE_REF) != 0)
 
 #if defined(_WIN32)
-# define uv__handle_platform_init(h)
+# define uv__handle_platform_init(h) ((h)->u.fd = -1)
 #else
 # define uv__handle_platform_init(h) ((h)->next_closing = NULL)
 #endif
index ff91a46..686dedd 100644 (file)
 
 #include "uv.h"
 
-#define UV_VERSION  ((UV_VERSION_MAJOR << 16) | \
-                     (UV_VERSION_MINOR <<  8) | \
-                     (UV_VERSION_PATCH))
-
 #define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
 #define UV_STRINGIFY_HELPER(v) #v
 
@@ -40,7 +36,7 @@
 
 
 unsigned int uv_version(void) {
-  return UV_VERSION;
+  return UV_VERSION_HEX;
 }
 
 
index 1154492..de0483e 100644 (file)
@@ -124,6 +124,8 @@ static void uv_init(void) {
 
 
 int uv_loop_init(uv_loop_t* loop) {
+  int err;
+
   /* Initialize libuv itself first */
   uv__once_init();
 
@@ -165,16 +167,27 @@ int uv_loop_init(uv_loop_t* loop) {
   loop->timer_counter = 0;
   loop->stop_flag = 0;
 
-  if (uv_mutex_init(&loop->wq_mutex))
-    abort();
+  err = uv_mutex_init(&loop->wq_mutex);
+  if (err)
+    goto fail_mutex_init;
 
-  if (uv_async_init(loop, &loop->wq_async, uv__work_done))
-    abort();
+  err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+  if (err)
+    goto fail_async_init;
 
   uv__handle_unref(&loop->wq_async);
   loop->wq_async.flags |= UV__HANDLE_INTERNAL;
 
   return 0;
+
+fail_async_init:
+  uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+  CloseHandle(loop->iocp);
+  loop->iocp = INVALID_HANDLE_VALUE;
+
+  return err;
 }
 
 
index eb205d3..ba68f78 100644 (file)
@@ -43,7 +43,7 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
   if (!ReadDirectoryChangesW(handle->dir_handle,
                              handle->buffer,
                              uv_directory_watcher_buffer_size,
-                             FALSE,
+                             (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
                              FILE_NOTIFY_CHANGE_FILE_NAME      |
                                FILE_NOTIFY_CHANGE_DIR_NAME     |
                                FILE_NOTIFY_CHANGE_ATTRIBUTES   |
@@ -63,6 +63,20 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
   handle->req_pending = 1;
 }
 
+static int uv_relative_path(const WCHAR* filename,
+                            const WCHAR* dir,
+                           WCHAR** relpath) {
+  int dirlen = wcslen(dir);
+  int filelen = wcslen(filename);
+  if (dir[dirlen - 1] == '\\')
+    dirlen--;
+  *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+  if (!*relpath)
+    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+  wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1);
+  (*relpath)[filelen - dirlen - 1] = L'\0';
+  return 0;
+}
 
 static int uv_split_path(const WCHAR* filename, WCHAR** dir,
     WCHAR** file) {
@@ -237,7 +251,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   if (!ReadDirectoryChangesW(handle->dir_handle,
                              handle->buffer,
                              uv_directory_watcher_buffer_size,
-                             FALSE,
+                             (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
                              FILE_NOTIFY_CHANGE_FILE_NAME      |
                                FILE_NOTIFY_CHANGE_DIR_NAME     |
                                FILE_NOTIFY_CHANGE_ATTRIBUTES   |
@@ -410,7 +424,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
 
               if (long_filenamew) {
                 /* Get the file name out of the long path. */
-                result = uv_split_path(long_filenamew, NULL, &filenamew);
+                result = uv_relative_path(long_filenamew,
+                                          handle->dirw,
+                                          &filenamew);
                 uv__free(long_filenamew);
 
                 if (result == 0) {
index 00d0197..4a17573 100644 (file)
@@ -116,8 +116,8 @@ void uv_fs_init() {
 }
 
 
-INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
-    const char* path, const char* new_path, const int copy_path) {
+INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
+    const char* new_path, const int copy_path) {
   char* buf;
   char* pos;
   ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
@@ -528,7 +528,11 @@ void fs__close(uv_fs_t* req) {
 
   VERIFY_FD(fd, req);
 
-  result = _close(fd);
+  if (fd > 2)
+    result = _close(fd);
+  else
+    result = 0;
+
   SET_REQ_RESULT(req, result);
 }
 
@@ -821,7 +825,11 @@ void fs__scandir(uv_fs_t* req) {
    * A file name is at most 256 WCHARs long.
    * According to MSDN, the buffer must be aligned at an 8-byte boundary.
    */
+#if _MSC_VER
   __declspec(align(8)) char buffer[8192];
+#else
+  __attribute__ ((aligned (8))) char buffer[8192];
+#endif
 
   STATIC_ASSERT(sizeof buffer >=
                 sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
@@ -1754,8 +1762,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
     req->result = UV_ECANCELED;
   }
 
-  if (req->cb != NULL)
-    req->cb(req);
+  req->cb(req);
 }
 
 
@@ -1784,7 +1791,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
 
   uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -1823,6 +1830,9 @@ int uv_fs_read(uv_loop_t* loop,
                unsigned int nbufs,
                int64_t offset,
                uv_fs_cb cb) {
+  if (bufs == NULL || nbufs == 0)
+    return UV_EINVAL;
+
   uv_fs_req_init(loop, req, UV_FS_READ, cb);
 
   req->file.fd = fd;
@@ -1856,6 +1866,9 @@ int uv_fs_write(uv_loop_t* loop,
                 unsigned int nbufs,
                 int64_t offset,
                 uv_fs_cb cb) {
+  if (bufs == NULL || nbufs == 0)
+    return UV_EINVAL;
+
   uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
 
   req->file.fd = fd;
@@ -1888,7 +1901,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -1909,7 +1922,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
 
   uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -1932,7 +1945,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
 
   uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
 
-  err = fs__capture_path(loop, req, tpl, NULL, TRUE);
+  err = fs__capture_path(req, tpl, NULL, TRUE);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -1951,7 +1964,7 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
   uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -1972,7 +1985,7 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
 
   uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -1995,7 +2008,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   uv_fs_req_init(loop, req, UV_FS_LINK, cb);
 
-  err = fs__capture_path(loop, req, path, new_path, cb != NULL);
+  err = fs__capture_path(req, path, new_path, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2016,7 +2029,7 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
 
-  err = fs__capture_path(loop, req, path, new_path, cb != NULL);
+  err = fs__capture_path(req, path, new_path, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2039,7 +2052,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2060,7 +2073,7 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
 
   uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2094,7 +2107,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
   uv_fs_req_init(loop, req, UV_FS_STAT, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2114,7 +2127,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
   uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2149,7 +2162,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
 
-  err = fs__capture_path(loop, req, path, new_path, cb != NULL);
+  err = fs__capture_path(req, path, new_path, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2238,7 +2251,7 @@ int uv_fs_access(uv_loop_t* loop,
 
   uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -2260,7 +2273,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
 
   uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
@@ -2300,7 +2313,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
 
   uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
 
-  err = fs__capture_path(loop, req, path, NULL, cb != NULL);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
   if (err) {
     return uv_translate_sys_error(err);
   }
index 04b2a54..8d4081b 100644 (file)
@@ -64,7 +64,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
 
 /* Used by all handles. */
 #define UV_HANDLE_CLOSED                        0x00000002
-#define UV_HANDLE_ENDGAME_QUEUED                0x00000004
+#define UV_HANDLE_ENDGAME_QUEUED                0x00000008
 
 /* uv-common.h: #define UV__HANDLE_CLOSING      0x00000001 */
 /* uv-common.h: #define UV__HANDLE_ACTIVE       0x00000040 */
@@ -76,7 +76,6 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
 #define UV_HANDLE_BOUND                         0x00000200
 #define UV_HANDLE_LISTENING                     0x00000800
 #define UV_HANDLE_CONNECTION                    0x00001000
-#define UV_HANDLE_CONNECTED                     0x00002000
 #define UV_HANDLE_READABLE                      0x00008000
 #define UV_HANDLE_WRITABLE                      0x00010000
 #define UV_HANDLE_READ_PENDING                  0x00020000
index d232efa..8312b1c 100644 (file)
@@ -180,6 +180,18 @@ static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
 }
 
 
+static void close_pipe(uv_pipe_t* pipe) {
+  assert(pipe->u.fd == -1 || pipe->u.fd > 2);
+  if (pipe->u.fd == -1)
+    CloseHandle(pipe->handle);
+  else
+    close(pipe->u.fd);
+
+  pipe->u.fd = -1;
+  pipe->handle = INVALID_HANDLE_VALUE;
+}
+
+
 int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
     char* name, size_t nameSize) {
   HANDLE pipeHandle;
@@ -233,6 +245,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
 static int uv_set_pipe_handle(uv_loop_t* loop,
                               uv_pipe_t* handle,
                               HANDLE pipeHandle,
+                              int fd,
                               DWORD duplex_flags) {
   NTSTATUS nt_status;
   IO_STATUS_BLOCK io_status;
@@ -241,6 +254,10 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
   DWORD current_mode = 0;
   DWORD err = 0;
 
+  if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
+      handle->handle != INVALID_HANDLE_VALUE)
+    return UV_EBUSY;
+
   if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
     err = GetLastError();
     if (err == ERROR_ACCESS_DENIED) {
@@ -292,6 +309,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
   }
 
   handle->handle = pipeHandle;
+  handle->u.fd = fd;
   handle->flags |= duplex_flags;
 
   return 0;
@@ -454,6 +472,8 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
 
 void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+  if (handle->flags & UV_HANDLE_BOUND)
+    return;
   handle->pipe.serv.pending_instances = count;
   handle->flags |= UV_HANDLE_PIPESERVER;
 }
@@ -527,6 +547,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   if (uv_set_pipe_handle(loop,
                          handle,
                          handle->pipe.serv.accept_reqs[0].pipeHandle,
+                         -1,
                          0)) {
     err = GetLastError();
     goto error;
@@ -580,7 +601,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
   }
 
   if (pipeHandle != INVALID_HANDLE_VALUE &&
-      !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) {
+      !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
     SET_REQ_SUCCESS(req);
   } else {
     SET_REQ_ERROR(req, GetLastError());
@@ -643,6 +664,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
   if (uv_set_pipe_handle(loop,
                          (uv_pipe_t*) req->handle,
                          pipeHandle,
+                         -1,
                          duplex_flags)) {
     err = GetLastError();
     goto error;
@@ -729,6 +751,7 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
         handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
       }
     }
+    handle->handle = INVALID_HANDLE_VALUE;
   }
 
   if (handle->flags & UV_HANDLE_CONNECTION) {
@@ -737,11 +760,8 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
   }
 
   if ((handle->flags & UV_HANDLE_CONNECTION)
-      && handle->handle != INVALID_HANDLE_VALUE) {
-    CloseHandle(handle->handle);
-    handle->handle = INVALID_HANDLE_VALUE;
-  }
-
+      && handle->handle != INVALID_HANDLE_VALUE)
+    close_pipe(handle);
 }
 
 
@@ -786,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
       return;
     }
 
-    if (uv_set_pipe_handle(loop, handle, req->pipeHandle, 0)) {
+    if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
       CloseHandle(req->pipeHandle);
       req->pipeHandle = INVALID_HANDLE_VALUE;
       SET_REQ_ERROR(req, GetLastError());
@@ -1770,8 +1790,7 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
   } else {
     /* This pipe is not readable. We can just close it to let the other end */
     /* know that we're done writing. */
-    CloseHandle(handle->handle);
-    handle->handle = INVALID_HANDLE_VALUE;
+    close_pipe(handle);
   }
 
   if (req->cb) {
@@ -1838,8 +1857,7 @@ static void eof_timer_cb(uv_timer_t* timer) {
   }
 
   /* Force both ends off the pipe. */
-  CloseHandle(pipe->handle);
-  pipe->handle = INVALID_HANDLE_VALUE;
+  close_pipe(pipe);
 
   /* Stop reading, so the pending read that is going to fail will */
   /* not be reported to the user. */
@@ -1874,6 +1892,27 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
   FILE_ACCESS_INFORMATION access;
   DWORD duplex_flags = 0;
 
+  if (os_handle == INVALID_HANDLE_VALUE)
+    return UV_EBADF;
+
+  /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+   * underlying OS handle and forget about the original fd.
+   * We could also opt to use the original OS handle and just never close it,
+   * but then there would be no reliable way to cancel pending read operations
+   * upon close.
+   */
+  if (file <= 2) {
+    if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+                         os_handle,
+                         INVALID_HANDLE_VALUE,
+                         &os_handle,
+                         0,
+                         FALSE,
+                         DUPLICATE_SAME_ACCESS))
+      return uv_translate_sys_error(GetLastError());
+    file = -1;
+  }
+
   /* Determine what kind of permissions we have on this handle.
    * Cygwin opens the pipe in message mode, but we can support it,
    * just query the access flags and set the stream flags accordingly.
@@ -1899,7 +1938,11 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
     duplex_flags |= UV_HANDLE_READABLE;
 
   if (os_handle == INVALID_HANDLE_VALUE ||
-      uv_set_pipe_handle(pipe->loop, pipe, os_handle, duplex_flags) == -1) {
+      uv_set_pipe_handle(pipe->loop,
+                         pipe,
+                         os_handle,
+                         file,
+                         duplex_flags) == -1) {
     return UV_EINVAL;
   }
 
index e81f799..e3c06f5 100644 (file)
@@ -407,7 +407,7 @@ int uv__stdio_create(uv_loop_t* loop,
           stream_handle = ((uv_tty_t*) stream)->handle;
           crt_flags = FOPEN | FDEV;
         } else if (stream->type == UV_NAMED_PIPE &&
-                   stream->flags & UV_HANDLE_CONNECTED) {
+                   stream->flags & UV_HANDLE_CONNECTION) {
           stream_handle = ((uv_pipe_t*) stream)->handle;
           crt_flags = FOPEN | FPIPE;
         } else {
index da89f28..0f56548 100644 (file)
@@ -78,19 +78,27 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign
 }
 
 
-static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
-    SOCKET socket, int family, int imported) {
+static int uv_tcp_set_socket(uv_loop_t* loop,
+                             uv_tcp_t* handle,
+                             SOCKET socket,
+                             int family,
+                             int imported) {
   DWORD yes = 1;
   int non_ifs_lsp;
   int err;
 
-  assert(handle->socket == INVALID_SOCKET);
+  if (handle->socket != INVALID_SOCKET)
+    return UV_EBUSY;
 
   /* Set the socket to nonblocking mode */
   if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
     return WSAGetLastError();
   }
 
+  /* Make the socket non-inheritable */
+  if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
+    return GetLastError();
+
   /* Associate it with the I/O completion port. */
   /* Use uv_handle_t pointer as completion key. */
   if (CreateIoCompletionPort((HANDLE)socket,
@@ -146,9 +154,18 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
 }
 
 
-int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
-  uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
+  int domain;
 
+  /* Use the lower 8 bits for the domain */
+  domain = flags & 0xFF;
+  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+    return UV_EINVAL;
+
+  if (flags & ~0xFF)
+    return UV_EINVAL;
+
+  uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
   handle->tcp.serv.accept_reqs = NULL;
   handle->tcp.serv.pending_accepts = NULL;
   handle->socket = INVALID_SOCKET;
@@ -158,10 +175,39 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
   handle->tcp.serv.processed_accepts = 0;
   handle->delayed_error = 0;
 
+  /* If anything fails beyond this point we need to remove the handle from
+   * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+   */
+
+  if (domain != AF_UNSPEC) {
+    SOCKET sock;
+    DWORD err;
+
+    sock = socket(domain, SOCK_STREAM, 0);
+    if (sock == INVALID_SOCKET) {
+      err = WSAGetLastError();
+      QUEUE_REMOVE(&handle->handle_queue);
+      return uv_translate_sys_error(err);
+    }
+
+    err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+    if (err) {
+      closesocket(sock);
+      QUEUE_REMOVE(&handle->handle_queue);
+      return uv_translate_sys_error(err);
+    }
+
+  }
+
   return 0;
 }
 
 
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
+  return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
 void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
   int err;
   unsigned int i;
@@ -267,13 +313,6 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
       return WSAGetLastError();
     }
 
-    /* Make the socket non-inheritable */
-    if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
-      err = GetLastError();
-      closesocket(sock);
-      return err;
-    }
-
     err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
     if (err) {
       closesocket(sock);
@@ -774,7 +813,7 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
                        int* namelen) {
   int result;
 
-  if (!(handle->flags & UV_HANDLE_BOUND)) {
+  if (handle->socket == INVALID_SOCKET) {
     return UV_EINVAL;
   }
 
@@ -796,7 +835,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
                        int* namelen) {
   int result;
 
-  if (!(handle->flags & UV_HANDLE_BOUND)) {
+  if (handle->socket == INVALID_SOCKET) {
     return UV_EINVAL;
   }
 
@@ -1165,12 +1204,6 @@ int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
     return WSAGetLastError();
   }
 
-  if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) {
-    err = GetLastError();
-    closesocket(socket);
-    return err;
-  }
-
   err = uv_tcp_set_socket(tcp->loop,
                           tcp,
                           socket,
@@ -1426,11 +1459,6 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
     return uv_translate_sys_error(GetLastError());
   }
 
-  /* Make the socket non-inheritable */
-  if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
-    return uv_translate_sys_error(GetLastError());
-  }
-
   err = uv_tcp_set_socket(handle->loop,
                           handle,
                           sock,
index e91ae9b..d7171fd 100644 (file)
@@ -191,6 +191,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
 
 
 uv_thread_t uv_thread_self(void) {
+  uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
   return (uv_thread_t) uv_key_get(&uv__current_thread_key);
 }
 
index 7b1e4ba..c3af02f 100644 (file)
@@ -55,6 +55,7 @@
 #define MAX_INPUT_BUFFER_LENGTH 8192
 
 
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
 static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
 
 
@@ -96,6 +97,15 @@ static CRITICAL_SECTION uv_tty_output_lock;
 
 static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
 
+static WORD uv_tty_default_text_attributes =
+    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+static char uv_tty_default_fg_color = 7;
+static char uv_tty_default_bg_color = 0;
+static char uv_tty_default_fg_bright = 0;
+static char uv_tty_default_bg_bright = 0;
+static char uv_tty_default_inverse = 0;
+
 
 void uv_console_init() {
   InitializeCriticalSection(&uv_tty_output_lock);
@@ -106,9 +116,26 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
   HANDLE handle;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
 
-  handle = (HANDLE) _get_osfhandle(fd);
-  if (handle == INVALID_HANDLE_VALUE) {
+  handle = (HANDLE) uv__get_osfhandle(fd);
+  if (handle == INVALID_HANDLE_VALUE)
     return UV_EBADF;
+
+  if (fd <= 2) {
+    /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+     * underlying OS handle and forget about the original fd.
+     * We could also opt to use the original OS handle and just never close it,
+     * but then there would be no reliable way to cancel pending read operations
+     * upon close.
+     */
+    if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+                         handle,
+                         INVALID_HANDLE_VALUE,
+                         &handle,
+                         0,
+                         FALSE,
+                         DUPLICATE_SAME_ACCESS))
+      return uv_translate_sys_error(GetLastError());
+    fd = -1;
   }
 
   if (!readable) {
@@ -126,6 +153,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
     /* is received. */
     uv_tty_output_handle = handle;
 
+    /* Remember the original console text attributes. */
+    uv_tty_capture_initial_style(&screen_buffer_info);
+
     uv_tty_update_virtual_window(&screen_buffer_info);
 
     LeaveCriticalSection(&uv_tty_output_lock);
@@ -136,6 +166,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
   uv_connection_init((uv_stream_t*) tty);
 
   tty->handle = handle;
+  tty->u.fd = fd;
   tty->reqs_pending = 0;
   tty->flags |= UV_HANDLE_BOUND;
 
@@ -170,6 +201,62 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
 }
 
 
+/* Set the default console text attributes based on how the console was
+ * configured when libuv started.
+ */
+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. */
+  if (style_captured)
+    return;
+
+  /* Save raw win32 attributes. */
+  uv_tty_default_text_attributes = info->wAttributes;
+
+  /* Convert black text on black background to use white text. */
+  if (uv_tty_default_text_attributes == 0)
+    uv_tty_default_text_attributes = 7;
+
+  /* Convert Win32 attributes to ANSI colors. */
+  uv_tty_default_fg_color = 0;
+  uv_tty_default_bg_color = 0;
+  uv_tty_default_fg_bright = 0;
+  uv_tty_default_bg_bright = 0;
+  uv_tty_default_inverse = 0;
+
+  if (uv_tty_default_text_attributes & FOREGROUND_RED)
+    uv_tty_default_fg_color |= 1;
+
+  if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
+    uv_tty_default_fg_color |= 2;
+
+  if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
+    uv_tty_default_fg_color |= 4;
+
+  if (uv_tty_default_text_attributes & BACKGROUND_RED)
+    uv_tty_default_bg_color |= 1;
+
+  if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
+    uv_tty_default_bg_color |= 2;
+
+  if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
+    uv_tty_default_bg_color |= 4;
+
+  if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
+    uv_tty_default_fg_bright = 1;
+
+  if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
+    uv_tty_default_bg_bright = 1;
+
+  if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
+    uv_tty_default_inverse = 1;
+
+  style_captured = 1;
+}
+
+
 int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
   DWORD flags;
   unsigned char was_reading;
@@ -1004,7 +1091,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
 
 static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
   const COORD origin = {0, 0};
-  const WORD char_attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+  const WORD char_attrs = uv_tty_default_text_attributes;
   CONSOLE_SCREEN_BUFFER_INFO info;
   DWORD count, written;
 
@@ -1160,11 +1247,11 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
 
   if (argc == 0) {
     /* Reset mode */
-    fg_color = 7;
-    bg_color = 0;
-    fg_bright = 0;
-    bg_bright = 0;
-    inverse = 0;
+    fg_color = uv_tty_default_fg_color;
+    bg_color = uv_tty_default_bg_color;
+    fg_bright = uv_tty_default_fg_bright;
+    bg_bright = uv_tty_default_bg_bright;
+    inverse = uv_tty_default_inverse;
   }
 
   for (i = 0; i < argc; i++) {
@@ -1172,11 +1259,11 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
 
     if (arg == 0) {
       /* Reset mode */
-      fg_color = 7;
-      bg_color = 0;
-      fg_bright = 0;
-      bg_bright = 0;
-      inverse = 0;
+      fg_color = uv_tty_default_fg_color;
+      bg_color = uv_tty_default_bg_color;
+      fg_bright = uv_tty_default_fg_bright;
+      bg_bright = uv_tty_default_bg_bright;
+      inverse = uv_tty_default_inverse;
 
     } else if (arg == 1) {
       /* Foreground bright on */
@@ -1213,8 +1300,8 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
 
     } else if (arg == 39) {
       /* Default text color */
-      fg_color = 7;
-      fg_bright = 0;
+      fg_color = uv_tty_default_fg_color;
+      fg_bright = uv_tty_default_fg_bright;
 
     } else if (arg >= 40 && arg <= 47) {
       /* Set background color */
@@ -1222,8 +1309,8 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
 
     } else if (arg ==  49) {
       /* Default background color */
-      bg_color = 0;
-      bg_bright = 0;
+      bg_color = uv_tty_default_bg_color;
+      bg_bright = uv_tty_default_bg_bright;
 
     } else if (arg >= 90 && arg <= 97) {
       /* Set bold foreground color */
@@ -1916,11 +2003,16 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
 
 
 void uv_tty_close(uv_tty_t* handle) {
-  CloseHandle(handle->handle);
+  assert(handle->u.fd == -1 || handle->u.fd > 2);
+  if (handle->u.fd == -1)
+    CloseHandle(handle->handle);
+  else
+    close(handle->u.fd);
 
   if (handle->flags & UV_HANDLE_READING)
     uv_tty_read_stop(handle);
 
+  handle->u.fd = -1;
   handle->handle = INVALID_HANDLE_VALUE;
   handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   uv__handle_closing(handle);
index 197e5d8..24792ec 100644 (file)
@@ -42,7 +42,7 @@ int uv_udp_getsockname(const uv_udp_t* handle,
                        int* namelen) {
   int result;
 
-  if (!(handle->flags & UV_HANDLE_BOUND)) {
+  if (handle->socket == INVALID_SOCKET) {
     return UV_EINVAL;
   }
 
@@ -61,7 +61,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
   WSAPROTOCOL_INFOW info;
   int opt_len;
 
-  assert(handle->socket == INVALID_SOCKET);
+  if (handle->socket != INVALID_SOCKET)
+    return UV_EBUSY;
 
   /* Set the socket to nonblocking mode */
   if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
@@ -122,9 +123,18 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
 }
 
 
-int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
-  uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+  int domain;
 
+  /* Use the lower 8 bits for the domain */
+  domain = flags & 0xFF;
+  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+    return UV_EINVAL;
+
+  if (flags & ~0xFF)
+    return UV_EINVAL;
+
+  uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
   handle->socket = INVALID_SOCKET;
   handle->reqs_pending = 0;
   handle->activecnt = 0;
@@ -132,15 +142,42 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
   handle->func_wsarecvfrom = WSARecvFrom;
   handle->send_queue_size = 0;
   handle->send_queue_count = 0;
-
   uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
   handle->recv_req.type = UV_UDP_RECV;
   handle->recv_req.data = handle;
 
+  /* If anything fails beyond this point we need to remove the handle from
+   * the handle queue, since it was added by uv__handle_init.
+   */
+
+  if (domain != AF_UNSPEC) {
+    SOCKET sock;
+    DWORD err;
+
+    sock = socket(domain, SOCK_DGRAM, 0);
+    if (sock == INVALID_SOCKET) {
+      err = WSAGetLastError();
+      QUEUE_REMOVE(&handle->handle_queue);
+      return uv_translate_sys_error(err);
+    }
+
+    err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+    if (err) {
+      closesocket(sock);
+      QUEUE_REMOVE(&handle->handle_queue);
+      return uv_translate_sys_error(err);
+    }
+  }
+
   return 0;
 }
 
 
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+  return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
 void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
   uv_udp_recv_stop(handle);
   closesocket(handle->socket);
@@ -190,25 +227,24 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
       closesocket(sock);
       return err;
     }
+  }
 
-    if (flags & UV_UDP_REUSEADDR) {
-      DWORD yes = 1;
-      /* Set SO_REUSEADDR on the socket. */
-      if (setsockopt(sock,
-                     SOL_SOCKET,
-                     SO_REUSEADDR,
-                     (char*) &yes,
-                     sizeof yes) == SOCKET_ERROR) {
-        err = WSAGetLastError();
-        closesocket(sock);
-        return err;
-      }
+  if (flags & UV_UDP_REUSEADDR) {
+    DWORD yes = 1;
+    /* Set SO_REUSEADDR on the socket. */
+    if (setsockopt(handle->socket,
+                   SOL_SOCKET,
+                   SO_REUSEADDR,
+                   (char*) &yes,
+                   sizeof yes) == SOCKET_ERROR) {
+      err = WSAGetLastError();
+      return err;
     }
-
-    if (addr->sa_family == AF_INET6)
-      handle->flags |= UV_HANDLE_IPV6;
   }
 
+  if (addr->sa_family == AF_INET6)
+    handle->flags |= UV_HANDLE_IPV6;
+
   if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
     /* On windows IPV6ONLY is on by default. */
     /* If the user doesn't specify it libuv turns it off. */
index 5c87de0..32d2589 100644 (file)
@@ -31,7 +31,7 @@
 
 #define sync_stat(req, path)                                                  \
   do {                                                                        \
-    uv_fs_stat(uv_default_loop(), (req), (path), NULL);                       \
+    uv_fs_stat(NULL, (req), (path), NULL);                                    \
     uv_fs_req_cleanup((req));                                                 \
   }                                                                           \
   while (0)
index f223981..bfed676 100644 (file)
@@ -304,7 +304,7 @@ static int pipe_echo_start(char* pipeName) {
 #ifndef _WIN32
   {
     uv_fs_t req;
-    uv_fs_unlink(uv_default_loop(), &req, pipeName, NULL);
+    uv_fs_unlink(NULL, &req, pipeName, NULL);
     uv_fs_req_cleanup(&req);
   }
 #endif
index 1f45874..b4be01f 100644 (file)
@@ -41,6 +41,7 @@ int ipc_helper_tcp_connection(void);
 int ipc_send_recv_helper(void);
 int ipc_helper_bind_twice(void);
 int stdio_over_pipes_helper(void);
+int spawn_stdin_stdout(void);
 
 static int maybe_run_test(int argc, char **argv);
 
@@ -172,5 +173,9 @@ static int maybe_run_test(int argc, char **argv) {
   }
 #endif  /* !_WIN32 */
 
+  if (strcmp(argv[1], "spawn_helper9") == 0) {
+    return spawn_stdin_stdout();
+  }
+
   return run_test(argv[1], 0, 1);
 }
index 5da720f..2264d1e 100644 (file)
@@ -37,6 +37,7 @@
 #include <assert.h>
 
 #include <sys/select.h>
+#include <sys/time.h>
 #include <pthread.h>
 
 
@@ -173,6 +174,9 @@ int process_wait(process_info_t* vec, int n, int timeout) {
   process_info_t* p;
   dowait_args args;
   pthread_t tid;
+  pthread_attr_t attr;
+  unsigned int elapsed_ms;
+  struct timeval timebase;
   struct timeval tv;
   fd_set fds;
 
@@ -199,20 +203,54 @@ int process_wait(process_info_t* vec, int n, int timeout) {
     return -1;
   }
 
-  r = pthread_create(&tid, NULL, dowait, &args);
+  if (pthread_attr_init(&attr))
+    abort();
+
+  if (pthread_attr_setstacksize(&attr, 256 * 1024))
+    abort();
+
+  r = pthread_create(&tid, &attr, dowait, &args);
+
+  if (pthread_attr_destroy(&attr))
+    abort();
+
   if (r) {
     perror("pthread_create()");
     retval = -1;
     goto terminate;
   }
 
-  tv.tv_sec = timeout / 1000;
-  tv.tv_usec = 0;
+  if (gettimeofday(&timebase, NULL))
+    abort();
+
+  tv = timebase;
+  for (;;) {
+    /* Check that gettimeofday() doesn't jump back in time. */
+    assert(tv.tv_sec == timebase.tv_sec ||
+           (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec));
+
+    elapsed_ms =
+        (tv.tv_sec - timebase.tv_sec) * 1000 +
+        (tv.tv_usec / 1000) -
+        (timebase.tv_usec / 1000);
+
+    r = 0;  /* Timeout. */
+    if (elapsed_ms >= (unsigned) timeout)
+      break;
 
-  FD_ZERO(&fds);
-  FD_SET(args.pipe[0], &fds);
+    tv.tv_sec = (timeout - elapsed_ms) / 1000;
+    tv.tv_usec = (timeout - elapsed_ms) % 1000 * 1000;
 
-  r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv);
+    FD_ZERO(&fds);
+    FD_SET(args.pipe[0], &fds);
+
+    r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv);
+    if (!(r == -1 && errno == EINTR))
+      break;
+
+    if (gettimeofday(&tv, NULL))
+      abort();
+  }
 
   if (r == -1) {
     perror("select()");
@@ -229,15 +267,11 @@ int process_wait(process_info_t* vec, int n, int timeout) {
       kill(p->pid, SIGTERM);
     }
     retval = -2;
-
-    /* Wait for thread to finish. */
-    r = pthread_join(tid, NULL);
-    if (r) {
-      perror("pthread_join");
-      retval = -1;
-    }
   }
 
+  if (pthread_join(tid, NULL))
+    abort();
+
 terminate:
   close(args.pipe[0]);
   close(args.pipe[1]);
index e06a50e..e736763 100644 (file)
@@ -179,8 +179,8 @@ enum test_status {
 
 #include <stdarg.h>
 
-/* Define inline for MSVC */
-# ifdef _MSC_VER
+/* Define inline for MSVC<2015 */
+# if defined(_MSC_VER) && _MSC_VER < 1900
 #  define inline __inline
 # endif
 
index 0a2ba33..a0908ce 100644 (file)
 
 static uv_fs_event_t fs_event;
 static const char file_prefix[] = "fsevent-";
+static const int fs_event_file_count = 16;
+#if defined(__APPLE__) || defined(_WIN32)
+static const char file_prefix_in_subdir[] = "subdir";
+#endif
 static uv_timer_t timer;
 static int timer_cb_called;
 static int close_cb_called;
-static const int fs_event_file_count = 128;
 static int fs_event_created;
+static int fs_event_removed;
 static int fs_event_cb_called;
 #if defined(PATH_MAX)
 static char fs_event_filename[PATH_MAX];
@@ -50,48 +54,45 @@ static char fs_event_filename[1024];
 #endif  /* defined(PATH_MAX) */
 static int timer_cb_touch_called;
 
-static void fs_event_unlink_files(uv_timer_t* handle);
-
-static void create_dir(uv_loop_t* loop, const char* name) {
+static void create_dir(const char* name) {
   int r;
   uv_fs_t req;
-  r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
+  r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
   ASSERT(r == 0 || r == UV_EEXIST);
   uv_fs_req_cleanup(&req);
 }
 
-static void create_file(uv_loop_t* loop, const char* name) {
+static void create_file(const char* name) {
   int r;
   uv_file file;
   uv_fs_t req;
 
-  r = uv_fs_open(loop, &req, name, O_WRONLY | O_CREAT,
-      S_IWUSR | S_IRUSR, NULL);
+  r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   file = r;
   uv_fs_req_cleanup(&req);
-  r = uv_fs_close(loop, &req, file, NULL);
+  r = uv_fs_close(NULL, &req, file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 }
 
-static void touch_file(uv_loop_t* loop, const char* name) {
+static void touch_file(const char* name) {
   int r;
   uv_file file;
   uv_fs_t req;
   uv_buf_t buf;
 
-  r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   file = r;
   uv_fs_req_cleanup(&req);
 
   buf = uv_buf_init("foo", 4);
-  r = uv_fs_write(loop, &req, file, &buf, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
   ASSERT(r >= 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_close(loop, &req, file, NULL);
+  r = uv_fs_close(NULL, &req, file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 }
@@ -119,6 +120,56 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
   uv_close((uv_handle_t*)handle, close_cb);
 }
 
+static const char* fs_event_get_filename(int i) {
+  snprintf(fs_event_filename,
+           sizeof(fs_event_filename),
+           "watch_dir/%s%d",
+           file_prefix,
+           i);
+  return fs_event_filename;
+}
+
+static void fs_event_create_files(uv_timer_t* handle) {
+  /* Make sure we're not attempting to create files we do not intend */
+  ASSERT(fs_event_created < fs_event_file_count);
+
+  /* Create the file */
+  create_file(fs_event_get_filename(fs_event_created));
+
+  if (++fs_event_created < fs_event_file_count) {
+    /* Create another file on a different event loop tick.  We do it this way
+     * to avoid fs events coalescing into one fs event. */
+    ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
+  }
+}
+
+static void fs_event_unlink_files(uv_timer_t* handle) {
+  int r;
+  int i;
+
+  /* NOTE: handle might be NULL if invoked not as timer callback */
+  if (handle == NULL) {
+    /* Unlink all files */
+    for (i = 0; i < 16; i++) {
+      r = remove(fs_event_get_filename(i));
+      if (handle != NULL)
+        ASSERT(r == 0);
+    }
+  } else {
+    /* Make sure we're not attempting to remove files we do not intend */
+    ASSERT(fs_event_removed < fs_event_file_count);
+
+    /* Remove the file */
+    ASSERT(0 == remove(fs_event_get_filename(fs_event_removed)));
+
+    if (++fs_event_removed < fs_event_file_count) {
+      /* Remove another file on a different event loop tick.  We do it this way
+       * to avoid fs events coalescing into one fs event. */
+      ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+    }
+  }
+}
+
 static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
                                        const char* filename,
                                        int events,
@@ -126,61 +177,92 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
   fs_event_cb_called++;
   ASSERT(handle == &fs_event);
   ASSERT(status == 0);
-  ASSERT(events == UV_RENAME);
+  ASSERT(events == UV_CHANGE || UV_RENAME);
   ASSERT(filename == NULL ||
          strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
 
-  /* Stop watching dir when received events about all files:
-   * both create and close events */
-  if (fs_event_cb_called == 2 * fs_event_file_count) {
-    ASSERT(0 == uv_fs_event_stop(handle));
+  if (fs_event_created + fs_event_removed == fs_event_file_count) {
+    /* Once we've processed all create events, delete all files */
+    ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+  } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+    /* Once we've processed all create and delete events, stop watching */
+    uv_close((uv_handle_t*) &timer, close_cb);
     uv_close((uv_handle_t*) handle, close_cb);
   }
 }
 
-static const char* fs_event_get_filename(int i) {
+#if defined(__APPLE__) || defined(_WIN32)
+static const char* fs_event_get_filename_in_subdir(int i) {
   snprintf(fs_event_filename,
            sizeof(fs_event_filename),
-           "watch_dir/%s%d",
+           "watch_dir/subdir/%s%d",
            file_prefix,
            i);
   return fs_event_filename;
 }
 
-static void fs_event_create_files(uv_timer_t* handle) {
-  int i;
-
-  /* Already created all files */
-  if (fs_event_created == fs_event_file_count) {
-    uv_close((uv_handle_t*) &timer, close_cb);
-    return;
-  }
+static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
+  /* Make sure we're not attempting to create files we do not intend */
+  ASSERT(fs_event_created < fs_event_file_count);
 
-  /* Create all files */
-  for (i = 0; i < 16; i++, fs_event_created++)
-    create_file(handle->loop, fs_event_get_filename(i));
+  /* Create the file */
+  create_file(fs_event_get_filename_in_subdir(fs_event_created));
 
-  /* And unlink them */
-  ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0));
+  if (++fs_event_created < fs_event_file_count) {
+    /* Create another file on a different event loop tick.  We do it this way
+     * to avoid fs events coalescing into one fs event. */
+    ASSERT(0 == uv_timer_start(&timer, fs_event_create_files_in_subdir, 1, 0));
+  }
 }
 
-void fs_event_unlink_files(uv_timer_t* handle) {
+static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
   int r;
   int i;
 
   /* NOTE: handle might be NULL if invoked not as timer callback */
+  if (handle == NULL) {
+    /* Unlink all files */
+    for (i = 0; i < 16; i++) {
+      r = remove(fs_event_get_filename_in_subdir(i));
+      if (handle != NULL)
+        ASSERT(r == 0);
+    }
+  } else {
+    /* Make sure we're not attempting to remove files we do not intend */
+    ASSERT(fs_event_removed < fs_event_file_count);
+
+    /* Remove the file */
+    ASSERT(0 == remove(fs_event_get_filename_in_subdir(fs_event_removed)));
 
-  /* Unlink all files */
-  for (i = 0; i < 16; i++) {
-    r = remove(fs_event_get_filename(i));
-    if (handle != NULL)
-      ASSERT(r == 0);
+    if (++fs_event_removed < fs_event_file_count) {
+      /* Remove another file on a different event loop tick.  We do it this way
+       * to avoid fs events coalescing into one fs event. */
+      ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+    }
   }
+}
+
+static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
+                                                 const char* filename,
+                                                 int events,
+                                                 int status) {
+  fs_event_cb_called++;
+  ASSERT(handle == &fs_event);
+  ASSERT(status == 0);
+  ASSERT(events == UV_CHANGE || UV_RENAME);
+  ASSERT(filename == NULL ||
+         strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0);
 
-  /* And create them again */
-  if (handle != NULL)
-    ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0));
+  if (fs_event_created + fs_event_removed == fs_event_file_count) {
+    /* Once we've processed all create events, delete all files */
+    ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+  } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+    /* Once we've processed all create and delete events, stop watching */
+    uv_close((uv_handle_t*) &timer, close_cb);
+    uv_close((uv_handle_t*) handle, close_cb);
+  }
 }
+#endif
 
 static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
   int events, int status) {
@@ -226,16 +308,16 @@ static void timer_cb_file(uv_timer_t* handle) {
   ++timer_cb_called;
 
   if (timer_cb_called == 1) {
-    touch_file(handle->loop, "watch_dir/file1");
+    touch_file("watch_dir/file1");
   } else {
-    touch_file(handle->loop, "watch_dir/file2");
+    touch_file("watch_dir/file2");
     uv_close((uv_handle_t*)handle, close_cb);
   }
 }
 
 static void timer_cb_touch(uv_timer_t* timer) {
   uv_close((uv_handle_t*)timer, NULL);
-  touch_file(timer->loop, "watch_file");
+  touch_file("watch_file");
   timer_cb_touch_called++;
 }
 
@@ -255,7 +337,7 @@ TEST_IMPL(fs_event_watch_dir) {
   remove("watch_dir/file2");
   remove("watch_dir/file1");
   remove("watch_dir/");
-  create_dir(loop, "watch_dir");
+  create_dir("watch_dir");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -268,8 +350,7 @@ TEST_IMPL(fs_event_watch_dir) {
 
   uv_run(loop, UV_RUN_DEFAULT);
 
-  ASSERT(fs_event_cb_called == 2 * fs_event_file_count);
-  ASSERT(fs_event_created == fs_event_file_count);
+  ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
   ASSERT(close_cb_called == 2);
 
   /* Cleanup */
@@ -282,6 +363,50 @@ TEST_IMPL(fs_event_watch_dir) {
   return 0;
 }
 
+TEST_IMPL(fs_event_watch_dir_recursive) {
+#if defined(__APPLE__) || defined(_WIN32)
+  uv_loop_t* loop;
+  int r;
+
+  /* Setup */
+  loop = uv_default_loop();
+  fs_event_unlink_files(NULL);
+  remove("watch_dir/file2");
+  remove("watch_dir/file1");
+  remove("watch_dir/subdir");
+  remove("watch_dir/");
+  create_dir("watch_dir");
+  create_dir("watch_dir/subdir");
+
+  r = uv_fs_event_init(loop, &fs_event);
+  ASSERT(r == 0);
+  r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file_in_subdir, "watch_dir", UV_FS_EVENT_RECURSIVE);
+  ASSERT(r == 0);
+  r = uv_timer_init(loop, &timer);
+  ASSERT(r == 0);
+  r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
+  ASSERT(r == 0);
+
+  uv_run(loop, UV_RUN_DEFAULT);
+
+  ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
+  ASSERT(close_cb_called == 2);
+
+  /* Cleanup */
+  fs_event_unlink_files_in_subdir(NULL);
+  remove("watch_dir/file2");
+  remove("watch_dir/file1");
+  remove("watch_dir/subdir");
+  remove("watch_dir/");
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+#else
+  RETURN_SKIP("Recursive directory watching not supported on this platform.");
+#endif
+}
+
+
 TEST_IMPL(fs_event_watch_file) {
   uv_loop_t* loop = uv_default_loop();
   int r;
@@ -290,9 +415,9 @@ TEST_IMPL(fs_event_watch_file) {
   remove("watch_dir/file2");
   remove("watch_dir/file1");
   remove("watch_dir/");
-  create_dir(loop, "watch_dir");
-  create_file(loop, "watch_dir/file1");
-  create_file(loop, "watch_dir/file2");
+  create_dir("watch_dir");
+  create_file("watch_dir/file1");
+  create_file("watch_dir/file2");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -348,7 +473,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
 
   /* Setup */
   remove("watch_file");
-  create_file(loop, "watch_file");
+  create_file("watch_file");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -389,8 +514,8 @@ TEST_IMPL(fs_event_no_callback_after_close) {
   /* Setup */
   remove("watch_dir/file1");
   remove("watch_dir/");
-  create_dir(loop, "watch_dir");
-  create_file(loop, "watch_dir/file1");
+  create_dir("watch_dir");
+  create_file("watch_dir/file1");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -402,7 +527,7 @@ TEST_IMPL(fs_event_no_callback_after_close) {
 
 
   uv_close((uv_handle_t*)&fs_event, close_cb);
-  touch_file(loop, "watch_dir/file1");
+  touch_file("watch_dir/file1");
   uv_run(loop, UV_RUN_DEFAULT);
 
   ASSERT(fs_event_cb_called == 0);
@@ -423,8 +548,8 @@ TEST_IMPL(fs_event_no_callback_on_close) {
   /* Setup */
   remove("watch_dir/file1");
   remove("watch_dir/");
-  create_dir(loop, "watch_dir");
-  create_file(loop, "watch_dir/file1");
+  create_dir("watch_dir");
+  create_file("watch_dir/file1");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -497,8 +622,8 @@ TEST_IMPL(fs_event_close_with_pending_event) {
 
   loop = uv_default_loop();
 
-  create_dir(loop, "watch_dir");
-  create_file(loop, "watch_dir/file");
+  create_dir("watch_dir");
+  create_file("watch_dir/file");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -506,7 +631,7 @@ TEST_IMPL(fs_event_close_with_pending_event) {
   ASSERT(r == 0);
 
   /* Generate an fs event. */
-  touch_file(loop, "watch_dir/file");
+  touch_file("watch_dir/file");
 
   uv_close((uv_handle_t*)&fs_event, close_cb);
 
@@ -554,12 +679,12 @@ TEST_IMPL(fs_event_close_in_callback) {
 
   loop = uv_default_loop();
 
-  create_dir(loop, "watch_dir");
-  create_file(loop, "watch_dir/file1");
-  create_file(loop, "watch_dir/file2");
-  create_file(loop, "watch_dir/file3");
-  create_file(loop, "watch_dir/file4");
-  create_file(loop, "watch_dir/file5");
+  create_dir("watch_dir");
+  create_file("watch_dir/file1");
+  create_file("watch_dir/file2");
+  create_file("watch_dir/file3");
+  create_file("watch_dir/file4");
+  create_file("watch_dir/file5");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -567,11 +692,11 @@ TEST_IMPL(fs_event_close_in_callback) {
   ASSERT(r == 0);
 
   /* Generate a couple of fs events. */
-  touch_file(loop, "watch_dir/file1");
-  touch_file(loop, "watch_dir/file2");
-  touch_file(loop, "watch_dir/file3");
-  touch_file(loop, "watch_dir/file4");
-  touch_file(loop, "watch_dir/file5");
+  touch_file("watch_dir/file1");
+  touch_file("watch_dir/file2");
+  touch_file("watch_dir/file3");
+  touch_file("watch_dir/file4");
+  touch_file("watch_dir/file5");
 
   uv_run(loop, UV_RUN_DEFAULT);
 
@@ -600,7 +725,7 @@ TEST_IMPL(fs_event_start_and_close) {
 
   loop = uv_default_loop();
 
-  create_dir(loop, "watch_dir");
+  create_dir("watch_dir");
 
   r = uv_fs_event_init(loop, &fs_event1);
   ASSERT(r == 0);
@@ -630,7 +755,7 @@ TEST_IMPL(fs_event_getpath) {
   char buf[1024];
   size_t len;
 
-  create_dir(loop, "watch_dir");
+  create_dir("watch_dir");
 
   r = uv_fs_event_init(loop, &fs_event);
   ASSERT(r == 0);
@@ -692,7 +817,7 @@ TEST_IMPL(fs_event_error_reporting) {
   TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
 
   remove("watch_dir/");
-  create_dir(uv_default_loop(), "watch_dir");
+  create_dir("watch_dir");
 
   /* Create a lot of loops, and start FSEventStream in each of them.
    * Eventually, this should create enough streams to make FSEventStreamStart()
index a0600b3..17b90e9 100644 (file)
@@ -119,7 +119,7 @@ static void check_permission(const char* filename, unsigned int mode) {
   uv_fs_t req;
   uv_stat_t* s;
 
-  r = uv_fs_stat(uv_default_loop(), &req, filename, NULL);
+  r = uv_fs_stat(NULL, &req, filename, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
 
@@ -402,7 +402,7 @@ static void check_mkdtemp_result(uv_fs_t* req) {
   check_permission(req->path, 0700);
 
   /* Check if req->path is actually a directory */
-  r = uv_fs_stat(uv_default_loop(), &stat_req, req->path, NULL);
+  r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
   ASSERT(r == 0);
   ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
   uv_fs_req_cleanup(&stat_req);
@@ -521,7 +521,7 @@ TEST_IMPL(fs_file_noent) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL);
   ASSERT(r == UV_ENOENT);
   ASSERT(req.result == UV_ENOENT);
   uv_fs_req_cleanup(&req);
@@ -549,7 +549,7 @@ TEST_IMPL(fs_file_nametoolong) {
   memset(name, 'a', TOO_LONG_NAME_LENGTH);
   name[TOO_LONG_NAME_LENGTH] = 0;
 
-  r = uv_fs_open(loop, &req, name, O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL);
   ASSERT(r == UV_ENAMETOOLONG);
   ASSERT(req.result == UV_ENAMETOOLONG);
   uv_fs_req_cleanup(&req);
@@ -572,7 +572,7 @@ TEST_IMPL(fs_file_loop) {
   loop = uv_default_loop();
 
   unlink("test_symlink");
-  r = uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL);
+  r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL);
 #ifdef _WIN32
   /*
    * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
@@ -585,7 +585,7 @@ TEST_IMPL(fs_file_loop) {
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL);
   ASSERT(r == UV_ELOOP);
   ASSERT(req.result == UV_ELOOP);
   uv_fs_req_cleanup(&req);
@@ -730,63 +730,62 @@ TEST_IMPL(fs_file_sync) {
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(read_req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7, NULL);
+  r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL);
   ASSERT(r == 0);
   ASSERT(ftruncate_req.result == 0);
   uv_fs_req_cleanup(&ftruncate_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", NULL);
+  r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
   ASSERT(r == 0);
   ASSERT(rename_req.result == 0);
   uv_fs_req_cleanup(&rename_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
-      NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(read_req.result >= 0);
   ASSERT(strcmp(buf, "test-bu") == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_unlink(loop, &unlink_req, "test_file2", NULL);
+  r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL);
   ASSERT(r == 0);
   ASSERT(unlink_req.result == 0);
   uv_fs_req_cleanup(&unlink_req);
@@ -808,19 +807,19 @@ TEST_IMPL(fs_file_write_null_buffer) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(NULL, 0);
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r == 0);
   ASSERT(write_req.result == 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
@@ -850,19 +849,19 @@ TEST_IMPL(fs_async_dir) {
   ASSERT(mkdir_cb_count == 1);
 
   /* Create 2 files synchronously. */
-  r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   uv_fs_req_cleanup(&open_req1);
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   uv_fs_req_cleanup(&open_req1);
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
 
@@ -873,7 +872,7 @@ TEST_IMPL(fs_async_dir) {
   ASSERT(scandir_cb_count == 1);
 
   /* sync uv_fs_scandir */
-  r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, NULL);
+  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
   ASSERT(r == 2);
   ASSERT(scandir_req.result == 2);
   ASSERT(scandir_req.ptr);
@@ -957,12 +956,12 @@ TEST_IMPL(fs_async_sendfile) {
   ASSERT(r == 0);
 
   /* Test starts here. */
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
-  r = uv_fs_open(loop, &open_req2, "test_file2", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req2.result >= 0);
@@ -975,10 +974,10 @@ TEST_IMPL(fs_async_sendfile) {
 
   ASSERT(sendfile_cb_count == 1);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
-  r = uv_fs_close(loop, &close_req, open_req2.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
 
@@ -1008,7 +1007,7 @@ TEST_IMPL(fs_mkdtemp) {
   ASSERT(mkdtemp_cb_count == 1);
 
   /* sync mkdtemp */
-  r = uv_fs_mkdtemp(loop, &mkdtemp_req2, path_template, NULL);
+  r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
   ASSERT(r == 0);
   check_mkdtemp_result(&mkdtemp_req2);
 
@@ -1040,7 +1039,7 @@ TEST_IMPL(fs_fstat) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1048,12 +1047,12 @@ TEST_IMPL(fs_fstat) {
   uv_fs_req_cleanup(&req);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
   ASSERT(r == sizeof(test_buf));
   ASSERT(req.result == sizeof(test_buf));
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_fstat(loop, &req, file, NULL);
+  r = uv_fs_fstat(NULL, &req, file, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   s = req.ptr;
@@ -1130,7 +1129,7 @@ TEST_IMPL(fs_fstat) {
   ASSERT(fstat_cb_count == 1);
 
 
-  r = uv_fs_close(loop, &req, file, NULL);
+  r = uv_fs_close(NULL, &req, file, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1161,7 +1160,7 @@ TEST_IMPL(fs_access) {
   loop = uv_default_loop();
 
   /* File should not exist */
-  r = uv_fs_access(loop, &req, "test_file", F_OK, NULL);
+  r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
   ASSERT(r < 0);
   ASSERT(req.result < 0);
   uv_fs_req_cleanup(&req);
@@ -1174,7 +1173,7 @@ TEST_IMPL(fs_access) {
   access_cb_count = 0; /* reset for the next test */
 
   /* Create file */
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
                  S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1182,7 +1181,7 @@ TEST_IMPL(fs_access) {
   uv_fs_req_cleanup(&req);
 
   /* File should exist */
-  r = uv_fs_access(loop, &req, "test_file", F_OK, NULL);
+  r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1195,17 +1194,17 @@ TEST_IMPL(fs_access) {
   access_cb_count = 0; /* reset for the next test */
 
   /* Close file */
-  r = uv_fs_close(loop, &req, file, NULL);
+  r = uv_fs_close(NULL, &req, file, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
   /* Directory access */
-  r = uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL);
+  r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_access(loop, &req, "test_dir", W_OK, NULL);
+  r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1235,7 +1234,7 @@ TEST_IMPL(fs_chmod) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1243,14 +1242,14 @@ TEST_IMPL(fs_chmod) {
   uv_fs_req_cleanup(&req);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
   ASSERT(r == sizeof(test_buf));
   ASSERT(req.result == sizeof(test_buf));
   uv_fs_req_cleanup(&req);
 
 #ifndef _WIN32
   /* Make the file write-only */
-  r = uv_fs_chmod(loop, &req, "test_file", 0200, NULL);
+  r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1259,7 +1258,7 @@ TEST_IMPL(fs_chmod) {
 #endif
 
   /* Make the file read-only */
-  r = uv_fs_chmod(loop, &req, "test_file", 0400, NULL);
+  r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1267,7 +1266,7 @@ TEST_IMPL(fs_chmod) {
   check_permission("test_file", 0400);
 
   /* Make the file read+write with sync uv_fs_fchmod */
-  r = uv_fs_fchmod(loop, &req, file, 0600, NULL);
+  r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1333,7 +1332,7 @@ TEST_IMPL(fs_unlink_readonly) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop,
+  r = uv_fs_open(NULL,
                  &req,
                  "test_file",
                  O_RDWR | O_CREAT,
@@ -1345,7 +1344,7 @@ TEST_IMPL(fs_unlink_readonly) {
   uv_fs_req_cleanup(&req);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
   ASSERT(r == sizeof(test_buf));
   ASSERT(req.result == sizeof(test_buf));
   uv_fs_req_cleanup(&req);
@@ -1353,7 +1352,7 @@ TEST_IMPL(fs_unlink_readonly) {
   close(file);
 
   /* Make the file read-only */
-  r = uv_fs_chmod(loop, &req, "test_file", 0400, NULL);
+  r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1361,7 +1360,7 @@ TEST_IMPL(fs_unlink_readonly) {
   check_permission("test_file", 0400);
 
   /* Try to unlink the file */
-  r = uv_fs_unlink(loop, &req, "test_file", NULL);
+  r = uv_fs_unlink(NULL, &req, "test_file", NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1373,7 +1372,7 @@ TEST_IMPL(fs_unlink_readonly) {
   uv_run(loop, UV_RUN_DEFAULT);
 
   /* Cleanup. */
-  uv_fs_chmod(loop, &req, "test_file", 0600, NULL);
+  uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
   uv_fs_req_cleanup(&req);
   unlink("test_file");
 
@@ -1392,7 +1391,7 @@ TEST_IMPL(fs_chown) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1400,13 +1399,13 @@ TEST_IMPL(fs_chown) {
   uv_fs_req_cleanup(&req);
 
   /* sync chown */
-  r = uv_fs_chown(loop, &req, "test_file", -1, -1, NULL);
+  r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
   /* sync fchown */
-  r = uv_fs_fchown(loop, &req, file, -1, -1, NULL);
+  r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
@@ -1458,7 +1457,7 @@ TEST_IMPL(fs_link) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1466,7 +1465,7 @@ TEST_IMPL(fs_link) {
   uv_fs_req_cleanup(&req);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
   ASSERT(r == sizeof(test_buf));
   ASSERT(req.result == sizeof(test_buf));
   uv_fs_req_cleanup(&req);
@@ -1474,12 +1473,12 @@ TEST_IMPL(fs_link) {
   close(file);
 
   /* sync link */
-  r = uv_fs_link(loop, &req, "test_file", "test_file_link", NULL);
+  r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_open(loop, &req, "test_file_link", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   link = req.result;
@@ -1487,7 +1486,7 @@ TEST_IMPL(fs_link) {
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL);
+  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
@@ -1500,7 +1499,7 @@ TEST_IMPL(fs_link) {
   uv_run(loop, UV_RUN_DEFAULT);
   ASSERT(link_cb_count == 1);
 
-  r = uv_fs_open(loop, &req, "test_file_link2", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   link = req.result;
@@ -1508,7 +1507,7 @@ TEST_IMPL(fs_link) {
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL);
+  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
@@ -1542,7 +1541,7 @@ TEST_IMPL(fs_readlink) {
   ASSERT(req.result == UV_ENOENT);
   uv_fs_req_cleanup(&req);
 
-  ASSERT(UV_ENOENT == uv_fs_readlink(loop, &req, "no_such_file", NULL));
+  ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL));
   ASSERT(req.ptr == NULL);
   ASSERT(req.result == UV_ENOENT);
   uv_fs_req_cleanup(&req);
@@ -1567,7 +1566,7 @@ TEST_IMPL(fs_symlink) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+  r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
@@ -1575,7 +1574,7 @@ TEST_IMPL(fs_symlink) {
   uv_fs_req_cleanup(&req);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &req, file, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
   ASSERT(r == sizeof(test_buf));
   ASSERT(req.result == sizeof(test_buf));
   uv_fs_req_cleanup(&req);
@@ -1583,7 +1582,7 @@ TEST_IMPL(fs_symlink) {
   close(file);
 
   /* sync symlink */
-  r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink", 0, NULL);
+  r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
 #ifdef _WIN32
   if (r < 0) {
     if (r == UV_ENOTSUP) {
@@ -1605,7 +1604,7 @@ TEST_IMPL(fs_symlink) {
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_open(loop, &req, "test_file_symlink", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   link = req.result;
@@ -1613,14 +1612,14 @@ TEST_IMPL(fs_symlink) {
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL);
+  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
 
   close(link);
 
-  r = uv_fs_symlink(loop,
+  r = uv_fs_symlink(NULL,
                     &req,
                     "test_file_symlink",
                     "test_file_symlink_symlink",
@@ -1629,7 +1628,7 @@ TEST_IMPL(fs_symlink) {
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_readlink(loop, &req, "test_file_symlink_symlink", NULL);
+  r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
   ASSERT(r == 0);
   ASSERT(strcmp(req.ptr, "test_file_symlink") == 0);
   uv_fs_req_cleanup(&req);
@@ -1645,7 +1644,7 @@ TEST_IMPL(fs_symlink) {
   uv_run(loop, UV_RUN_DEFAULT);
   ASSERT(symlink_cb_count == 1);
 
-  r = uv_fs_open(loop, &req, "test_file_symlink2", O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   link = req.result;
@@ -1653,14 +1652,14 @@ TEST_IMPL(fs_symlink) {
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &req, link, &iov, 1, 0, NULL);
+  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
 
   close(link);
 
-  r = uv_fs_symlink(loop,
+  r = uv_fs_symlink(NULL,
                     &req,
                     "test_file_symlink2",
                     "test_file_symlink2_symlink",
@@ -1706,7 +1705,7 @@ TEST_IMPL(fs_symlink_dir) {
 
   loop = uv_default_loop();
 
-  uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL);
+  uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
   uv_fs_req_cleanup(&req);
 
 #ifdef _WIN32
@@ -1723,18 +1722,18 @@ TEST_IMPL(fs_symlink_dir) {
   test_dir = "test_dir";
 #endif
 
-  r = uv_fs_symlink(loop, &req, test_dir, "test_dir_symlink",
+  r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink",
     UV_FS_SYMLINK_JUNCTION, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_stat(loop, &req, "test_dir_symlink", NULL);
+  r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
   ASSERT(r == 0);
   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_lstat(loop, &req, "test_dir_symlink", NULL);
+  r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
   ASSERT(r == 0);
   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
 #ifdef _WIN32
@@ -1744,7 +1743,7 @@ TEST_IMPL(fs_symlink_dir) {
 #endif
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_readlink(loop, &req, "test_dir_symlink", NULL);
+  r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
   ASSERT(r == 0);
 #ifdef _WIN32
   ASSERT(strcmp(req.ptr, test_dir + 4) == 0);
@@ -1753,23 +1752,23 @@ TEST_IMPL(fs_symlink_dir) {
 #endif
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   uv_fs_req_cleanup(&open_req1);
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   uv_fs_req_cleanup(&open_req1);
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_scandir(loop, &scandir_req, "test_dir_symlink", 0, NULL);
+  r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
   ASSERT(r == 2);
   ASSERT(scandir_req.result == 2);
   ASSERT(scandir_req.ptr);
@@ -1785,15 +1784,15 @@ TEST_IMPL(fs_symlink_dir) {
   ASSERT(!scandir_req.ptr);
 
   /* unlink will remove the directory symlink */
-  r = uv_fs_unlink(loop, &req, "test_dir_symlink", NULL);
+  r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_scandir(loop, &scandir_req, "test_dir_symlink", 0, NULL);
+  r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
   ASSERT(r == UV_ENOENT);
   uv_fs_req_cleanup(&scandir_req);
 
-  r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, NULL);
+  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
   ASSERT(r == 2);
   ASSERT(scandir_req.result == 2);
   ASSERT(scandir_req.ptr);
@@ -1830,8 +1829,7 @@ TEST_IMPL(fs_utime) {
   /* Setup. */
   loop = uv_default_loop();
   unlink(path);
-  r = uv_fs_open(loop, &req, path, O_RDWR | O_CREAT,
-      S_IWUSR | S_IRUSR, NULL);
+  r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   uv_fs_req_cleanup(&req);
@@ -1839,12 +1837,12 @@ TEST_IMPL(fs_utime) {
 
   atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
 
-  r = uv_fs_utime(loop, &req, path, atime, mtime, NULL);
+  r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_stat(loop, &req, path, NULL);
+  r = uv_fs_stat(NULL, &req, path, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   check_utime(path, atime, mtime);
@@ -1875,26 +1873,26 @@ TEST_IMPL(fs_stat_root) {
   int r;
   uv_loop_t* loop = uv_default_loop();
 
-  r = uv_fs_stat(loop, &stat_req, "\\", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
   ASSERT(r == 0);
 
-  r = uv_fs_stat(loop, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
   ASSERT(r == 0);
 
-  r = uv_fs_stat(loop, &stat_req, "..", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "..", NULL);
   ASSERT(r == 0);
 
-  r = uv_fs_stat(loop, &stat_req, "..\\", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
   ASSERT(r == 0);
 
   /* stats the current directory on c: */
-  r = uv_fs_stat(loop, &stat_req, "c:", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
   ASSERT(r == 0);
 
-  r = uv_fs_stat(loop, &stat_req, "c:\\", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
   ASSERT(r == 0);
 
-  r = uv_fs_stat(loop, &stat_req, "\\\\?\\C:\\", NULL);
+  r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
   ASSERT(r == 0);
 
   MAKE_VALGRIND_HAPPY();
@@ -1915,8 +1913,7 @@ TEST_IMPL(fs_futime) {
   /* Setup. */
   loop = uv_default_loop();
   unlink(path);
-  r = uv_fs_open(loop, &req, path, O_RDWR | O_CREAT,
-      S_IWUSR | S_IRUSR, NULL);
+  r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   uv_fs_req_cleanup(&req);
@@ -1924,18 +1921,18 @@ TEST_IMPL(fs_futime) {
 
   atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
 
-  r = uv_fs_open(loop, &req, path, O_RDWR, 0, NULL);
+  r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   file = req.result; /* FIXME probably not how it's supposed to be used */
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_futime(loop, &req, file, atime, mtime, NULL);
+  r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_stat(loop, &req, path, NULL);
+  r = uv_fs_stat(NULL, &req, path, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   check_utime(path, atime, mtime);
@@ -1968,7 +1965,7 @@ TEST_IMPL(fs_stat_missing_path) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_stat(loop, &req, "non_existent_file", NULL);
+  r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
   ASSERT(r == UV_ENOENT);
   ASSERT(req.result == UV_ENOENT);
   uv_fs_req_cleanup(&req);
@@ -1987,13 +1984,13 @@ TEST_IMPL(fs_scandir_empty_dir) {
   path = "./empty_dir/";
   loop = uv_default_loop();
 
-  uv_fs_mkdir(loop, &req, path, 0777, NULL);
+  uv_fs_mkdir(NULL, &req, path, 0777, NULL);
   uv_fs_req_cleanup(&req);
 
   /* Fill the req to ensure that required fields are cleaned up */
   memset(&req, 0xdb, sizeof(req));
 
-  r = uv_fs_scandir(loop, &req, path, 0, NULL);
+  r = uv_fs_scandir(NULL, &req, path, 0, NULL);
   ASSERT(r == 0);
   ASSERT(req.result == 0);
   ASSERT(req.ptr == NULL);
@@ -2007,7 +2004,7 @@ TEST_IMPL(fs_scandir_empty_dir) {
   uv_run(loop, UV_RUN_DEFAULT);
   ASSERT(scandir_cb_count == 1);
 
-  uv_fs_rmdir(loop, &req, path, NULL);
+  uv_fs_rmdir(NULL, &req, path, NULL);
   uv_fs_req_cleanup(&req);
 
   MAKE_VALGRIND_HAPPY();
@@ -2022,7 +2019,7 @@ TEST_IMPL(fs_scandir_file) {
   path = "test/fixtures/empty_file";
   loop = uv_default_loop();
 
-  r = uv_fs_scandir(loop, &scandir_req, path, 0, NULL);
+  r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
   ASSERT(r == UV_ENOTDIR);
   uv_fs_req_cleanup(&scandir_req);
 
@@ -2046,14 +2043,14 @@ TEST_IMPL(fs_open_dir) {
   path = ".";
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &req, path, O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(req.result >= 0);
   ASSERT(req.ptr == NULL);
   file = r;
   uv_fs_req_cleanup(&req);
 
-  r = uv_fs_close(loop, &req, file, NULL);
+  r = uv_fs_close(NULL, &req, file, NULL);
   ASSERT(r == 0);
 
   r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple);
@@ -2076,47 +2073,46 @@ TEST_IMPL(fs_file_open_append) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
-      NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
   printf("read = %d\n", r);
   ASSERT(r == 26);
   ASSERT(read_req.result == 26);
@@ -2125,7 +2121,7 @@ TEST_IMPL(fs_file_open_append) {
                 sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
@@ -2147,54 +2143,53 @@ TEST_IMPL(fs_rename_to_existing_file) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file2", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", NULL);
+  r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
   ASSERT(r == 0);
   ASSERT(rename_req.result == 0);
   uv_fs_req_cleanup(&rename_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
-      NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(read_req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
@@ -2216,44 +2211,44 @@ TEST_IMPL(fs_read_file_eof) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   iov = uv_buf_init(test_buf, sizeof(test_buf));
-  r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
 
   memset(buf, 0, sizeof(buf));
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
   ASSERT(r >= 0);
   ASSERT(read_req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
   uv_fs_req_cleanup(&read_req);
 
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1,
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
                  read_req.result, NULL);
   ASSERT(r == 0);
   ASSERT(read_req.result == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
@@ -2275,7 +2270,7 @@ TEST_IMPL(fs_write_multiple_bufs) {
 
   loop = uv_default_loop();
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
       S_IWUSR | S_IRUSR, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
@@ -2283,17 +2278,17 @@ TEST_IMPL(fs_write_multiple_bufs) {
 
   iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
   iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
-  r = uv_fs_write(loop, &write_req, open_req1.result, iovs, 2, 0, NULL);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(write_req.result >= 0);
   uv_fs_req_cleanup(&write_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
 
-  r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL);
+  r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(open_req1.result >= 0);
   uv_fs_req_cleanup(&open_req1);
@@ -2303,7 +2298,7 @@ TEST_IMPL(fs_write_multiple_bufs) {
   /* Read the strings back to separate buffers. */
   iovs[0] = uv_buf_init(buf, sizeof(test_buf));
   iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
-  r = uv_fs_read(loop, &read_req, open_req1.result, iovs, 2, 0, NULL);
+  r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
   ASSERT(r >= 0);
   ASSERT(read_req.result >= 0);
   ASSERT(strcmp(buf, test_buf) == 0);
@@ -2311,13 +2306,13 @@ TEST_IMPL(fs_write_multiple_bufs) {
   uv_fs_req_cleanup(&read_req);
 
   iov = uv_buf_init(buf, sizeof(buf));
-  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1,
+  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
                  read_req.result, NULL);
   ASSERT(r == 0);
   ASSERT(read_req.result == 0);
   uv_fs_req_cleanup(&read_req);
 
-  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
   ASSERT(r == 0);
   ASSERT(close_req.result == 0);
   uv_fs_req_cleanup(&close_req);
@@ -2328,3 +2323,211 @@ TEST_IMPL(fs_write_multiple_bufs) {
   MAKE_VALGRIND_HAPPY();
   return 0;
 }
+
+
+TEST_IMPL(fs_write_alotof_bufs) {
+  const size_t iovcount = 54321;
+  uv_buf_t* iovs;
+  char* buffer;
+  size_t index;
+  int r;
+
+  /* Setup. */
+  unlink("test_file");
+
+  loop = uv_default_loop();
+
+  iovs = malloc(sizeof(*iovs) * iovcount);
+  ASSERT(iovs != NULL);
+
+  r = uv_fs_open(NULL,
+                 &open_req1,
+                 "test_file",
+                 O_RDWR | O_CREAT,
+                 S_IWUSR | S_IRUSR,
+                 NULL);
+  ASSERT(r >= 0);
+  ASSERT(open_req1.result >= 0);
+  uv_fs_req_cleanup(&open_req1);
+
+  for (index = 0; index < iovcount; ++index)
+    iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+  r = uv_fs_write(NULL,
+                  &write_req,
+                  open_req1.result,
+                  iovs,
+                  iovcount,
+                  -1,
+                  NULL);
+  ASSERT(r >= 0);
+  ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+  uv_fs_req_cleanup(&write_req);
+
+  /* Read the strings back to separate buffers. */
+  buffer = malloc(sizeof(test_buf) * iovcount);
+  ASSERT(buffer != NULL);
+
+  for (index = 0; index < iovcount; ++index)
+    iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+                              sizeof(test_buf));
+
+  r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, 0, NULL);
+  ASSERT(r >= 0);
+  ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
+
+  for (index = 0; index < iovcount; ++index)
+    ASSERT(strncmp(buffer + index * sizeof(test_buf),
+                   test_buf,
+                   sizeof(test_buf)) == 0);
+
+  uv_fs_req_cleanup(&read_req);
+  free(buffer);
+
+  iov = uv_buf_init(buf, sizeof(buf));
+  r = uv_fs_read(NULL,
+                 &read_req,
+                 open_req1.result,
+                 &iov,
+                 1,
+                 read_req.result,
+                 NULL);
+  ASSERT(r == 0);
+  ASSERT(read_req.result == 0);
+  uv_fs_req_cleanup(&read_req);
+
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+  ASSERT(r == 0);
+  ASSERT(close_req.result == 0);
+  uv_fs_req_cleanup(&close_req);
+
+  /* Cleanup */
+  unlink("test_file");
+  free(iovs);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(fs_write_alotof_bufs_with_offset) {
+  const size_t iovcount = 54321;
+  uv_buf_t* iovs;
+  char* buffer;
+  size_t index;
+  int r;
+  int64_t offset;
+  char* filler = "0123456789";
+  int filler_len = strlen(filler);
+
+  /* Setup. */
+  unlink("test_file");
+
+  loop = uv_default_loop();
+
+  iovs = malloc(sizeof(*iovs) * iovcount);
+  ASSERT(iovs != NULL);
+
+  r = uv_fs_open(NULL,
+                 &open_req1,
+                 "test_file",
+                 O_RDWR | O_CREAT,
+                 S_IWUSR | S_IRUSR,
+                 NULL);
+  ASSERT(r >= 0);
+  ASSERT(open_req1.result >= 0);
+  uv_fs_req_cleanup(&open_req1);
+
+  iov = uv_buf_init(filler, filler_len);
+  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+  ASSERT(r == filler_len);
+  ASSERT(write_req.result == filler_len);
+  uv_fs_req_cleanup(&write_req);
+  offset = (int64_t)r;
+
+  for (index = 0; index < iovcount; ++index)
+    iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+  r = uv_fs_write(NULL,
+                  &write_req,
+                  open_req1.result,
+                  iovs,
+                  iovcount,
+                  offset,
+                  NULL);
+  ASSERT(r >= 0);
+  ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+  uv_fs_req_cleanup(&write_req);
+
+  /* Read the strings back to separate buffers. */
+  buffer = malloc(sizeof(test_buf) * iovcount);
+  ASSERT(buffer != NULL);
+
+  for (index = 0; index < iovcount; ++index)
+    iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+                              sizeof(test_buf));
+
+  r = uv_fs_read(NULL, &read_req, open_req1.result,
+                 iovs, iovcount, offset, NULL);
+  ASSERT(r >= 0);
+  ASSERT(read_req.result == sizeof(test_buf) * iovcount);
+
+  for (index = 0; index < iovcount; ++index)
+    ASSERT(strncmp(buffer + index * sizeof(test_buf),
+                   test_buf,
+                   sizeof(test_buf)) == 0);
+
+  uv_fs_req_cleanup(&read_req);
+  free(buffer);
+
+  r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
+  ASSERT(r == 0);
+  ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
+         offset + (int64_t)(iovcount * sizeof(test_buf)));
+  uv_fs_req_cleanup(&stat_req);
+
+  iov = uv_buf_init(buf, sizeof(buf));
+  r = uv_fs_read(NULL,
+                 &read_req,
+                 open_req1.result,
+                 &iov,
+                 1,
+                 read_req.result + offset,
+                 NULL);
+  ASSERT(r == 0);
+  ASSERT(read_req.result == 0);
+  uv_fs_req_cleanup(&read_req);
+
+  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+  ASSERT(r == 0);
+  ASSERT(close_req.result == 0);
+  uv_fs_req_cleanup(&close_req);
+
+  /* Cleanup */
+  unlink("test_file");
+  free(iovs);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(fs_read_write_null_arguments) {
+  int r;
+
+  r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
+  ASSERT(r == UV_EINVAL);
+
+  r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
+  ASSERT(r == UV_EINVAL);
+
+  iov = uv_buf_init(NULL, 0);
+  r = uv_fs_read(NULL, NULL, 0, &iov, 0, -1, NULL);
+  ASSERT(r == UV_EINVAL);
+
+  iov = uv_buf_init(NULL, 0);
+  r = uv_fs_write(NULL, NULL, 0, &iov, 0, -1, NULL);
+  ASSERT(r == UV_EINVAL);
+
+  return 0;
+}
index 1e4018c..3189966 100644 (file)
@@ -66,6 +66,7 @@ TEST_DECLARE   (tcp_write_fail)
 TEST_DECLARE   (tcp_try_write)
 TEST_DECLARE   (tcp_write_queue_order)
 TEST_DECLARE   (tcp_open)
+TEST_DECLARE   (tcp_open_twice)
 TEST_DECLARE   (tcp_connect_error_after_write)
 TEST_DECLARE   (tcp_shutdown_after_write)
 TEST_DECLARE   (tcp_bind_error_addrinuse)
@@ -80,6 +81,10 @@ TEST_DECLARE   (tcp_connect_error_fault)
 TEST_DECLARE   (tcp_connect_timeout)
 TEST_DECLARE   (tcp_close_while_connecting)
 TEST_DECLARE   (tcp_close)
+TEST_DECLARE   (tcp_create_early)
+TEST_DECLARE   (tcp_create_early_bad_bind)
+TEST_DECLARE   (tcp_create_early_bad_domain)
+TEST_DECLARE   (tcp_create_early_accept)
 #ifndef _WIN32
 TEST_DECLARE   (tcp_close_accept)
 TEST_DECLARE   (tcp_oob)
@@ -95,6 +100,9 @@ TEST_DECLARE   (tcp_bind6_error_inval)
 TEST_DECLARE   (tcp_bind6_localhost_ok)
 TEST_DECLARE   (udp_bind)
 TEST_DECLARE   (udp_bind_reuseaddr)
+TEST_DECLARE   (udp_create_early)
+TEST_DECLARE   (udp_create_early_bad_bind)
+TEST_DECLARE   (udp_create_early_bad_domain)
 TEST_DECLARE   (udp_send_and_recv)
 TEST_DECLARE   (udp_send_immediate)
 TEST_DECLARE   (udp_send_unreachable)
@@ -110,10 +118,12 @@ TEST_DECLARE   (udp_options)
 TEST_DECLARE   (udp_options6)
 TEST_DECLARE   (udp_no_autobind)
 TEST_DECLARE   (udp_open)
+TEST_DECLARE   (udp_open_twice)
 TEST_DECLARE   (udp_try_send)
 TEST_DECLARE   (pipe_bind_error_addrinuse)
 TEST_DECLARE   (pipe_bind_error_addrnotavail)
 TEST_DECLARE   (pipe_bind_error_inval)
+TEST_DECLARE   (pipe_connect_multiple)
 TEST_DECLARE   (pipe_listen_without_bind)
 TEST_DECLARE   (pipe_connect_bad_name)
 TEST_DECLARE   (pipe_connect_to_file)
@@ -121,6 +131,7 @@ TEST_DECLARE   (pipe_connect_on_prepare)
 TEST_DECLARE   (pipe_getsockname)
 TEST_DECLARE   (pipe_getsockname_abstract)
 TEST_DECLARE   (pipe_getsockname_blocking)
+TEST_DECLARE   (pipe_pending_instances)
 TEST_DECLARE   (pipe_sendmsg)
 TEST_DECLARE   (pipe_server_close)
 TEST_DECLARE   (connection_fail)
@@ -221,6 +232,7 @@ TEST_DECLARE   (spawn_stdout_and_stderr_to_file_swap)
 TEST_DECLARE   (spawn_auto_unref)
 TEST_DECLARE   (spawn_closed_process_io)
 TEST_DECLARE   (spawn_reads_child_path)
+TEST_DECLARE   (spawn_inherit_streams)
 TEST_DECLARE   (fs_poll)
 TEST_DECLARE   (fs_poll_getpath)
 TEST_DECLARE   (kill)
@@ -248,6 +260,7 @@ TEST_DECLARE   (fs_file_open_append)
 TEST_DECLARE   (fs_stat_missing_path)
 TEST_DECLARE   (fs_read_file_eof)
 TEST_DECLARE   (fs_event_watch_dir)
+TEST_DECLARE   (fs_event_watch_dir_recursive)
 TEST_DECLARE   (fs_event_watch_file)
 TEST_DECLARE   (fs_event_watch_file_twice)
 TEST_DECLARE   (fs_event_watch_file_current_dir)
@@ -264,6 +277,9 @@ TEST_DECLARE   (fs_scandir_file)
 TEST_DECLARE   (fs_open_dir)
 TEST_DECLARE   (fs_rename_to_existing_file)
 TEST_DECLARE   (fs_write_multiple_bufs)
+TEST_DECLARE   (fs_read_write_null_arguments)
+TEST_DECLARE   (fs_write_alotof_bufs)
+TEST_DECLARE   (fs_write_alotof_bufs_with_offset)
 TEST_DECLARE   (threadpool_queue_work_simple)
 TEST_DECLARE   (threadpool_queue_work_einval)
 TEST_DECLARE   (threadpool_multiple_event_loops)
@@ -289,8 +305,10 @@ TEST_DECLARE   (ip6_addr_link_local)
 TEST_DECLARE   (poll_close_doesnt_corrupt_stack)
 TEST_DECLARE   (poll_closesocket)
 TEST_DECLARE   (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
 TEST_DECLARE   (argument_escaping)
 TEST_DECLARE   (environment_creation)
+#endif
 TEST_DECLARE   (listen_with_simultaneous_accepts)
 TEST_DECLARE   (listen_no_simultaneous_accepts)
 TEST_DECLARE   (fs_stat_root)
@@ -393,6 +411,7 @@ TASK_LIST_START
 
   TEST_ENTRY  (tcp_open)
   TEST_HELPER (tcp_open, tcp4_echo_server)
+  TEST_ENTRY  (tcp_open_twice)
 
   TEST_ENTRY  (tcp_shutdown_after_write)
   TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
@@ -410,6 +429,10 @@ TASK_LIST_START
   TEST_ENTRY  (tcp_connect_timeout)
   TEST_ENTRY  (tcp_close_while_connecting)
   TEST_ENTRY  (tcp_close)
+  TEST_ENTRY  (tcp_create_early)
+  TEST_ENTRY  (tcp_create_early_bad_bind)
+  TEST_ENTRY  (tcp_create_early_bad_domain)
+  TEST_ENTRY  (tcp_create_early_accept)
 #ifndef _WIN32
   TEST_ENTRY  (tcp_close_accept)
   TEST_ENTRY  (tcp_oob)
@@ -429,6 +452,9 @@ TASK_LIST_START
 
   TEST_ENTRY  (udp_bind)
   TEST_ENTRY  (udp_bind_reuseaddr)
+  TEST_ENTRY  (udp_create_early)
+  TEST_ENTRY  (udp_create_early_bad_bind)
+  TEST_ENTRY  (udp_create_early_bad_domain)
   TEST_ENTRY  (udp_send_and_recv)
   TEST_ENTRY  (udp_send_immediate)
   TEST_ENTRY  (udp_send_unreachable)
@@ -447,14 +473,17 @@ TASK_LIST_START
 
   TEST_ENTRY  (udp_open)
   TEST_HELPER (udp_open, udp4_echo_server)
+  TEST_ENTRY  (udp_open_twice)
 
   TEST_ENTRY  (pipe_bind_error_addrinuse)
   TEST_ENTRY  (pipe_bind_error_addrnotavail)
   TEST_ENTRY  (pipe_bind_error_inval)
+  TEST_ENTRY  (pipe_connect_multiple)
   TEST_ENTRY  (pipe_listen_without_bind)
   TEST_ENTRY  (pipe_getsockname)
   TEST_ENTRY  (pipe_getsockname_abstract)
   TEST_ENTRY  (pipe_getsockname_blocking)
+  TEST_ENTRY  (pipe_pending_instances)
   TEST_ENTRY  (pipe_sendmsg)
 
   TEST_ENTRY  (connection_fail)
@@ -590,6 +619,7 @@ TASK_LIST_START
   TEST_ENTRY  (spawn_auto_unref)
   TEST_ENTRY  (spawn_closed_process_io)
   TEST_ENTRY  (spawn_reads_child_path)
+  TEST_ENTRY  (spawn_inherit_streams)
   TEST_ENTRY  (fs_poll)
   TEST_ENTRY  (fs_poll_getpath)
   TEST_ENTRY  (kill)
@@ -598,8 +628,10 @@ TASK_LIST_START
   TEST_ENTRY  (poll_close_doesnt_corrupt_stack)
   TEST_ENTRY  (poll_closesocket)
   TEST_ENTRY  (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
   TEST_ENTRY  (argument_escaping)
   TEST_ENTRY  (environment_creation)
+# endif
   TEST_ENTRY  (listen_with_simultaneous_accepts)
   TEST_ENTRY  (listen_no_simultaneous_accepts)
   TEST_ENTRY  (fs_stat_root)
@@ -644,6 +676,7 @@ TASK_LIST_START
   TEST_ENTRY  (fs_read_file_eof)
   TEST_ENTRY  (fs_file_open_append)
   TEST_ENTRY  (fs_event_watch_dir)
+  TEST_ENTRY  (fs_event_watch_dir_recursive)
   TEST_ENTRY  (fs_event_watch_file)
   TEST_ENTRY  (fs_event_watch_file_twice)
   TEST_ENTRY  (fs_event_watch_file_current_dir)
@@ -660,6 +693,9 @@ TASK_LIST_START
   TEST_ENTRY  (fs_open_dir)
   TEST_ENTRY  (fs_rename_to_existing_file)
   TEST_ENTRY  (fs_write_multiple_bufs)
+  TEST_ENTRY  (fs_write_alotof_bufs)
+  TEST_ENTRY  (fs_write_alotof_bufs_with_offset)
+  TEST_ENTRY  (fs_read_write_null_arguments)
   TEST_ENTRY  (threadpool_queue_work_simple)
   TEST_ENTRY  (threadpool_queue_work_einval)
   TEST_ENTRY  (threadpool_multiple_event_loops)
diff --git a/deps/uv/test/test-pipe-connect-multiple.c b/deps/uv/test/test-pipe-connect-multiple.c
new file mode 100644 (file)
index 0000000..3de5a9a
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connection_cb_called = 0;
+static int connect_cb_called = 0;
+
+#define NUM_CLIENTS 4
+
+typedef struct {
+  uv_pipe_t pipe_handle;
+  uv_connect_t conn_req;
+} client_t;
+
+static uv_pipe_t server_handle;
+static client_t clients[NUM_CLIENTS];
+static uv_pipe_t connections[NUM_CLIENTS];
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+  int r;
+  uv_pipe_t* conn;
+  ASSERT(status == 0);
+
+  conn = &connections[connection_cb_called];
+  r = uv_pipe_init(server->loop, conn, 0);
+  ASSERT(r == 0);
+
+  r = uv_accept(server, (uv_stream_t*)conn);
+  ASSERT(r == 0);
+
+  if (++connection_cb_called == NUM_CLIENTS &&
+      connect_cb_called == NUM_CLIENTS) {
+    uv_stop(server->loop);
+  }
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+  ASSERT(status == 0);
+  if (++connect_cb_called == NUM_CLIENTS &&
+      connection_cb_called == NUM_CLIENTS) {
+    uv_stop(connect_req->handle->loop);
+  }
+}
+
+
+TEST_IMPL(pipe_connect_multiple) {
+  int i;
+  int r;
+  uv_loop_t* loop;
+
+  loop = uv_default_loop();
+
+  r = uv_pipe_init(loop, &server_handle, 0);
+  ASSERT(r == 0);
+
+  r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
+  ASSERT(r == 0);
+
+  r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb);
+  ASSERT(r == 0);
+
+  for (i = 0; i < NUM_CLIENTS; i++) {
+    r = uv_pipe_init(loop, &clients[i].pipe_handle, 0);
+    ASSERT(r == 0);
+    uv_pipe_connect(&clients[i].conn_req,
+                    &clients[i].pipe_handle,
+                    TEST_PIPENAME,
+                    connect_cb);
+  }
+
+  uv_run(loop, UV_RUN_DEFAULT);
+
+  ASSERT(connection_cb_called == NUM_CLIENTS);
+  ASSERT(connect_cb_called == NUM_CLIENTS);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
diff --git a/deps/uv/test/test-pipe-pending-instances.c b/deps/uv/test/test-pipe-pending-instances.c
new file mode 100644 (file)
index 0000000..b6ff911
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+  ASSERT(0 && "this will never be called");
+}
+
+
+TEST_IMPL(pipe_pending_instances) {
+  int r;
+  uv_pipe_t pipe_handle;
+  uv_loop_t* loop;
+
+  loop = uv_default_loop();
+
+  r = uv_pipe_init(loop, &pipe_handle, 0);
+  ASSERT(r == 0);
+
+  uv_pipe_pending_instances(&pipe_handle, 8);
+
+  r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
+  ASSERT(r == 0);
+
+  uv_pipe_pending_instances(&pipe_handle, 16);
+
+  r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb);
+  ASSERT(r == 0);
+
+  uv_close((uv_handle_t*)&pipe_handle, NULL);
+
+  r = uv_run(loop, UV_RUN_DEFAULT);
+  ASSERT(r == 0);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index f8fef36..1581299 100644 (file)
@@ -185,6 +185,7 @@ static void loop_creating_worker(void* context) {
     ASSERT(r == 0);
 
     uv_loop_close(loop);
+    free(loop);
 
     increment_counter(&loop_creation_counter);
   } while (!stop);
index d01862a..e71f0f7 100644 (file)
@@ -277,7 +277,7 @@ TEST_IMPL(spawn_stdout_to_file) {
 
   init_process_options("spawn_helper2", exit_cb);
 
-  r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
+  r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
       S_IRUSR | S_IWUSR, NULL);
   ASSERT(r != -1);
   uv_fs_req_cleanup(&fs_req);
@@ -300,11 +300,11 @@ TEST_IMPL(spawn_stdout_to_file) {
   ASSERT(close_cb_called == 1);
 
   buf = uv_buf_init(output, sizeof(output));
-  r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
+  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
   ASSERT(r == 12);
   uv_fs_req_cleanup(&fs_req);
 
-  r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
+  r = uv_fs_close(NULL, &fs_req, file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&fs_req);
 
@@ -331,7 +331,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
 
   init_process_options("spawn_helper6", exit_cb);
 
-  r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
+  r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
       S_IRUSR | S_IWUSR, NULL);
   ASSERT(r != -1);
   uv_fs_req_cleanup(&fs_req);
@@ -356,11 +356,11 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
   ASSERT(close_cb_called == 1);
 
   buf = uv_buf_init(output, sizeof(output));
-  r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
+  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
   ASSERT(r == 27);
   uv_fs_req_cleanup(&fs_req);
 
-  r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
+  r = uv_fs_close(NULL, &fs_req, file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&fs_req);
 
@@ -389,7 +389,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
   init_process_options("spawn_helper6", exit_cb);
 
   /* Replace stderr with our file */
-  r = uv_fs_open(uv_default_loop(),
+  r = uv_fs_open(NULL,
                  &fs_req,
                  "stdout_file",
                  O_CREAT | O_RDWR,
@@ -418,11 +418,11 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
   ASSERT(close_cb_called == 1);
 
   buf = uv_buf_init(output, sizeof(output));
-  r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
+  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
   ASSERT(r == 27);
   uv_fs_req_cleanup(&fs_req);
 
-  r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
+  r = uv_fs_close(NULL, &fs_req, file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&fs_req);
 
@@ -456,7 +456,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
   init_process_options("spawn_helper6", exit_cb);
 
   /* open 'stdout_file' and replace STDOUT_FILENO with it */
-  r = uv_fs_open(uv_default_loop(),
+  r = uv_fs_open(NULL,
                  &fs_req,
                  "stdout_file",
                  O_CREAT | O_RDWR,
@@ -468,7 +468,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
   ASSERT(stdout_file != -1);
 
   /* open 'stderr_file' and replace STDERR_FILENO with it */
-  r = uv_fs_open(uv_default_loop(), &fs_req, "stderr_file", O_CREAT | O_RDWR,
+  r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
       S_IRUSR | S_IWUSR, NULL);
   ASSERT(r != -1);
   uv_fs_req_cleanup(&fs_req);
@@ -497,11 +497,11 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
   buf = uv_buf_init(output, sizeof(output));
 
   /* check the content of stdout_file */
-  r = uv_fs_read(uv_default_loop(), &fs_req, stdout_file, &buf, 1, 0, NULL);
+  r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
   ASSERT(r >= 15);
   uv_fs_req_cleanup(&fs_req);
 
-  r = uv_fs_close(uv_default_loop(), &fs_req, stdout_file, NULL);
+  r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&fs_req);
 
@@ -509,11 +509,11 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
   ASSERT(strncmp("hello errworld\n", output, 15) == 0);
 
   /* check the content of stderr_file */
-  r = uv_fs_read(uv_default_loop(), &fs_req, stderr_file, &buf, 1, 0, NULL);
+  r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
   ASSERT(r >= 12);
   uv_fs_req_cleanup(&fs_req);
 
-  r = uv_fs_close(uv_default_loop(), &fs_req, stderr_file, NULL);
+  r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
   ASSERT(r == 0);
   uv_fs_req_cleanup(&fs_req);
 
@@ -994,6 +994,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
 }
 
 
+#if !defined(USING_UV_SHARED)
 int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
 WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
 
@@ -1196,6 +1197,7 @@ TEST_IMPL(environment_creation) {
 
   return 0;
 }
+#endif
 
 /* Regression test for issue #909 */
 TEST_IMPL(spawn_with_an_odd_path) {
@@ -1397,8 +1399,9 @@ TEST_IMPL(spawn_fs_open) {
   uv_buf_t buf;
   uv_stdio_container_t stdio[1];
 
-  fd = uv_fs_open(uv_default_loop(), &fs_req, "/dev/null", O_RDWR, 0, NULL);
+  fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
   ASSERT(fd >= 0);
+  uv_fs_req_cleanup(&fs_req);
 
   init_process_options("spawn_helper8", exit_cb);
 
@@ -1415,7 +1418,7 @@ TEST_IMPL(spawn_fs_open) {
   ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
 
   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
-  ASSERT(0 == uv_fs_close(uv_default_loop(), &fs_req, fd, NULL));
+  ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
 
   ASSERT(exit_cb_called == 1);
   ASSERT(close_cb_called == 2);  /* One for `in`, one for process */
@@ -1540,3 +1543,164 @@ TEST_IMPL(spawn_reads_child_path) {
   MAKE_VALGRIND_HAPPY();
   return 0;
 }
+
+#ifndef _WIN32
+static int mpipe(int *fds) {
+  if (pipe(fds) == -1)
+    return -1;
+  if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+      fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+    close(fds[0]);
+    close(fds[1]);
+    return -1;
+  }
+  return 0;
+}
+#else
+static int mpipe(int *fds) {
+  SECURITY_ATTRIBUTES attr;
+  HANDLE readh, writeh;
+  attr.nLength = sizeof(attr);
+  attr.lpSecurityDescriptor = NULL;
+  attr.bInheritHandle = FALSE;
+  if (!CreatePipe(&readh, &writeh, &attr, 0))
+    return -1;
+  fds[0] = _open_osfhandle((intptr_t)readh, 0);
+  fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+  if (fds[0] == -1 || fds[1] == -1) {
+    CloseHandle(readh);
+    CloseHandle(writeh);
+    return -1;
+  }
+  return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_inherit_streams) {
+  uv_process_t child_req;
+  uv_stdio_container_t child_stdio[2];
+  int fds_stdin[2];
+  int fds_stdout[2];
+  uv_pipe_t pipe_stdin_child;
+  uv_pipe_t pipe_stdout_child;
+  uv_pipe_t pipe_stdin_parent;
+  uv_pipe_t pipe_stdout_parent;
+  unsigned char ubuf[OUTPUT_SIZE - 1];
+  uv_buf_t buf;
+  unsigned int i;
+  int r;
+  uv_write_t write_req;
+  uv_loop_t* loop;
+
+  init_process_options("spawn_helper9", exit_cb);
+
+  loop = uv_default_loop();
+  ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
+  ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
+  ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
+  ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
+
+  ASSERT(mpipe(fds_stdin) != -1);
+  ASSERT(mpipe(fds_stdout) != -1);
+
+  ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
+  ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
+  ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
+  ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
+
+  child_stdio[0].flags = UV_INHERIT_STREAM;
+  child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
+
+  child_stdio[1].flags = UV_INHERIT_STREAM;
+  child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
+
+  options.stdio = child_stdio;
+  options.stdio_count = 2;
+
+  ASSERT(uv_spawn(loop, &child_req, &options) == 0);
+
+  uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
+  uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
+
+  buf = uv_buf_init((char*)ubuf, sizeof ubuf);
+  for (i = 0; i < sizeof ubuf; ++i)
+    ubuf[i] = i & 255u;
+  memset(output, 0, sizeof ubuf);
+
+  r = uv_write(&write_req,
+               (uv_stream_t*)&pipe_stdin_parent,
+               &buf,
+               1,
+               write_cb);
+  ASSERT(r == 0);
+
+  r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
+  ASSERT(r == 0);
+
+  r = uv_run(loop, UV_RUN_DEFAULT);
+  ASSERT(r == 0);
+
+  ASSERT(exit_cb_called == 1);
+  ASSERT(close_cb_called == 3);
+
+  r = memcmp(ubuf, output, sizeof ubuf);
+  ASSERT(r == 0);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+/* Helper for child process of spawn_inherit_streams */
+#ifndef _WIN32
+int spawn_stdin_stdout(void) {
+  char buf[1024];
+  char* pbuf;
+  for (;;) {
+    ssize_t r, w, c;
+    do {
+      r = read(0, buf, sizeof buf);
+    } while (r == -1 && errno == EINTR);
+    if (r == 0) {
+      return 1;
+    }
+    ASSERT(r > 0);
+    c = r;
+    pbuf = buf;
+    while (c) {
+      do {
+        w = write(1, pbuf, (size_t)c);
+      } while (w == -1 && errno == EINTR);
+      ASSERT(w >= 0);
+      pbuf = pbuf + w;
+      c = c - w;
+    }
+  }
+  return 2;
+}
+#else
+int spawn_stdin_stdout(void) {
+  char buf[1024];
+  char* pbuf;
+  HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
+  HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+  ASSERT(h_stdin != INVALID_HANDLE_VALUE);
+  ASSERT(h_stdout != INVALID_HANDLE_VALUE);
+  for (;;) {
+    DWORD n_read;
+    DWORD n_written;
+    DWORD to_write;
+    if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
+      ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
+      return 1;
+    }
+    to_write = n_read;
+    pbuf = buf;
+    while (to_write) {
+      ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
+      to_write -= n_written;
+      pbuf += n_written;
+    }
+  }
+  return 2;
+}
+#endif /* !_WIN32 */
index 0a69a0d..2c39b65 100644 (file)
@@ -59,14 +59,18 @@ TEST_IMPL(tcp_close_while_connecting) {
   uv_connect_t connect_req;
   struct sockaddr_in addr;
   uv_loop_t* loop;
+  int r;
 
   loop = uv_default_loop();
   ASSERT(0 == uv_ip4_addr("1.2.3.4", TEST_PORT, &addr));
   ASSERT(0 == uv_tcp_init(loop, &tcp_handle));
-  ASSERT(0 == uv_tcp_connect(&connect_req,
-                             &tcp_handle,
-                             (const struct sockaddr*) &addr,
-                             connect_cb));
+  r = uv_tcp_connect(&connect_req,
+                     &tcp_handle,
+                     (const struct sockaddr*) &addr,
+                     connect_cb);
+  if (r == UV_ENETUNREACH)
+    RETURN_SKIP("Network unreachable.");
+  ASSERT(r == 0);
   ASSERT(0 == uv_timer_init(loop, &timer1_handle));
   ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0));
   ASSERT(0 == uv_timer_init(loop, &timer2_handle));
index a22c773..081424b 100644 (file)
@@ -79,6 +79,8 @@ TEST_IMPL(tcp_connect_timeout) {
                      &conn,
                      (const struct sockaddr*) &addr,
                      connect_cb);
+  if (r == UV_ENETUNREACH)
+    RETURN_SKIP("Network unreachable.");
   ASSERT(r == 0);
 
   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
diff --git a/deps/uv/test/test-tcp-create-socket-early.c b/deps/uv/test/test-tcp-create-socket-early.c
new file mode 100644 (file)
index 0000000..65650ad
--- /dev/null
@@ -0,0 +1,206 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * 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>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+static void on_connect(uv_connect_t* req, int status) {
+  ASSERT(status == 0);
+  uv_close((uv_handle_t*) req->handle, NULL);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+  uv_tcp_t* handle;
+  int r;
+
+  ASSERT(status == 0);
+
+  handle = malloc(sizeof(*handle));
+  ASSERT(handle != NULL);
+
+  r = uv_tcp_init_ex(server->loop, handle, AF_INET);
+  ASSERT(r == 0);
+
+  r = uv_accept(server, (uv_stream_t*)handle);
+  ASSERT(r == UV_EBUSY);
+
+  uv_close((uv_handle_t*) server, NULL);
+  uv_close((uv_handle_t*) handle, (uv_close_cb)free);
+}
+
+
+static void tcp_listener(uv_loop_t* loop, uv_tcp_t* server) {
+  struct sockaddr_in addr;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+  r = uv_tcp_init(loop, server);
+  ASSERT(r == 0);
+
+  r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
+  ASSERT(r == 0);
+
+  r = uv_listen((uv_stream_t*) server, 128, on_connection);
+  ASSERT(r == 0);
+}
+
+
+static void tcp_connector(uv_loop_t* loop, uv_tcp_t* client, uv_connect_t* req) {
+  struct sockaddr_in server_addr;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+
+  r = uv_tcp_init(loop, client);
+  ASSERT(r == 0);
+
+  r = uv_tcp_connect(req,
+                     client,
+                     (const struct sockaddr*) &server_addr,
+                     on_connect);
+  ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_create_early) {
+  struct sockaddr_in addr;
+  struct sockaddr_in sockname;
+  uv_tcp_t client;
+  uv_os_fd_t fd;
+  int r, namelen;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET);
+  ASSERT(r == 0);
+
+  r = uv_fileno((const uv_handle_t*) &client, &fd);
+  ASSERT(r == 0);
+  ASSERT(fd != INVALID_FD);
+
+  /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+  namelen = sizeof sockname;
+  r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+  ASSERT(r == 0);
+  ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+  r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+  ASSERT(r == 0);
+
+  namelen = sizeof sockname;
+  r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+  ASSERT(r == 0);
+  ASSERT(memcmp(&addr.sin_addr,
+                &sockname.sin_addr,
+                sizeof(addr.sin_addr)) == 0);
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_bind) {
+  struct sockaddr_in addr;
+  uv_tcp_t client;
+  uv_os_fd_t fd;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6);
+  ASSERT(r == 0);
+
+  r = uv_fileno((const uv_handle_t*) &client, &fd);
+  ASSERT(r == 0);
+  ASSERT(fd != INVALID_FD);
+
+  /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+  {
+    int namelen;
+    struct sockaddr_in6 sockname;
+    namelen = sizeof sockname;
+    r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+    ASSERT(r == 0);
+    ASSERT(sockname.sin6_family == AF_INET6);
+  }
+#endif
+
+  r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+  ASSERT(r == UV_EINVAL);
+#else
+  ASSERT(r == UV_EFAULT);
+#endif
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_domain) {
+  uv_tcp_t client;
+  int r;
+
+  r = uv_tcp_init_ex(uv_default_loop(), &client, 47);
+  ASSERT(r == UV_EINVAL);
+
+  r = uv_tcp_init_ex(uv_default_loop(), &client, 1024);
+  ASSERT(r == UV_EINVAL);
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_accept) {
+  uv_tcp_t client, server;
+  uv_connect_t connect_req;
+
+  tcp_listener(uv_default_loop(), &server);
+  tcp_connector(uv_default_loop(), &client, &connect_req);
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index edeacc7..6c8d43d 100644 (file)
@@ -71,6 +71,17 @@ static uv_os_sock_t create_tcp_socket(void) {
 }
 
 
+static void close_socket(uv_os_sock_t sock) {
+  int r;
+#ifdef _WIN32
+  r = closesocket(sock);
+#else
+  r = close(sock);
+#endif
+  ASSERT(r == 0);
+}
+
+
 static void alloc_cb(uv_handle_t* handle,
                      size_t suggested_size,
                      uv_buf_t* buf) {
@@ -180,3 +191,30 @@ TEST_IMPL(tcp_open) {
   MAKE_VALGRIND_HAPPY();
   return 0;
 }
+
+
+TEST_IMPL(tcp_open_twice) {
+  uv_tcp_t client;
+  uv_os_sock_t sock1, sock2;
+  int r;
+
+  startup();
+  sock1 = create_tcp_socket();
+  sock2 = create_tcp_socket();
+
+  r = uv_tcp_init(uv_default_loop(), &client);
+  ASSERT(r == 0);
+
+  r = uv_tcp_open(&client, sock1);
+  ASSERT(r == 0);
+
+  r = uv_tcp_open(&client, sock2);
+  ASSERT(r == UV_EBUSY);
+  close_socket(sock2);
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
diff --git a/deps/uv/test/test-tcp-squelch-connreset.c b/deps/uv/test/test-tcp-squelch-connreset.c
new file mode 100644 (file)
index 0000000..f1c5743
--- /dev/null
@@ -0,0 +1,119 @@
+/* Copyright (c) 2015, Santiago Gimeno <santiago.gimeno@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_client;
+static uv_tcp_t tcp_server_client;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+static void alloc_cb(uv_handle_t* handle,
+                     size_t size,
+                     uv_buf_t* buf) {
+  buf->base = malloc(size);
+  buf->len = size;
+}
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+  free(buf->base);
+  ASSERT(nread == UV_EOF);
+}
+
+static void on_connect(uv_connect_t* req, int status) {
+  int r;
+  uv_buf_t outbuf;
+
+  ASSERT(req != NULL);
+  ASSERT(status == 0);
+
+  outbuf = uv_buf_init("ping", 4);
+  r = uv_write(&write_req, (uv_stream_t*) req->handle, &outbuf, 1, NULL);
+  ASSERT(r == 0);
+
+  r = uv_read_start((uv_stream_t*) req->handle, alloc_cb, read_cb);
+  ASSERT(r == 0);
+}
+
+static void on_connection(uv_stream_t* server, int status) {
+  int r;
+
+  ASSERT(status == 0);
+
+  r = uv_tcp_init(uv_default_loop(), &tcp_server_client);
+  ASSERT(r == 0);
+
+  r = uv_accept(server, (uv_stream_t*) &tcp_server_client);
+  ASSERT(r == 0);
+
+  uv_close((uv_handle_t*) &tcp_server_client, NULL);
+  uv_close((uv_handle_t*) &tcp_server, NULL);
+}
+
+static void start_server(void) {
+  struct sockaddr_in addr;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+  r = uv_tcp_init(uv_default_loop(), &tcp_server);
+  ASSERT(r == 0);
+
+  r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+  ASSERT(r == 0);
+
+  r = uv_listen((uv_stream_t*) &tcp_server, SOMAXCONN, on_connection);
+  ASSERT(r == 0);
+}
+
+static void start_client(void) {
+  struct sockaddr_in addr;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_tcp_init(uv_default_loop(), &tcp_client);
+  ASSERT(r == 0);
+
+  r = uv_tcp_connect(&connect_req,
+                     &tcp_client,
+                     (const struct sockaddr*) &addr,
+                     on_connect);
+  ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_squelch_connreset) {
+
+  start_server();
+
+  start_client();
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index f999cba..cb45622 100644 (file)
@@ -279,10 +279,12 @@ TEST_IMPL(threadpool_cancel_fs) {
   uv_fs_t reqs[25];
   uv_loop_t* loop;
   unsigned n;
+  uv_buf_t iov;
 
   INIT_CANCEL_INFO(&ci, reqs);
   loop = uv_default_loop();
   saturate_threadpool();
+  iov = uv_buf_init(NULL, 0);
 
   /* Needs to match ARRAY_SIZE(fs_reqs). */
   n = 0;
@@ -300,7 +302,7 @@ TEST_IMPL(threadpool_cancel_fs) {
   ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb));
   ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
   ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb));
-  ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, NULL, 0, 0, fs_cb));
+  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_rename(loop, reqs + n++, "/", "/", fs_cb));
@@ -310,7 +312,7 @@ TEST_IMPL(threadpool_cancel_fs) {
   ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb));
   ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb));
   ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb));
-  ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, NULL, 0, 0, fs_cb));
+  ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
   ASSERT(n == ARRAY_SIZE(reqs));
 
   ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
diff --git a/deps/uv/test/test-udp-create-socket-early.c b/deps/uv/test/test-udp-create-socket-early.c
new file mode 100644 (file)
index 0000000..3d01524
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * 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>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+TEST_IMPL(udp_create_early) {
+  struct sockaddr_in addr;
+  struct sockaddr_in sockname;
+  uv_udp_t client;
+  uv_os_fd_t fd;
+  int r, namelen;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET);
+  ASSERT(r == 0);
+
+  r = uv_fileno((const uv_handle_t*) &client, &fd);
+  ASSERT(r == 0);
+  ASSERT(fd != INVALID_FD);
+
+  /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+  namelen = sizeof sockname;
+  r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+  ASSERT(r == 0);
+  ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+  r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+  ASSERT(r == 0);
+
+  namelen = sizeof sockname;
+  r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+  ASSERT(r == 0);
+  ASSERT(memcmp(&addr.sin_addr,
+                &sockname.sin_addr,
+                sizeof(addr.sin_addr)) == 0);
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_bind) {
+  struct sockaddr_in addr;
+  uv_udp_t client;
+  uv_os_fd_t fd;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6);
+  ASSERT(r == 0);
+
+  r = uv_fileno((const uv_handle_t*) &client, &fd);
+  ASSERT(r == 0);
+  ASSERT(fd != INVALID_FD);
+
+  /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+  {
+    int namelen;
+    struct sockaddr_in6 sockname;
+    namelen = sizeof sockname;
+    r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+    ASSERT(r == 0);
+    ASSERT(sockname.sin6_family == AF_INET6);
+  }
+#endif
+
+  r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+  ASSERT(r == UV_EINVAL);
+#else
+  ASSERT(r == UV_EFAULT);
+#endif
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_domain) {
+  uv_udp_t client;
+  int r;
+
+  r = uv_udp_init_ex(uv_default_loop(), &client, 47);
+  ASSERT(r == UV_EINVAL);
+
+  r = uv_udp_init_ex(uv_default_loop(), &client, 1024);
+  ASSERT(r == UV_EINVAL);
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index f0679c5..71001a7 100644 (file)
@@ -44,7 +44,7 @@ static void close_cb(uv_handle_t* handle) {
 
 static void sv_send_cb(uv_udp_send_t* req, int status) {
   ASSERT(req != NULL);
-  ASSERT(status == 0);
+  ASSERT(status == 0 || status == UV_ENETUNREACH);
   CHECK_HANDLE(req->handle);
 
   sv_send_cb_called++;
index 686edf3..6110a8d 100644 (file)
@@ -116,6 +116,8 @@ TEST_IMPL(udp_multicast_join) {
 
   /* join the multicast channel */
   r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP);
+  if (r == UV_ENODEV)
+    RETURN_SKIP("No multicast support.");
   ASSERT(r == 0);
 
   r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
index 9ba201a..873cb6d 100644 (file)
@@ -124,6 +124,11 @@ TEST_IMPL(udp_multicast_join6) {
 #else
   r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP);
 #endif
+  if (r == UV_ENODEV) {
+    MAKE_VALGRIND_HAPPY();
+    RETURN_SKIP("No ipv6 multicast route");
+  }
+
   ASSERT(r == 0);
 
   r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
index bed0ea1..7f1af9b 100644 (file)
@@ -44,7 +44,7 @@ static void close_cb(uv_handle_t* handle) {
 
 static void sv_send_cb(uv_udp_send_t* req, int status) {
   ASSERT(req != NULL);
-  ASSERT(status == 0);
+  ASSERT(status == 0 || status == UV_ENETUNREACH);
   CHECK_HANDLE(req->handle);
 
   sv_send_cb_called++;
index b2b6117..4d77f45 100644 (file)
@@ -67,6 +67,17 @@ static uv_os_sock_t create_udp_socket(void) {
 }
 
 
+static void close_socket(uv_os_sock_t sock) {
+  int r;
+#ifdef _WIN32
+  r = closesocket(sock);
+#else
+  r = close(sock);
+#endif
+  ASSERT(r == 0);
+}
+
+
 static void alloc_cb(uv_handle_t* handle,
                      size_t suggested_size,
                      uv_buf_t* buf) {
@@ -164,3 +175,30 @@ TEST_IMPL(udp_open) {
   MAKE_VALGRIND_HAPPY();
   return 0;
 }
+
+
+TEST_IMPL(udp_open_twice) {
+  uv_udp_t client;
+  uv_os_sock_t sock1, sock2;
+  int r;
+
+  startup();
+  sock1 = create_udp_socket();
+  sock2 = create_udp_socket();
+
+  r = uv_udp_init(uv_default_loop(), &client);
+  ASSERT(r == 0);
+
+  r = uv_udp_open(&client, sock1);
+  ASSERT(r == 0);
+
+  r = uv_udp_open(&client, sock2);
+  ASSERT(r == UV_EBUSY);
+  close_socket(sock2);
+
+  uv_close((uv_handle_t*) &client, NULL);
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index 7173a82..8049faa 100644 (file)
         'test/test-ping-pong.c',
         'test/test-pipe-bind-error.c',
         'test/test-pipe-connect-error.c',
+        'test/test-pipe-connect-multiple.c',
         'test/test-pipe-connect-prepare.c',
         'test/test-pipe-getsockname.c',
+        'test/test-pipe-pending-instances.c',
         'test/test-pipe-sendmsg.c',
         'test/test-pipe-server-close.c',
         'test/test-pipe-close-stdout-read-stdin.c',
         'test/test-tcp-close.c',
         'test/test-tcp-close-accept.c',
         'test/test-tcp-close-while-connecting.c',
+        'test/test-tcp-create-socket-early.c',
         'test/test-tcp-connect-error-after-write.c',
         'test/test-tcp-shutdown-after-write.c',
         'test/test-tcp-flags.c',
         'test/test-timer.c',
         'test/test-tty.c',
         'test/test-udp-bind.c',
+        'test/test-udp-create-socket-early.c',
         'test/test-udp-dgram-too-big.c',
         'test/test-udp-ipv6.c',
         'test/test-udp-open.c',
             '_XOPEN_SOURCE=500',
           ],
         }],
+        ['uv_library=="shared_library"', {
+          'defines': [ 'USING_UV_SHARED=1' ]
+        }],
       ],
       'msvs-settings': {
         'VCLinkerTool': {
             'test/runner-unix.c',
             'test/runner-unix.h',
           ]
-        }]
+        }],
+        ['uv_library=="shared_library"', {
+          'defines': [ 'USING_UV_SHARED=1' ]
+        }],
       ],
       'msvs-settings': {
         'VCLinkerTool': {