deps: update libuv to 1.5.0
authorSaúl Ibarra Corretgé <saghul@gmail.com>
Wed, 6 May 2015 07:46:15 +0000 (09:46 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Wed, 6 May 2015 21:08:52 +0000 (23:08 +0200)
Fixes: https://github.com/iojs/io.js/issues/1397
Fixes: https://github.com/iojs/io.js/issues/1512
Fixes: https://github.com/iojs/io.js/issues/1621
Fixes: https://github.com/iojs/io.js/issues/862
PR-URL: https://github.com/iojs/io.js/pull/1646
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
75 files changed:
deps/uv/AUTHORS
deps/uv/ChangeLog
deps/uv/Makefile.am
deps/uv/README.md
deps/uv/configure.ac
deps/uv/docs/src/conf.py
deps/uv/docs/src/design.rst
deps/uv/docs/src/dns.rst
deps/uv/docs/src/fs.rst
deps/uv/docs/src/loop.rst
deps/uv/docs/src/misc.rst
deps/uv/docs/src/pipe.rst
deps/uv/docs/src/poll.rst
deps/uv/docs/src/sphinx-plugins/manpage.py [new file with mode: 0644]
deps/uv/docs/src/stream.rst
deps/uv/docs/src/tcp.rst
deps/uv/docs/src/threadpool.rst
deps/uv/docs/src/tty.rst
deps/uv/docs/src/udp.rst
deps/uv/include/uv-version.h
deps/uv/include/uv-win.h
deps/uv/include/uv.h
deps/uv/src/unix/aix.c
deps/uv/src/unix/android-ifaddrs.c
deps/uv/src/unix/fs.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/linux-core.c
deps/uv/src/unix/linux-syscalls.c
deps/uv/src/unix/process.c
deps/uv/src/unix/stream.c
deps/uv/src/unix/tty.c
deps/uv/src/unix/udp.c
deps/uv/src/uv-common.c
deps/uv/src/win/core.c
deps/uv/src/win/error.c
deps/uv/src/win/fs-event.c
deps/uv/src/win/fs.c
deps/uv/src/win/getaddrinfo.c
deps/uv/src/win/getnameinfo.c
deps/uv/src/win/pipe.c
deps/uv/src/win/poll.c
deps/uv/src/win/process.c
deps/uv/src/win/req-inl.h
deps/uv/src/win/stream-inl.h
deps/uv/src/win/stream.c
deps/uv/src/win/tcp.c
deps/uv/src/win/tty.c
deps/uv/src/win/udp.c
deps/uv/src/win/util.c
deps/uv/test/benchmark-getaddrinfo.c
deps/uv/test/benchmark-loop-count.c
deps/uv/test/benchmark-million-timers.c
deps/uv/test/benchmark-ping-pongs.c
deps/uv/test/benchmark-pound.c
deps/uv/test/benchmark-pump.c
deps/uv/test/benchmark-sizes.c
deps/uv/test/benchmark-spawn.c
deps/uv/test/run-benchmarks.c
deps/uv/test/run-tests.c
deps/uv/test/runner.c
deps/uv/test/task.h
deps/uv/test/test-fs.c
deps/uv/test/test-handle-fileno.c
deps/uv/test/test-idle.c
deps/uv/test/test-ip6-addr.c
deps/uv/test/test-list.h
deps/uv/test/test-loop-handles.c
deps/uv/test/test-osx-select.c
deps/uv/test/test-pipe-set-non-blocking.c
deps/uv/test/test-spawn.c
deps/uv/test/test-tcp-write-fail.c [new file with mode: 0644]
deps/uv/test/test-timer-again.c
deps/uv/test/test-tty.c
deps/uv/uv.gyp
deps/uv/vcbuild.bat

index 6929fff..a0e3dd4 100644 (file)
@@ -181,3 +181,19 @@ Johan Bergström <bugs@bergstroem.nu>
 Alex Mo <almosnow@gmail.com>
 Luis Martinez de Bartolome <lasote@gmail.com>
 Michael Penick <michael.penick@datastax.com>
+Michael <michael_dawson@ca.ibm.com>
+Massimiliano Torromeo <massimiliano.torromeo@gmail.com>
+TomCrypto <thomas.beneteau@yahoo.fr>
+Brett Vickers <brett@beevik.com>
+Ole André Vadla Ravnås <oleavr@gmail.com>
+Kazuho Oku <kazuhooku@gmail.com>
+Ryan Phillips <ryan.phillips@rackspace.com>
+Brian Green <briangreenery@gmail.com>
+Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
+Corey Farrell <git@cfware.com>
+Per Nilsson <pni@qlik.com>
+Alan Rogers <alanjrogers@me.com>
+Daryl Haresign <github@daryl.haresign.com>
+Rui Abreu Ferreira <raf-ep@gmx.com>
+João Reis <reis@janeasystems.com>
+farblue68 <farblue68@gmail.com>
index 7bbe502..e5c7980 100644 (file)
@@ -1,4 +1,108 @@
-2015.02.27, Version 1.4.2 (Stable)
+2015.05.07, Version 1.5.0 (Stable), 4e77f74c7b95b639b3397095db1bc5bcc016c203
+
+Changes since version 1.4.2:
+
+* doc: clarify that the thread pool primites are not thread safe (Andrius
+  Bentkus)
+
+* aix: always deregister closing fds from epoll (Michael)
+
+* unix: fix glibc-2.20+ macro incompatibility (Massimiliano Torromeo)
+
+* doc: add Sphinx plugin for generating links to man pages (Saúl Ibarra
+  Corretgé)
+
+* doc: link system and library calls to man pages (Saúl Ibarra Corretgé)
+
+* doc: document uv_getnameinfo_t.{host|service} (Saúl Ibarra Corretgé)
+
+* build: update the location of gyp (Stephen von Takach)
+
+* win: name all anonymous structs and unions (TomCrypto)
+
+* linux: work around epoll bug in kernels 3.10-3.19 (Ben Noordhuis)
+
+* darwin: fix size calculation in select() fallback (Ole André Vadla Ravnås)
+
+* solaris: fix setsockopt for multicast options (Julien Gilli)
+
+* test: fix race condition in multithreaded test (Ben Noordhuis)
+
+* doc: fix long lines in tty.rst (Ben Noordhuis)
+
+* test: use UV_TTY_MODE_* values in tty test (Ben Noordhuis)
+
+* unix: don't clobber errno in uv_tty_reset_mode() (Ben Noordhuis)
+
+* unix: reject non-tty fds in uv_tty_init() (Ben Noordhuis)
+
+* win: fix pipe blocking writes (Alexis Campailla)
+
+* build: fix cross-compiling for iOS (Steven Kabbes)
+
+* win: remove unnecessary malloc.h
+
+* include: use `extern "c++"` for defining C++ code (Kazuho Oku)
+
+* unix: reap child on execvp() failure (Ryan Phillips)
+
+* windows: fix handle leak on EMFILE (Brian Green)
+
+* test: fix tty_file, close handle if initialized (Saúl Ibarra Corretgé)
+
+* doc: clarify what uv_*_open accepts (Saúl Ibarra Corretgé)
+
+* doc: clarify that we don't maintain external doc resources (Saúl Ibarra
+  Corretgé)
+
+* build: add documentation for ninja support (Devchandra Meetei Leishangthem)
+
+* doc: document uv_buf_t members (Corey Farrell)
+
+* linux: fix epoll_pwait() fallback on arm64 (Ben Noordhuis)
+
+* android: fix compilation warning (Saúl Ibarra Corretgé)
+
+* unix: don't close the fds we just setup (Sam Roberts)
+
+* test: spawn child replacing std{out,err} to stderr (Saúl Ibarra Corretgé)
+
+* unix: fix swapping fds order in uv_spawn (Saúl Ibarra Corretgé)
+
+* unix: fix potential bug if dup2 fails in uv_spawn (Saúl Ibarra Corretgé)
+
+* test: remove LOG and LOGF variadic macros (Saúl Ibarra Corretgé)
+
+* win: fix uv_fs_access on directories (Saúl Ibarra Corretgé)
+
+* win: fix of double free in uv_uptime (Per Nilsson)
+
+* unix: open "/dev/null" instead of "/" for emfile_fd (Alan Rogers)
+
+* docs: add some missing words (Daryl Haresign)
+
+* unix: clean up uv_fs_open() O_CLOEXEC logic (Ben Noordhuis)
+
+* build: set SONAME for shared library in uv.gyp (Rui Abreu Ferreira)
+
+* windows: define snprintf replacement as inline instead of static (Rui Abreu
+  Ferreira)
+
+* win: fix unlink of readonly files (João Reis)
+
+* doc: fix uv_run(UV_RUN_DEFAULT) description (Ben Noordhuis)
+
+* linux: intercept syscall when running under memory sanitizer (Keno Fischer)
+
+* aix: fix uv_interface_addresses return value (farblue68)
+
+* windows: defer reporting TCP write failure until next tick (Saúl Ibarra
+  Corretgé)
+
+* test: add test for deferred TCP write failure (Saúl Ibarra Corretgé)
+
+
+2015.02.27, Version 1.4.2 (Stable), 1a7391348a11d5450c0f69c828d5302e2cb842eb
 
 Changes since version 1.4.1:
 
index 9c511db..b9fb80c 100644 (file)
@@ -226,6 +226,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
                          test/test-tcp-write-to-half-open-connection.c \
                          test/test-tcp-write-after-connect.c \
                          test/test-tcp-writealot.c \
+                         test/test-tcp-write-fail.c \
                          test/test-tcp-try-write.c \
                          test/test-tcp-write-queue-order.c \
                          test/test-thread-equal.c \
index a267f0d..a7da8b8 100644 (file)
@@ -72,19 +72,23 @@ NOTE: Windows users need to use make.bat instead of plain 'make'.
 
 Documentation can be browsed online [here](http://docs.libuv.org).
 
+The [tests and benchmarks](https://github.com/libuv/libuv/tree/master/test)
+also serve as API specification and usage examples.
+
 ### Other resources
 
  * [An Introduction to libuv](http://nikhilm.github.com/uvbook/)
    &mdash; An overview of libuv with tutorials.
  * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4)
    &mdash; High-level introductory talk about libuv.
- * [Tests and benchmarks](https://github.com/libuv/libuv/tree/master/test)
-   &mdash; API specification and usage examples.
  * [libuv-dox](https://github.com/thlorenz/libuv-dox)
    &mdash; Documenting types and methods of libuv, mostly by reading uv.h.
  * [learnuv](https://github.com/thlorenz/learnuv)
    &mdash; Learn uv for fun and profit, a self guided workshop to libuv.
 
+These resources are not handled by libuv maintainers and might be out of
+date. Please verify it before opening new issues.
+
 ## Build Instructions
 
 For GCC there are two build methods: via autotools or via [GYP][].
@@ -113,8 +117,6 @@ To have GYP generate build script for another system, checkout GYP into the
 project tree manually:
 
     $ git clone https://chromium.googlesource.com/external/gyp.git build/gyp
-    OR
-    $ svn co http://gyp.googlecode.com/svn/trunk build/gyp
 
 ### Unix
 
@@ -153,6 +155,15 @@ Run:
 Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
 `-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
 
+### Using Ninja
+
+To use ninja for build on ninja supported platforms, run:
+
+    $ ./gyp_uv.py -f ninja
+    $ ninja -C out/Debug     #for debug build OR
+    $ ninja -C out/Release
+
+
 ### Running tests
 
 Run:
index 9473d5f..71cb470 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.4.2], [https://github.com/libuv/libuv/issues])
+AC_INIT([libuv], [1.5.0], [https://github.com/libuv/libuv/issues])
 AC_CONFIG_MACRO_DIR([m4])
 m4_include([m4/libuv-extra-automake-flags.m4])
 m4_include([m4/as_case.m4])
index f614fc5..b9eaa13 100644 (file)
@@ -38,7 +38,7 @@ def get_libuv_version():
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('sphinx-plugins'))
 
 # -- General configuration ------------------------------------------------
 
@@ -48,7 +48,7 @@ def get_libuv_version():
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = []
+extensions = ['manpage']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['templates']
index 63141be..34c3cff 100644 (file)
@@ -40,7 +40,7 @@ The I/O loop
 The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O
 operations, and it's meant to be tied to a single thread. One can run multiple event loops
 as long as each runs in a different thread. The libuv event loop (or any other API involving
-the loop or handles, for that matter) **is not thread-safe** except stated otherwise.
+the loop or handles, for that matter) **is not thread-safe** except where stated otherwise.
 
 The event loop follows the rather usual single threaded asynchronous I/O approach: all (network)
 I/O is performed on non-blocking sockets which are polled using the best mechanism available
@@ -113,7 +113,7 @@ stages of a loop iteration:
 
 .. note::
     While the polling mechanism is different, libuv makes the execution model consistent
-    Unix systems and Windows.
+    across Unix systems and Windows.
 
 
 File I/O
index 3b15377..1d88158 100644 (file)
@@ -51,6 +51,18 @@ Public members
     Loop that started this getnameinfo request and where completion will be
     reported. Readonly.
 
+.. c:member:: char[NI_MAXHOST] uv_getnameinfo_t.host
+
+    Char array containing the resulting host. It's null terminated.
+
+    .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. c:member:: char[NI_MAXSERV] uv_getnameinfo_t.service
+
+    Char array containing the resulting service. It's null terminated.
+
+    .. versionchanged:: 1.3.0 the field is declared as public.
+
 .. seealso:: The :c:type:`uv_req_t` members also apply.
 
 
@@ -59,7 +71,7 @@ API
 
 .. c:function:: int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints)
 
-    Asynchronous ``getaddrinfo(3)``.
+    Asynchronous :man:`getaddrinfo(3)`.
 
     Either node or service may be NULL but not both.
 
@@ -84,7 +96,7 @@ API
 
 .. c:function:: int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags)
 
-    Asynchronous ``getnameinfo(3)``.
+    Asynchronous :man:`getnameinfo(3)`.
 
     Returns 0 on success or an error code < 0 on failure. If successful, the
     callback will get called sometime in the future with the lookup result.
index cd535f7..c2a3fc2 100644 (file)
@@ -162,46 +162,46 @@ API
 
 .. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
 
-    Equivalent to ``close(2)``.
+    Equivalent to :man:`close(2)`.
 
 .. c:function:: int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
 
-    Equivalent to ``open(2)``.
+    Equivalent to :man:`open(2)`.
 
 .. 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 ``preadv(2)``.
+    Equivalent to :man:`preadv(2)`.
 
 .. c:function:: int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
 
-    Equivalent to ``unlink(2)``.
+    Equivalent to :man:`unlink(2)`.
 
 .. c:function:: int uv_fs_write(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 ``pwritev(2)``.
+    Equivalent to :man:`pwritev(2)`.
 
 .. c:function:: int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
 
-    Equivalent to ``mkdir(2)``.
+    Equivalent to :man:`mkdir(2)`.
 
     .. note::
         `mode` is currently not implemented on Windows.
 
 .. c:function:: int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb)
 
-    Equivalent to ``mkdtemp(3)``.
+    Equivalent to :man:`mkdtemp(3)`.
 
     .. note::
         The result can be found as a null terminated string at `req->path`.
 
 .. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
 
-    Equivalent to ``rmdir(2)``.
+    Equivalent to :man:`rmdir(2)`.
 
 .. c:function:: int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb)
 .. c:function:: int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent)
 
-    Equivalent to ``scandir(3)``, with a slightly different API. Once the callback
+    Equivalent to :man:`scandir(3)`, with a slightly different API. Once the callback
     for the request is called, the user can use :c:func:`uv_fs_scandir_next` to
     get `ent` populated with the next directory entry data. When there are no
     more entries ``UV_EOF`` will be returned.
@@ -210,49 +210,49 @@ API
 .. 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)
 
-    Equivalent to ``(f/l)stat(2)``.
+    Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively.
 
 .. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
 
-    Equivalent to ``rename(2)``.
+    Equivalent to :man:`rename(2)`.
 
 .. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
 
-    Equivalent to ``fsync(2)``.
+    Equivalent to :man:`fsync(2)`.
 
 .. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
 
-    Equivalent to ``fdatasync(2)``.
+    Equivalent to :man:`fdatasync(2)`.
 
 .. c:function:: int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb)
 
-    Equivalent to ``ftruncate(2)``.
+    Equivalent to :man:`ftruncate(2)`.
 
 .. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb)
 
-    Limited equivalent to ``sendfile(2)``.
+    Limited equivalent to :man:`sendfile(2)`.
 
 .. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
 
-    Equivalent to ``access(2)`` on Unix. Windows uses ``GetFileAttributesW()``.
+    Equivalent to :man:`access(2)` on Unix. Windows uses ``GetFileAttributesW()``.
 
 .. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
 .. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb)
 
-    Equivalent to ``(f)chmod(2)``.
+    Equivalent to :man:`chmod(2)` and :man:`fchmod(2)` respectively.
 
 .. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb)
 .. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb)
 
-    Equivalent to ``(f)utime(s)(2)``.
+    Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively.
 
 .. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
 
-    Equivalent to ``link(2)``.
+    Equivalent to :man:`link(2)`.
 
 .. c:function:: int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb)
 
-    Equivalent to ``symlink(2)``.
+    Equivalent to :man:`symlink(2)`.
 
     .. note::
         On Windows the `flags` parameter can be specified to control how the symlink will
@@ -265,12 +265,12 @@ API
 
 .. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
 
-    Equivalent to ``readlink(2)``.
+    Equivalent to :man:`readlink(2)`.
 
 .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
 .. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
 
-    Equivalent to ``(f)chown(2)``.
+    Equivalent to :man:`chown(2)` and :man:`fchown(2)` respectively.
 
     .. note::
         These functions are not implemented on Windows.
index 203672b..2a01d79 100644 (file)
@@ -92,7 +92,9 @@ API
     specified mode:
 
     - UV_RUN_DEFAULT: Runs the event loop until there are no more active and
-      referenced handles or requests. Always returns zero.
+      referenced handles or requests. Returns non-zero if :c:func:`uv_stop`
+      was called and there are still active handles or requests.  Returns
+      zero in all other cases.
     - UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if
       there are no pending callbacks. Returns zero when done (no active handles
       or requests left), or non-zero if more callbacks are expected (meaning
index 10c349e..bb97a26 100644 (file)
@@ -15,6 +15,17 @@ Data types
 
     Buffer data type.
 
+    .. c:member:: char* uv_buf_t.base
+
+        Pointer to the base of the buffer. Readonly.
+
+    .. c:member:: size_t uv_buf_t.len
+
+        Total bytes in the buffer. Readonly.
+
+        .. note::
+            On Windows this field is ULONG.
+
 .. c:type:: uv_file
 
     Cross platform representation of a file handle.
@@ -26,7 +37,7 @@ Data types
 .. c:type:: uv_os_fd_t
 
     Abstract representation of a file descriptor. On Unix systems this is a
-    `typedef` of `int` and on Windows fa `HANDLE`.
+    `typedef` of `int` and on Windows a `HANDLE`.
 
 .. c:type:: uv_rusage_t
 
@@ -101,7 +112,8 @@ API
     descriptor. Usually this will be used during initialization to guess the
     type of the stdio streams.
 
-    For ``isatty()`` functionality use this function and test for ``UV_TTY``.
+    For :man:`isatty(3)` equivalent functionality use this function and test
+    for ``UV_TTY``.
 
 .. c:function:: unsigned int uv_version(void)
 
@@ -195,8 +207,8 @@ API
 .. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size)
 .. c:function:: int uv_inet_pton(int af, const char* src, void* dst)
 
-    Cross-platform IPv6-capable implementation of the 'standard' ``inet_ntop()``
-    and ``inet_pton()`` functions. On success they return 0. In case of error
+    Cross-platform IPv6-capable implementation of :man:`inet_ntop(3)`
+    and :man:`inet_pton(3)`. On success they return 0. In case of error
     the target `dst` pointer is unmodified.
 
 .. c:function:: int uv_exepath(char* buffer, size_t* size)
index 8f8402c..df896a0 100644 (file)
@@ -40,6 +40,10 @@ API
 
     .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
 
+    .. note::
+        The passed file descriptor or HANDLE is not checked for its type, but
+        it's required that it represents a valid pipe.
+
 .. c:function:: int uv_pipe_bind(uv_pipe_t* handle, const char* name)
 
     Bind the pipe to a file path (Unix) or a name (Windows).
index 907cb1a..6dc4183 100644 (file)
@@ -5,7 +5,7 @@
 ===================================
 
 Poll handles are used to watch file descriptors for readability and
-writability, similar to the purpose of poll(2).
+writability, similar to the purpose of :man:`poll(2)`.
 
 The purpose of poll handles is to enable integrating external libraries that
 rely on the event loop to signal it about the socket status changes, like
@@ -29,7 +29,7 @@ closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`.
 
 .. note::
     On windows only sockets can be polled with poll handles. On Unix any file
-    descriptor that would be accepted by poll(2) can be used.
+    descriptor that would be accepted by :man:`poll(2)` can be used.
 
 
 Data types
diff --git a/deps/uv/docs/src/sphinx-plugins/manpage.py b/deps/uv/docs/src/sphinx-plugins/manpage.py
new file mode 100644 (file)
index 0000000..1d1dc37
--- /dev/null
@@ -0,0 +1,46 @@
+# encoding: utf-8
+
+#
+# Copyright (c) 2013 Dariusz Dwornikowski.  All rights reserved.
+#
+# Adapted from https://github.com/tdi/sphinxcontrib-manpage
+# License: Apache 2
+#
+
+
+import re
+
+from docutils import nodes, utils
+from docutils.parsers.rst.roles import set_classes
+from string import Template
+
+
+def make_link_node(rawtext, app, name, manpage_num, options):
+    ref = app.config.man_url_regex
+    if not ref:
+        ref = "http://linux.die.net/man/%s/%s" % (manpage_num, name)
+    else:
+        s = Template(ref)
+        ref = s.substitute(num=manpage_num, topic=name)
+    set_classes(options)
+    node = nodes.reference(rawtext, "%s(%s)" % (name, manpage_num), refuri=ref, **options)
+    return node
+
+
+def man_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+    app = inliner.document.settings.env.app
+    p = re.compile("([a-zA-Z0-9_\.-_]+)\((\d)\)")
+    m = p.match(text)
+
+    manpage_num = m.group(2)
+    name = m.group(1)
+    node = make_link_node(rawtext, app, name, manpage_num, options)
+    return [node], []
+
+
+def setup(app):
+    app.info('Initializing manpage plugin')
+    app.add_role('man', man_role)
+    app.add_config_value('man_url_regex', None, 'env')
+    return
+
index 1f6682a..880f0e2 100644 (file)
@@ -104,7 +104,7 @@ API
 .. c:function:: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
 
     Start listening for incoming connections. `backlog` indicates the number of
-    connections the kernel might queue, same as ``listen(2)``. When a new
+    connections the kernel might queue, same as :man:`listen(2)`. When a new
     incoming connection is received the :c:type:`uv_connection_cb` callback is
     called.
 
index 8baedde..2b5d268 100644 (file)
@@ -38,6 +38,10 @@ API
 
     .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
 
+    .. note::
+        The passed file descriptor or SOCKET is not checked for its type, but
+        it's required that it represents a valid stream socket.
+
 .. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
 
     Enable / disable Nagle's algorithm.
index 89f0084..1894950 100644 (file)
@@ -18,6 +18,10 @@ libuv preallocates and initializes the maximum number of threads allowed by
 ``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead
 (~1MB for 128 threads) but increases the performance of threading at runtime.
 
+.. note::
+    Note that even though a global thread pool which is shared across all events
+    loops is used, the functions are not thread safe.
+
 
 Data types
 ----------
index 6c20c84..18f34ef 100644 (file)
@@ -24,14 +24,14 @@ Data types
 
     ::
 
-        typedef enum {
-            /* Initial/normal terminal mode */
-            UV_TTY_MODE_NORMAL,
-            /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
-            UV_TTY_MODE_RAW,
-            /* Binary-safe I/O mode for IPC (Unix-only) */
-            UV_TTY_MODE_IO
-        } uv_tty_mode_t;
+      typedef enum {
+          /* Initial/normal terminal mode */
+          UV_TTY_MODE_NORMAL,
+          /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+          UV_TTY_MODE_RAW,
+          /* Binary-safe I/O mode for IPC (Unix-only) */
+          UV_TTY_MODE_IO
+      } uv_tty_mode_t;
 
 
 
@@ -58,18 +58,22 @@ API
     `readable`, specifies if you plan on calling :c:func:`uv_read_start` with
     this stream. stdin is readable, stdout is not.
 
-    On Unix this function will try to open ``/dev/tty`` and use it if the passed file
-    descriptor refers to a TTY. This lets libuv put the tty in non-blocking mode
-    without affecting other processes that share the tty.
+    On Unix this function will try to open ``/dev/tty`` and use it if the passed
+    file descriptor refers to a TTY. This lets libuv put the tty in non-blocking
+    mode without affecting other processes that share the tty.
 
     .. note::
-        If opening ``/dev/tty`` fails, libuv falls back to blocking writes for non-readable
-        TTY streams.
+        If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
+        non-readable TTY streams.
+
+    .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
+                        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)
 
-    .. versionchanged:: 1.2.0: the mode is specified as a :c:type:`uv_tty_mode_t`
-                        value.
+    .. versionchanged:: 1.2.0: the mode is specified as a
+                        :c:type:`uv_tty_mode_t` value.
 
     Set the TTY using the specified terminal mode.
 
index 9c4aa21..ec7ce56 100644 (file)
@@ -122,6 +122,10 @@ API
 
     .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
 
+    .. note::
+        The passed file descriptor or SOCKET is not checked for its type, but
+        it's required that it represents a valid datagram socket.
+
 .. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags)
 
     Bind the UDP handle to an IP address and port.
index 836d399..0b4e6d7 100644 (file)
@@ -31,8 +31,8 @@
  */
 
 #define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 4
-#define UV_VERSION_PATCH 2
+#define UV_VERSION_MINOR 5
+#define UV_VERSION_PATCH 0
 #define UV_VERSION_IS_RELEASE 1
 #define UV_VERSION_SUFFIX ""
 
index 24b22b3..fd84420 100644 (file)
@@ -43,16 +43,6 @@ typedef struct pollfd {
 # define LOCALE_INVARIANT 0x007f
 #endif
 
-#ifndef _malloca
-# if defined(_DEBUG)
-#  define _malloca(size) malloc(size)
-#  define _freea(ptr) free(ptr)
-# else
-#  define _malloca(size) alloca(size)
-#  define _freea(ptr)
-# endif
-#endif
-
 #include <mswsock.h>
 #include <ws2tcpip.h>
 #include <windows.h>
@@ -366,8 +356,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
     struct {                                                                  \
       OVERLAPPED overlapped;                                                  \
       size_t queued_bytes;                                                    \
-    };                                                                        \
-  };                                                                          \
+    } io;                                                                     \
+  } u;                                                                        \
   struct uv_req_s* next_req;
 
 #define UV_WRITE_PRIVATE_FIELDS                                               \
@@ -419,9 +409,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   int activecnt;                                                              \
   uv_read_t read_req;                                                         \
   union {                                                                     \
-    struct { uv_stream_connection_fields };                                   \
-    struct { uv_stream_server_fields     };                                   \
-  };
+    struct { uv_stream_connection_fields } conn;                              \
+    struct { uv_stream_server_fields     } serv;                              \
+  } stream;
 
 #define uv_tcp_server_fields                                                  \
   uv_tcp_accept_t* accept_reqs;                                               \
@@ -437,9 +427,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   SOCKET socket;                                                              \
   int delayed_error;                                                          \
   union {                                                                     \
-    struct { uv_tcp_server_fields };                                          \
-    struct { uv_tcp_connection_fields };                                      \
-  };
+    struct { uv_tcp_server_fields } serv;                                     \
+    struct { uv_tcp_connection_fields } conn;                                 \
+  } tcp;
 
 #define UV_UDP_PRIVATE_FIELDS                                                 \
   SOCKET socket;                                                              \
@@ -476,9 +466,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   HANDLE handle;                                                              \
   WCHAR* name;                                                                \
   union {                                                                     \
-    struct { uv_pipe_server_fields };                                         \
-    struct { uv_pipe_connection_fields };                                     \
-  };
+    struct { uv_pipe_server_fields } serv;                                    \
+    struct { uv_pipe_connection_fields } conn;                                \
+  } pipe;
 
 /* TODO: put the parser states in an union - TTY handles are always */
 /* half-duplex so read-state can safely overlap write-state. */
@@ -496,7 +486,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
       unsigned char last_key_len;                                             \
       WCHAR last_utf16_high_surrogate;                                        \
       INPUT_RECORD last_input_record;                                         \
-    };                                                                        \
+    } rd;                                                                     \
     struct {                                                                  \
       /* Used for writable TTY handles */                                     \
       /* utf8-to-utf16 conversion state */                                    \
@@ -510,8 +500,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
       unsigned short ansi_csi_argv[4];                                        \
       COORD saved_position;                                                   \
       WORD saved_attributes;                                                  \
-    };                                                                        \
-  };
+    } wr;                                                                     \
+  } tty;
 
 #define UV_POLL_PRIVATE_FIELDS                                                \
   SOCKET socket;                                                              \
@@ -600,7 +590,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
     /* TODO: remove me in 0.9. */                                             \
     WCHAR* pathw;                                                             \
     int fd;                                                                   \
-  };                                                                          \
+  } file;                                                                     \
   union {                                                                     \
     struct {                                                                  \
       int mode;                                                               \
@@ -611,12 +601,12 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
       uv_buf_t* bufs;                                                         \
       int64_t offset;                                                         \
       uv_buf_t bufsml[4];                                                     \
-    };                                                                        \
+    } info;                                                                   \
     struct {                                                                  \
       double atime;                                                           \
       double mtime;                                                           \
-    };                                                                        \
-  };
+    } time;                                                                   \
+  } fs;
 
 #define UV_WORK_PRIVATE_FIELDS                                                \
   struct uv__work work_req;
index 55f7521..75b3a4a 100644 (file)
@@ -644,13 +644,13 @@ UV_EXTERN int uv_tty_reset_mode(void);
 UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+extern "C++" {
 
 inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
   return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
 }
 
-extern "C" {
+}
 #endif
 
 UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
@@ -799,6 +799,7 @@ struct uv_getnameinfo_s {
   UV_REQ_FIELDS
   /* read-only */
   uv_loop_t* loop;
+  /* host and service are marked as private, but they really aren't. */
   UV_GETNAMEINFO_PRIVATE_FIELDS
 };
 
index ec800c7..e21a9cc 100644 (file)
@@ -1111,19 +1111,19 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   *count = 0;
 
   if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
-    return -ENOSYS;
+    return -errno;
   }
 
   if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
-    uv__close(sockfd);
-    return -ENOSYS;
+    SAVE_ERRNO(uv__close(sockfd));
+    return -errno;
   }
 
   ifc.ifc_req = (struct ifreq*)malloc(size);
   ifc.ifc_len = size;
   if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
-    uv__close(sockfd);
-    return -ENOSYS;
+    SAVE_ERRNO(uv__close(sockfd));
+    return -errno;
   }
 
 #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
@@ -1141,8 +1141,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
 
     memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
     if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
-      uv__close(sockfd);
-      return -ENOSYS;
+      SAVE_ERRNO(uv__close(sockfd));
+      return -errno;
     }
 
     if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
@@ -1218,16 +1218,23 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
   struct pollfd* events;
   uintptr_t i;
   uintptr_t nfds;
+  struct poll_ctl pc;
 
   assert(loop->watchers != NULL);
 
   events = (struct pollfd*) loop->watchers[loop->nwatchers];
   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
-  if (events == NULL)
-    return;
 
-  /* Invalidate events with same file descriptor */
-  for (i = 0; i < nfds; i++)
-    if ((int) events[i].fd == fd)
-      events[i].fd = -1;
+  if (events != NULL)
+    /* Invalidate events with same file descriptor */
+    for (i = 0; i < nfds; i++)
+      if ((int) events[i].fd == fd)
+        events[i].fd = -1;
+
+  /* Remove the file descriptor from the poll set */
+  pc.events = 0;
+  pc.cmd = PS_DELETE;
+  pc.fd = fd;
+  if(loop->backend_fd >= 0)
+    pollset_ctl(loop->backend_fd, &pc, 1);
 }
index 3cda578..a99b019 100644 (file)
@@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "android-ifaddrs.h"
+#include "uv-common.h"
 
 #include <string.h>
 #include <stdlib.h>
index e7eee2f..7792801 100644 (file)
@@ -202,6 +202,44 @@ static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
 }
 
 
+static ssize_t uv__fs_open(uv_fs_t* req) {
+  static int no_cloexec_support;
+  int r;
+
+  /* Try O_CLOEXEC before entering locks */
+  if (no_cloexec_support == 0) {
+#ifdef O_CLOEXEC
+    r = open(req->path, req->flags | O_CLOEXEC, req->mode);
+    if (r >= 0)
+      return r;
+    if (errno != EINVAL)
+      return r;
+    no_cloexec_support = 1;
+#endif  /* O_CLOEXEC */
+  }
+
+  if (req->cb != NULL)
+    uv_rwlock_rdlock(&req->loop->cloexec_lock);
+
+  r = open(req->path, req->flags, req->mode);
+
+  /* In case of failure `uv__cloexec` will leave error in `errno`,
+   * so it is enough to just set `r` to `-1`.
+   */
+  if (r >= 0 && uv__cloexec(r, 1) != 0) {
+    r = uv__close(r);
+    if (r != 0 && r != -EINPROGRESS)
+      abort();
+    r = -1;
+  }
+
+  if (req->cb != NULL)
+    uv_rwlock_rdunlock(&req->loop->cloexec_lock);
+
+  return r;
+}
+
+
 static ssize_t uv__fs_read(uv_fs_t* req) {
 #if defined(__linux__)
   static int no_preadv;
@@ -661,8 +699,22 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
   dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
   dst->st_flags = src->st_flags;
   dst->st_gen = src->st_gen;
-#elif !defined(_AIX) && \
-  (defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE))
+#elif defined(__ANDROID__)
+  dst->st_atim.tv_sec = src->st_atime;
+  dst->st_atim.tv_nsec = src->st_atime_nsec;
+  dst->st_mtim.tv_sec = src->st_mtime;
+  dst->st_mtim.tv_nsec = src->st_mtime_nsec;
+  dst->st_ctim.tv_sec = src->st_ctime;
+  dst->st_ctim.tv_nsec = src->st_ctime_nsec;
+  dst->st_birthtim.tv_sec = src->st_ctime;
+  dst->st_birthtim.tv_nsec = src->st_ctime_nsec;
+  dst->st_flags = 0;
+  dst->st_gen = 0;
+#elif !defined(_AIX) && (       \
+    defined(_BSD_SOURCE)     || \
+    defined(_SVID_SOURCE)    || \
+    defined(_XOPEN_SOURCE)   || \
+    defined(_DEFAULT_SOURCE))
   dst->st_atim.tv_sec = src->st_atim.tv_sec;
   dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
   dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
@@ -729,9 +781,6 @@ static void uv__fs_work(struct uv__work* w) {
   int retry_on_eintr;
   uv_fs_t* req;
   ssize_t r;
-#ifdef O_CLOEXEC
-  static int no_cloexec_support;
-#endif  /* O_CLOEXEC */
 
   req = container_of(w, uv_fs_t, work_req);
   retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
@@ -760,6 +809,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(LINK, link(req->path, req->new_path));
     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(SCANDIR, uv__fs_scandir(req));
     X(READLINK, uv__fs_readlink(req));
@@ -771,41 +821,10 @@ static void uv__fs_work(struct uv__work* w) {
     X(UNLINK, unlink(req->path));
     X(UTIME, uv__fs_utime(req));
     X(WRITE, uv__fs_write(req));
-    case UV_FS_OPEN:
-#ifdef O_CLOEXEC
-      /* Try O_CLOEXEC before entering locks */
-      if (!no_cloexec_support) {
-        r = open(req->path, req->flags | O_CLOEXEC, req->mode);
-        if (r >= 0)
-          break;
-        if (errno != EINVAL)
-          break;
-        no_cloexec_support = 1;
-      }
-#endif  /* O_CLOEXEC */
-      if (req->cb != NULL)
-        uv_rwlock_rdlock(&req->loop->cloexec_lock);
-      r = open(req->path, req->flags, req->mode);
-
-      /*
-       * In case of failure `uv__cloexec` will leave error in `errno`,
-       * so it is enough to just set `r` to `-1`.
-       */
-      if (r >= 0 && uv__cloexec(r, 1) != 0) {
-        r = uv__close(r);
-        if (r != 0 && r != -EINPROGRESS)
-          abort();
-        r = -1;
-      }
-      if (req->cb != NULL)
-        uv_rwlock_rdunlock(&req->loop->cloexec_lock);
-      break;
     default: abort();
     }
-
 #undef X
-  }
-  while (r == -1 && errno == EINTR && retry_on_eintr);
+  } while (r == -1 && errno == EINTR && retry_on_eintr);
 
   if (r == -1)
     req->result = -errno;
index 101dc74..31db5e2 100644 (file)
@@ -55,6 +55,9 @@
 #define ACCESS_ONCE(type, var)                                                \
   (*(volatile type*) &(var))
 
+#define ROUND_UP(a, b)                                                        \
+  ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
+
 #define UNREACHABLE()                                                         \
   do {                                                                        \
     assert(0 && "unreachable code");                                          \
index 33a735d..d07494d 100644 (file)
@@ -130,8 +130,13 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
    *
    * We pass in a dummy epoll_event, to work around a bug in old kernels.
    */
-  if (loop->backend_fd >= 0)
+  if (loop->backend_fd >= 0) {
+    /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
+     * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
+     */
+    memset(&dummy, 0, sizeof(dummy));
     uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
+  }
 }
 
 
index 7bf2c0f..566e1f3 100644 (file)
 #include <sys/types.h>
 #include <errno.h>
 
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+#  define MSAN_ACTIVE 1
+#  include <sanitizer/msan_interface.h>
+# endif
+#endif
+
 #if defined(__i386__)
 # ifndef __NR_socketcall
 #  define __NR_socketcall 102
@@ -310,7 +317,13 @@ int uv__epoll_wait(int epfd,
                    int nevents,
                    int timeout) {
 #if defined(__NR_epoll_wait)
-  return syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
+  int result;
+  result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
+#if MSAN_ACTIVE
+  if (result > 0)
+    __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+  return result;
 #else
   return errno = ENOSYS, -1;
 #endif
@@ -323,13 +336,19 @@ int uv__epoll_pwait(int epfd,
                     int timeout,
                     uint64_t sigmask) {
 #if defined(__NR_epoll_pwait)
-  return syscall(__NR_epoll_pwait,
-                 epfd,
-                 events,
-                 nevents,
-                 timeout,
-                 &sigmask,
-                 sizeof(sigmask));
+  int result;
+  result = syscall(__NR_epoll_pwait,
+                   epfd,
+                   events,
+                   nevents,
+                   timeout,
+                   &sigmask,
+                   sizeof(sigmask));
+#if MSAN_ACTIVE
+  if (result > 0)
+    __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+  return result;
 #else
   return errno = ENOSYS, -1;
 #endif
@@ -374,7 +393,13 @@ int uv__inotify_rm_watch(int fd, int32_t wd) {
 
 int uv__pipe2(int pipefd[2], int flags) {
 #if defined(__NR_pipe2)
-  return syscall(__NR_pipe2, pipefd, flags);
+  int result;
+  result = syscall(__NR_pipe2, pipefd, flags);
+#if MSAN_ACTIVE
+  if (!result)
+    __msan_unpoison(pipefd, sizeof(int[2]));
+#endif
+  return result;
 #else
   return errno = ENOSYS, -1;
 #endif
index be283b4..380f3db 100644 (file)
@@ -280,6 +280,21 @@ static void uv__process_child_init(const uv_process_options_t* options,
   if (options->flags & UV_PROCESS_DETACHED)
     setsid();
 
+  /* First duplicate low numbered fds, since it's not safe to duplicate them,
+   * they could get replaced. Example: swapping stdout and stderr; without
+   * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+   * stdout and stderr go to the same fd, which was not the intention. */
+  for (fd = 0; fd < stdio_count; fd++) {
+    use_fd = pipes[fd][1];
+    if (use_fd < 0 || use_fd >= fd)
+      continue;
+    pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+    if (pipes[fd][1] == -1) {
+      uv__write_int(error_fd, -errno);
+      _exit(127);
+    }
+  }
+
   for (fd = 0; fd < stdio_count; fd++) {
     close_fd = pipes[fd][0];
     use_fd = pipes[fd][1];
@@ -304,7 +319,12 @@ static void uv__process_child_init(const uv_process_options_t* options,
     if (fd == use_fd)
       uv__cloexec(use_fd, 0);
     else
-      dup2(use_fd, fd);
+      fd = dup2(use_fd, fd);
+
+    if (fd == -1) {
+      uv__write_int(error_fd, -errno);
+      _exit(127);
+    }
 
     if (fd <= 2)
       uv__nonblock(fd, 0);
@@ -316,8 +336,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
   for (fd = 0; fd < stdio_count; fd++) {
     use_fd = pipes[fd][1];
 
-    if (use_fd >= 0 && fd != use_fd)
-      close(use_fd);
+    if (use_fd >= stdio_count)
+      uv__close(use_fd);
   }
 
   if (options->cwd != NULL && chdir(options->cwd)) {
@@ -367,6 +387,7 @@ int uv_spawn(uv_loop_t* loop,
   int err;
   int exec_errorno;
   int i;
+  int status;
 
   assert(options->file != NULL);
   assert(!(options->flags & ~(UV_PROCESS_DETACHED |
@@ -453,11 +474,17 @@ int uv_spawn(uv_loop_t* loop,
 
   if (r == 0)
     ; /* okay, EOF */
-  else if (r == sizeof(exec_errorno))
-    ; /* okay, read errorno */
-  else if (r == -1 && errno == EPIPE)
-    ; /* okay, got EPIPE */
-  else
+  else if (r == sizeof(exec_errorno)) {
+    do
+      err = waitpid(pid, &status, 0); /* okay, read errorno */
+    while (err == -1 && errno == EINTR);
+    assert(err == pid);
+  } else if (r == -1 && errno == EPIPE) {
+    do
+      err = waitpid(pid, &status, 0); /* okay, got EPIPE */
+    while (err == -1 && errno == EINTR);
+    assert(err == pid);
+  } else
     abort();
 
   uv__close(signal_pipe[0]);
index 518a2fc..48827b6 100644 (file)
@@ -88,7 +88,12 @@ void uv__stream_init(uv_loop_t* loop,
   stream->write_queue_size = 0;
 
   if (loop->emfile_fd == -1) {
-    err = uv__open_cloexec("/", O_RDONLY);
+    err = uv__open_cloexec("/dev/null", O_RDONLY);
+    if (err < 0)
+        /* In the rare case that "/dev/null" isn't mounted open "/"
+         * instead.
+         */
+        err = uv__open_cloexec("/", O_RDONLY);
     if (err >= 0)
       loop->emfile_fd = err;
   }
@@ -301,7 +306,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
   if (fds[1] > max_fd)
     max_fd = fds[1];
 
-  sread_sz = (max_fd + NBBY) / NBBY;
+  sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY;
   swrite_sz = sread_sz;
 
   s = malloc(sizeof(*s) + sread_sz + swrite_sz);
index b1782df..7783548 100644 (file)
@@ -35,10 +35,19 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
 
 
 int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
+  uv_handle_type type;
   int flags;
   int newfd;
   int r;
 
+  /* File descriptors that refer to files cannot be monitored with epoll.
+   * That restriction also applies to character devices like /dev/random
+   * (but obviously not /dev/tty.)
+   */
+  type = uv_guess_handle(fd);
+  if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
+    return -EINVAL;
+
   flags = 0;
   newfd = -1;
 
@@ -54,7 +63,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
    * different struct file, hence changing its properties doesn't affect
    * other processes.
    */
-  if (isatty(fd)) {
+  if (type == UV_TTY) {
     r = uv__open_cloexec("/dev/tty", O_RDWR);
 
     if (r < 0) {
@@ -237,8 +246,10 @@ uv_handle_type uv_guess_handle(uv_file file) {
  * critical section when the signal was raised.
  */
 int uv_tty_reset_mode(void) {
+  int saved_errno;
   int err;
 
+  saved_errno = errno;
   if (!uv_spinlock_trylock(&termios_spinlock))
     return -EBUSY;  /* In uv_tty_set_mode(). */
 
@@ -248,5 +259,7 @@ int uv_tty_reset_mode(void) {
       err = -errno;
 
   uv_spinlock_unlock(&termios_spinlock);
+  errno = saved_errno;
+
   return err;
 }
index 941c0ae..22c2e13 100644 (file)
@@ -601,40 +601,47 @@ int uv_udp_set_membership(uv_udp_t* handle,
   }
 }
 
-
-static int uv__setsockopt_maybe_char(uv_udp_t* handle,
-                                     int option4,
-                                     int option6,
-                                     int val) {
+static int uv__setsockopt(uv_udp_t* handle,
+                         int option4,
+                         int option6,
+                         const void* val,
+                         size_t size) {
   int r;
-#if defined(__sun) || defined(_AIX)
-  char arg = val;
-#else
-  int arg = val;
-#endif
-
-  if (val < 0 || val > 255)
-    return -EINVAL;
 
   if (handle->flags & UV_HANDLE_IPV6)
     r = setsockopt(handle->io_watcher.fd,
                    IPPROTO_IPV6,
                    option6,
-                   &arg,
-                   sizeof(arg));
+                   val,
+                   size);
   else
     r = setsockopt(handle->io_watcher.fd,
                    IPPROTO_IP,
                    option4,
-                   &arg,
-                   sizeof(arg));
-
+                   val,
+                   size);
   if (r)
     return -errno;
 
   return 0;
 }
 
+static int uv__setsockopt_maybe_char(uv_udp_t* handle,
+                                     int option4,
+                                     int option6,
+                                     int val) {
+#if defined(__sun) || defined(_AIX)
+  char arg = val;
+#else
+  int arg = val;
+#endif
+
+  if (val < 0 || val > 255)
+    return -EINVAL;
+
+  return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
+}
+
 
 int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
   if (setsockopt(handle->io_watcher.fd,
@@ -653,6 +660,20 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
   if (ttl < 1 || ttl > 255)
     return -EINVAL;
 
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
+ * 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)
+  return uv__setsockopt(handle,
+                        IP_TTL,
+                        IPV6_UNICAST_HOPS,
+                        &ttl,
+                        sizeof(ttl));
+#endif /* defined(__sun) */
+
   return uv__setsockopt_maybe_char(handle,
                                    IP_TTL,
                                    IPV6_UNICAST_HOPS,
@@ -661,6 +682,21 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
 
 
 int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
+ * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun)
+  if (handle->flags & UV_HANDLE_IPV6)
+    return uv__setsockopt(handle,
+                          IP_MULTICAST_TTL,
+                          IPV6_MULTICAST_HOPS,
+                          &ttl,
+                          sizeof(ttl));
+#endif /* defined(__sun) */
+
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_TTL,
                                    IPV6_MULTICAST_HOPS,
@@ -669,6 +705,21 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
 
 
 int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
+ * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun)
+  if (handle->flags & UV_HANDLE_IPV6)
+    return uv__setsockopt(handle,
+                          IP_MULTICAST_LOOP,
+                          IPV6_MULTICAST_LOOP,
+                          &on,
+                          sizeof(on));
+#endif /* defined(__sun) */
+
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_LOOP,
                                    IPV6_MULTICAST_LOOP,
index 791c09b..02341f8 100644 (file)
@@ -379,15 +379,28 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
   return 0;
 }
 
+/* The windows implementation does not have the same structure layout as
+ * the unix implementation (nbufs is not directly inside req but is
+ * contained in a nested union/struct) so this function locates it.
+*/
+static unsigned int* uv__get_nbufs(uv_fs_t* req) {
+#ifdef _WIN32
+  return &req->fs.info.nbufs;
+#else
+  return &req->nbufs;
+#endif
+}
 
 void uv__fs_scandir_cleanup(uv_fs_t* req) {
   uv__dirent_t** dents;
 
+  unsigned int* nbufs = uv__get_nbufs(req);
+
   dents = req->ptr;
-  if (req->nbufs > 0 && req->nbufs != (unsigned int) req->result)
-    req->nbufs--;
-  for (; req->nbufs < (unsigned int) req->result; req->nbufs++)
-    free(dents[req->nbufs]);
+  if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
+    (*nbufs)--;
+  for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
+    free(dents[*nbufs]);
 }
 
 
@@ -395,20 +408,22 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
   uv__dirent_t** dents;
   uv__dirent_t* dent;
 
+  unsigned int* nbufs = uv__get_nbufs(req);
+
   dents = req->ptr;
 
   /* Free previous entity */
-  if (req->nbufs > 0)
-    free(dents[req->nbufs - 1]);
+  if (*nbufs > 0)
+    free(dents[*nbufs - 1]);
 
   /* End was already reached */
-  if (req->nbufs == (unsigned int) req->result) {
+  if (*nbufs == (unsigned int) req->result) {
     free(dents);
     req->ptr = NULL;
     return UV_EOF;
   }
 
-  dent = dents[req->nbufs++];
+  dent = dents[(*nbufs)++];
 
   ent->name = dent->d_name;
 #ifdef HAVE_DIRENT_TYPES
@@ -522,6 +537,7 @@ void uv_loop_delete(uv_loop_t* loop) {
   default_loop = default_loop_ptr;
 
   err = uv_loop_close(loop);
+  (void) err;    /* Squelch compiler warnings. */
   assert(err == 0);
   if (loop != default_loop)
     free(loop);
index a101159..1154492 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
-#include <malloc.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 5c55147..a265a27 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <assert.h>
 #include <errno.h>
-#include <malloc.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
index 7ad99a8..640651b 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <assert.h>
-#include <malloc.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
@@ -39,7 +38,8 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
   assert(handle->dir_handle != INVALID_HANDLE_VALUE);
   assert(!handle->req_pending);
 
-  memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
+  memset(&(handle->req.u.io.overlapped), 0,
+         sizeof(handle->req.u.io.overlapped));
   if (!ReadDirectoryChangesW(handle->dir_handle,
                              handle->buffer,
                              uv_directory_watcher_buffer_size,
@@ -53,7 +53,7 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
                                FILE_NOTIFY_CHANGE_CREATION     |
                                FILE_NOTIFY_CHANGE_SECURITY,
                              NULL,
-                             &handle->req.overlapped,
+                             &handle->req.u.io.overlapped,
                              NULL)) {
     /* Make this req pending reporting an error. */
     SET_REQ_ERROR(&handle->req, GetLastError());
@@ -232,7 +232,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
+  memset(&(handle->req.u.io.overlapped), 0,
+         sizeof(handle->req.u.io.overlapped));
 
   if (!ReadDirectoryChangesW(handle->dir_handle,
                              handle->buffer,
@@ -247,7 +248,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
                                FILE_NOTIFY_CHANGE_CREATION     |
                                FILE_NOTIFY_CHANGE_SECURITY,
                              NULL,
-                             &handle->req.overlapped,
+                             &handle->req.u.io.overlapped,
                              NULL)) {
     last_error = GetLastError();
     goto error;
@@ -349,7 +350,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
   file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
 
   if (REQ_SUCCESS(req)) {
-    if (req->overlapped.InternalHigh > 0) {
+    if (req->u.io.overlapped.InternalHigh > 0) {
       do {
         file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
         assert(!filename);
index 33bc9da..af7ec74 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <assert.h>
 #include <stdlib.h>
-#include <malloc.h>
 #include <direct.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -161,8 +160,8 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
 
 
   if (buf_sz == 0) {
-    req->pathw = NULL;
-    req->new_pathw = NULL;
+    req->file.pathw = NULL;
+    req->fs.info.new_pathw = NULL;
     req->path = NULL;
     return 0;
   }
@@ -182,10 +181,10 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
                                   (WCHAR*) pos,
                                   pathw_len);
     assert(r == (DWORD) pathw_len);
-    req->pathw = (WCHAR*) pos;
+    req->file.pathw = (WCHAR*) pos;
     pos += r * sizeof(WCHAR);
   } else {
-    req->pathw = NULL;
+    req->file.pathw = NULL;
   }
 
   if (new_path != NULL) {
@@ -196,10 +195,10 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
                                   (WCHAR*) pos,
                                   new_pathw_len);
     assert(r == (DWORD) new_pathw_len);
-    req->new_pathw = (WCHAR*) pos;
+    req->fs.info.new_pathw = (WCHAR*) pos;
     pos += r * sizeof(WCHAR);
   } else {
-    req->new_pathw = NULL;
+    req->fs.info.new_pathw = NULL;
   }
 
   if (!copy_path) {
@@ -388,7 +387,7 @@ void fs__open(uv_fs_t* req) {
   DWORD attributes = 0;
   HANDLE file;
   int fd, current_umask;
-  int flags = req->file_flags;
+  int flags = req->fs.info.file_flags;
 
   /* Obtain the active umask. umask() never fails and returns the previous */
   /* umask. */
@@ -450,7 +449,7 @@ void fs__open(uv_fs_t* req) {
 
   attributes |= FILE_ATTRIBUTE_NORMAL;
   if (flags & _O_CREAT) {
-    if (!((req->mode & ~current_umask) & _S_IWRITE)) {
+    if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
       attributes |= FILE_ATTRIBUTE_READONLY;
     }
   }
@@ -480,7 +479,7 @@ void fs__open(uv_fs_t* req) {
   /* Setting this flag makes it possible to open a directory. */
   attributes |= FILE_FLAG_BACKUP_SEMANTICS;
 
-  file = CreateFileW(req->pathw,
+  file = CreateFileW(req->file.pathw,
                      access,
                      share,
                      NULL,
@@ -512,6 +511,7 @@ void fs__open(uv_fs_t* req) {
       SET_REQ_WIN32_ERROR(req, GetLastError());
     else
       SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+    CloseHandle(file);
     return;
   }
 
@@ -523,7 +523,7 @@ void fs__open(uv_fs_t* req) {
 }
 
 void fs__close(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   int result;
 
   VERIFY_FD(fd, req);
@@ -534,8 +534,8 @@ void fs__close(uv_fs_t* req) {
 
 
 void fs__read(uv_fs_t* req) {
-  int fd = req->fd;
-  int64_t offset = req->offset;
+  int fd = req->file.fd;
+  int64_t offset = req->fs.info.offset;
   HANDLE handle;
   OVERLAPPED overlapped, *overlapped_ptr;
   LARGE_INTEGER offset_;
@@ -572,13 +572,13 @@ void fs__read(uv_fs_t* req) {
     }
 
     result = ReadFile(handle,
-                      req->bufs[index].base,
-                      req->bufs[index].len,
+                      req->fs.info.bufs[index].base,
+                      req->fs.info.bufs[index].len,
                       &incremental_bytes,
                       overlapped_ptr);
     bytes += incremental_bytes;
     ++index;
-  } while (result && index < req->nbufs);
+  } while (result && index < req->fs.info.nbufs);
 
   if (result || bytes > 0) {
     SET_REQ_RESULT(req, bytes);
@@ -594,8 +594,8 @@ void fs__read(uv_fs_t* req) {
 
 
 void fs__write(uv_fs_t* req) {
-  int fd = req->fd;
-  int64_t offset = req->offset;
+  int fd = req->file.fd;
+  int64_t offset = req->fs.info.offset;
   HANDLE handle;
   OVERLAPPED overlapped, *overlapped_ptr;
   LARGE_INTEGER offset_;
@@ -630,13 +630,13 @@ void fs__write(uv_fs_t* req) {
     }
 
     result = WriteFile(handle,
-                       req->bufs[index].base,
-                       req->bufs[index].len,
+                       req->fs.info.bufs[index].base,
+                       req->fs.info.bufs[index].len,
                        &incremental_bytes,
                        overlapped_ptr);
     bytes += incremental_bytes;
     ++index;
-  } while (result && index < req->nbufs);
+  } while (result && index < req->fs.info.nbufs);
 
   if (result || bytes > 0) {
     SET_REQ_RESULT(req, bytes);
@@ -647,13 +647,13 @@ void fs__write(uv_fs_t* req) {
 
 
 void fs__rmdir(uv_fs_t* req) {
-  int result = _wrmdir(req->pathw);
+  int result = _wrmdir(req->file.pathw);
   SET_REQ_RESULT(req, result);
 }
 
 
 void fs__unlink(uv_fs_t* req) {
-  const WCHAR* pathw = req->pathw;
+  const WCHAR* pathw = req->file.pathw;
   HANDLE handle;
   BY_HANDLE_FILE_INFORMATION info;
   FILE_DISPOSITION_INFORMATION disposition;
@@ -661,7 +661,7 @@ void fs__unlink(uv_fs_t* req) {
   NTSTATUS status;
 
   handle = CreateFileW(pathw,
-                       FILE_READ_ATTRIBUTES | DELETE,
+                       FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                        NULL,
                        OPEN_EXISTING,
@@ -703,6 +703,24 @@ void fs__unlink(uv_fs_t* req) {
     }
   }
 
+  if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+    /* Remove read-only attribute */
+    FILE_BASIC_INFORMATION basic = { 0 };
+
+    basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+    status = pNtSetInformationFile(handle,
+                                   &iosb,
+                                   &basic,
+                                   sizeof basic,
+                                   FileBasicInformation);
+    if (!NT_SUCCESS(status)) {
+      SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+      CloseHandle(handle);
+      return;
+    }
+  }
+
   /* Try to set the delete flag. */
   disposition.DeleteFile = TRUE;
   status = pNtSetInformationFile(handle,
@@ -722,7 +740,7 @@ void fs__unlink(uv_fs_t* req) {
 
 void fs__mkdir(uv_fs_t* req) {
   /* TODO: use req->mode. */
-  int result = _wmkdir(req->pathw);
+  int result = _wmkdir(req->file.pathw);
   SET_REQ_RESULT(req, result);
 }
 
@@ -740,8 +758,8 @@ void fs__mkdtemp(uv_fs_t* req) {
   uint64_t v;
   BOOL released;
 
-  len = wcslen(req->pathw);
-  ep = req->pathw + len;
+  len = wcslen(req->file.pathw);
+  ep = req->file.pathw + len;
   if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
     return;
@@ -766,7 +784,7 @@ void fs__mkdtemp(uv_fs_t* req) {
       v /= num_chars;
     }
 
-    if (_wmkdir(req->pathw) == 0) {
+    if (_wmkdir(req->file.pathw) == 0) {
       len = strlen(req->path);
       wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
       SET_REQ_RESULT(req, 0);
@@ -810,7 +828,7 @@ void fs__scandir(uv_fs_t* req) {
 
   /* Open the directory. */
   dir_handle =
-      CreateFileW(req->pathw,
+      CreateFileW(req->file.pathw,
                   FILE_LIST_DIRECTORY | SYNCHRONIZE,
                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                   NULL,
@@ -956,7 +974,7 @@ void fs__scandir(uv_fs_t* req) {
   SET_REQ_RESULT(req, dirents_used);
 
   /* `nbufs` will be used as index by uv_fs_scandir_next. */
-  req->nbufs = 0;
+  req->fs.info.nbufs = 0;
 
   return;
 
@@ -1125,7 +1143,7 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
     flags |= FILE_FLAG_OPEN_REPARSE_POINT;
   }
 
-  handle = CreateFileW(req->pathw,
+  handle = CreateFileW(req->file.pathw,
                        FILE_READ_ATTRIBUTES,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                        NULL,
@@ -1159,19 +1177,19 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
 
 
 static void fs__stat(uv_fs_t* req) {
-  fs__stat_prepare_path(req->pathw);
+  fs__stat_prepare_path(req->file.pathw);
   fs__stat_impl(req, 0);
 }
 
 
 static void fs__lstat(uv_fs_t* req) {
-  fs__stat_prepare_path(req->pathw);
+  fs__stat_prepare_path(req->file.pathw);
   fs__stat_impl(req, 1);
 }
 
 
 static void fs__fstat(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   HANDLE handle;
 
   VERIFY_FD(fd, req);
@@ -1194,7 +1212,7 @@ static void fs__fstat(uv_fs_t* req) {
 
 
 static void fs__rename(uv_fs_t* req) {
-  if (!MoveFileExW(req->pathw, req->new_pathw, MOVEFILE_REPLACE_EXISTING)) {
+  if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
     return;
   }
@@ -1204,7 +1222,7 @@ static void fs__rename(uv_fs_t* req) {
 
 
 INLINE static void fs__sync_impl(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   int result;
 
   VERIFY_FD(fd, req);
@@ -1229,7 +1247,7 @@ static void fs__fdatasync(uv_fs_t* req) {
 
 
 static void fs__ftruncate(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   HANDLE handle;
   NTSTATUS status;
   IO_STATUS_BLOCK io_status;
@@ -1239,7 +1257,7 @@ static void fs__ftruncate(uv_fs_t* req) {
 
   handle = uv__get_osfhandle(fd);
 
-  eof_info.EndOfFile.QuadPart = req->offset;
+  eof_info.EndOfFile.QuadPart = req->fs.info.offset;
 
   status = pNtSetInformationFile(handle,
                                  &io_status,
@@ -1256,9 +1274,9 @@ static void fs__ftruncate(uv_fs_t* req) {
 
 
 static void fs__sendfile(uv_fs_t* req) {
-  int fd_in = req->fd, fd_out = req->fd_out;
-  size_t length = req->bufsml[0].len;
-  int64_t offset = req->offset;
+  int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
+  size_t length = req->fs.info.bufsml[0].len;
+  int64_t offset = req->fs.info.offset;
   const size_t max_buf_size = 65536;
   size_t buf_size = length < max_buf_size ? length : max_buf_size;
   int n, result = 0;
@@ -1303,32 +1321,39 @@ static void fs__sendfile(uv_fs_t* req) {
 
 
 static void fs__access(uv_fs_t* req) {
-  DWORD attr = GetFileAttributesW(req->pathw);
+  DWORD attr = GetFileAttributesW(req->file.pathw);
 
   if (attr == INVALID_FILE_ATTRIBUTES) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
     return;
   }
 
-  if ((req->flags & W_OK) &&
-      ((attr & FILE_ATTRIBUTE_READONLY) ||
-      (attr & FILE_ATTRIBUTE_DIRECTORY))) {
+  /*
+   * Access is possible if
+   * - write access wasn't requested,
+   * - or the file isn't read-only,
+   * - or it's a directory.
+   * (Directories cannot be read-only on Windows.)
+   */
+  if (!(req->flags & W_OK) ||
+      !(attr & FILE_ATTRIBUTE_READONLY) ||
+      (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+    SET_REQ_RESULT(req, 0);
+  } else {
     SET_REQ_WIN32_ERROR(req, UV_EPERM);
-    return;
   }
 
-  SET_REQ_RESULT(req, 0);
 }
 
 
 static void fs__chmod(uv_fs_t* req) {
-  int result = _wchmod(req->pathw, req->mode);
+  int result = _wchmod(req->file.pathw, req->fs.info.mode);
   SET_REQ_RESULT(req, result);
 }
 
 
 static void fs__fchmod(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   HANDLE handle;
   NTSTATUS nt_status;
   IO_STATUS_BLOCK io_status;
@@ -1349,7 +1374,7 @@ static void fs__fchmod(uv_fs_t* req) {
     return;
   }
 
-  if (req->mode & _S_IWRITE) {
+  if (req->fs.info.mode & _S_IWRITE) {
     file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
   } else {
     file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
@@ -1387,7 +1412,7 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
 static void fs__utime(uv_fs_t* req) {
   HANDLE handle;
 
-  handle = CreateFileW(req->pathw,
+  handle = CreateFileW(req->file.pathw,
                        FILE_WRITE_ATTRIBUTES,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                        NULL,
@@ -1400,7 +1425,7 @@ static void fs__utime(uv_fs_t* req) {
     return;
   }
 
-  if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
+  if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
     CloseHandle(handle);
     return;
@@ -1413,7 +1438,7 @@ static void fs__utime(uv_fs_t* req) {
 
 
 static void fs__futime(uv_fs_t* req) {
-  int fd = req->fd;
+  int fd = req->file.fd;
   HANDLE handle;
   VERIFY_FD(fd, req);
 
@@ -1424,7 +1449,7 @@ static void fs__futime(uv_fs_t* req) {
     return;
   }
 
-  if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
+  if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
     return;
   }
@@ -1434,7 +1459,7 @@ static void fs__futime(uv_fs_t* req) {
 
 
 static void fs__link(uv_fs_t* req) {
-  DWORD r = CreateHardLinkW(req->new_pathw, req->pathw, NULL);
+  DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
   if (r == 0) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
   } else {
@@ -1614,9 +1639,9 @@ error:
 
 
 static void fs__symlink(uv_fs_t* req) {
-  WCHAR* pathw = req->pathw;
-  WCHAR* new_pathw = req->new_pathw;
-  int flags = req->file_flags;
+  WCHAR* pathw = req->file.pathw;
+  WCHAR* new_pathw = req->fs.info.new_pathw;
+  int flags = req->fs.info.file_flags;
   int result;
 
 
@@ -1640,7 +1665,7 @@ static void fs__symlink(uv_fs_t* req) {
 static void fs__readlink(uv_fs_t* req) {
   HANDLE handle;
 
-  handle = CreateFileW(req->pathw,
+  handle = CreateFileW(req->file.pathw,
                        0,
                        0,
                        NULL,
@@ -1739,14 +1764,14 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
     return;
 
   if (req->flags & UV_FS_FREE_PATHS)
-    free(req->pathw);
+    free(req->file.pathw);
 
   if (req->flags & UV_FS_FREE_PTR)
     free(req->ptr);
 
   req->path = NULL;
-  req->pathw = NULL;
-  req->new_pathw = NULL;
+  req->file.pathw = NULL;
+  req->fs.info.new_pathw = NULL;
   req->ptr = NULL;
 
   req->flags |= UV_FS_CLEANEDUP;
@@ -1764,8 +1789,8 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
     return uv_translate_sys_error(err);
   }
 
-  req->file_flags = flags;
-  req->mode = mode;
+  req->fs.info.file_flags = flags;
+  req->fs.info.mode = mode;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1779,7 +1804,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
 
 int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
-  req->fd = fd;
+  req->file.fd = fd;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1800,19 +1825,19 @@ int uv_fs_read(uv_loop_t* loop,
                uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_READ, cb);
 
-  req->fd = fd;
+  req->file.fd = fd;
 
-  req->nbufs = nbufs;
-  req->bufs = req->bufsml;
-  if (nbufs > ARRAY_SIZE(req->bufsml))
-    req->bufs = malloc(nbufs * sizeof(*bufs));
+  req->fs.info.nbufs = nbufs;
+  req->fs.info.bufs = req->fs.info.bufsml;
+  if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+    req->fs.info.bufs = malloc(nbufs * sizeof(*bufs));
 
-  if (req->bufs == NULL)
+  if (req->fs.info.bufs == NULL)
     return UV_ENOMEM;
 
-  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+  memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
 
-  req->offset = offset;
+  req->fs.info.offset = offset;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1833,19 +1858,19 @@ int uv_fs_write(uv_loop_t* loop,
                 uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
 
-  req->fd = fd;
+  req->file.fd = fd;
 
-  req->nbufs = nbufs;
-  req->bufs = req->bufsml;
-  if (nbufs > ARRAY_SIZE(req->bufsml))
-    req->bufs = malloc(nbufs * sizeof(*bufs));
+  req->fs.info.nbufs = nbufs;
+  req->fs.info.bufs = req->fs.info.bufsml;
+  if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+    req->fs.info.bufs = malloc(nbufs * sizeof(*bufs));
 
-  if (req->bufs == NULL)
+  if (req->fs.info.bufs == NULL)
     return UV_ENOMEM;
 
-  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+  memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
 
-  req->offset = offset;
+  req->fs.info.offset = offset;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1889,7 +1914,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
     return uv_translate_sys_error(err);
   }
 
-  req->mode = mode;
+  req->fs.info.mode = mode;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1952,7 +1977,7 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
     return uv_translate_sys_error(err);
   }
 
-  req->file_flags = flags;
+  req->fs.info.file_flags = flags;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -1996,7 +2021,7 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
     return uv_translate_sys_error(err);
   }
 
-  req->file_flags = flags;
+  req->fs.info.file_flags = flags;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2106,7 +2131,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
 int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
-  req->fd = fd;
+  req->file.fd = fd;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2141,7 +2166,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
 int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
-  req->fd = fd;
+  req->file.fd = fd;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2155,7 +2180,7 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
 
 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
-  req->fd = fd;
+  req->file.fd = fd;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2171,8 +2196,8 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
     int64_t offset, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
 
-  req->fd = fd;
-  req->offset = offset;
+  req->file.fd = fd;
+  req->fs.info.offset = offset;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2189,10 +2214,10 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
     uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
 
-  req->fd = fd_in;
-  req->fd_out = fd_out;
-  req->offset = in_offset;
-  req->bufsml[0].len = length;
+  req->file.fd = fd_in;
+  req->fs.info.fd_out = fd_out;
+  req->fs.info.offset = in_offset;
+  req->fs.info.bufsml[0].len = length;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2240,7 +2265,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
     return uv_translate_sys_error(err);
   }
 
-  req->mode = mode;
+  req->fs.info.mode = mode;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2256,8 +2281,8 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
     uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
 
-  req->fd = fd;
-  req->mode = mode;
+  req->file.fd = fd;
+  req->fs.info.mode = mode;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2280,8 +2305,8 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
     return uv_translate_sys_error(err);
   }
 
-  req->atime = atime;
-  req->mtime = mtime;
+  req->fs.time.atime = atime;
+  req->fs.time.mtime = mtime;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
@@ -2297,9 +2322,9 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
     double mtime, uv_fs_cb cb) {
   uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
 
-  req->fd = fd;
-  req->atime = atime;
-  req->mtime = mtime;
+  req->file.fd = fd;
+  req->fs.time.atime = atime;
+  req->fs.time.mtime = mtime;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
index f103f5f..f3802cd 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <assert.h>
-#include <malloc.h>
 
 #include "uv.h"
 #include "internal.h"
index b1d045c..66b64b8 100644 (file)
@@ -20,7 +20,6 @@
 */
 
 #include <assert.h>
-#include <malloc.h>
 #include <stdio.h>
 
 #include "uv.h"
index 57fab06..5a0e542 100644 (file)
@@ -95,15 +95,15 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
   handle->reqs_pending = 0;
   handle->handle = INVALID_HANDLE_VALUE;
   handle->name = NULL;
-  handle->ipc_pid = 0;
-  handle->remaining_ipc_rawdata_bytes = 0;
-  QUEUE_INIT(&handle->pending_ipc_info.queue);
-  handle->pending_ipc_info.queue_len = 0;
+  handle->pipe.conn.ipc_pid = 0;
+  handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
+  QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
+  handle->pipe.conn.pending_ipc_info.queue_len = 0;
   handle->ipc = ipc;
-  handle->non_overlapped_writes_tail = NULL;
-  handle->readfile_thread = NULL;
+  handle->pipe.conn.non_overlapped_writes_tail = NULL;
+  handle->pipe.conn.readfile_thread = NULL;
 
-  uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
+  uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
 
   return 0;
 }
@@ -112,11 +112,11 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
 static void uv_pipe_connection_init(uv_pipe_t* handle) {
   uv_connection_init((uv_stream_t*) handle);
   handle->read_req.data = handle;
-  handle->eof_timer = NULL;
+  handle->pipe.conn.eof_timer = NULL;
   assert(!(handle->flags & UV_HANDLE_PIPESERVER));
   if (pCancelSynchronousIo &&
       handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
-      uv_mutex_init(&handle->readfile_mutex);
+      uv_mutex_init(&handle->pipe.conn.readfile_mutex);
       handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE;
   }
 }
@@ -330,16 +330,16 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
   if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
     handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE;
-    uv_mutex_destroy(&handle->readfile_mutex);
+    uv_mutex_destroy(&handle->pipe.conn.readfile_mutex);
   }
 
   if ((handle->flags & UV_HANDLE_CONNECTION) &&
-      handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
-    req = handle->shutdown_req;
+      handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
+    req = handle->stream.conn.shutdown_req;
 
     /* Clear the shutdown_req field so we don't go here again. */
-    handle->shutdown_req = NULL;
+    handle->stream.conn.shutdown_req = NULL;
 
     if (handle->flags & UV__HANDLE_CLOSING) {
       UNREGISTER_HANDLE_REQ(loop, handle, req);
@@ -408,11 +408,11 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
     if (handle->flags & UV_HANDLE_CONNECTION) {
       /* Free pending sockets */
-      while (!QUEUE_EMPTY(&handle->pending_ipc_info.queue)) {
+      while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) {
         QUEUE* q;
         SOCKET socket;
 
-        q = QUEUE_HEAD(&handle->pending_ipc_info.queue);
+        q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue);
         QUEUE_REMOVE(q);
         item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
 
@@ -428,7 +428,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
         if (socket != INVALID_SOCKET)
           closesocket(socket);
       }
-      handle->pending_ipc_info.queue_len = 0;
+      handle->pipe.conn.pending_ipc_info.queue_len = 0;
 
       if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
         if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
@@ -443,9 +443,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
     }
 
     if (handle->flags & UV_HANDLE_PIPESERVER) {
-      assert(handle->accept_reqs);
-      free(handle->accept_reqs);
-      handle->accept_reqs = NULL;
+      assert(handle->pipe.serv.accept_reqs);
+      free(handle->pipe.serv.accept_reqs);
+      handle->pipe.serv.accept_reqs = NULL;
     }
 
     uv__handle_close(handle);
@@ -454,7 +454,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
 
 void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
-  handle->pending_instances = count;
+  handle->pipe.serv.pending_instances = count;
   handle->flags |= UV_HANDLE_PIPESERVER;
 }
 
@@ -474,17 +474,17 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   }
 
   if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
-    handle->pending_instances = default_pending_pipe_instances;
+    handle->pipe.serv.pending_instances = default_pending_pipe_instances;
   }
 
-  handle->accept_reqs = (uv_pipe_accept_t*)
-    malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances);
-  if (!handle->accept_reqs) {
+  handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
+    malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
+  if (!handle->pipe.serv.accept_reqs) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  for (i = 0; i < handle->pending_instances; i++) {
-    req = &handle->accept_reqs[i];
+  for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+    req = &handle->pipe.serv.accept_reqs[i];
     uv_req_init(loop, (uv_req_t*) req);
     req->type = UV_ACCEPT;
     req->data = handle;
@@ -508,13 +508,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
    * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
    * If this fails then there's already a pipe server for the given pipe name.
    */
-  handle->accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
+  handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
       FILE_FLAG_FIRST_PIPE_INSTANCE,
       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
       PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
 
-  if (handle->accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
+  if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
     err = GetLastError();
     if (err == ERROR_ACCESS_DENIED) {
       err = WSAEADDRINUSE;  /* Translates to UV_EADDRINUSE. */
@@ -524,12 +524,15 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
     goto error;
   }
 
-  if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle, 0)) {
+  if (uv_set_pipe_handle(loop,
+                         handle,
+                         handle->pipe.serv.accept_reqs[0].pipeHandle,
+                         0)) {
     err = GetLastError();
     goto error;
   }
 
-  handle->pending_accepts = NULL;
+  handle->pipe.serv.pending_accepts = NULL;
   handle->flags |= UV_HANDLE_PIPESERVER;
   handle->flags |= UV_HANDLE_BOUND;
 
@@ -541,9 +544,9 @@ error:
     handle->name = NULL;
   }
 
-  if (handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
-    CloseHandle(handle->accept_reqs[0].pipeHandle);
-    handle->accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
+  if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
+    CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
+    handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
   }
 
   return uv_translate_sys_error(err);
@@ -677,15 +680,15 @@ void uv__pipe_pause_read(uv_pipe_t* handle) {
          any access to a NamedPipe to deadlock if
          any process has called ReadFile */
       HANDLE h;
-      uv_mutex_lock(&handle->readfile_mutex);
-      h = handle->readfile_thread;
+      uv_mutex_lock(&handle->pipe.conn.readfile_mutex);
+      h = handle->pipe.conn.readfile_thread;
       while (h) {
         /* spinlock: we expect this to finish quickly,
            or we are probably about to deadlock anyways
            (in the kernel), so it doesn't matter */
         pCancelSynchronousIo(h);
         SwitchToThread(); /* yield thread control briefly */
-        h = handle->readfile_thread;
+        h = handle->pipe.conn.readfile_thread;
       }
   }
 }
@@ -693,7 +696,7 @@ void uv__pipe_pause_read(uv_pipe_t* handle) {
 
 void uv__pipe_unpause_read(uv_pipe_t* handle) {
   if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
-    uv_mutex_unlock(&handle->readfile_mutex);
+    uv_mutex_unlock(&handle->pipe.conn.readfile_mutex);
   }
 }
 
@@ -719,11 +722,11 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
   }
 
   if (handle->flags & UV_HANDLE_PIPESERVER) {
-    for (i = 0; i < handle->pending_instances; i++) {
-      pipeHandle = handle->accept_reqs[i].pipeHandle;
+    for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+      pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
       if (pipeHandle != INVALID_HANDLE_VALUE) {
         CloseHandle(pipeHandle);
-        handle->accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
+        handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
       }
     }
   }
@@ -796,9 +799,9 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
   assert(req->pipeHandle != INVALID_HANDLE_VALUE);
 
   /* Prepare the overlapped structure. */
-  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+  memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
 
-  if (!ConnectNamedPipe(req->pipeHandle, &req->overlapped) &&
+  if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
       GetLastError() != ERROR_IO_PENDING) {
     if (GetLastError() == ERROR_PIPE_CONNECTED) {
       SET_REQ_SUCCESS(req);
@@ -826,14 +829,14 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
   int err;
 
   if (server->ipc) {
-    if (QUEUE_EMPTY(&server->pending_ipc_info.queue)) {
+    if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) {
       /* No valid pending sockets. */
       return WSAEWOULDBLOCK;
     }
 
-    q = QUEUE_HEAD(&server->pending_ipc_info.queue);
+    q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue);
     QUEUE_REMOVE(q);
-    server->pending_ipc_info.queue_len--;
+    server->pipe.conn.pending_ipc_info.queue_len--;
     item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
 
     err = uv_tcp_import((uv_tcp_t*)client,
@@ -849,7 +852,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
 
     /* Find a connection instance that has been connected, but not yet */
     /* accepted. */
-    req = server->pending_accepts;
+    req = server->pipe.serv.pending_accepts;
 
     if (!req) {
       /* No valid connections found, so we error out. */
@@ -862,7 +865,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
     pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
 
     /* Prepare the req to pick up a new connection */
-    server->pending_accepts = req->next_pending;
+    server->pipe.serv.pending_accepts = req->next_pending;
     req->next_pending = NULL;
     req->pipeHandle = INVALID_HANDLE_VALUE;
 
@@ -881,7 +884,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
   int i;
 
   if (handle->flags & UV_HANDLE_LISTENING) {
-    handle->connection_cb = cb;
+    handle->stream.serv.connection_cb = cb;
   }
 
   if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -898,13 +901,13 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
 
   handle->flags |= UV_HANDLE_LISTENING;
   INCREASE_ACTIVE_COUNT(loop, handle);
-  handle->connection_cb = cb;
+  handle->stream.serv.connection_cb = cb;
 
   /* First pipe handle should have already been created in uv_pipe_bind */
-  assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
+  assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
 
-  for (i = 0; i < handle->pending_instances; i++) {
-    uv_pipe_queue_accept(loop, handle, &handle->accept_reqs[i], i == 0);
+  for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+    uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
   }
 
   return 0;
@@ -919,7 +922,7 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
   uv_loop_t* loop = handle->loop;
   HANDLE hThread = NULL;
   DWORD err;
-  uv_mutex_t *m = &handle->readfile_mutex;
+  uv_mutex_t *m = &handle->pipe.conn.readfile_mutex;
 
   assert(req != NULL);
   assert(req->type == UV_READ);
@@ -930,7 +933,7 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
     if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
                         GetCurrentProcess(), &hThread,
                         0, TRUE, DUPLICATE_SAME_ACCESS)) {
-      handle->readfile_thread = hThread;
+      handle->pipe.conn.readfile_thread = hThread;
     } else {
       hThread = NULL;
     }
@@ -948,10 +951,10 @@ restart_readfile:
         handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
       if (handle->flags & UV_HANDLE_READING) {
         /* just a brief break to do something else */
-        handle->readfile_thread = NULL;
+        handle->pipe.conn.readfile_thread = NULL;
         /* resume after it is finished */
         uv_mutex_lock(m);
-        handle->readfile_thread = hThread;
+        handle->pipe.conn.readfile_thread = hThread;
         uv_mutex_unlock(m);
         goto restart_readfile;
       } else {
@@ -960,9 +963,9 @@ restart_readfile:
     }
   }
   if (hThread) {
-    assert(hThread == handle->readfile_thread);
+    assert(hThread == handle->pipe.conn.readfile_thread);
     /* mutex does not control clearing readfile_thread */
-    handle->readfile_thread = NULL;
+    handle->pipe.conn.readfile_thread = NULL;
     uv_mutex_lock(m);
     /* only when we hold the mutex lock is it safe to
        open or close the handle */
@@ -1017,9 +1020,9 @@ static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out)
   assert(!timed_out);
 
   if (!PostQueuedCompletionStatus(handle->loop->iocp,
-                                  req->overlapped.InternalHigh,
+                                  req->u.io.overlapped.InternalHigh,
                                   0,
-                                  &req->overlapped)) {
+                                  &req->u.io.overlapped)) {
     uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
   }
 }
@@ -1036,9 +1039,9 @@ static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out
   assert(!timed_out);
 
   if (!PostQueuedCompletionStatus(handle->loop->iocp,
-                                  req->overlapped.InternalHigh,
+                                  req->u.io.overlapped.InternalHigh,
                                   0,
-                                  &req->overlapped)) {
+                                  &req->u.io.overlapped)) {
     uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
   }
 }
@@ -1064,9 +1067,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
       goto error;
     }
   } else {
-    memset(&req->overlapped, 0, sizeof(req->overlapped));
+    memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
     if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
-      req->overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
+      req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
     }
 
     /* Do 0-read */
@@ -1074,7 +1077,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
                       &uv_zero_,
                       0,
                       NULL,
-                      &req->overlapped);
+                      &req->u.io.overlapped);
 
     if (!result && GetLastError() != ERROR_IO_PENDING) {
       /* Make this req pending reporting an error. */
@@ -1091,7 +1094,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
       }
       if (req->wait_handle == INVALID_HANDLE_VALUE) {
         if (!RegisterWaitForSingleObject(&req->wait_handle,
-            req->overlapped.hEvent, post_completion_read_wait, (void*) req,
+            req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
             INFINITE, WT_EXECUTEINWAITTHREAD)) {
           SET_REQ_ERROR(req, GetLastError());
           goto error;
@@ -1135,14 +1138,14 @@ int uv_pipe_read_start(uv_pipe_t* handle,
 static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
     uv_write_t* req) {
   req->next_req = NULL;
-  if (handle->non_overlapped_writes_tail) {
+  if (handle->pipe.conn.non_overlapped_writes_tail) {
     req->next_req =
-      handle->non_overlapped_writes_tail->next_req;
-    handle->non_overlapped_writes_tail->next_req = (uv_req_t*)req;
-    handle->non_overlapped_writes_tail = req;
+      handle->pipe.conn.non_overlapped_writes_tail->next_req;
+    handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
+    handle->pipe.conn.non_overlapped_writes_tail = req;
   } else {
     req->next_req = (uv_req_t*)req;
-    handle->non_overlapped_writes_tail = req;
+    handle->pipe.conn.non_overlapped_writes_tail = req;
   }
 }
 
@@ -1150,13 +1153,13 @@ static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
 static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
   uv_write_t* req;
 
-  if (handle->non_overlapped_writes_tail) {
-    req = (uv_write_t*)handle->non_overlapped_writes_tail->next_req;
+  if (handle->pipe.conn.non_overlapped_writes_tail) {
+    req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
 
-    if (req == handle->non_overlapped_writes_tail) {
-      handle->non_overlapped_writes_tail = NULL;
+    if (req == handle->pipe.conn.non_overlapped_writes_tail) {
+      handle->pipe.conn.non_overlapped_writes_tail = NULL;
     } else {
-      handle->non_overlapped_writes_tail->next_req =
+      handle->pipe.conn.non_overlapped_writes_tail->next_req =
         req->next_req;
     }
 
@@ -1213,7 +1216,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
   req->ipc_header = 0;
   req->event_handle = NULL;
   req->wait_handle = INVALID_HANDLE_VALUE;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
   if (handle->ipc) {
     assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
@@ -1223,7 +1226,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
     if (send_handle) {
       tcp_send_handle = (uv_tcp_t*)send_handle;
 
-      err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
+      err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
           &ipc_frame.socket_info_ex.socket_info);
       if (err) {
         return err;
@@ -1255,8 +1258,8 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
        * Try to use the preallocated write req if it's available.
        * Otherwise allocate a new one.
        */
-      if (handle->ipc_header_write_req.type != UV_WRITE) {
-        ipc_header_req = (uv_write_t*)&handle->ipc_header_write_req;
+      if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) {
+        ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req;
       } else {
         ipc_header_req = (uv_write_t*)malloc(sizeof(uv_write_t));
         if (!ipc_header_req) {
@@ -1272,12 +1275,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
     }
 
     /* Write the header or the whole frame. */
-    memset(&ipc_header_req->overlapped, 0, sizeof(ipc_header_req->overlapped));
+    memset(&ipc_header_req->u.io.overlapped, 0,
+           sizeof(ipc_header_req->u.io.overlapped));
 
     /* Using overlapped IO, but wait for completion before returning.
        This write is blocking because ipc_frame is on stack. */
-    ipc_header_req->overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
-    if (!ipc_header_req->overlapped.hEvent) {
+    ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+    if (!ipc_header_req->u.io.overlapped.hEvent) {
       uv_fatal_error(GetLastError(), "CreateEvent");
     }
 
@@ -1286,29 +1290,29 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
                         ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
                           sizeof(ipc_frame) : sizeof(ipc_frame.header),
                         NULL,
-                        &ipc_header_req->overlapped);
+                        &ipc_header_req->u.io.overlapped);
     if (!result && GetLastError() != ERROR_IO_PENDING) {
       err = GetLastError();
-      CloseHandle(ipc_header_req->overlapped.hEvent);
+      CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
       return err;
     }
 
     if (!result) {
       /* Request not completed immediately. Wait for it.*/
-      if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) !=
+      if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) !=
           WAIT_OBJECT_0) {
         err = GetLastError();
-        CloseHandle(ipc_header_req->overlapped.hEvent);
+        CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
         return err;
       }
     }
-    ipc_header_req->queued_bytes = 0;
-    CloseHandle(ipc_header_req->overlapped.hEvent);
-    ipc_header_req->overlapped.hEvent = NULL;
+    ipc_header_req->u.io.queued_bytes = 0;
+    CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+    ipc_header_req->u.io.overlapped.hEvent = NULL;
 
     REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
     handle->reqs_pending++;
-    handle->write_reqs_pending++;
+    handle->stream.conn.write_reqs_pending++;
 
     /* If we don't have any raw data to write - we're done. */
     if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
@@ -1331,28 +1335,28 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
       return err;
     } else {
       /* Request completed immediately. */
-      req->queued_bytes = 0;
+      req->u.io.queued_bytes = 0;
     }
 
     REGISTER_HANDLE_REQ(loop, handle, req);
     handle->reqs_pending++;
-    handle->write_reqs_pending++;
+    handle->stream.conn.write_reqs_pending++;
     POST_COMPLETION_FOR_REQ(loop, req);
     return 0;
   } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
     req->write_buffer = bufs[0];
     uv_insert_non_overlapped_write_req(handle, req);
-    if (handle->write_reqs_pending == 0) {
+    if (handle->stream.conn.write_reqs_pending == 0) {
       uv_queue_non_overlapped_write(handle);
     }
 
     /* Request queued by the kernel. */
-    req->queued_bytes = uv__count_bufs(bufs, nbufs);
-    handle->write_queue_size += req->queued_bytes;
+    req->u.io.queued_bytes = bufs[0].len;
+    handle->write_queue_size += req->u.io.queued_bytes;
   } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
     /* Using overlapped IO, but wait for completion before returning */
-    req->overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
-    if (!req->overlapped.hEvent) {
+    req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+    if (!req->u.io.overlapped.hEvent) {
       uv_fatal_error(GetLastError(), "CreateEvent");
     }
 
@@ -1360,40 +1364,40 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
                        bufs[0].base,
                        bufs[0].len,
                        NULL,
-                       &req->overlapped);
+                       &req->u.io.overlapped);
 
     if (!result && GetLastError() != ERROR_IO_PENDING) {
       err = GetLastError();
-      CloseHandle(req->overlapped.hEvent);
+      CloseHandle(req->u.io.overlapped.hEvent);
       return err;
     }
 
     if (result) {
       /* Request completed immediately. */
-      req->queued_bytes = 0;
+      req->u.io.queued_bytes = 0;
     } else {
-      assert(ipc_header_req != NULL);
       /* Request queued by the kernel. */
-      if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) !=
+      req->u.io.queued_bytes = bufs[0].len;
+      handle->write_queue_size += req->u.io.queued_bytes;
+      if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
           WAIT_OBJECT_0) {
         err = GetLastError();
-        CloseHandle(ipc_header_req->overlapped.hEvent);
+        CloseHandle(req->u.io.overlapped.hEvent);
         return uv_translate_sys_error(err);
       }
     }
-    CloseHandle(req->overlapped.hEvent);
+    CloseHandle(req->u.io.overlapped.hEvent);
 
     REGISTER_HANDLE_REQ(loop, handle, req);
     handle->reqs_pending++;
-    handle->write_reqs_pending++;
-    POST_COMPLETION_FOR_REQ(loop, req);
+    handle->stream.conn.write_reqs_pending++;
     return 0;
   } else {
     result = WriteFile(handle->handle,
                        bufs[0].base,
                        bufs[0].len,
                        NULL,
-                       &req->overlapped);
+                       &req->u.io.overlapped);
 
     if (!result && GetLastError() != ERROR_IO_PENDING) {
       return GetLastError();
@@ -1401,11 +1405,11 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
 
     if (result) {
       /* Request completed immediately. */
-      req->queued_bytes = 0;
+      req->u.io.queued_bytes = 0;
     } else {
       /* Request queued by the kernel. */
-      req->queued_bytes = uv__count_bufs(bufs, nbufs);
-      handle->write_queue_size += req->queued_bytes;
+      req->u.io.queued_bytes = bufs[0].len;
+      handle->write_queue_size += req->u.io.queued_bytes;
     }
 
     if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
@@ -1414,7 +1418,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
         uv_fatal_error(GetLastError(), "CreateEvent");
       }
       if (!RegisterWaitForSingleObject(&req->wait_handle,
-          req->overlapped.hEvent, post_completion_write_wait, (void*) req,
+          req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD)) {
         return GetLastError();
       }
@@ -1423,7 +1427,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
 
   REGISTER_HANDLE_REQ(loop, handle, req);
   handle->reqs_pending++;
-  handle->write_reqs_pending++;
+  handle->stream.conn.write_reqs_pending++;
 
   return 0;
 }
@@ -1500,8 +1504,8 @@ void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
 
   memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
   item->tcp_connection = tcp_connection;
-  QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member);
-  handle->pending_ipc_info.queue_len++;
+  QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member);
+  handle->pipe.conn.pending_ipc_info.queue_len++;
 }
 
 
@@ -1544,7 +1548,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
 
       if (handle->ipc) {
         /* Use the IPC framing protocol to read the incoming data. */
-        if (handle->remaining_ipc_rawdata_bytes == 0) {
+        if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) {
           /* We're reading a new frame.  First, read the header. */
           assert(avail >= sizeof(ipc_frame.header));
 
@@ -1587,12 +1591,12 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
           }
 
           if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
-            handle->remaining_ipc_rawdata_bytes =
+            handle->pipe.conn.remaining_ipc_rawdata_bytes =
               ipc_frame.header.raw_data_length;
             continue;
           }
         } else {
-          avail = min(avail, (DWORD)handle->remaining_ipc_rawdata_bytes);
+          avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes);
         }
       }
 
@@ -1610,9 +1614,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
                    NULL)) {
         /* Successful read */
         if (handle->ipc) {
-          assert(handle->remaining_ipc_rawdata_bytes >= bytes);
-          handle->remaining_ipc_rawdata_bytes =
-            handle->remaining_ipc_rawdata_bytes - bytes;
+          assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes);
+          handle->pipe.conn.remaining_ipc_rawdata_bytes =
+            handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes;
         }
         handle->read_cb((uv_stream_t*)handle, bytes, &buf);
 
@@ -1643,8 +1647,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
 
   assert(handle->type == UV_NAMED_PIPE);
 
-  assert(handle->write_queue_size >= req->queued_bytes);
-  handle->write_queue_size -= req->queued_bytes;
+  assert(handle->write_queue_size >= req->u.io.queued_bytes);
+  handle->write_queue_size -= req->u.io.queued_bytes;
 
   UNREGISTER_HANDLE_REQ(loop, handle, req);
 
@@ -1660,7 +1664,7 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
   }
 
   if (req->ipc_header) {
-    if (req == &handle->ipc_header_write_req) {
+    if (req == &handle->pipe.conn.ipc_header_write_req) {
       req->type = UV_UNKNOWN_REQ;
     } else {
       free(req);
@@ -1672,16 +1676,16 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
     }
   }
 
-  handle->write_reqs_pending--;
+  handle->stream.conn.write_reqs_pending--;
 
   if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
-      handle->non_overlapped_writes_tail) {
-    assert(handle->write_reqs_pending > 0);
+      handle->pipe.conn.non_overlapped_writes_tail) {
+    assert(handle->stream.conn.write_reqs_pending > 0);
     uv_queue_non_overlapped_write(handle);
   }
 
-  if (handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
+  if (handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
 
@@ -1704,11 +1708,11 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
 
   if (REQ_SUCCESS(req)) {
     assert(req->pipeHandle != INVALID_HANDLE_VALUE);
-    req->next_pending = handle->pending_accepts;
-    handle->pending_accepts = req;
+    req->next_pending = handle->pipe.serv.pending_accepts;
+    handle->pipe.serv.pending_accepts = req;
 
-    if (handle->connection_cb) {
-      handle->connection_cb((uv_stream_t*)handle, 0);
+    if (handle->stream.serv.connection_cb) {
+      handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
     }
   } else {
     if (req->pipeHandle != INVALID_HANDLE_VALUE) {
@@ -1781,23 +1785,23 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
 static void eof_timer_init(uv_pipe_t* pipe) {
   int r;
 
-  assert(pipe->eof_timer == NULL);
+  assert(pipe->pipe.conn.eof_timer == NULL);
   assert(pipe->flags & UV_HANDLE_CONNECTION);
 
-  pipe->eof_timer = (uv_timer_t*) malloc(sizeof *pipe->eof_timer);
+  pipe->pipe.conn.eof_timer = (uv_timer_t*) malloc(sizeof *pipe->pipe.conn.eof_timer);
 
-  r = uv_timer_init(pipe->loop, pipe->eof_timer);
+  r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
   assert(r == 0); /* timers can't fail */
-  pipe->eof_timer->data = pipe;
-  uv_unref((uv_handle_t*) pipe->eof_timer);
+  pipe->pipe.conn.eof_timer->data = pipe;
+  uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
 }
 
 
 static void eof_timer_start(uv_pipe_t* pipe) {
   assert(pipe->flags & UV_HANDLE_CONNECTION);
 
-  if (pipe->eof_timer != NULL) {
-    uv_timer_start(pipe->eof_timer, eof_timer_cb, eof_timeout, 0);
+  if (pipe->pipe.conn.eof_timer != NULL) {
+    uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
   }
 }
 
@@ -1805,8 +1809,8 @@ static void eof_timer_start(uv_pipe_t* pipe) {
 static void eof_timer_stop(uv_pipe_t* pipe) {
   assert(pipe->flags & UV_HANDLE_CONNECTION);
 
-  if (pipe->eof_timer != NULL) {
-    uv_timer_stop(pipe->eof_timer);
+  if (pipe->pipe.conn.eof_timer != NULL) {
+    uv_timer_stop(pipe->pipe.conn.eof_timer);
   }
 }
 
@@ -1829,7 +1833,7 @@ static void eof_timer_cb(uv_timer_t* timer) {
   /* Therefore we check here if the read request has completed but will */
   /* be processed later. */
   if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
-      HasOverlappedIoCompleted(&pipe->read_req.overlapped)) {
+      HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
     return;
   }
 
@@ -1850,9 +1854,9 @@ static void eof_timer_cb(uv_timer_t* timer) {
 static void eof_timer_destroy(uv_pipe_t* pipe) {
   assert(pipe->flags & UV_HANDLE_CONNECTION);
 
-  if (pipe->eof_timer) {
-    uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
-    pipe->eof_timer = NULL;
+  if (pipe->pipe.conn.eof_timer) {
+    uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
+    pipe->pipe.conn.eof_timer = NULL;
   }
 }
 
@@ -1903,8 +1907,8 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
 
   if (pipe->ipc) {
     assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
-    pipe->ipc_pid = uv_parent_pid();
-    assert(pipe->ipc_pid != -1);
+    pipe->pipe.conn.ipc_pid = uv_parent_pid();
+    assert(pipe->pipe.conn.ipc_pid != -1);
   }
   return 0;
 }
@@ -2027,7 +2031,7 @@ cleanup:
 int uv_pipe_pending_count(uv_pipe_t* handle) {
   if (!handle->ipc)
     return 0;
-  return handle->pending_ipc_info.queue_len;
+  return handle->pipe.conn.pending_ipc_info.queue_len;
 }
 
 
@@ -2060,7 +2064,7 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
 uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
   if (!handle->ipc)
     return UV_UNKNOWN_HANDLE;
-  if (handle->pending_ipc_info.queue_len == 0)
+  if (handle->pipe.conn.pending_ipc_info.queue_len == 0)
     return UV_UNKNOWN_HANDLE;
   else
     return UV_TCP;
index 4d8e1f9..ce861d6 100644 (file)
@@ -112,12 +112,12 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
     afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
   }
 
-  memset(&req->overlapped, 0, sizeof req->overlapped);
+  memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
 
   result = uv_msafd_poll((SOCKET) handle->peer_socket,
                          afd_poll_info,
                          afd_poll_info,
-                         &req->overlapped);
+                         &req->u.io.overlapped);
   if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
     /* Queue this req, reporting an error. */
     SET_REQ_ERROR(req, WSAGetLastError());
@@ -380,7 +380,7 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
   }
 
   SET_REQ_SUCCESS(req);
-  req->overlapped.InternalHigh = (DWORD) reported_events;
+  req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
   POST_COMPLETION_FOR_REQ(handle->loop, req);
 
   return 0;
@@ -442,7 +442,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
     }
   } else {
     /* Got some events. */
-    int events = req->overlapped.InternalHigh & handle->events & ~mask_events;
+    int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
     if (events != 0) {
       handle->poll_cb(handle, 0, events);
     }
index 3a0106f..887595f 100644 (file)
@@ -707,7 +707,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   }
 
   /* second pass: copy to UTF-16 environment block */
-  dst_copy = _malloca(env_len * sizeof(WCHAR));
+  dst_copy = malloc(env_len * sizeof(WCHAR));
   if (!dst_copy) {
     return ERROR_OUTOFMEMORY;
   }
@@ -725,7 +725,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
                                 (int) (env_len - (ptr - dst_copy)));
       if (len <= 0) {
         DWORD err = GetLastError();
-        _freea(dst_copy);
+        free(dst_copy);
         return err;
       }
       *ptr_copy++ = ptr;
@@ -767,7 +767,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   /* final pass: copy, in sort order, and inserting required variables */
   dst = malloc((1+env_len) * sizeof(WCHAR));
   if (!dst) {
-    _freea(dst_copy);
+    free(dst_copy);
     return ERROR_OUTOFMEMORY;
   }
 
@@ -812,7 +812,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   assert(env_len == (ptr - dst));
   *ptr = L'\0';
 
-  _freea(dst_copy);
+  free(dst_copy);
   *dst_ptr = dst;
   return 0;
 }
@@ -1124,7 +1124,7 @@ int uv_spawn(uv_loop_t* loop,
     if (fdopt->flags & UV_CREATE_PIPE &&
         fdopt->data.stream->type == UV_NAMED_PIPE &&
         ((uv_pipe_t*) fdopt->data.stream)->ipc) {
-      ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId;
+      ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
     }
   }
 
index 46c7d9b..b5e502e 100644 (file)
@@ -29,7 +29,7 @@
 
 
 #define SET_REQ_STATUS(req, status)                                     \
-   (req)->overlapped.Internal = (ULONG_PTR) (status)
+   (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
 
 #define SET_REQ_ERROR(req, error)                                       \
   SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
@@ -38,7 +38,7 @@
   SET_REQ_STATUS((req), STATUS_SUCCESS)
 
 #define GET_REQ_STATUS(req)                                             \
-  ((NTSTATUS) (req)->overlapped.Internal)
+  ((NTSTATUS) (req)->u.io.overlapped.Internal)
 
 #define REQ_SUCCESS(req)                                                \
   (NT_SUCCESS(GET_REQ_STATUS((req))))
@@ -74,7 +74,7 @@
   if (!PostQueuedCompletionStatus((loop)->iocp,                         \
                                   0,                                    \
                                   0,                                    \
-                                  &((req)->overlapped))) {              \
+                                  &((req)->u.io.overlapped))) {         \
     uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");       \
   }
 
@@ -86,13 +86,24 @@ INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
 
 
 INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
-  return CONTAINING_RECORD(overlapped, uv_req_t, overlapped);
+  return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
 }
 
 
 INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
   req->next_req = NULL;
   if (loop->pending_reqs_tail) {
+#ifdef _DEBUG
+    /* Ensure the request is not already in the queue, or the queue
+     * will get corrupted.
+     */
+    uv_req_t* current = loop->pending_reqs_tail;
+    do {
+      assert(req != current);
+      current = current->next_req;
+    } while(current != loop->pending_reqs_tail);
+#endif
+
     req->next_req = loop->pending_reqs_tail->next_req;
     loop->pending_reqs_tail->next_req = req;
     loop->pending_reqs_tail = req;
index 97a6b90..b7a3c11 100644 (file)
@@ -41,7 +41,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
 
 INLINE static void uv_connection_init(uv_stream_t* handle) {
   handle->flags |= UV_HANDLE_CONNECTION;
-  handle->write_reqs_pending = 0;
+  handle->stream.conn.write_reqs_pending = 0;
 
   uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
   handle->read_req.event_handle = NULL;
@@ -49,7 +49,7 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
   handle->read_req.type = UV_READ;
   handle->read_req.data = handle;
 
-  handle->shutdown_req = NULL;
+  handle->stream.conn.shutdown_req = NULL;
 }
 
 
index 36d88d0..a2466e5 100644 (file)
@@ -216,7 +216,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
   req->cb = cb;
 
   handle->flags &= ~UV_HANDLE_WRITABLE;
-  handle->shutdown_req = req;
+  handle->stream.conn.shutdown_req = req;
   handle->reqs_pending++;
   REGISTER_HANDLE_REQ(loop, handle, req);
 
index c5ddbed..8b0e18c 100644 (file)
@@ -149,13 +149,13 @@ 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);
 
-  handle->accept_reqs = NULL;
-  handle->pending_accepts = NULL;
+  handle->tcp.serv.accept_reqs = NULL;
+  handle->tcp.serv.pending_accepts = NULL;
   handle->socket = INVALID_SOCKET;
   handle->reqs_pending = 0;
-  handle->func_acceptex = NULL;
-  handle->func_connectex = NULL;
-  handle->processed_accepts = 0;
+  handle->tcp.serv.func_acceptex = NULL;
+  handle->tcp.conn.func_connectex = NULL;
+  handle->tcp.serv.processed_accepts = 0;
   handle->delayed_error = 0;
 
   return 0;
@@ -168,10 +168,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
   uv_tcp_accept_t* req;
 
   if (handle->flags & UV_HANDLE_CONNECTION &&
-      handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
+      handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
 
-    UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
+    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
 
     err = 0;
     if (handle->flags & UV__HANDLE_CLOSING) {
@@ -180,12 +180,12 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
       err = WSAGetLastError();
     }
 
-    if (handle->shutdown_req->cb) {
-      handle->shutdown_req->cb(handle->shutdown_req,
+    if (handle->stream.conn.shutdown_req->cb) {
+      handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
                                uv_translate_sys_error(err));
     }
 
-    handle->shutdown_req = NULL;
+    handle->stream.conn.shutdown_req = NULL;
     DECREASE_PENDING_REQ_COUNT(handle);
     return;
   }
@@ -200,10 +200,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
       handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
     }
 
-    if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->accept_reqs) {
+    if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
       if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
         for (i = 0; i < uv_simultaneous_server_accepts; i++) {
-          req = &handle->accept_reqs[i];
+          req = &handle->tcp.serv.accept_reqs[i];
           if (req->wait_handle != INVALID_HANDLE_VALUE) {
             UnregisterWait(req->wait_handle);
             req->wait_handle = INVALID_HANDLE_VALUE;
@@ -215,8 +215,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
         }
       }
 
-      free(handle->accept_reqs);
-      handle->accept_reqs = NULL;
+      free(handle->tcp.serv.accept_reqs);
+      handle->tcp.serv.accept_reqs = NULL;
     }
 
     if (handle->flags & UV_HANDLE_CONNECTION &&
@@ -327,9 +327,9 @@ static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
   assert(!timed_out);
 
   if (!PostQueuedCompletionStatus(handle->loop->iocp,
-                                  req->overlapped.InternalHigh,
+                                  req->u.io.overlapped.InternalHigh,
                                   0,
-                                  &req->overlapped)) {
+                                  &req->u.io.overlapped)) {
     uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
   }
 }
@@ -346,9 +346,9 @@ static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
   assert(!timed_out);
 
   if (!PostQueuedCompletionStatus(handle->loop->iocp,
-                                  req->overlapped.InternalHigh,
+                                  req->u.io.overlapped.InternalHigh,
                                   0,
-                                  &req->overlapped)) {
+                                  &req->u.io.overlapped)) {
     uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
   }
 }
@@ -390,19 +390,19 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
   }
 
   /* Prepare the overlapped structure. */
-  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+  memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
   if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
-    req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+    req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
   }
 
-  success = handle->func_acceptex(handle->socket,
-                                  accept_socket,
-                                  (void*)req->accept_buffer,
-                                  0,
-                                  sizeof(struct sockaddr_storage),
-                                  sizeof(struct sockaddr_storage),
-                                  &bytes,
-                                  &req->overlapped);
+  success = handle->tcp.serv.func_acceptex(handle->socket,
+                                          accept_socket,
+                                          (void*)req->accept_buffer,
+                                          0,
+                                          sizeof(struct sockaddr_storage),
+                                          sizeof(struct sockaddr_storage),
+                                          &bytes,
+                                          &req->u.io.overlapped);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
     /* Process the req without IOCP. */
@@ -432,7 +432,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
     closesocket(accept_socket);
     /* Destroy the event handle */
     if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
-      CloseHandle(req->overlapped.hEvent);
+      CloseHandle(req->u.io.overlapped.hEvent);
       req->event_handle = NULL;
     }
   }
@@ -449,7 +449,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
   assert(!(handle->flags & UV_HANDLE_READ_PENDING));
 
   req = &handle->read_req;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
   /*
    * Preallocate a read buffer if the number of active streams is below
@@ -457,13 +457,13 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
   */
   if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
     handle->flags &= ~UV_HANDLE_ZERO_READ;
-    handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->read_buffer);
-    if (handle->read_buffer.len == 0) {
-      handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->read_buffer);
+    handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
+    if (handle->tcp.conn.read_buffer.len == 0) {
+      handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
       return;
     }
-    assert(handle->read_buffer.base != NULL);
-    buf = handle->read_buffer;
+    assert(handle->tcp.conn.read_buffer.base != NULL);
+    buf = handle->tcp.conn.read_buffer;
   } else {
     handle->flags |= UV_HANDLE_ZERO_READ;
     buf.base = (char*) &uv_zero_;
@@ -471,10 +471,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
   }
 
   /* Prepare the overlapped structure. */
-  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+  memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
   if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
     assert(req->event_handle);
-    req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+    req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
   }
 
   flags = 0;
@@ -483,13 +483,13 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
                    1,
                    &bytes,
                    &flags,
-                   &req->overlapped,
+                   &req->u.io.overlapped,
                    NULL);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
     /* Process the req without IOCP. */
     handle->flags |= UV_HANDLE_READ_PENDING;
-    req->overlapped.InternalHigh = bytes;
+    req->u.io.overlapped.InternalHigh = bytes;
     handle->reqs_pending++;
     uv_insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
@@ -522,7 +522,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
   assert(backlog > 0);
 
   if (handle->flags & UV_HANDLE_LISTENING) {
-    handle->connection_cb = cb;
+    handle->stream.serv.connection_cb = cb;
   }
 
   if (handle->flags & UV_HANDLE_READING) {
@@ -544,8 +544,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
       return handle->delayed_error;
   }
 
-  if (!handle->func_acceptex) {
-    if (!uv_get_acceptex_function(handle->socket, &handle->func_acceptex)) {
+  if (!handle->tcp.serv.func_acceptex) {
+    if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
       return WSAEAFNOSUPPORT;
     }
   }
@@ -556,21 +556,21 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
   }
 
   handle->flags |= UV_HANDLE_LISTENING;
-  handle->connection_cb = cb;
+  handle->stream.serv.connection_cb = cb;
   INCREASE_ACTIVE_COUNT(loop, handle);
 
   simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
     : uv_simultaneous_server_accepts;
 
-  if(!handle->accept_reqs) {
-    handle->accept_reqs = (uv_tcp_accept_t*)
+  if(!handle->tcp.serv.accept_reqs) {
+    handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
       malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
-    if (!handle->accept_reqs) {
+    if (!handle->tcp.serv.accept_reqs) {
       uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
     }
 
     for (i = 0; i < simultaneous_accepts; i++) {
-      req = &handle->accept_reqs[i];
+      req = &handle->tcp.serv.accept_reqs[i];
       uv_req_init(loop, (uv_req_t*)req);
       req->type = UV_ACCEPT;
       req->accept_socket = INVALID_SOCKET;
@@ -593,7 +593,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
     /* doesn't know how how many requests were initialized, so it will */
     /* try to clean up {uv_simultaneous_server_accepts} requests. */
     for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
-      req = &handle->accept_reqs[i];
+      req = &handle->tcp.serv.accept_reqs[i];
       uv_req_init(loop, (uv_req_t*) req);
       req->type = UV_ACCEPT;
       req->accept_socket = INVALID_SOCKET;
@@ -612,7 +612,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
   int err = 0;
   int family;
 
-  uv_tcp_accept_t* req = server->pending_accepts;
+  uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
 
   if (!req) {
     /* No valid connections found, so we error out. */
@@ -643,7 +643,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
   }
 
   /* Prepare the req to pick up a new connection */
-  server->pending_accepts = req->next_pending;
+  server->tcp.serv.pending_accepts = req->next_pending;
   req->next_pending = NULL;
   req->accept_socket = INVALID_SOCKET;
 
@@ -655,15 +655,15 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
       /* We better be switching to a single pending accept. */
       assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
 
-      server->processed_accepts++;
+      server->tcp.serv.processed_accepts++;
 
-      if (server->processed_accepts >= uv_simultaneous_server_accepts) {
-        server->processed_accepts = 0;
+      if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
+        server->tcp.serv.processed_accepts = 0;
         /*
          * All previously queued accept requests are now processed.
          * We now switch to queueing just a single accept.
          */
-        uv_tcp_queue_accept(server, &server->accept_reqs[0]);
+        uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
         server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
         server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
       }
@@ -732,8 +732,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
       return handle->delayed_error;
   }
 
-  if (!handle->func_connectex) {
-    if (!uv_get_connectex_function(handle->socket, &handle->func_connectex)) {
+  if (!handle->tcp.conn.func_connectex) {
+    if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
       return WSAEAFNOSUPPORT;
     }
   }
@@ -742,15 +742,15 @@ static int uv_tcp_try_connect(uv_connect_t* req,
   req->type = UV_CONNECT;
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
-  success = handle->func_connectex(handle->socket,
-                                   addr,
-                                   addrlen,
-                                   NULL,
-                                   0,
-                                   &bytes,
-                                   &req->overlapped);
+  success = handle->tcp.conn.func_connectex(handle->socket,
+                                           addr,
+                                           addrlen,
+                                           NULL,
+                                           0,
+                                           &bytes,
+                                           &req->u.io.overlapped);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
     /* Process the req without IOCP. */
@@ -828,13 +828,13 @@ int uv_tcp_write(uv_loop_t* loop,
   req->cb = cb;
 
   /* Prepare the overlapped structure. */
-  memset(&(req->overlapped), 0, sizeof(req->overlapped));
+  memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
   if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
     req->event_handle = CreateEvent(NULL, 0, 0, NULL);
     if (!req->event_handle) {
       uv_fatal_error(GetLastError(), "CreateEvent");
     }
-    req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+    req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
     req->wait_handle = INVALID_HANDLE_VALUE;
   }
 
@@ -843,23 +843,23 @@ int uv_tcp_write(uv_loop_t* loop,
                    nbufs,
                    &bytes,
                    0,
-                   &req->overlapped,
+                   &req->u.io.overlapped,
                    NULL);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
     /* Request completed immediately. */
-    req->queued_bytes = 0;
+    req->u.io.queued_bytes = 0;
     handle->reqs_pending++;
-    handle->write_reqs_pending++;
+    handle->stream.conn.write_reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*) req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
-    req->queued_bytes = uv__count_bufs(bufs, nbufs);
+    req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
     handle->reqs_pending++;
-    handle->write_reqs_pending++;
+    handle->stream.conn.write_reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
-    handle->write_queue_size += req->queued_bytes;
+    handle->write_queue_size += req->u.io.queued_bytes;
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
         !RegisterWaitForSingleObject(&req->wait_handle,
           req->event_handle, post_write_completion, (void*) req,
@@ -868,8 +868,13 @@ int uv_tcp_write(uv_loop_t* loop,
       uv_insert_pending_req(loop, (uv_req_t*)req);
     }
   } else {
-    /* Send failed due to an error. */
-    return WSAGetLastError();
+    /* Send failed due to an error, report it later */
+    req->u.io.queued_bytes = 0;
+    handle->reqs_pending++;
+    handle->stream.conn.write_reqs_pending++;
+    REGISTER_HANDLE_REQ(loop, handle, req);
+    SET_REQ_ERROR(req, WSAGetLastError());
+    uv_insert_pending_req(loop, (uv_req_t*) req);
   }
 
   return 0;
@@ -882,7 +887,7 @@ int uv__tcp_try_write(uv_tcp_t* handle,
   int result;
   DWORD bytes;
 
-  if (handle->write_reqs_pending > 0)
+  if (handle->stream.conn.write_reqs_pending > 0)
     return UV_EAGAIN;
 
   result = WSASend(handle->socket,
@@ -916,7 +921,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
       handle->flags &= ~UV_HANDLE_READING;
       DECREASE_ACTIVE_COUNT(loop, handle);
       buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
-            uv_buf_init(NULL, 0) : handle->read_buffer;
+            uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
 
       err = GET_REQ_SOCK_ERROR(req);
 
@@ -934,13 +939,13 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
   } else {
     if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
       /* The read was done with a non-zero buffer length. */
-      if (req->overlapped.InternalHigh > 0) {
+      if (req->u.io.overlapped.InternalHigh > 0) {
         /* Successful read */
         handle->read_cb((uv_stream_t*)handle,
-                        req->overlapped.InternalHigh,
-                        &handle->read_buffer);
+                        req->u.io.overlapped.InternalHigh,
+                        &handle->tcp.conn.read_buffer);
         /* Read again only if bytes == buf.len */
-        if (req->overlapped.InternalHigh < handle->read_buffer.len) {
+        if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
           goto done;
         }
       } else {
@@ -953,7 +958,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
 
         buf.base = 0;
         buf.len = 0;
-        handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->read_buffer);
+        handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
         goto done;
       }
     }
@@ -1032,8 +1037,8 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
 
   assert(handle->type == UV_TCP);
 
-  assert(handle->write_queue_size >= req->queued_bytes);
-  handle->write_queue_size -= req->queued_bytes;
+  assert(handle->write_queue_size >= req->u.io.queued_bytes);
+  handle->write_queue_size -= req->u.io.queued_bytes;
 
   UNREGISTER_HANDLE_REQ(loop, handle, req);
 
@@ -1057,9 +1062,9 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
     req->cb(req, err);
   }
 
-  handle->write_reqs_pending--;
-  if (handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
+  handle->stream.conn.write_reqs_pending--;
+  if (handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
 
@@ -1082,10 +1087,10 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
     if (handle->flags & UV_HANDLE_LISTENING) {
       handle->flags &= ~UV_HANDLE_LISTENING;
       DECREASE_ACTIVE_COUNT(loop, handle);
-      if (handle->connection_cb) {
+      if (handle->stream.serv.connection_cb) {
         err = GET_REQ_SOCK_ERROR(req);
-        handle->connection_cb((uv_stream_t*)handle,
-                              uv_translate_sys_error(err));
+        handle->stream.serv.connection_cb((uv_stream_t*)handle,
+                                      uv_translate_sys_error(err));
       }
     }
   } else if (REQ_SUCCESS(req) &&
@@ -1094,12 +1099,12 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
                   SO_UPDATE_ACCEPT_CONTEXT,
                   (char*)&handle->socket,
                   sizeof(handle->socket)) == 0) {
-    req->next_pending = handle->pending_accepts;
-    handle->pending_accepts = req;
+    req->next_pending = handle->tcp.serv.pending_accepts;
+    handle->tcp.serv.pending_accepts = req;
 
     /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
-    if (handle->connection_cb) {
-      handle->connection_cb((uv_stream_t*)handle, 0);
+    if (handle->stream.serv.connection_cb) {
+      handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
     }
   } else {
     /* Error related to accepted socket is ignored because the server */
@@ -1357,7 +1362,7 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
     }
 
   } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
-             tcp->accept_reqs != NULL) {
+             tcp->tcp.serv.accept_reqs != NULL) {
     /* Under normal circumstances closesocket() will ensure that all pending */
     /* accept reqs are canceled. However, when the socket is shared the */
     /* presence of another reference to the socket in another process will */
@@ -1371,9 +1376,9 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
       /* cause the connection to be aborted. */
       unsigned int i;
       for (i = 0; i < uv_simultaneous_server_accepts; i++) {
-        uv_tcp_accept_t* req = &tcp->accept_reqs[i];
+        uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
         if (req->accept_socket != INVALID_SOCKET &&
-            !HasOverlappedIoCompleted(&req->overlapped)) {
+            !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
           closesocket(req->accept_socket);
           req->accept_socket = INVALID_SOCKET;
         }
index 6034210..7b1e4ba 100644 (file)
@@ -142,28 +142,28 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
   if (readable) {
     /* Initialize TTY input specific fields. */
     tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
-    tty->read_line_handle = NULL;
-    tty->read_line_buffer = uv_null_buf_;
-    tty->read_raw_wait = NULL;
+    tty->tty.rd.read_line_handle = NULL;
+    tty->tty.rd.read_line_buffer = uv_null_buf_;
+    tty->tty.rd.read_raw_wait = NULL;
 
     /* Init keycode-to-vt100 mapper state. */
-    tty->last_key_len = 0;
-    tty->last_key_offset = 0;
-    tty->last_utf16_high_surrogate = 0;
-    memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
+    tty->tty.rd.last_key_len = 0;
+    tty->tty.rd.last_key_offset = 0;
+    tty->tty.rd.last_utf16_high_surrogate = 0;
+    memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
   } else {
     /* TTY output specific fields. */
     tty->flags |= UV_HANDLE_WRITABLE;
 
     /* Init utf8-to-utf16 conversion state. */
-    tty->utf8_bytes_left = 0;
-    tty->utf8_codepoint = 0;
+    tty->tty.wr.utf8_bytes_left = 0;
+    tty->tty.wr.utf8_codepoint = 0;
 
     /* Initialize eol conversion state */
-    tty->previous_eol = 0;
+    tty->tty.wr.previous_eol = 0;
 
     /* Init ANSI parser state. */
-    tty->ansi_parser_state = ANSI_NORMAL;
+    tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
   }
 
   return 0;
@@ -268,8 +268,8 @@ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
   handle = (uv_tty_t*) req->data;
   loop = handle->loop;
 
-  UnregisterWait(handle->read_raw_wait);
-  handle->read_raw_wait = NULL;
+  UnregisterWait(handle->tty.rd.read_raw_wait);
+  handle->tty.rd.read_raw_wait = NULL;
 
   SET_REQ_SUCCESS(req);
   POST_COMPLETION_FOR_REQ(loop, req);
@@ -285,19 +285,19 @@ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
 
   assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
 
-  handle->read_line_buffer = uv_null_buf_;
+  handle->tty.rd.read_line_buffer = uv_null_buf_;
 
   req = &handle->read_req;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
-  r = RegisterWaitForSingleObject(&handle->read_raw_wait,
+  r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
                                   handle->handle,
                                   uv_tty_post_raw_read,
                                   (void*) req,
                                   INFINITE,
                                   WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
   if (!r) {
-    handle->read_raw_wait = NULL;
+    handle->tty.rd.read_raw_wait = NULL;
     SET_REQ_ERROR(req, GetLastError());
     uv_insert_pending_req(loop, (uv_req_t*)req);
   }
@@ -321,12 +321,12 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
   handle = (uv_tty_t*) req->data;
   loop = handle->loop;
 
-  assert(handle->read_line_buffer.base != NULL);
-  assert(handle->read_line_buffer.len > 0);
+  assert(handle->tty.rd.read_line_buffer.base != NULL);
+  assert(handle->tty.rd.read_line_buffer.len > 0);
 
   /* ReadConsole can't handle big buffers. */
-  if (handle->read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
-    bytes = handle->read_line_buffer.len;
+  if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
+    bytes = handle->tty.rd.read_line_buffer.len;
   } else {
     bytes = MAX_INPUT_BUFFER_LENGTH;
   }
@@ -335,7 +335,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
   /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
   chars = bytes / 3;
 
-  if (ReadConsoleW(handle->read_line_handle,
+  if (ReadConsoleW(handle->tty.rd.read_line_handle,
                    (void*) utf16,
                    chars,
                    &read_chars,
@@ -344,12 +344,12 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
                                      0,
                                      utf16,
                                      read_chars,
-                                     handle->read_line_buffer.base,
+                                     handle->tty.rd.read_line_buffer.base,
                                      bytes,
                                      NULL,
                                      NULL);
     SET_REQ_SUCCESS(req);
-    req->overlapped.InternalHigh = read_bytes;
+    req->u.io.overlapped.InternalHigh = read_bytes;
   } else {
     SET_REQ_ERROR(req, GetLastError());
   }
@@ -368,30 +368,30 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
   assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
 
   req = &handle->read_req;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
-  handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->read_line_buffer);
-  if (handle->read_line_buffer.len == 0) {
+  handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
+  if (handle->tty.rd.read_line_buffer.len == 0) {
     handle->read_cb((uv_stream_t*) handle,
                     UV_ENOBUFS,
-                    &handle->read_line_buffer);
+                    &handle->tty.rd.read_line_buffer);
     return;
   }
-  assert(handle->read_line_buffer.base != NULL);
+  assert(handle->tty.rd.read_line_buffer.base != NULL);
 
   /* Duplicate the console handle, so if we want to cancel the read, we can */
   /* just close this handle duplicate. */
-  if (handle->read_line_handle == NULL) {
+  if (handle->tty.rd.read_line_handle == NULL) {
     HANDLE this_process = GetCurrentProcess();
     r = DuplicateHandle(this_process,
                         handle->handle,
                         this_process,
-                        &handle->read_line_handle,
+                        &handle->tty.rd.read_line_handle,
                         0,
                         0,
                         DUPLICATE_SAME_ACCESS);
     if (!r) {
-      handle->read_line_handle = NULL;
+      handle->tty.rd.read_line_handle = NULL;
       SET_REQ_ERROR(req, GetLastError());
       uv_insert_pending_req(loop, (uv_req_t*)req);
       goto out;
@@ -489,8 +489,8 @@ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
 
 void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* req) {
-  /* Shortcut for handle->last_input_record.Event.KeyEvent. */
-#define KEV handle->last_input_record.Event.KeyEvent
+  /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
+#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
 
   DWORD records_left, records_read;
   uv_buf_t buf;
@@ -531,12 +531,12 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
   buf = uv_null_buf_;
   buf_used = 0;
 
-  while ((records_left > 0 || handle->last_key_len > 0) &&
+  while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
          (handle->flags & UV_HANDLE_READING)) {
-    if (handle->last_key_len == 0) {
+    if (handle->tty.rd.last_key_len == 0) {
       /* Read the next input record */
       if (!ReadConsoleInputW(handle->handle,
-                             &handle->last_input_record,
+                             &handle->tty.rd.last_input_record,
                              1,
                              &records_read)) {
         handle->flags &= ~UV_HANDLE_READING;
@@ -551,7 +551,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
       /* If the window was resized, recompute the virtual window size. This */
       /* will trigger a SIGWINCH signal if the window size changed in an */
       /* way that matters to libuv. */
-      if (handle->last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+      if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
         CONSOLE_SCREEN_BUFFER_INFO info;
 
         EnterCriticalSection(&uv_tty_output_lock);
@@ -567,7 +567,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
       }
 
       /* Ignore other events that are not key or resize events. */
-      if (handle->last_input_record.EventType != KEY_EVENT) {
+      if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
         continue;
       }
 
@@ -613,7 +613,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         if (KEV.uChar.UnicodeChar >= 0xD800 &&
             KEV.uChar.UnicodeChar < 0xDC00) {
           /* UTF-16 high surrogate */
-          handle->last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
+          handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
           continue;
         }
 
@@ -622,7 +622,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
             && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
             RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
-          handle->last_key[0] = '\033';
+          handle->tty.rd.last_key[0] = '\033';
           prefix_len = 1;
         } else {
           prefix_len = 0;
@@ -631,14 +631,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         if (KEV.uChar.UnicodeChar >= 0xDC00 &&
             KEV.uChar.UnicodeChar < 0xE000) {
           /* UTF-16 surrogate pair */
-          WCHAR utf16_buffer[2] = { handle->last_utf16_high_surrogate,
+          WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
                                     KEV.uChar.UnicodeChar};
           char_len = WideCharToMultiByte(CP_UTF8,
                                          0,
                                          utf16_buffer,
                                          2,
-                                         &handle->last_key[prefix_len],
-                                         sizeof handle->last_key,
+                                         &handle->tty.rd.last_key[prefix_len],
+                                         sizeof handle->tty.rd.last_key,
                                          NULL,
                                          NULL);
         } else {
@@ -647,14 +647,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
                                          0,
                                          &KEV.uChar.UnicodeChar,
                                          1,
-                                         &handle->last_key[prefix_len],
-                                         sizeof handle->last_key,
+                                         &handle->tty.rd.last_key[prefix_len],
+                                         sizeof handle->tty.rd.last_key,
                                          NULL,
                                          NULL);
         }
 
         /* Whatever happened, the last character wasn't a high surrogate. */
-        handle->last_utf16_high_surrogate = 0;
+        handle->tty.rd.last_utf16_high_surrogate = 0;
 
         /* If the utf16 character(s) couldn't be converted something must */
         /* be wrong. */
@@ -667,8 +667,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
           goto out;
         }
 
-        handle->last_key_len = (unsigned char) (prefix_len + char_len);
-        handle->last_key_offset = 0;
+        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
+        handle->tty.rd.last_key_offset = 0;
         continue;
 
       } else {
@@ -690,23 +690,23 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
 
         /* Prefix with \x033 when the alt key was held. */
         if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
-          handle->last_key[0] = '\033';
+          handle->tty.rd.last_key[0] = '\033';
           prefix_len = 1;
         } else {
           prefix_len = 0;
         }
 
         /* Copy the vt100 sequence to the handle buffer. */
-        assert(prefix_len + vt100_len < sizeof handle->last_key);
-        memcpy(&handle->last_key[prefix_len], vt100, vt100_len);
+        assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
+        memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
 
-        handle->last_key_len = (unsigned char) (prefix_len + vt100_len);
-        handle->last_key_offset = 0;
+        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
+        handle->tty.rd.last_key_offset = 0;
         continue;
       }
     } else {
       /* Copy any bytes left from the last keypress to the user buffer. */
-      if (handle->last_key_offset < handle->last_key_len) {
+      if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
         /* Allocate a buffer if needed */
         if (buf_used == 0) {
           handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
@@ -717,7 +717,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
           assert(buf.base != NULL);
         }
 
-        buf.base[buf_used++] = handle->last_key[handle->last_key_offset++];
+        buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
 
         /* If the buffer is full, emit it */
         if ((size_t) buf_used == buf.len) {
@@ -731,11 +731,11 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
 
       /* Apply dwRepeat from the last input record. */
       if (--KEV.wRepeatCount > 0) {
-        handle->last_key_offset = 0;
+        handle->tty.rd.last_key_offset = 0;
         continue;
       }
 
-      handle->last_key_len = 0;
+      handle->tty.rd.last_key_len = 0;
       continue;
     }
   }
@@ -766,15 +766,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
   assert(handle->type == UV_TTY);
   assert(handle->flags & UV_HANDLE_TTY_READABLE);
 
-  buf = handle->read_line_buffer;
+  buf = handle->tty.rd.read_line_buffer;
 
   handle->flags &= ~UV_HANDLE_READ_PENDING;
-  handle->read_line_buffer = uv_null_buf_;
+  handle->tty.rd.read_line_buffer = uv_null_buf_;
 
   if (!REQ_SUCCESS(req)) {
     /* Read was not successful */
     if ((handle->flags & UV_HANDLE_READING) &&
-        handle->read_line_handle != NULL) {
+        handle->tty.rd.read_line_handle != NULL) {
       /* Real error */
       handle->flags &= ~UV_HANDLE_READING;
       DECREASE_ACTIVE_COUNT(loop, handle);
@@ -789,7 +789,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
   } else {
     /* Read successful */
     /* TODO: read unicode, convert to utf-8 */
-    DWORD bytes = req->overlapped.InternalHigh;
+    DWORD bytes = req->u.io.overlapped.InternalHigh;
     handle->read_cb((uv_stream_t*) handle, bytes, &buf);
   }
 
@@ -811,7 +811,7 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
   /* If the read_line_buffer member is zero, it must have been an raw read. */
   /* Otherwise it was a line-buffered read. */
   /* FIXME: This is quite obscure. Use a flag or something. */
-  if (handle->read_line_buffer.len == 0) {
+  if (handle->tty.rd.read_line_buffer.len == 0) {
     uv_process_tty_read_raw_req(loop, handle, req);
   } else {
     uv_process_tty_read_line_req(loop, handle, req);
@@ -840,7 +840,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
 
   /* Maybe the user stopped reading half-way while processing key events. */
   /* Short-circuit if this could be the case. */
-  if (handle->last_key_len > 0) {
+  if (handle->tty.rd.last_key_len > 0) {
     SET_REQ_SUCCESS(&handle->read_req);
     uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
     return 0;
@@ -869,10 +869,10 @@ int uv_tty_read_stop(uv_tty_t* handle) {
   }
 
   /* Cancel line-buffered read */
-  if (handle->read_line_handle != NULL) {
+  if (handle->tty.rd.read_line_handle != NULL) {
     /* Closing this handle will cancel the ReadConsole operation */
-    CloseHandle(handle->read_line_handle);
-    handle->read_line_handle = NULL;
+    CloseHandle(handle->tty.rd.read_line_handle);
+    handle->tty.rd.read_line_handle = NULL;
   }
 
 
@@ -1149,8 +1149,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     } while (0)
 
 static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
-  unsigned short argc = handle->ansi_csi_argc;
-  unsigned short* argv = handle->ansi_csi_argv;
+  unsigned short argc = handle->tty.wr.ansi_csi_argc;
+  unsigned short* argv = handle->tty.wr.ansi_csi_argv;
   int i;
   CONSOLE_SCREEN_BUFFER_INFO info;
 
@@ -1319,12 +1319,12 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
 
   uv_tty_update_virtual_window(&info);
 
-  handle->saved_position.X = info.dwCursorPosition.X;
-  handle->saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+  handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
+  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
   handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
 
   if (save_attributes) {
-    handle->saved_attributes = info.wAttributes &
+    handle->tty.wr.saved_attributes = info.wAttributes &
         (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
     handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
   }
@@ -1344,9 +1344,9 @@ static int uv_tty_restore_state(uv_tty_t* handle,
 
   if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
     if (uv_tty_move_caret(handle,
-                          handle->saved_position.X,
+                          handle->tty.wr.saved_position.X,
                           0,
-                          handle->saved_position.Y,
+                          handle->tty.wr.saved_position.Y,
                           0,
                           error) != 0) {
       return -1;
@@ -1362,7 +1362,7 @@ static int uv_tty_restore_state(uv_tty_t* handle,
 
     new_attributes = info.wAttributes;
     new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
-    new_attributes |= handle->saved_attributes;
+    new_attributes |= handle->tty.wr.saved_attributes;
 
     if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
       *error = GetLastError();
@@ -1412,10 +1412,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
   } while (0)
 
   /* Cache for fast access */
-  unsigned char utf8_bytes_left = handle->utf8_bytes_left;
-  unsigned int utf8_codepoint = handle->utf8_codepoint;
-  unsigned char previous_eol = handle->previous_eol;
-  unsigned char ansi_parser_state = handle->ansi_parser_state;
+  unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
+  unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
+  unsigned char previous_eol = handle->tty.wr.previous_eol;
+  unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
 
   /* Store the error here. If we encounter an error, stop trying to do i/o */
   /* but keep parsing the buffer so we leave the parser in a consistent */
@@ -1492,7 +1492,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 
           case 0233:
             ansi_parser_state = ANSI_CSI;
-            handle->ansi_csi_argc = 0;
+            handle->tty.wr.ansi_csi_argc = 0;
             continue;
         }
 
@@ -1500,7 +1500,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         switch (utf8_codepoint) {
           case '[':
             ansi_parser_state = ANSI_CSI;
-            handle->ansi_csi_argc = 0;
+            handle->tty.wr.ansi_csi_argc = 0;
             continue;
 
           case '^':
@@ -1557,20 +1557,20 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               /* We were not currently parsing a number */
 
               /* Check for too many arguments */
-              if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) {
+              if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
                 ansi_parser_state |= ANSI_IGNORE;
                 continue;
               }
 
               ansi_parser_state |= ANSI_IN_ARG;
-              handle->ansi_csi_argc++;
-              handle->ansi_csi_argv[handle->ansi_csi_argc - 1] =
+              handle->tty.wr.ansi_csi_argc++;
+              handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
                   (unsigned short) utf8_codepoint - '0';
               continue;
             } else {
               /* We were already parsing a number. Parse next digit. */
               uint32_t value = 10 *
-                  handle->ansi_csi_argv[handle->ansi_csi_argc - 1];
+                  handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
 
               /* Check for overflow. */
               if (value > UINT16_MAX) {
@@ -1578,7 +1578,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 continue;
               }
 
-               handle->ansi_csi_argv[handle->ansi_csi_argc - 1] =
+               handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
                    (unsigned short) value + (utf8_codepoint - '0');
                continue;
             }
@@ -1593,25 +1593,25 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               /* If ANSI_IN_ARG is not set, add another argument and */
               /* default it to 0. */
               /* Check for too many arguments */
-              if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) {
+              if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
                 ansi_parser_state |= ANSI_IGNORE;
                 continue;
               }
 
-              handle->ansi_csi_argc++;
-              handle->ansi_csi_argv[handle->ansi_csi_argc - 1] = 0;
+              handle->tty.wr.ansi_csi_argc++;
+              handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
               continue;
             }
 
           } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
-                     handle->ansi_csi_argc == 0) {
+                     handle->tty.wr.ansi_csi_argc == 0) {
             /* Ignores '?' if it is the first character after CSI[ */
             /* This is an extension character from the VT100 codeset */
             /* that is supported and used by most ANSI terminals today. */
             continue;
 
           } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
-                     (handle->ansi_csi_argc > 0 || utf8_codepoint != '[')) {
+                     (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
             int x, y, d;
 
             /* Command byte */
@@ -1619,50 +1619,50 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               case 'A':
                 /* cursor up */
                 FLUSH_TEXT();
-                y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
+                y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
                 uv_tty_move_caret(handle, 0, 1, y, 1, error);
                 break;
 
               case 'B':
                 /* cursor down */
                 FLUSH_TEXT();
-                y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
+                y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
                 uv_tty_move_caret(handle, 0, 1, y, 1, error);
                 break;
 
               case 'C':
                 /* cursor forward */
                 FLUSH_TEXT();
-                x = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
+                x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
                 uv_tty_move_caret(handle, x, 1, 0, 1, error);
                 break;
 
               case 'D':
                 /* cursor back */
                 FLUSH_TEXT();
-                x = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
+                x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
                 uv_tty_move_caret(handle, x, 1, 0, 1, error);
                 break;
 
               case 'E':
                 /* cursor next line */
                 FLUSH_TEXT();
-                y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
+                y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
                 uv_tty_move_caret(handle, 0, 0, y, 1, error);
                 break;
 
               case 'F':
                 /* cursor previous line */
                 FLUSH_TEXT();
-                y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
+                y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
                 uv_tty_move_caret(handle, 0, 0, y, 1, error);
                 break;
 
               case 'G':
                 /* cursor horizontal move absolute */
                 FLUSH_TEXT();
-                x = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0])
-                  ? handle->ansi_csi_argv[0] - 1 : 0;
+                x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
                 uv_tty_move_caret(handle, x, 0, 0, 1, error);
                 break;
 
@@ -1670,17 +1670,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               case 'f':
                 /* cursor move absolute */
                 FLUSH_TEXT();
-                y = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0])
-                  ? handle->ansi_csi_argv[0] - 1 : 0;
-                x = (handle->ansi_csi_argc >= 2 && handle->ansi_csi_argv[1])
-                  ? handle->ansi_csi_argv[1] - 1 : 0;
+                y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+                x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+                  ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
                 uv_tty_move_caret(handle, x, 0, y, 0, error);
                 break;
 
               case 'J':
                 /* Erase screen */
                 FLUSH_TEXT();
-                d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0;
+                d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
                 if (d >= 0 && d <= 2) {
                   uv_tty_clear(handle, d, 1, error);
                 }
@@ -1689,7 +1689,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               case 'K':
                 /* Erase line */
                 FLUSH_TEXT();
-                d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0;
+                d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
                 if (d >= 0 && d <= 2) {
                   uv_tty_clear(handle, d, 0, error);
                 }
@@ -1715,8 +1715,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 
               case 'l':
                 /* Hide the cursor */
-                if (handle->ansi_csi_argc == 1 &&
-                    handle->ansi_csi_argv[0] == 25) {
+                if (handle->tty.wr.ansi_csi_argc == 1 &&
+                    handle->tty.wr.ansi_csi_argv[0] == 25) {
                   FLUSH_TEXT();
                   uv_tty_set_cursor_visibility(handle, 0, error);
                 }
@@ -1724,8 +1724,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 
               case 'h':
                 /* Show the cursor */
-                if (handle->ansi_csi_argc == 1 &&
-                    handle->ansi_csi_argv[0] == 25) {
+                if (handle->tty.wr.ansi_csi_argc == 1 &&
+                    handle->tty.wr.ansi_csi_argv[0] == 25) {
                   FLUSH_TEXT();
                   uv_tty_set_cursor_visibility(handle, 1, error);
                 }
@@ -1830,10 +1830,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
   FLUSH_TEXT();
 
   /* Copy cached values back to struct. */
-  handle->utf8_bytes_left = utf8_bytes_left;
-  handle->utf8_codepoint = utf8_codepoint;
-  handle->previous_eol = previous_eol;
-  handle->ansi_parser_state = ansi_parser_state;
+  handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
+  handle->tty.wr.utf8_codepoint = utf8_codepoint;
+  handle->tty.wr.previous_eol = previous_eol;
+  handle->tty.wr.ansi_parser_state = ansi_parser_state;
 
   LeaveCriticalSection(&uv_tty_output_lock);
 
@@ -1861,10 +1861,10 @@ int uv_tty_write(uv_loop_t* loop,
   req->cb = cb;
 
   handle->reqs_pending++;
-  handle->write_reqs_pending++;
+  handle->stream.conn.write_reqs_pending++;
   REGISTER_HANDLE_REQ(loop, handle, req);
 
-  req->queued_bytes = 0;
+  req->u.io.queued_bytes = 0;
 
   if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
     SET_REQ_SUCCESS(req);
@@ -1883,7 +1883,7 @@ int uv__tty_try_write(uv_tty_t* handle,
                       unsigned int nbufs) {
   DWORD error;
 
-  if (handle->write_reqs_pending > 0)
+  if (handle->stream.conn.write_reqs_pending > 0)
     return UV_EAGAIN;
 
   if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
@@ -1897,7 +1897,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
   uv_write_t* req) {
   int err;
 
-  handle->write_queue_size -= req->queued_bytes;
+  handle->write_queue_size -= req->u.io.queued_bytes;
   UNREGISTER_HANDLE_REQ(loop, handle, req);
 
   if (req->cb) {
@@ -1905,9 +1905,9 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
     req->cb(req, uv_translate_sys_error(err));
   }
 
-  handle->write_reqs_pending--;
-  if (handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
+  handle->stream.conn.write_reqs_pending--;
+  if (handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
 
@@ -1933,20 +1933,20 @@ void uv_tty_close(uv_tty_t* handle) {
 
 void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
   if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
-      handle->shutdown_req != NULL &&
-      handle->write_reqs_pending == 0) {
-    UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
+      handle->stream.conn.shutdown_req != NULL &&
+      handle->stream.conn.write_reqs_pending == 0) {
+    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
 
     /* TTY shutdown is really just a no-op */
-    if (handle->shutdown_req->cb) {
+    if (handle->stream.conn.shutdown_req->cb) {
       if (handle->flags & UV__HANDLE_CLOSING) {
-        handle->shutdown_req->cb(handle->shutdown_req, UV_ECANCELED);
+        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
       } else {
-        handle->shutdown_req->cb(handle->shutdown_req, 0);
+        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
       }
     }
 
-    handle->shutdown_req = NULL;
+    handle->stream.conn.shutdown_req = NULL;
 
     DECREASE_PENDING_REQ_COUNT(handle);
     return;
@@ -1957,12 +1957,12 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
     /* The console handle duplicate used for line reading should be destroyed */
     /* by uv_tty_read_stop. */
     assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
-           handle->read_line_handle == NULL);
+           handle->tty.rd.read_line_handle == NULL);
 
     /* The wait handle used for raw reading should be unregistered when the */
     /* wait callback runs. */
     assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
-           handle->read_raw_wait == NULL);
+           handle->tty.rd.read_raw_wait == NULL);
 
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_close(handle);
index 73b5bd5..197e5d8 100644 (file)
@@ -244,7 +244,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
   assert(!(handle->flags & UV_HANDLE_READ_PENDING));
 
   req = &handle->recv_req;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
   /*
    * Preallocate a read buffer if the number of active streams is below
@@ -272,13 +272,13 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
                                       &flags,
                                       (struct sockaddr*) &handle->recv_from,
                                       &handle->recv_from_len,
-                                      &req->overlapped,
+                                      &req->u.io.overlapped,
                                       NULL);
 
     if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
       /* Process the req without IOCP. */
       handle->flags |= UV_HANDLE_READ_PENDING;
-      req->overlapped.InternalHigh = bytes;
+      req->u.io.overlapped.InternalHigh = bytes;
       handle->reqs_pending++;
       uv_insert_pending_req(loop, req);
     } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
@@ -304,13 +304,13 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
                                   1,
                                   &bytes,
                                   &flags,
-                                  &req->overlapped,
+                                  &req->u.io.overlapped,
                                   NULL);
 
     if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
       /* Process the req without IOCP. */
       handle->flags |= UV_HANDLE_READ_PENDING;
-      req->overlapped.InternalHigh = bytes;
+      req->u.io.overlapped.InternalHigh = bytes;
       handle->reqs_pending++;
       uv_insert_pending_req(loop, req);
     } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
@@ -384,7 +384,7 @@ static int uv__send(uv_udp_send_t* req,
   req->type = UV_UDP_SEND;
   req->handle = handle;
   req->cb = cb;
-  memset(&req->overlapped, 0, sizeof(req->overlapped));
+  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
   result = WSASendTo(handle->socket,
                      (WSABUF*)bufs,
@@ -393,22 +393,22 @@ static int uv__send(uv_udp_send_t* req,
                      0,
                      addr,
                      addrlen,
-                     &req->overlapped,
+                     &req->u.io.overlapped,
                      NULL);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
     /* Request completed immediately. */
-    req->queued_bytes = 0;
+    req->u.io.queued_bytes = 0;
     handle->reqs_pending++;
-    handle->send_queue_size += req->queued_bytes;
+    handle->send_queue_size += req->u.io.queued_bytes;
     handle->send_queue_count++;
     REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
-    req->queued_bytes = uv__count_bufs(bufs, nbufs);
+    req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
     handle->reqs_pending++;
-    handle->send_queue_size += req->queued_bytes;
+    handle->send_queue_size += req->u.io.queued_bytes;
     handle->send_queue_count++;
     REGISTER_HANDLE_REQ(loop, handle, req);
   } else {
@@ -459,7 +459,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
     /* Successful read */
     partial = !REQ_SUCCESS(req);
     handle->recv_cb(handle,
-                    req->overlapped.InternalHigh,
+                    req->u.io.overlapped.InternalHigh,
                     &handle->recv_buffer,
                     (const struct sockaddr*) &handle->recv_from,
                     partial ? UV_UDP_PARTIAL : 0);
@@ -536,9 +536,9 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
 
   assert(handle->type == UV_UDP);
 
-  assert(handle->send_queue_size >= req->queued_bytes);
+  assert(handle->send_queue_size >= req->u.io.queued_bytes);
   assert(handle->send_queue_count >= 1);
-  handle->send_queue_size -= req->queued_bytes;
+  handle->send_queue_size -= req->u.io.queued_bytes;
   handle->send_queue_count--;
 
   UNREGISTER_HANDLE_REQ(loop, handle, req);
index 43d843f..3697d5a 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 #include <direct.h>
 #include <limits.h>
-#include <malloc.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
@@ -535,14 +534,14 @@ int uv_uptime(double* uptime) {
       return uv_translate_sys_error(result);
     }
 
-    free(malloced_buffer);
-
     buffer_size *= 2;
     /* Don't let the buffer grow infinitely. */
     if (buffer_size > 1 << 20) {
       goto internalError;
     }
 
+    free(malloced_buffer);
+
     buffer = malloced_buffer = (BYTE*) malloc(buffer_size);
     if (malloced_buffer == NULL) {
       *uptime = 0;
index c7f99a2..1dbc23d 100644 (file)
@@ -83,8 +83,9 @@ BENCHMARK_IMPL(getaddrinfo) {
   ASSERT(calls_initiated == TOTAL_CALLS);
   ASSERT(calls_completed == TOTAL_CALLS);
 
-  LOGF("getaddrinfo: %.0f req/s\n",
-       (double) calls_completed / (double) (end_time - start_time) * 1000.0);
+  fprintf(stderr, "getaddrinfo: %.0f req/s\n",
+          (double) calls_completed / (double) (end_time - start_time) * 1000.0);
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index 5cb8132..970a94c 100644 (file)
@@ -62,10 +62,11 @@ BENCHMARK_IMPL(loop_count) {
 
   ASSERT(ticks == NUM_TICKS);
 
-  LOGF("loop_count: %d ticks in %.2fs (%.0f/s)\n",
-       NUM_TICKS,
-       ns / 1e9,
-       NUM_TICKS / (ns / 1e9));
+  fprintf(stderr, "loop_count: %d ticks in %.2fs (%.0f/s)\n",
+          NUM_TICKS,
+          ns / 1e9,
+          NUM_TICKS / (ns / 1e9));
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
@@ -83,7 +84,8 @@ BENCHMARK_IMPL(loop_count_timed) {
 
   uv_run(loop, UV_RUN_DEFAULT);
 
-  LOGF("loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);
+  fprintf(stderr, "loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index 6027d60..60a308b 100644 (file)
@@ -75,10 +75,11 @@ BENCHMARK_IMPL(million_timers) {
   ASSERT(close_cb_called == NUM_TIMERS);
   free(timers);
 
-  LOGF("%.2f seconds total\n", (after_all - before_all) / 1e9);
-  LOGF("%.2f seconds init\n", (before_run - before_all) / 1e9);
-  LOGF("%.2f seconds dispatch\n", (after_run - before_run) / 1e9);
-  LOGF("%.2f seconds cleanup\n", (after_all - after_run) / 1e9);
+  fprintf(stderr, "%.2f seconds total\n", (after_all - before_all) / 1e9);
+  fprintf(stderr, "%.2f seconds init\n", (before_run - before_all) / 1e9);
+  fprintf(stderr, "%.2f seconds dispatch\n", (after_run - before_run) / 1e9);
+  fprintf(stderr, "%.2f seconds cleanup\n", (after_all - after_run) / 1e9);
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index bb560d7..646a7df 100644 (file)
@@ -80,7 +80,8 @@ static void pinger_close_cb(uv_handle_t* handle) {
   pinger_t* pinger;
 
   pinger = (pinger_t*)handle->data;
-  LOGF("ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
+  fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
+  fflush(stderr);
 
   free(pinger);
 
index 5879285..79f3634 100644 (file)
@@ -299,11 +299,12 @@ static int pound_it(int concurrency,
   /* Number of fractional seconds it took to run the benchmark. */
   secs = (double)(end_time - start_time) / NANOSEC;
 
-  LOGF("%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
-       type,
-       concurrency,
-       closed_streams / secs,
-       conns_failed);
+  fprintf(stderr, "%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
+          type,
+          concurrency,
+          closed_streams / secs,
+          conns_failed);
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index d58f46a..88f2dc5 100644 (file)
@@ -90,9 +90,10 @@ static void show_stats(uv_timer_t* handle) {
   int i;
 
 #if PRINT_STATS
-  LOGF("connections: %d, write: %.1f gbit/s\n",
-       write_sockets,
-       gbit(nsent, STATS_INTERVAL));
+  fprintf(stderr, "connections: %d, write: %.1f gbit/s\n",
+          write_sockets,
+          gbit(nsent, STATS_INTERVAL));
+  fflush(stderr);
 #endif
 
   /* Exit if the show is over */
@@ -101,10 +102,11 @@ static void show_stats(uv_timer_t* handle) {
     uv_update_time(loop);
     diff = uv_now(loop) - start_time;
 
-    LOGF("%s_pump%d_client: %.1f gbit/s\n",
-         type == TCP ? "tcp" : "pipe",
-         write_sockets,
-         gbit(nsent_total, diff));
+    fprintf(stderr, "%s_pump%d_client: %.1f gbit/s\n",
+            type == TCP ? "tcp" : "pipe",
+            write_sockets,
+            gbit(nsent_total, diff));
+    fflush(stderr);
 
     for (i = 0; i < write_sockets; i++) {
       if (type == TCP)
@@ -128,10 +130,11 @@ static void read_show_stats(void) {
   uv_update_time(loop);
   diff = uv_now(loop) - start_time;
 
-  LOGF("%s_pump%d_server: %.1f gbit/s\n",
-       type == TCP ? "tcp" : "pipe",
-       max_read_sockets,
-       gbit(nrecv_total, diff));
+  fprintf(stderr, "%s_pump%d_server: %.1f gbit/s\n",
+          type == TCP ? "tcp" : "pipe",
+          max_read_sockets,
+          gbit(nrecv_total, diff));
+  fflush(stderr);
 }
 
 
@@ -213,7 +216,10 @@ static void do_write(uv_stream_t* stream) {
 static void connect_cb(uv_connect_t* req, int status) {
   int i;
 
-  if (status) LOG(uv_strerror(status));
+  if (status) {
+    fprintf(stderr, "%s", uv_strerror(status));
+    fflush(stderr);
+  }
   ASSERT(status == 0);
 
   write_sockets++;
index 8ccf10e..9bf42f9 100644 (file)
 
 
 BENCHMARK_IMPL(sizes) {
-  LOGF("uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t));
-  LOGF("uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t));
-  LOGF("uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t));
-  LOGF("uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t));
-  LOGF("uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t));
-  LOGF("uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t));
-  LOGF("uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t));
-  LOGF("uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t));
-  LOGF("uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t));
-  LOGF("uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
-  LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
-  LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
-  LOGF("uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
-  LOGF("uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
-  LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
-  LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
-  LOGF("uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t));
+  fprintf(stderr, "uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t));
+  fprintf(stderr, "uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t));
+  fprintf(stderr, "uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t));
+  fprintf(stderr, "uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t));
+  fprintf(stderr, "uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t));
+  fprintf(stderr, "uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t));
+  fprintf(stderr, "uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t));
+  fprintf(stderr, "uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t));
+  fprintf(stderr, "uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t));
+  fprintf(stderr, "uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
+  fprintf(stderr, "uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
+  fprintf(stderr, "uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
+  fprintf(stderr, "uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
+  fprintf(stderr, "uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
+  fprintf(stderr, "uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
+  fprintf(stderr, "uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
+  fprintf(stderr, "uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t));
+  fflush(stderr);
   return 0;
 }
index 9cae41a..ed9ad60 100644 (file)
@@ -155,8 +155,9 @@ BENCHMARK_IMPL(spawn) {
   uv_update_time(loop);
   end_time = uv_now(loop);
 
-  LOGF("spawn: %.0f spawns/s\n",
-       (double) N / (double) (end_time - start_time) * 1000.0);
+  fprintf(stderr, "spawn: %.0f spawns/s\n",
+          (double) N / (double) (end_time - start_time) * 1000.0);
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index 8d4f549..6e42623 100644 (file)
@@ -41,7 +41,8 @@ int main(int argc, char **argv) {
   case 2: return maybe_run_test(argc, argv);
   case 3: return run_test_part(argv[1], argv[2]);
   default:
-    LOGF("Too many arguments.\n");
+    fprintf(stderr, "Too many arguments.\n");
+    fflush(stderr);
     return EXIT_FAILURE;
   }
 
index e92c930..1f45874 100644 (file)
@@ -56,7 +56,8 @@ int main(int argc, char **argv) {
   case 2: return maybe_run_test(argc, argv);
   case 3: return run_test_part(argv[1], argv[2]);
   default:
-    LOGF("Too many arguments.\n");
+    fprintf(stderr, "Too many arguments.\n");
+    fflush(stderr);
     return EXIT_FAILURE;
   }
 
index e896d43..e094def 100644 (file)
@@ -43,13 +43,14 @@ static void log_progress(int total,
     total = 1;
 
   progress = 100 * (passed + failed + skipped + todos) / total;
-  LOGF("[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
-       progress,
-       passed,
-       failed,
-       todos,
-       skipped,
-       name);
+  fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
+          progress,
+          passed,
+          failed,
+          todos,
+          skipped,
+          name);
+  fflush(stderr);
 }
 
 
@@ -109,7 +110,8 @@ int run_tests(int benchmark_output) {
   }
 
   if (tap_output) {
-    LOGF("1..%d\n", total);
+    fprintf(stderr, "1..%d\n", total);
+    fflush(stderr);
   }
 
   /* Run all tests. */
@@ -184,7 +186,8 @@ void log_tap_result(int test_count,
     reason[0] = '\0';
   }
 
-  LOGF("%s %d - %s%s%s\n", result, test_count, test, directive, reason);
+  fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
+  fflush(stderr);
 }
 
 
@@ -320,49 +323,55 @@ out:
   /* Show error and output from processes if the test failed. */
   if (status != 0 || task->show_output) {
     if (tap_output) {
-      LOGF("#");
+      fprintf(stderr, "#");
     } else if (status == TEST_TODO) {
-      LOGF("\n`%s` todo\n", test);
+      fprintf(stderr, "\n`%s` todo\n", test);
     } else if (status == TEST_SKIP) {
-      LOGF("\n`%s` skipped\n", test);
+      fprintf(stderr, "\n`%s` skipped\n", test);
     } else if (status != 0) {
-      LOGF("\n`%s` failed: %s\n", test, errmsg);
+      fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
     } else {
-      LOGF("\n");
+      fprintf(stderr, "\n");
     }
+    fflush(stderr);
 
     for (i = 0; i < process_count; i++) {
       switch (process_output_size(&processes[i])) {
        case -1:
-        LOGF("Output from process `%s`: (unavailable)\n",
-             process_get_name(&processes[i]));
+        fprintf(stderr, "Output from process `%s`: (unavailable)\n",
+                process_get_name(&processes[i]));
+        fflush(stderr);
         break;
 
        case 0:
-        LOGF("Output from process `%s`: (no output)\n",
-             process_get_name(&processes[i]));
+        fprintf(stderr, "Output from process `%s`: (no output)\n",
+                process_get_name(&processes[i]));
+        fflush(stderr);
         break;
 
        default:
-        LOGF("Output from process `%s`:\n", process_get_name(&processes[i]));
+        fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
+        fflush(stderr);
         process_copy_output(&processes[i], fileno(stderr));
         break;
       }
     }
 
     if (!tap_output) {
-      LOG("=============================================================\n");
+      fprintf(stderr, "=============================================================\n");
     }
 
   /* In benchmark mode show concise output from the main process. */
   } else if (benchmark_output) {
     switch (process_output_size(main_proc)) {
      case -1:
-      LOGF("%s: (unavailable)\n", test);
+      fprintf(stderr, "%s: (unavailable)\n", test);
+      fflush(stderr);
       break;
 
      case 0:
-      LOGF("%s: (no output)\n", test);
+      fprintf(stderr, "%s: (no output)\n", test);
+      fflush(stderr);
       break;
 
      default:
@@ -397,7 +406,8 @@ int run_test_part(const char* test, const char* part) {
     }
   }
 
-  LOGF("No test part with that name: %s:%s\n", test, part);
+  fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
+  fflush(stderr);
   return 255;
 }
 
index 07584c5..ea0503e 100644 (file)
@@ -76,19 +76,6 @@ typedef enum {
   PIPE
 } stream_type;
 
-/* Log to stderr. */
-#define LOG(...)                        \
-  do {                                  \
-    fprintf(stderr, "%s", __VA_ARGS__); \
-    fflush(stderr);                     \
-  } while (0)
-
-#define LOGF(...)                       \
-  do {                                  \
-    fprintf(stderr, __VA_ARGS__);       \
-    fflush(stderr);                     \
-  } while (0)
-
 /* Die with fatal error. */
 #define FATAL(msg)                                        \
   do {                                                    \
@@ -158,13 +145,15 @@ enum test_status {
 
 #define RETURN_TODO(explanation)                                              \
   do {                                                                        \
-    LOGF("%s\n", explanation);                                                \
+    fprintf(stderr, "%s\n", explanation);                                     \
+    fflush(stderr);                                                           \
     return TEST_TODO;                                                         \
   } while (0)
 
 #define RETURN_SKIP(explanation)                                              \
   do {                                                                        \
-    LOGF("%s\n", explanation);                                                \
+    fprintf(stderr, "%s\n", explanation);                                     \
+    fflush(stderr);                                                           \
     return TEST_SKIP;                                                         \
   } while (0)
 
@@ -190,10 +179,15 @@ enum test_status {
 
 #include <stdarg.h>
 
+/* Define inline for MSVC */
+# ifdef _MSC_VER
+#  define inline __inline
+# endif
+
 /* Emulate snprintf() on Windows, _snprintf() doesn't zero-terminate the buffer
  * on overflow...
  */
-static int snprintf(char* buf, size_t len, const char* fmt, ...) {
+inline int snprintf(char* buf, size_t len, const char* fmt, ...) {
   va_list ap;
   int n;
 
index cc5dc74..a0600b3 100644 (file)
@@ -1094,7 +1094,8 @@ TEST_IMPL(fs_fstat) {
 #elif defined(__sun) || \
       defined(_BSD_SOURCE) || \
       defined(_SVID_SOURCE) || \
-      defined(_XOPEN_SOURCE)
+      defined(_XOPEN_SOURCE) || \
+      defined(_DEFAULT_SOURCE)
   ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec);
   ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec);
   ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec);
@@ -1155,6 +1156,7 @@ TEST_IMPL(fs_access) {
 
   /* Setup. */
   unlink("test_file");
+  rmdir("test_dir");
 
   loop = uv_default_loop();
 
@@ -1198,6 +1200,16 @@ TEST_IMPL(fs_access) {
   ASSERT(req.result == 0);
   uv_fs_req_cleanup(&req);
 
+  /* Directory access */
+  r = uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_access(loop, &req, "test_dir", W_OK, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  uv_fs_req_cleanup(&req);
+
   /*
    * Run the loop just to check we don't have make any extraneous uv_ref()
    * calls. This should drop out immediately.
@@ -1206,6 +1218,7 @@ TEST_IMPL(fs_access) {
 
   /* Cleanup. */
   unlink("test_file");
+  rmdir("test_dir");
 
   MAKE_VALGRIND_HAPPY();
   return 0;
@@ -1310,6 +1323,65 @@ TEST_IMPL(fs_chmod) {
 }
 
 
+TEST_IMPL(fs_unlink_readonly) {
+  int r;
+  uv_fs_t req;
+  uv_file file;
+
+  /* Setup. */
+  unlink("test_file");
+
+  loop = uv_default_loop();
+
+  r = uv_fs_open(loop,
+                 &req,
+                 "test_file",
+                 O_RDWR | O_CREAT,
+                 S_IWUSR | S_IRUSR,
+                 NULL);
+  ASSERT(r >= 0);
+  ASSERT(req.result >= 0);
+  file = req.result;
+  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);
+  ASSERT(r == sizeof(test_buf));
+  ASSERT(req.result == sizeof(test_buf));
+  uv_fs_req_cleanup(&req);
+
+  close(file);
+
+  /* Make the file read-only */
+  r = uv_fs_chmod(loop, &req, "test_file", 0400, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  uv_fs_req_cleanup(&req);
+
+  check_permission("test_file", 0400);
+
+  /* Try to unlink the file */
+  r = uv_fs_unlink(loop, &req, "test_file", NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  uv_fs_req_cleanup(&req);
+
+  /*
+  * Run the loop just to check we don't have make any extraneous uv_ref()
+  * calls. This should drop out immediately.
+  */
+  uv_run(loop, UV_RUN_DEFAULT);
+
+  /* Cleanup. */
+  uv_fs_chmod(loop, &req, "test_file", 0600, NULL);
+  uv_fs_req_cleanup(&req);
+  unlink("test_file");
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+
 TEST_IMPL(fs_chown) {
   int r;
   uv_fs_t req;
index df5e984..3fe933a 100644 (file)
@@ -102,7 +102,8 @@ TEST_IMPL(handle_fileno) {
 
   tty_fd = get_tty_fd();
   if (tty_fd < 0) {
-    LOGF("Cannot open a TTY fd");
+    fprintf(stderr, "Cannot open a TTY fd");
+    fflush(stderr);
   } else {
     r = uv_tty_init(loop, &tty, tty_fd, 0);
     ASSERT(r == 0);
index 0e991c3..f49d196 100644 (file)
@@ -46,7 +46,8 @@ static void timer_cb(uv_timer_t* handle) {
   uv_close((uv_handle_t*) &timer_handle, close_cb);
 
   timer_cb_called++;
-  LOGF("timer_cb %d\n", timer_cb_called);
+  fprintf(stderr, "timer_cb %d\n", timer_cb_called);
+  fflush(stderr);
 }
 
 
@@ -54,7 +55,8 @@ static void idle_cb(uv_idle_t* handle) {
   ASSERT(handle == &idle_handle);
 
   idle_cb_called++;
-  LOGF("idle_cb %d\n", idle_cb_called);
+  fprintf(stderr, "idle_cb %d\n", idle_cb_called);
+  fflush(stderr);
 }
 
 
@@ -62,7 +64,8 @@ static void check_cb(uv_check_t* handle) {
   ASSERT(handle == &check_handle);
 
   check_cb_called++;
-  LOGF("check_cb %d\n", check_cb_called);
+  fprintf(stderr, "check_cb %d\n", check_cb_called);
+  fflush(stderr);
 }
 
 
index cf8491f..869b099 100644 (file)
@@ -77,14 +77,16 @@ TEST_IMPL(ip6_addr_link_local) {
              device_name);
 #endif
 
-    LOGF("Testing link-local address %s "
-         "(iface_index: 0x%02x, device_name: %s)\n",
-         scoped_addr,
-         iface_index,
-         device_name);
+    fprintf(stderr, "Testing link-local address %s "
+            "(iface_index: 0x%02x, device_name: %s)\n",
+            scoped_addr,
+            iface_index,
+            device_name);
+    fflush(stderr);
 
     ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr));
-    LOGF("Got scope_id 0x%02x\n", addr.sin6_scope_id);
+    fprintf(stderr, "Got scope_id 0x%02x\n", addr.sin6_scope_id);
+    fflush(stderr);
     ASSERT(iface_index == addr.sin6_scope_id);
   }
 
index aac15e0..1e3c13d 100644 (file)
@@ -43,6 +43,7 @@ TEST_DECLARE   (semaphore_1)
 TEST_DECLARE   (semaphore_2)
 TEST_DECLARE   (semaphore_3)
 TEST_DECLARE   (tty)
+TEST_DECLARE   (tty_file)
 TEST_DECLARE   (stdio_over_pipes)
 TEST_DECLARE   (ip6_pton)
 TEST_DECLARE   (ipc_listen_before_write)
@@ -61,6 +62,7 @@ TEST_DECLARE   (multiple_listen)
 TEST_DECLARE   (tcp_write_after_connect)
 #endif
 TEST_DECLARE   (tcp_writealot)
+TEST_DECLARE   (tcp_write_fail)
 TEST_DECLARE   (tcp_try_write)
 TEST_DECLARE   (tcp_write_queue_order)
 TEST_DECLARE   (tcp_open)
@@ -195,6 +197,9 @@ TEST_DECLARE   (fail_always)
 TEST_DECLARE   (pass_always)
 TEST_DECLARE   (socket_buffer_size)
 TEST_DECLARE   (spawn_fails)
+#ifndef _WIN32
+TEST_DECLARE   (spawn_fails_check_for_waitpid_cleanup)
+#endif
 TEST_DECLARE   (spawn_exit_code)
 TEST_DECLARE   (spawn_stdout)
 TEST_DECLARE   (spawn_stdin)
@@ -209,6 +214,8 @@ TEST_DECLARE   (spawn_setuid_fails)
 TEST_DECLARE   (spawn_setgid_fails)
 TEST_DECLARE   (spawn_stdout_to_file)
 TEST_DECLARE   (spawn_stdout_and_stderr_to_file)
+TEST_DECLARE   (spawn_stdout_and_stderr_to_file2)
+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)
@@ -227,6 +234,7 @@ TEST_DECLARE   (fs_mkdtemp)
 TEST_DECLARE   (fs_fstat)
 TEST_DECLARE   (fs_access)
 TEST_DECLARE   (fs_chmod)
+TEST_DECLARE   (fs_unlink_readonly)
 TEST_DECLARE   (fs_chown)
 TEST_DECLARE   (fs_link)
 TEST_DECLARE   (fs_readlink)
@@ -343,6 +351,7 @@ TASK_LIST_START
 #endif
   TEST_ENTRY  (pipe_set_non_blocking)
   TEST_ENTRY  (tty)
+  TEST_ENTRY  (tty_file)
   TEST_ENTRY  (stdio_over_pipes)
   TEST_ENTRY  (ip6_pton)
   TEST_ENTRY  (ipc_listen_before_write)
@@ -372,6 +381,9 @@ TASK_LIST_START
   TEST_ENTRY  (tcp_writealot)
   TEST_HELPER (tcp_writealot, tcp4_echo_server)
 
+  TEST_ENTRY  (tcp_write_fail)
+  TEST_HELPER (tcp_write_fail, tcp4_echo_server)
+
   TEST_ENTRY  (tcp_try_write)
 
   TEST_ENTRY  (tcp_write_queue_order)
@@ -551,6 +563,9 @@ TASK_LIST_START
   TEST_ENTRY  (socket_buffer_size)
 
   TEST_ENTRY  (spawn_fails)
+#ifndef _WIN32
+  TEST_ENTRY  (spawn_fails_check_for_waitpid_cleanup)
+#endif
   TEST_ENTRY  (spawn_exit_code)
   TEST_ENTRY  (spawn_stdout)
   TEST_ENTRY  (spawn_stdin)
@@ -565,6 +580,8 @@ TASK_LIST_START
   TEST_ENTRY  (spawn_setgid_fails)
   TEST_ENTRY  (spawn_stdout_to_file)
   TEST_ENTRY  (spawn_stdout_and_stderr_to_file)
+  TEST_ENTRY  (spawn_stdout_and_stderr_to_file2)
+  TEST_ENTRY  (spawn_stdout_and_stderr_to_file_swap)
   TEST_ENTRY  (spawn_auto_unref)
   TEST_ENTRY  (spawn_closed_process_io)
   TEST_ENTRY  (spawn_reads_child_path)
@@ -611,6 +628,7 @@ TASK_LIST_START
   TEST_ENTRY  (fs_fstat)
   TEST_ENTRY  (fs_access)
   TEST_ENTRY  (fs_chmod)
+  TEST_ENTRY  (fs_unlink_readonly)
   TEST_ENTRY  (fs_chown)
   TEST_ENTRY  (fs_utime)
   TEST_ENTRY  (fs_futime)
index 0986de5..c3e8498 100644 (file)
@@ -113,7 +113,8 @@ static void timer_cb(uv_timer_t* handle) {
 
 
 static void idle_2_close_cb(uv_handle_t* handle) {
-  LOG("IDLE_2_CLOSE_CB\n");
+  fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n");
+  fflush(stderr);
 
   ASSERT(handle == (uv_handle_t*)&idle_2_handle);
 
@@ -125,7 +126,8 @@ static void idle_2_close_cb(uv_handle_t* handle) {
 
 
 static void idle_2_cb(uv_idle_t* handle) {
-  LOG("IDLE_2_CB\n");
+  fprintf(stderr, "%s", "IDLE_2_CB\n");
+  fflush(stderr);
 
   ASSERT(handle == &idle_2_handle);
 
@@ -138,7 +140,8 @@ static void idle_2_cb(uv_idle_t* handle) {
 static void idle_1_cb(uv_idle_t* handle) {
   int r;
 
-  LOG("IDLE_1_CB\n");
+  fprintf(stderr, "%s", "IDLE_1_CB\n");
+  fflush(stderr);
 
   ASSERT(handle != NULL);
   ASSERT(idles_1_active > 0);
@@ -164,7 +167,8 @@ static void idle_1_cb(uv_idle_t* handle) {
 
 
 static void idle_1_close_cb(uv_handle_t* handle) {
-  LOG("IDLE_1_CLOSE_CB\n");
+  fprintf(stderr, "%s", "IDLE_1_CLOSE_CB\n");
+  fflush(stderr);
 
   ASSERT(handle != NULL);
 
@@ -173,7 +177,8 @@ static void idle_1_close_cb(uv_handle_t* handle) {
 
 
 static void prepare_1_close_cb(uv_handle_t* handle) {
-  LOG("PREPARE_1_CLOSE_CB");
+  fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB");
+  fflush(stderr);
   ASSERT(handle == (uv_handle_t*)&prepare_1_handle);
 
   prepare_1_close_cb_called++;
@@ -181,7 +186,8 @@ static void prepare_1_close_cb(uv_handle_t* handle) {
 
 
 static void check_close_cb(uv_handle_t* handle) {
-  LOG("CHECK_CLOSE_CB\n");
+  fprintf(stderr, "%s", "CHECK_CLOSE_CB\n");
+  fflush(stderr);
   ASSERT(handle == (uv_handle_t*)&check_handle);
 
   check_close_cb_called++;
@@ -189,7 +195,8 @@ static void check_close_cb(uv_handle_t* handle) {
 
 
 static void prepare_2_close_cb(uv_handle_t* handle) {
-  LOG("PREPARE_2_CLOSE_CB\n");
+  fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n");
+  fflush(stderr);
   ASSERT(handle == (uv_handle_t*)&prepare_2_handle);
 
   prepare_2_close_cb_called++;
@@ -199,8 +206,8 @@ static void prepare_2_close_cb(uv_handle_t* handle) {
 static void check_cb(uv_check_t* handle) {
   int i, r;
 
-  LOG("CHECK_CB\n");
-
+  fprintf(stderr, "%s", "CHECK_CB\n");
+  fflush(stderr);
   ASSERT(handle == &check_handle);
 
   if (loop_iteration < ITERATIONS) {
@@ -235,8 +242,8 @@ static void check_cb(uv_check_t* handle) {
 static void prepare_2_cb(uv_prepare_t* handle) {
   int r;
 
-  LOG("PREPARE_2_CB\n");
-
+  fprintf(stderr, "%s", "PREPARE_2_CB\n");
+  fflush(stderr);
   ASSERT(handle == &prepare_2_handle);
 
   /* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */
@@ -255,8 +262,8 @@ static void prepare_2_cb(uv_prepare_t* handle) {
 static void prepare_1_cb(uv_prepare_t* handle) {
   int r;
 
-  LOG("PREPARE_1_CB\n");
-
+  fprintf(stderr, "%s", "PREPARE_1_CB\n");
+  fflush(stderr);
   ASSERT(handle == &prepare_1_handle);
 
   if (loop_iteration % 2 == 0) {
index 6ccf603..a0afda9 100644 (file)
@@ -39,6 +39,7 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
 
 static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
   fprintf(stdout, "got data %d\n", ++read_count);
+  fflush(stdout);
 
   if (read_count == 3)
     uv_close((uv_handle_t*) stream, NULL);
@@ -55,7 +56,8 @@ TEST_IMPL(osx_select) {
 
   fd = open("/dev/tty", O_RDONLY);
   if (fd < 0) {
-    LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fflush(stderr);
     return TEST_SKIP;
   }
 
@@ -107,7 +109,8 @@ TEST_IMPL(osx_select_many_fds) {
 
   fd = open("/dev/tty", O_RDONLY);
   if (fd < 0) {
-    LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fflush(stderr);
     return TEST_SKIP;
   }
 
index 5cf2c19..fcc9fc0 100644 (file)
@@ -88,8 +88,8 @@ TEST_IMPL(pipe_set_non_blocking) {
   uv_close((uv_handle_t*) &pipe_handle, NULL);
   ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
 
-  ASSERT(0 == close(fd[1]));  /* fd[0] is closed by uv_close(). */
   ASSERT(0 == uv_thread_join(&thread));
+  ASSERT(0 == close(fd[1]));  /* fd[0] is closed by uv_close(). */
   uv_barrier_destroy(&ctx.barrier);
 
   MAKE_VALGRIND_HAPPY();
index 9b00300..d01862a 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "uv.h"
 #include "task.h"
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,6 +35,7 @@
 # include <wchar.h>
 #else
 # include <unistd.h>
+# include <sys/wait.h>
 #endif
 
 
@@ -180,6 +182,37 @@ TEST_IMPL(spawn_fails) {
 }
 
 
+#ifndef _WIN32
+TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
+  int r;
+  int status;
+  int err;
+
+  init_process_options("", fail_cb);
+  options.file = options.args[0] = "program-that-had-better-not-exist";
+
+  r = uv_spawn(uv_default_loop(), &process, &options);
+  ASSERT(r == UV_ENOENT || r == UV_EACCES);
+  ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+  /* verify the child is successfully cleaned up within libuv */
+  do
+    err = waitpid(process.pid, &status, 0);
+  while (err == -1 && errno == EINTR);
+
+  ASSERT(err == -1);
+  ASSERT(errno == ECHILD);
+
+  uv_close((uv_handle_t*) &process, NULL);
+  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+#endif
+
+
 TEST_IMPL(spawn_exit_code) {
   int r;
 
@@ -342,6 +375,163 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
 }
 
 
+TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
+#ifndef _WIN32
+  int r;
+  uv_file file;
+  uv_fs_t fs_req;
+  uv_stdio_container_t stdio[3];
+  uv_buf_t buf;
+
+  /* Setup. */
+  unlink("stdout_file");
+
+  init_process_options("spawn_helper6", exit_cb);
+
+  /* Replace stderr with our file */
+  r = uv_fs_open(uv_default_loop(),
+                 &fs_req,
+                 "stdout_file",
+                 O_CREAT | O_RDWR,
+                 S_IRUSR | S_IWUSR,
+                 NULL);
+  ASSERT(r != -1);
+  uv_fs_req_cleanup(&fs_req);
+  file = dup2(r, STDERR_FILENO);
+  ASSERT(file != -1);
+
+  options.stdio = stdio;
+  options.stdio[0].flags = UV_IGNORE;
+  options.stdio[1].flags = UV_INHERIT_FD;
+  options.stdio[1].data.fd = file;
+  options.stdio[2].flags = UV_INHERIT_FD;
+  options.stdio[2].data.fd = file;
+  options.stdio_count = 3;
+
+  r = uv_spawn(uv_default_loop(), &process, &options);
+  ASSERT(r == 0);
+
+  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+  ASSERT(r == 0);
+
+  ASSERT(exit_cb_called == 1);
+  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);
+  ASSERT(r == 27);
+  uv_fs_req_cleanup(&fs_req);
+
+  r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&fs_req);
+
+  printf("output is: %s", output);
+  ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+  /* Cleanup. */
+  unlink("stdout_file");
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+#else
+  RETURN_SKIP("Unix only test");
+#endif
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
+#ifndef _WIN32
+  int r;
+  uv_file stdout_file;
+  uv_file stderr_file;
+  uv_fs_t fs_req;
+  uv_stdio_container_t stdio[3];
+  uv_buf_t buf;
+
+  /* Setup. */
+  unlink("stdout_file");
+  unlink("stderr_file");
+
+  init_process_options("spawn_helper6", exit_cb);
+
+  /* open 'stdout_file' and replace STDOUT_FILENO with it */
+  r = uv_fs_open(uv_default_loop(),
+                 &fs_req,
+                 "stdout_file",
+                 O_CREAT | O_RDWR,
+                 S_IRUSR | S_IWUSR,
+                 NULL);
+  ASSERT(r != -1);
+  uv_fs_req_cleanup(&fs_req);
+  stdout_file = dup2(r, STDOUT_FILENO);
+  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,
+      S_IRUSR | S_IWUSR, NULL);
+  ASSERT(r != -1);
+  uv_fs_req_cleanup(&fs_req);
+  stderr_file = dup2(r, STDERR_FILENO);
+  ASSERT(stderr_file != -1);
+
+  /* now we're going to swap them: the child process' stdout will be our
+   * stderr_file and vice versa */
+  options.stdio = stdio;
+  options.stdio[0].flags = UV_IGNORE;
+  options.stdio[1].flags = UV_INHERIT_FD;
+  options.stdio[1].data.fd = stderr_file;
+  options.stdio[2].flags = UV_INHERIT_FD;
+  options.stdio[2].data.fd = stdout_file;
+  options.stdio_count = 3;
+
+  r = uv_spawn(uv_default_loop(), &process, &options);
+  ASSERT(r == 0);
+
+  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+  ASSERT(r == 0);
+
+  ASSERT(exit_cb_called == 1);
+  ASSERT(close_cb_called == 1);
+
+  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);
+  ASSERT(r >= 15);
+  uv_fs_req_cleanup(&fs_req);
+
+  r = uv_fs_close(uv_default_loop(), &fs_req, stdout_file, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&fs_req);
+
+  printf("output is: %s", output);
+  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);
+  ASSERT(r >= 12);
+  uv_fs_req_cleanup(&fs_req);
+
+  r = uv_fs_close(uv_default_loop(), &fs_req, stderr_file, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&fs_req);
+
+  printf("output is: %s", output);
+  ASSERT(strncmp("hello world\n", output, 12) == 0);
+
+  /* Cleanup. */
+  unlink("stdout_file");
+  unlink("stderr_file");
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+#else
+  RETURN_SKIP("Unix only test");
+#endif
+}
+
+
 TEST_IMPL(spawn_stdin) {
   int r;
   uv_pipe_t out;
@@ -1007,7 +1197,7 @@ TEST_IMPL(environment_creation) {
   return 0;
 }
 
-// Regression test for issue #909
+/* Regression test for issue #909 */
 TEST_IMPL(spawn_with_an_odd_path) {
   int r;
 
diff --git a/deps/uv/test/test-tcp-write-fail.c b/deps/uv/test/test-tcp-write-fail.c
new file mode 100644 (file)
index 0000000..2840d81
--- /dev/null
@@ -0,0 +1,115 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+
+static void close_socket(uv_tcp_t* sock) {
+  uv_os_fd_t fd;
+  int r;
+
+  r = uv_fileno((uv_handle_t*)sock, &fd);
+  ASSERT(r == 0);
+#ifdef _WIN32
+  r = closesocket(fd);
+#else
+  r = close(fd);
+#endif
+  ASSERT(r == 0);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+  ASSERT(handle != NULL);
+  close_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+  ASSERT(req != NULL);
+
+  ASSERT(status != 0);
+  fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+  write_cb_called++;
+
+  uv_close((uv_handle_t*)(req->handle), close_cb);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+  uv_buf_t buf;
+  uv_stream_t* stream;
+  int r;
+
+  ASSERT(req == &connect_req);
+  ASSERT(status == 0);
+
+  stream = req->handle;
+  connect_cb_called++;
+
+  /* close the socket, the hard way */
+  close_socket((uv_tcp_t*)stream);
+
+  buf = uv_buf_init("hello\n", 6);
+  r = uv_write(&write_req, stream, &buf, 1, write_cb);
+  ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_write_fail) {
+  struct sockaddr_in addr;
+  uv_tcp_t client;
+  int r;
+
+  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+  r = uv_tcp_init(uv_default_loop(), &client);
+  ASSERT(r == 0);
+
+  r = uv_tcp_connect(&connect_req,
+                     &client,
+                     (const struct sockaddr*) &addr,
+                     connect_cb);
+  ASSERT(r == 0);
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+  ASSERT(connect_cb_called == 1);
+  ASSERT(write_cb_called == 1);
+  ASSERT(close_cb_called == 1);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
index 095cd9e..f93c509 100644 (file)
@@ -47,8 +47,9 @@ static void repeat_1_cb(uv_timer_t* handle) {
   ASSERT(handle == &repeat_1);
   ASSERT(uv_timer_get_repeat((uv_timer_t*)handle) == 50);
 
-  LOGF("repeat_1_cb called after %ld ms\n",
-      (long int)(uv_now(uv_default_loop()) - start_time));
+  fprintf(stderr, "repeat_1_cb called after %ld ms\n",
+          (long int)(uv_now(uv_default_loop()) - start_time));
+  fflush(stderr);
 
   repeat_1_cb_called++;
 
@@ -69,8 +70,9 @@ static void repeat_2_cb(uv_timer_t* handle) {
   ASSERT(handle == &repeat_2);
   ASSERT(repeat_2_cb_allowed);
 
-  LOGF("repeat_2_cb called after %ld ms\n",
-      (long int)(uv_now(uv_default_loop()) - start_time));
+  fprintf(stderr, "repeat_2_cb called after %ld ms\n",
+          (long int)(uv_now(uv_default_loop()) - start_time));
+  fflush(stderr);
 
   repeat_2_cb_called++;
 
@@ -80,8 +82,9 @@ static void repeat_2_cb(uv_timer_t* handle) {
     return;
   }
 
-  LOGF("uv_timer_get_repeat %ld ms\n",
-      (long int)uv_timer_get_repeat(&repeat_2));
+  fprintf(stderr, "uv_timer_get_repeat %ld ms\n",
+          (long int)uv_timer_get_repeat(&repeat_2));
+  fflush(stderr);
   ASSERT(uv_timer_get_repeat(&repeat_2) == 100);
 
   /* This shouldn't take effect immediately. */
@@ -129,8 +132,9 @@ TEST_IMPL(timer_again) {
   ASSERT(repeat_2_cb_called == 2);
   ASSERT(close_cb_called == 2);
 
-  LOGF("Test took %ld ms (expected ~700 ms)\n",
-       (long int)(uv_now(uv_default_loop()) - start_time));
+  fprintf(stderr, "Test took %ld ms (expected ~700 ms)\n",
+          (long int)(uv_now(uv_default_loop()) - start_time));
+  fflush(stderr);
 
   MAKE_VALGRIND_HAPPY();
   return 0;
index 7e1ce26..81e612c 100644 (file)
@@ -66,13 +66,15 @@ TEST_IMPL(tty) {
 #else /* unix */
   ttyin_fd = open("/dev/tty", O_RDONLY, 0);
   if (ttyin_fd < 0) {
-    LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+    fflush(stderr);
     return TEST_SKIP;
   }
 
   ttyout_fd = open("/dev/tty", O_WRONLY, 0);
   if (ttyout_fd < 0) {
-    LOGF("Cannot open /dev/tty as write-only: %s\n", strerror(errno));
+    fprintf(stderr, "Cannot open /dev/tty as write-only: %s\n", strerror(errno));
+    fflush(stderr);
     return TEST_SKIP;
   }
 #endif
@@ -111,13 +113,20 @@ TEST_IMPL(tty) {
   ASSERT(height > 10);
 
   /* Turn on raw mode. */
-  r = uv_tty_set_mode(&tty_in, 1);
+  r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
   ASSERT(r == 0);
 
   /* Turn off raw mode. */
-  r = uv_tty_set_mode(&tty_in, 0);
+  r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_NORMAL);
   ASSERT(r == 0);
 
+  /* Calling uv_tty_reset_mode() repeatedly should not clobber errno. */
+  errno = 0;
+  ASSERT(0 == uv_tty_reset_mode());
+  ASSERT(0 == uv_tty_reset_mode());
+  ASSERT(0 == uv_tty_reset_mode());
+  ASSERT(0 == errno);
+
   /* TODO check the actual mode! */
 
   uv_close((uv_handle_t*) &tty_in, NULL);
@@ -128,3 +137,45 @@ TEST_IMPL(tty) {
   MAKE_VALGRIND_HAPPY();
   return 0;
 }
+
+
+TEST_IMPL(tty_file) {
+#ifndef _WIN32
+  uv_loop_t loop;
+  uv_tty_t tty;
+  int fd;
+
+  ASSERT(0 == uv_loop_init(&loop));
+
+  fd = open("test/fixtures/empty_file", O_RDONLY);
+  if (fd != -1) {
+    ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+    ASSERT(0 == close(fd));
+  }
+
+  fd = open("/dev/random", O_RDONLY);
+  if (fd != -1) {
+    ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+    ASSERT(0 == close(fd));
+  }
+
+  fd = open("/dev/zero", O_RDONLY);
+  if (fd != -1) {
+    ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+    ASSERT(0 == close(fd));
+  }
+
+  fd = open("/dev/tty", O_RDONLY);
+  if (fd != -1) {
+    ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1));
+    ASSERT(0 == close(fd));
+    uv_close((uv_handle_t*) &tty, NULL);
+  }
+
+  ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+  ASSERT(0 == uv_loop_close(&loop));
+
+  MAKE_VALGRIND_HAPPY();
+#endif
+  return 0;
+}
index 1ef8c05..acaed86 100644 (file)
@@ -39,7 +39,7 @@
               '_FILE_OFFSET_BITS=64',
             ],
           }],
-          ['OS == "mac"', {
+          ['OS in "mac ios"', {
             'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ],
           }],
           ['OS == "linux"', {
               'cflags': [ '-fPIC' ],
             }],
             ['uv_library=="shared_library" and OS!="mac"', {
-              'link_settings': {
-                # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR
-                # in include/uv-version.h
-                'libraries': [ '-Wl,-soname,libuv.so.1.0' ],
-              },
+              # This will cause gyp to set soname
+              # Must correspond with UV_VERSION_MAJOR
+              # in include/uv-version.h
+              'product_extension': 'so.1',
             }],
           ],
         }],
-        [ 'OS in "linux mac android"', {
+        [ 'OS in "linux mac ios android"', {
           'sources': [ 'src/unix/proctitle.c' ],
         }],
-        [ 'OS=="mac"', {
+        [ 'OS in "mac ios"', {
           'sources': [
             'src/unix/darwin.c',
             'src/unix/fsevents.c',
             'libraries': [ '-lkvm' ],
           },
         }],
-        [ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', {
+        [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', {
           'sources': [ 'src/unix/kqueue.c' ],
         }],
         ['uv_library=="shared_library"', {
         'test/test-tcp-write-to-half-open-connection.c',
         'test/test-tcp-write-after-connect.c',
         'test/test-tcp-writealot.c',
+        'test/test-tcp-write-fail.c',
         'test/test-tcp-try-write.c',
         'test/test-tcp-unexpected-read.c',
         'test/test-tcp-oob.c',
index d3b7aa1..084ab95 100644 (file)
@@ -90,8 +90,8 @@ if defined noprojgen goto msbuild
 
 @rem Generate the VS project.
 if exist build\gyp goto have_gyp
-echo git clone https://git.chromium.org/external/gyp.git build/gyp
-git clone https://git.chromium.org/external/gyp.git build/gyp
+echo git clone https://chromium.googlesource.com/external/gyp build/gyp
+git clone https://chromium.googlesource.com/external/gyp build/gyp
 if errorlevel 1 goto gyp_install_failed
 goto have_gyp