From 395b16170c54a789d7e8a775b820da54cd906bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 1 Apr 2016 11:19:19 +0200 Subject: [PATCH 1/6] deps: upgrade libuv to 1.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/nodejs/node/issues/5737 Fixes: https://github.com/nodejs/node/issues/4643 Fixes: https://github.com/nodejs/node/issues/4291 Fixes: https://github.com/nodejs/node-v0.x-archive/issues/8960 Refs: https://github.com/nodejs/node/pull/3594 PR-URL: https://github.com/nodejs/node/pull/5994 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Johan Bergström --- deps/uv/.gitignore | 3 + deps/uv/.mailmap | 6 + deps/uv/AUTHORS | 13 + deps/uv/CONTRIBUTING.md | 9 +- deps/uv/ChangeLog | 139 ++++++++++ deps/uv/MAINTAINERS.md | 1 + deps/uv/Makefile.am | 13 +- deps/uv/Makefile.mingw | 1 - deps/uv/README.md | 8 +- deps/uv/appveyor.yml | 2 +- deps/uv/autogen.sh | 2 +- deps/uv/checksparse.sh | 2 + deps/uv/configure.ac | 2 +- deps/uv/docs/src/loop.rst | 7 +- deps/uv/docs/src/misc.rst | 54 +++- deps/uv/docs/src/poll.rst | 17 +- deps/uv/docs/src/stream.rst | 8 +- deps/uv/docs/src/tty.rst | 16 +- deps/uv/gyp_uv.py | 5 +- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv-win.h | 5 - deps/uv/include/uv.h | 15 +- deps/uv/src/fs-poll.c | 5 +- deps/uv/src/unix/aix.c | 63 ++--- deps/uv/src/unix/core.c | 194 +++++++++++-- deps/uv/src/unix/fs.c | 17 +- deps/uv/src/unix/internal.h | 31 ++- deps/uv/src/unix/kqueue.c | 21 ++ deps/uv/src/unix/linux-core.c | 77 ++++-- deps/uv/src/unix/linux-syscalls.h | 1 + deps/uv/src/unix/pipe.c | 11 +- deps/uv/src/unix/poll.c | 16 +- deps/uv/src/unix/process.c | 6 +- deps/uv/src/unix/stream.c | 22 +- deps/uv/src/unix/sunos.c | 11 + deps/uv/src/unix/thread.c | 33 ++- deps/uv/src/unix/tty.c | 36 ++- deps/uv/src/uv-common.c | 5 +- deps/uv/src/win/core.c | 130 +++++---- deps/uv/src/win/dl.c | 7 +- deps/uv/src/win/fs-event.c | 108 ++++---- deps/uv/src/win/fs.c | 25 +- deps/uv/src/win/getaddrinfo.c | 61 +++-- deps/uv/src/win/internal.h | 3 +- deps/uv/src/win/pipe.c | 23 +- deps/uv/src/win/poll.c | 15 +- deps/uv/src/win/timer.c | 9 +- deps/uv/src/win/tty.c | 9 +- deps/uv/src/win/util.c | 254 ++++++++++++++---- deps/uv/test/runner-unix.c | 2 +- deps/uv/test/task.h | 10 +- deps/uv/test/test-condvar.c | 100 ++++--- deps/uv/test/test-eintr-handling.c | 94 +++++++ deps/uv/test/test-fs-event.c | 28 ++ deps/uv/test/test-fs-poll.c | 1 + deps/uv/test/test-get-passwd.c | 80 ++++++ deps/uv/test/test-homedir.c | 21 ++ deps/uv/test/test-list.h | 29 ++ .../test/test-pipe-close-stdout-read-stdin.c | 3 + deps/uv/test/test-pipe-getsockname.c | 1 + deps/uv/test/test-platform-output.c | 11 + deps/uv/test/test-poll.c | 52 +++- .../uv/test/test-tcp-close-while-connecting.c | 2 +- deps/uv/test/test-thread.c | 21 ++ deps/uv/test/test-timer.c | 27 ++ deps/uv/test/test-tmpdir.c | 71 +++++ deps/uv/test/test-tty.c | 39 +++ deps/uv/uv.gyp | 21 +- deps/uv/vcbuild.bat | 5 + 69 files changed, 1746 insertions(+), 395 deletions(-) create mode 100644 deps/uv/test/test-eintr-handling.c create mode 100644 deps/uv/test/test-get-passwd.c create mode 100644 deps/uv/test/test-tmpdir.c diff --git a/deps/uv/.gitignore b/deps/uv/.gitignore index 1eaaca8406e957..86a8a5b7b8584d 100644 --- a/deps/uv/.gitignore +++ b/deps/uv/.gitignore @@ -65,6 +65,9 @@ ipch # sphinx generated files /docs/build/ +# Clion / IntelliJ project files +/.idea/ + *.xcodeproj *.xcworkspace diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 0a152ba8dbb0c4..7a51588c0b7188 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -8,9 +8,11 @@ Brian White Brian White Caleb James DeLisle Christoph Iserlohn +Devchandra Meetei Leishangthem Fedor Indutny Frank Denis Isaac Z. Schlueter +Jason Williams Justin Venus Keno Fischer Keno Fischer @@ -18,6 +20,9 @@ Leith Bade Leonard Hecker Maciej Małecki Marc Schlaich +Michael +Michael Neumann +Nicholas Vavilov Rasmus Christian Pedersen Rasmus Christian Pedersen Robert Mustacchi @@ -25,6 +30,7 @@ Ryan Dahl Ryan Emery Sam Roberts San-Tai Hsu +Santiago Gimeno Saúl Ibarra Corretgé Shigeki Ohtsu Timothy J. Fontaine diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 8dc3955cad5bf3..9a9e9c2a2204b8 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -240,3 +240,16 @@ Yuval Brik Joran Dirk Greef Andrey Mazo sztomi +Martin Bark +Dave +Alexis Murzeau +Didiet +Nan Xiang <514580344@qq.com> +Samuel Lorétan +Nándor István Krácser +Katsutoshi Horie +Lukasz Jagiello +Robert Chiras +Kári Tristan Helgason +Krishnaraj Bhat +Enno Boland diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index b46edd492aab47..ef5c2b2feaae9f 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -23,8 +23,7 @@ The stable branch is effectively frozen; patches that change the libuv API/ABI or affect the run-time behavior of applications get rejected. In case of doubt, open an issue in the [issue tracker][], post your question -to the [libuv mailing list], or contact one of project maintainers -(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][]. +to the [libuv mailing list], or contact one of [project maintainers][] on [IRC][]. Especially do so if you plan to work on something big. Nothing is more frustrating than seeing your hard work go to waste because your vision @@ -138,7 +137,10 @@ $ git rebase upstream/v1.x # or upstream/master ### TEST Bug fixes and features should come with tests. Add your tests in the -`test/` directory. Tests also need to be registered in `test/test-list.h`. +`test/` directory. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. +- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. + Look at other tests to see how they should be structured (license boilerplate, the way entry points are declared, etc.). @@ -164,3 +166,4 @@ not send out notifications when you add commits. [libuv mailing list]: http://groups.google.com/group/libuv [IRC]: http://webchat.freelibuv.net/?channels=libuv [Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index af0743af72c8db..85d40113e4f052 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,142 @@ +2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 + +Changes since version 1.8.0: + +* win: wait for full timeout duration (João Reis) + +* unix: fix support for uClibc-ng (Martin Bark) + +* doc: indicate where new test files need to be added (Dave) + +* test,unix: fix logic error in test runner (Ben Noordhuis) + +* fs: don't nullify req->bufs on EINTR (Dave) + +* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) + +* build: invoke libtoolize with --copy (Ben Noordhuis) + +* test: fixup eintr_handling (Saúl Ibarra Corretgé) + +* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) + +* test,win: fix compilation with shared lib (Alexis Murzeau) + +* test: fix race condition in pipe-close-stdout (Imran Iqbal) + +* unix,win: add uv_os_tmpdir() (cjihrig) + +* ios: fix undefined PTHREAD_STACK_MIN (Didiet) + +* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) + +* unix: report errors for unpollable fds (Ben Noordhuis) + +* win: fix watching root files (Nicholas Vavilov) + +* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) + +* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) + +* test,win: fix compilation warning (Saúl Ibarra Corretgé) + +* test: use uv_loop_close and assert its result (Nan Xiang) + +* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) + +* osx: protected use of potentially undefined macro (Samuel Lorétan) + +* linux: fix compilation with musl (Saúl Ibarra Corretgé) + +* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) + +* doc: add missing link in README (Saúl Ibarra Corretgé) + +* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) + +* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) + +* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) + +* doc: add missing write callback to example (Nándor István Krácser) + +* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) + +* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) + +* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) + +* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) + +* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) + +* linux: fix cpu count (Lukasz Jagiello) + +* unix: fix uv__handle_type for AIX (Imran Iqbal) + +* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* unix: fix compile error in Android using bionic (Robert Chiras) + +* linux: add braces to multi-statement if (Kári Tristan Helgason) + +* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) + +* unix: add fork-safe open file function (Kári Tristan Helgason) + +* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) + +* linux: remove redundant call to rewind() (Krishnaraj Bhat) + +* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) + +* test: fix poll_bad_fdtype for AIX (Imran Iqbal) + +* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) + +* poll: add UV_DISCONNECT event (Santiago Gimeno) + +* fs: realpath: fix string size before converting (Yuval Brik) + +* win: use native APIs for UTF conversions (cjihrig) + +* doc: clarify uv_loop_close() (Ben Noordhuis) + +* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) + +* win,build: remove unused build defines (Saúl Ibarra Corretgé) + +* win: fix buffer overflow in fs events (Joran Dirk Greef) + +* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) + +* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) + +* test: add missing copyright header (cjihrig) + +* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) + +* unix,win: add uv_get_passwd() (cjihrig) + +* process: fix uv_spawn edge-case (Santiago Gimeno) + +* test: use %ld for printing uid/gid (Ben Noordhuis) + +* aix: fix ahafs implementation (Imran Iqbal) + +* aix: do not store absolute path to ahafs (Imran Iqbal) + +* process: close process pipes safely (Santiago Gimeno) + +* unix: open ttyname instead of /dev/tty (Enno Boland) + +* unix: remove outdated comment (Kári Tristan Helgason) + + 2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 Changes since version 1.7.5: diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 4db2f5130c060d..2f0e618ca24149 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -6,6 +6,7 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 0ef781ff198804..dfd4353a31b649 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -43,7 +43,6 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ @@ -130,6 +129,7 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests test_run_tests_CFLAGS = +test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ test/echo-server.c \ @@ -151,6 +151,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ + test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-error.c \ @@ -161,6 +162,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-get-currentexe.c \ test/test-get-loadavg.c \ test/test-get-memory.c \ + test/test-get-passwd.c \ test/test-getaddrinfo.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ @@ -242,6 +244,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer-again.c \ test/test-timer-from-check.c \ test/test-timer.c \ + test/test-tmpdir.c \ test/test-tty.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ @@ -280,7 +283,7 @@ endif if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT +libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE include_HEADERS += include/uv-aix.h libuv_la_SOURCES += src/unix/aix.c endif @@ -301,15 +304,18 @@ libuv_la_SOURCES += src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if DRAGONFLY include_HEADERS += include/uv-bsd.h +test_run_tests_LDFLAGS += -lutil endif if FREEBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +test_run_tests_LDFLAGS += -lutil endif if LINUX @@ -320,16 +326,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if NETBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c +test_run_tests_LDFLAGS += -lutil endif if OPENBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c +test_run_tests_LDFLAGS += -lutil endif if SUNOS diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 156f15dab159f1..3130bac473d30c 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -20,7 +20,6 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ diff --git a/deps/uv/README.md b/deps/uv/README.md index dfd24ba79d1850..17304a7ab57125 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -156,11 +156,16 @@ project tree manually: ### Unix -Run: +For Debug builds (recommended) run: $ ./gyp_uv.py -f make $ make -C out +For Release builds run: + + $ ./gyp_uv.py -f make + $ BUILDTYPE=Release make -C out + Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. ### OS X @@ -243,3 +248,4 @@ See the [guidelines for contributing][]. [Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png +[x32]: https://en.wikipedia.org/wiki/X32_ABI diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index 9aa63c5a5d2e73..835730b924c8ff 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.8.0.build{build} +version: v1.9.0.build{build} install: - cinst -y nsis diff --git a/deps/uv/autogen.sh b/deps/uv/autogen.sh index 0574778a4e1040..271c2ee8c33c44 100755 --- a/deps/uv/autogen.sh +++ b/deps/uv/autogen.sh @@ -40,7 +40,7 @@ echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ > m4/libuv-extra-automake-flags.m4 set -ex -"$LIBTOOLIZE" +"$LIBTOOLIZE" --copy "$ACLOCAL" -I m4 "$AUTOCONF" "$AUTOMAKE" --add-missing --copy diff --git a/deps/uv/checksparse.sh b/deps/uv/checksparse.sh index 619cf6f8b672d8..68e3bde39305da 100755 --- a/deps/uv/checksparse.sh +++ b/deps/uv/checksparse.sh @@ -101,6 +101,7 @@ test/test-fs.c test/test-get-currentexe.c test/test-get-loadavg.c test/test-get-memory.c +test/test-get-passwd.c test/test-getaddrinfo.c test/test-getsockname.c test/test-homedir.c @@ -155,6 +156,7 @@ test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c test/test-timer.c +test/test-tmpdir.c test/test-tty.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 011bee2a891e73..2d5a3b9de5eb6d 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index 2a01d796375e8e..1f504cb391f169 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -71,9 +71,10 @@ API .. c:function:: int uv_loop_close(uv_loop_t* loop) - Closes all internal loop resources. This function must only be called once - the loop has finished its execution or it will return UV_EBUSY. After this - function returns the user shall free the memory allocated for the loop. + Releases all internal loop resources. Call this function only when the loop + has finished executing and all open handles and requests have been closed, + or it will return UV_EBUSY. After this function returns, the user can free + the memory allocated for the loop. .. c:function:: uv_loop_t* uv_default_loop(void) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 2ce0887db0c278..f32af48ff9e92d 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -122,6 +122,20 @@ Data types } netmask; } uv_interface_address_t; +.. c:type:: uv_passwd_t + + Data type for password file information. + + :: + + typedef struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; + } uv_passwd_t; + API --- @@ -265,14 +279,50 @@ API `uv_os_homedir()` first checks the `HOME` environment variable using :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The user's home directory is stored in `buffer`. When `uv_os_homedir()` is - called, `size` indicates the maximum size of `buffer`. On success or - `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`. + called, `size` indicates the maximum size of `buffer`. On success `size` is set + to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. .. warning:: `uv_os_homedir()` is not thread safe. .. versionadded:: 1.6.0 +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success `size` is set to the string length of `buffer` (which does not + include the terminating null). On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + +.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) + + Gets a subset of the password file entry for the current effective uid (not + the real uid). The populated data includes the username, euid, gid, shell, + and home directory. On non-Windows systems, all data comes from + :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no + meaning, and shell is `NULL`. After successfully calling this function, the + memory allocated to `pwd` needs to be freed with + :c:func:`uv_os_free_passwd`. + + .. versionadded:: 1.9.0 + +.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) + + Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. + + .. versionadded:: 1.9.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst index 6dc41839ac1e92..69d45be6d32b29 100644 --- a/deps/uv/docs/src/poll.rst +++ b/deps/uv/docs/src/poll.rst @@ -4,8 +4,8 @@ :c:type:`uv_poll_t` --- Poll handle =================================== -Poll handles are used to watch file descriptors for readability and -writability, similar to the purpose of :man:`poll(2)`. +Poll handles are used to watch file descriptors for readability, +writability and disconnection 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 @@ -51,7 +51,8 @@ Data types enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; @@ -82,10 +83,14 @@ API .. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) Starts polling the file descriptor. `events` is a bitmask consisting made up - of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback - will be called with `status` set to 0, and the detected events set on the + of UV_READABLE, UV_WRITABLE and UV_DISCONNECT. As soon as an event is detected + the callback will be called with `status` set to 0, and the detected events set on the `events` field. + The UV_DISCONNECT event is optional in the sense that it may not be + reported and the user is free to ignore it, but it can help optimize the shutdown + path because an extra read or write call might be avoided. + If an error happens while polling, `status` will be < 0 and corresponds with one of the UV_E* error codes (see :ref:`errors`). The user should not close the socket while the handle is active. If the user does that @@ -96,6 +101,8 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. c:function:: int uv_poll_stop(uv_poll_t* poll) Stop polling the file descriptor, the callback will no longer be called. diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index 9f0aacd16435d0..ed0c79d0045616 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -148,6 +148,10 @@ API :: + void cb(uv_write_t* req, int status) { + /* Logic which handles the write result */ + } + uv_buf_t a[] = { { .base = "1", .len = 1 }, { .base = "2", .len = 1 } @@ -162,8 +166,8 @@ API uv_write_t req2; /* writes "1234" */ - uv_write(&req1, stream, a, 2); - uv_write(&req2, stream, b, 2); + uv_write(&req1, stream, a, 2, cb); + uv_write(&req2, stream, b, 2, cb); .. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 655dca9ca20641..01a0585287affc 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -58,14 +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 determine the path of the fd of the terminal + using :man:`ttyname_r(3)`, open it, 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. + + This function is not thread safe on systems that don't support + ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. .. note:: - If opening ``/dev/tty`` fails, libuv falls back to blocking writes for + If reopening the TTY fails, libuv falls back to blocking writes for non-readable TTY streams. + .. versionchanged:: 1.9.0: the path of the TTY is determined by + :man:`ttyname_r(3)`. In earlier versions libuv opened + `/dev/tty` instead. + .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file descriptor that refers to a file returns `UV_EINVAL` on UNIX. diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index 39933f624d5c40..bd37d95c4713f6 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -27,6 +27,7 @@ def host_arch(): machine = platform.machine() if machine == 'i386': return 'ia32' + if machine == 'AMD64': return 'x64' if machine == 'x86_64': return 'x64' if machine.startswith('arm'): return 'arm' if machine.startswith('mips'): return 'mips' @@ -36,7 +37,7 @@ def host_arch(): def run_gyp(args): rc = gyp.main(args) if rc != 0: - print 'Error running GYP' + print('Error running GYP') sys.exit(rc) @@ -89,5 +90,5 @@ def run_gyp(args): args.append('--no-parallel') gyp_args = list(args) - print gyp_args + print(gyp_args) run_gyp(gyp_args) diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 6e61f55ed20d85..cb666182892dea 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 8 +#define UV_VERSION_MINOR 9 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 300be476203ed4..6b537fed0d9019 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -634,11 +634,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct uv_req_s signal_req; \ unsigned long pending_signum; -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size); -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size); - #ifndef F_OK #define F_OK 0 #endif diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index dd3111a960e69b..baa0b28124ba59 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -230,6 +230,7 @@ typedef struct uv_work_s uv_work_t; typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; +typedef struct uv_passwd_s uv_passwd_t; typedef enum { UV_LOOP_BLOCK_SIGNAL @@ -714,7 +715,8 @@ struct uv_poll_s { enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); @@ -1000,6 +1002,14 @@ struct uv_interface_address_s { } netmask; }; +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + typedef enum { UV_DIRENT_UNKNOWN, UV_DIRENT_FILE, @@ -1049,6 +1059,9 @@ typedef struct { UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); +UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 44d47b88ed22e7..ee73d5a2e6e949 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -138,13 +138,14 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { assert(ctx != NULL); required_len = strlen(ctx->path); - if (required_len > *size) { - *size = required_len; + if (required_len >= *size) { + *size = required_len + 1; return UV_ENOBUFS; } memcpy(buffer, ctx->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index c90b7e5cb9ba0c..bcaa5ee50bc203 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -91,6 +91,24 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return -errno; + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd events[1024]; struct pollfd pqry; @@ -506,7 +524,7 @@ static int uv__makedir_p(const char *dir) { if (*p == '/') { *p = 0; err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if(err != 0) + if (err != 0 && errno != EEXIST) return err; *p = '/'; } @@ -707,59 +725,44 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int int bytes, rc = 0; uv_fs_event_t* handle; int events = 0; - int i = 0; char fname[PATH_MAX]; char *p; handle = container_of(event_watch, uv_fs_event_t, event_watcher); - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - fname[i] = 0; - } - i = 0; - /* At this point, we assume that polling has been done on the * file descriptor, so we can just read the AHAFS event occurrence * data and parse its results without having to block anything */ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); - assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file"); + assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); /* Parse the data */ if(bytes > 0) rc = uv__parse_data(result_data, &events, handle); + /* Unrecoverable error */ + if (rc == -1) + return; + /* For directory changes, the name of the files that triggered the change * are never absolute pathnames */ if (uv__path_is_a_directory(handle->path) == 0) { p = handle->dir_filename; - while(*p != NULL){ - fname[i]= *p; - i++; - p++; - } } else { - /* For file changes, figure out whether filename is absolute or not */ - if (handle->path[0] == '/') { - p = strrchr(handle->path, '/'); + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else p++; - - while(*p != NULL) { - fname[i]= *p; - i++; - p++; - } - } } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; - /* Unrecoverable error */ - if (rc == -1) - return; - else /* Call the actual JavaScript callback function */ - handle->cb(handle, (const char*)&fname, events, 0); + handle->cb(handle, fname, events, 0); } #endif @@ -839,7 +842,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, /* Setup/Initialize all the libuv routines */ uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); - handle->path = uv__strdup((const char*)&absolute_path); + handle->path = uv__strdup(filename); handle->cb = cb; uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index cedd86ed34a128..9aaca84187001e 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -53,6 +53,9 @@ # include /* _NSGetExecutablePath */ # include # include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif #endif #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -427,6 +430,22 @@ int uv__socket(int domain, int type, int protocol) { return sockfd; } +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + int uv__accept(int sockfd) { int peerfd; @@ -435,7 +454,7 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) || __FreeBSD__ >= 10 +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) static int no_accept4; if (no_accept4) @@ -479,12 +498,11 @@ int uv__accept(int sockfd) { } -int uv__close(int fd) { +int uv__close_nocheckstdio(int fd) { int saved_errno; int rc; assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ - assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ saved_errno = errno; rc = close(fd); @@ -499,6 +517,12 @@ int uv__close(int fd) { } +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + return uv__close_nocheckstdio(fd); +} + + #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(_AIX) || defined(__DragonFly__) @@ -809,7 +833,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -842,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -874,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -889,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } @@ -930,8 +954,7 @@ int uv__open_cloexec(const char* path, int flags) { int err; int fd; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \ - defined(__DragonFly__) +#if defined(UV__O_CLOEXEC) static int no_cloexec; if (!no_cloexec) { @@ -1014,17 +1037,10 @@ int uv__dup2_cloexec(int oldfd, int newfd) { int uv_os_homedir(char* buffer, size_t* size) { - struct passwd pw; - struct passwd* result; + uv_passwd_t pwd; char* buf; - uid_t uid; - size_t bufsize; size_t len; - long initsize; int r; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); -#endif if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; @@ -1036,7 +1052,7 @@ int uv_os_homedir(char* buffer, size_t* size) { len = strlen(buf); if (len >= *size) { - *size = len; + *size = len + 1; return -ENOBUFS; } @@ -1046,13 +1062,102 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return -ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); if (getpwuid_r == NULL) return -ENOSYS; #endif - /* HOME is not set, so call getpwuid() */ + if (pwd == NULL) + return -EINVAL; + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (initsize <= 0) @@ -1060,7 +1165,7 @@ int uv_os_homedir(char* buffer, size_t* size) { else bufsize = (size_t) initsize; - uid = getuid(); + uid = geteuid(); buf = NULL; for (;;) { @@ -1088,17 +1193,54 @@ int uv_os_homedir(char* buffer, size_t* size) { return -ENOENT; } - len = strlen(pw.pw_dir); + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); - if (len >= *size) { - *size = len; + if (pwd->username == NULL) { uv__free(buf); - return -ENOBUFS; + return -ENOMEM; } - memcpy(buffer, pw.pw_dir, len + 1); - *size = len; + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + uv__free(buf); return 0; } + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 57b65be25a85ea..8936ad9d837095 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -127,8 +127,8 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { #if defined(__linux__) || defined(__sun) || defined(__NetBSD__) return fdatasync(req->file); -#elif defined(__APPLE__) && defined(F_FULLFSYNC) - return fcntl(req->file, F_FULLFSYNC); +#elif defined(__APPLE__) && defined(SYS_fdatasync) + return syscall(SYS_fdatasync, req->file); #else return fsync(req->file); #endif @@ -749,13 +749,13 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_gen = src->st_gen; #elif defined(__ANDROID__) dst->st_atim.tv_sec = src->st_atime; - dst->st_atim.tv_nsec = src->st_atime_nsec; + dst->st_atim.tv_nsec = src->st_atimensec; dst->st_mtim.tv_sec = src->st_mtime; - dst->st_mtim.tv_nsec = src->st_mtime_nsec; + dst->st_mtim.tv_nsec = src->st_mtimensec; dst->st_ctim.tv_sec = src->st_ctime; - dst->st_ctim.tv_nsec = src->st_ctime_nsec; + dst->st_ctim.tv_nsec = src->st_ctimensec; dst->st_birthtim.tv_sec = src->st_ctime; - dst->st_birthtim.tv_nsec = src->st_ctime_nsec; + dst->st_birthtim.tv_nsec = src->st_ctimensec; dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ @@ -858,9 +858,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) total += result; } + if (errno == EINTR && total == -1) + return total; + if (bufs != req->bufsml) uv__free(bufs); + req->bufs = NULL; + req->nbufs = 0; return total; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 741fa57d69cad3..938e76f1d18d88 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -28,6 +28,7 @@ #include /* abort */ #include /* strrchr */ #include /* O_CLOEXEC, may be */ +#include #if defined(__STRICT_ANSI__) # define inline __inline @@ -89,17 +90,18 @@ #endif #if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLIN UV__EPOLLIN +# define UV__POLLOUT UV__EPOLLOUT +# define UV__POLLERR UV__EPOLLERR +# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLRDHUP UV__EPOLLRDHUP #endif #if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP +# define UV__POLLIN POLLIN +# define UV__POLLOUT POLLOUT +# define UV__POLLERR POLLERR +# define UV__POLLHUP POLLHUP #endif #ifndef UV__POLLIN @@ -118,6 +120,14 @@ # define UV__POLLHUP 8 #endif +#ifndef UV__POLLRDHUP +# ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +# else +# define UV__POLLRDHUP 0x200 +# endif +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. @@ -167,6 +177,7 @@ struct uv__stream_queued_fds_s { /* core */ int uv__nonblock(int fd, int set); int uv__close(int fd); +int uv__close_nocheckstdio(int fd); int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); @@ -180,6 +191,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); int uv__io_active(const uv__io_t* w, unsigned int events); +int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ /* async */ @@ -245,6 +257,9 @@ void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); uv_handle_type uv__handle_type(int fd); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + #if defined(__APPLE__) int uv___stream_fd(const uv_stream_t* handle); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 495f20d285fa30..400b4a4b7c6842 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -48,6 +48,24 @@ int uv__kqueue_init(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = -errno; + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; @@ -241,6 +259,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->flags & EV_ERROR) revents |= UV__POLLERR; + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + if (revents == 0) continue; diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 3ff6fb15e93557..fb8ac3f2379851 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -39,7 +39,7 @@ #define HAVE_IFADDRS_H 1 #ifdef __UCLIBC__ -# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32 +# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 # undef HAVE_IFADDRS_H # endif #endif @@ -52,7 +52,7 @@ # endif # include # include -# include +# include #endif /* HAVE_IFADDRS_H */ /* Available from 2.6.32 onwards. */ @@ -69,7 +69,7 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static unsigned long read_cpufreq(unsigned int cpunum); @@ -140,6 +140,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = UV__EPOLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = -errno; + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes * effectively infinite on 32 bits architectures. To avoid blocking @@ -532,15 +552,42 @@ int uv_uptime(double* uptime) { } +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + *numcpus = num; + return 0; +} + + int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int numcpus; uv_cpu_info_t* ci; int err; + FILE* statfile_fp; *cpu_infos = NULL; *count = 0; - numcpus = sysconf(_SC_NPROCESSORS_ONLN); + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + return err; + assert(numcpus != (unsigned int) -1); assert(numcpus != 0); @@ -550,7 +597,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = read_models(numcpus, ci); if (err == 0) - err = read_times(numcpus, ci); + err = read_times(statfile_fp, numcpus, ci); + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); if (err) { uv_free_cpu_info(ci, numcpus); @@ -608,7 +659,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { defined(__i386__) || \ defined(__mips__) || \ defined(__x86_64__) - fp = fopen("/proc/cpuinfo", "r"); + fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) return -errno; @@ -676,7 +727,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; @@ -688,22 +739,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { unsigned int num; unsigned int len; char buf[1024]; - FILE* fp; clock_ticks = sysconf(_SC_CLK_TCK); assert(clock_ticks != (unsigned long) -1); assert(clock_ticks != 0); - fp = fopen("/proc/stat", "r"); - if (fp == NULL) - return -errno; + rewind(statfile_fp); - if (!fgets(buf, sizeof(buf), fp)) + if (!fgets(buf, sizeof(buf), statfile_fp)) abort(); num = 0; - while (fgets(buf, sizeof(buf), fp)) { + while (fgets(buf, sizeof(buf), statfile_fp)) { if (num >= numcpus) break; @@ -742,7 +790,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { ts.irq = clock_ticks * irq; ci[num++].cpu_times = ts; } - fclose(fp); assert(num == numcpus); return 0; @@ -759,7 +806,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) { "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpunum); - fp = fopen(buf, "r"); + fp = uv__open_file(buf); if (fp == NULL) return 0; diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 96e79439cf07ab..4260df111f3ae4 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -76,6 +76,7 @@ #define UV__EPOLLOUT 4 #define UV__EPOLLERR 8 #define UV__EPOLLHUP 16 +#define UV__EPOLLRDHUP 0x2000 #define UV__EPOLLONESHOT 0x40000000 #define UV__EPOLLET 0x80000000 diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 7f87a713bf40fe..d4fdfa9d5a5480 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -200,9 +200,6 @@ void uv_pipe_connect(uv_connect_t* req, if (err) uv__io_feed(handle->loop, &handle->io_watcher); - /* Mimic the Windows pipe implementation, always - * return 0 and let the callback handle errors. - */ } @@ -234,14 +231,18 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, addrlen = strlen(sa.sun_path); - if (addrlen > *size) { - *size = addrlen; + if (addrlen >= *size) { + *size = addrlen + 1; return UV_ENOBUFS; } memcpy(buffer, sa.sun_path, addrlen); *size = addrlen; + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 37da3b95851b07..e5efb17160ff95 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -34,7 +34,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; @@ -45,6 +45,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { pevents |= UV_READABLE; if (events & UV__POLLOUT) pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; handle->poll_cb(handle, 0, pevents); } @@ -53,6 +55,10 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + err = uv__io_check_fd(loop, fd); + if (err) + return err; + err = uv__nonblock(fd, 1); if (err) return err; @@ -71,7 +77,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_stop(handle->loop, + &handle->io_watcher, + UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -86,7 +94,7 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); uv__poll_stop(handle); @@ -99,6 +107,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events |= UV__POLLIN; if (pevents & UV_WRITABLE) events |= UV__POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; uv__io_start(handle->loop, &handle->io_watcher, events); uv__handle_start(handle); diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 571f8cd778c74f..ef10a3422dc518 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -498,7 +498,7 @@ int uv_spawn(uv_loop_t* loop, } else abort(); - uv__close(signal_pipe[0]); + uv__close_nocheckstdio(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); @@ -530,9 +530,9 @@ int uv_spawn(uv_loop_t* loop, if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) continue; if (pipes[i][0] != -1) - close(pipes[i][0]); + uv__close_nocheckstdio(pipes[i][0]); if (pipes[i][1] != -1) - close(pipes[i][1]); + uv__close_nocheckstdio(pipes[i][1]); } uv__free(pipes); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 7d7ab2633b6f2d..9043664dfcaf9a 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -946,13 +946,14 @@ static void uv__write_callbacks(uv_stream_t* stream) { uv_handle_type uv__handle_type(int fd) { struct sockaddr_storage ss; + socklen_t sslen; socklen_t len; int type; memset(&ss, 0, sizeof(ss)); - len = sizeof(ss); + sslen = sizeof(ss); - if (getsockname(fd, (struct sockaddr*)&ss, &len)) + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) return UV_UNKNOWN_HANDLE; len = sizeof type; @@ -961,6 +962,14 @@ uv_handle_type uv__handle_type(int fd) { return UV_UNKNOWN_HANDLE; if (type == SOCK_STREAM) { +#if defined(_AIX) + /* on AIX the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (sslen == 0) + return UV_NAMED_PIPE; +#endif switch (ss.ss_family) { case AF_UNIX: return UV_NAMED_PIPE; @@ -1082,6 +1091,11 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { } +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; @@ -1187,6 +1201,10 @@ static void uv__read(uv_stream_t* stream) { } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + #undef UV__CMSG_FD_COUNT #undef UV__CMSG_FD_SIZE diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 0c46817b446e61..9a6cc42b5bf3fd 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -116,6 +116,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return -errno; + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index c56a3170259e90..c35bc926bf0fac 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -27,6 +27,9 @@ #include #include +#include /* getrlimit() */ + +#include #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -55,6 +58,11 @@ static void* uv__thread_start(void *arg) int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct thread_ctx* ctx; int err; + pthread_attr_t* attr; +#if defined(__APPLE__) + pthread_attr_t attr_storage; + struct rlimit lim; +#endif ctx = uv__malloc(sizeof(*ctx)); if (ctx == NULL) @@ -63,7 +71,30 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->entry = entry; ctx->arg = arg; - err = pthread_create(tid, NULL, uv__thread_start, ctx); + /* On OSX threads other than the main thread are created with a reduced stack + * size by default, adjust it to RLIMIT_STACK. + */ +#if defined(__APPLE__) + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + attr = &attr_storage; + if (pthread_attr_init(attr)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY && + lim.rlim_cur >= PTHREAD_STACK_MIN) { + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); + } +#else + attr = NULL; +#endif + + err = pthread_create(tid, attr, uv__thread_start, ctx); + + if (attr != NULL) + pthread_attr_destroy(attr); if (err) uv__free(ctx); diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7cc5b714ed302c..32fa37eac96307 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -23,6 +23,7 @@ #include "internal.h" #include "spinlock.h" +#include #include #include #include @@ -33,12 +34,30 @@ static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} 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; + char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -62,7 +81,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * other processes. */ if (type == UV_TTY) { - r = uv__open_cloexec("/dev/tty", O_RDWR); + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; if (r < 0) { /* fallback to using blocking writes */ @@ -185,8 +212,13 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); - if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws)) + if (err == -1) return -errno; *width = ws.ws_col; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 40ed28fec5a662..6b8c584fbe75b1 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -451,13 +451,14 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { } required_len = strlen(handle->path); - if (required_len > *size) { - *size = required_len; + if (required_len >= *size) { + *size = required_len + 1; return UV_ENOBUFS; } memcpy(buffer, handle->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index de0483e1023017..ba306ebc083fbb 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -256,30 +256,48 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; + int repeat; + uint64_t timeout_time; - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); + timeout_time = loop->time + timeout; - if (overlapped) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlapped); - uv_insert_pending_req(loop, req); + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; } } @@ -290,33 +308,51 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; - - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); - - if (success) { - for (i = 0; i < count; i++) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); - uv_insert_pending_req(loop, req); + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } } - - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + break; } } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index e5f3407f8eb27e..39e400ab2dbd19 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -31,7 +31,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { lib->handle = NULL; lib->errmsg = NULL; - if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { return uv__dlerror(lib, GetLastError()); } diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 76ecfebaa24c39..77c935a2d8c8fe 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -63,19 +63,19 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, handle->req_pending = 1; } -static int uv_relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { - int dirlen = wcslen(dir); - int filelen = wcslen(filename); - if (dir[dirlen - 1] == '\\') +static void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + size_t filenamelen = wcslen(filename); + size_t relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1); - (*relpath)[filelen - dirlen - 1] = L'\0'; - return 0; + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; } static int uv_split_path(const WCHAR* filename, WCHAR** dir, @@ -101,12 +101,12 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir, *file = wcsdup(filename); } else { if (dir) { - *dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR)); + *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - wcsncpy(*dir, filename, i); - (*dir)[i] = L'\0'; + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = L'\0'; } *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR)); @@ -159,14 +159,20 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__handle_start(handle); /* Convert name to UTF16. */ - name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR); + + name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); pathw = (WCHAR*)uv__malloc(name_size); if (!pathw) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(path, pathw, - name_size / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + pathw, + name_size / sizeof(WCHAR))) { return uv_translate_sys_error(GetLastError()); } @@ -340,7 +346,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; - int err, sizew, size, result; + int err, sizew, size; char* filename = NULL; WCHAR* filenamew, *long_filenamew = NULL; DWORD offset = 0; @@ -425,39 +431,23 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (long_filenamew) { /* Get the file name out of the long path. */ - result = uv_relative_path(long_filenamew, - handle->dirw, - &filenamew); + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); uv__free(long_filenamew); - - if (result == 0) { - long_filenamew = filenamew; - sizew = -1; - } else { - long_filenamew = NULL; - } - } - - /* - * We could not resolve the long form explicitly. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); - } - } else { - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); + long_filenamew = filenamew; + sizew = -1; } } + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } } else { /* We already have the long name of the file, so just use it. */ filenamew = handle->filew; @@ -466,20 +456,28 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (filenamew) { /* Convert the filename to utf8. */ - size = uv_utf16_to_utf8(filenamew, - sizew, - NULL, - 0); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + NULL, + 0, + NULL, + NULL); if (size) { filename = (char*)uv__malloc(size + 1); if (!filename) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - size = uv_utf16_to_utf8(filenamew, - sizew, - filename, - size); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + filename, + size, + NULL, + NULL); if (size) { filename[size] = '\0'; } else { diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index a32b0127f7e1e9..16e3ae7cf1b416 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -1717,25 +1717,26 @@ static void fs__readlink(uv_fs_t* req) { static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { int r; DWORD w_realpath_len; - WCHAR* w_realpath_ptr; - WCHAR* w_finalpath_ptr = NULL; + WCHAR* w_realpath_ptr = NULL; + WCHAR* w_realpath_buf; w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); if (w_realpath_len == 0) { return -1; } - w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); - if (w_realpath_ptr == NULL) { + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { SetLastError(ERROR_OUTOFMEMORY); return -1; } + w_realpath_ptr = w_realpath_buf; if (pGetFinalPathNameByHandleW(handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } @@ -1744,20 +1745,22 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { if (wcsncmp(w_realpath_ptr, UNC_PATH_PREFIX, UNC_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 6; - *w_finalpath_ptr = L'\\'; + w_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; } else if (wcsncmp(w_realpath_ptr, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 4; + w_realpath_ptr += 4; + w_realpath_len -= 4; } else { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } - r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); - uv__free(w_realpath_ptr); + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); return r; } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index ceed3b7638b457..744f8e02629ccd 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -126,7 +126,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); if (name_len == 0) { req->retcode = uv_translate_sys_error(GetLastError()); goto complete; @@ -170,16 +177,24 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - NULL, - 0); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); assert(name_len > 0); assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); assert(name_len > 0); addrinfo_ptr->ai_canonname = cur_ptr; cur_ptr += ALIGNED_SIZE(name_len); @@ -261,7 +276,8 @@ int uv_getaddrinfo(uv_loop_t* loop, /* calculate required memory size for all input values */ if (node != NULL) { - nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR)); + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); if (nodesize == 0) { err = GetLastError(); goto error; @@ -269,7 +285,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } if (service != NULL) { - servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + NULL, + 0) * sizeof(WCHAR)); if (servicesize == 0) { err = GetLastError(); @@ -294,9 +315,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* the request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(node, - (WCHAR*) alloc_ptr, - nodesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } @@ -309,9 +333,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* in the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(service, - (WCHAR*) alloc_ptr, - servicesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 783f21af0fe9f1..c724793bf05a41 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -246,7 +246,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); DWORD uv__next_timeout(const uv_loop_t* loop); -void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv_process_timers(uv_loop_t* loop); @@ -329,6 +328,8 @@ uint64_t uv__hrtime(double scale); int uv_parent_pid(); int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index bcce80c77e5d57..a784325c589474 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -513,13 +513,18 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } @@ -627,13 +632,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, req->cb = cb; /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } @@ -2038,9 +2048,9 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) *size = 0; err = uv_translate_sys_error(GetLastError()); goto error; - } else if (pipe_prefix_len + addrlen > *size) { + } else if (pipe_prefix_len + addrlen >= *size) { /* "\\\\.\\pipe" + name */ - *size = pipe_prefix_len + addrlen; + *size = pipe_prefix_len + addrlen + 1; err = UV_ENOBUFS; goto error; } @@ -2062,6 +2072,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) addrlen += pipe_prefix_len; *size = addrlen; + buffer[addrlen] = '\0'; err = 0; goto cleanup; diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index ce861d6ffc41eb..d479e521efe24f 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -91,7 +91,11 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; } else { - assert(0); + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ return; } @@ -107,6 +111,10 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { if (handle->events & UV_READABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } } if (handle->events & UV_WRITABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; @@ -184,6 +192,9 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { events |= UV_READABLE; + if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } } if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL)) != 0) { @@ -218,7 +229,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); assert(!(handle->flags & UV__HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); handle->events = events; diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 0da541a2c8685c..27ca7716af6d8a 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -34,13 +34,8 @@ void uv_update_time(uv_loop_t* loop) { uint64_t new_time = uv__hrtime(UV__MILLISEC); - if (new_time > loop->time) { - loop->time = new_time; - } -} - -void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { - loop->time += msecs; + assert(new_time >= loop->time); + loop->time = new_time; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index d87cc699097cf7..1b27f60a6f0c9c 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -292,12 +292,9 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { was_reading = 1; alloc_cb = tty->alloc_cb; read_cb = tty->read_cb; - - if (was_reading) { - err = uv_tty_read_stop(tty); - if (err) { - return uv_translate_sys_error(err); - } + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); } } else { was_reading = 0; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index cb247513046351..1788b1780e9bba 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -87,30 +87,6 @@ void uv__util_init() { } -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size) { - return WideCharToMultiByte(CP_UTF8, - 0, - utf16Buffer, - utf16Size, - utf8Buffer, - utf8Size, - NULL, - NULL); -} - - -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size) { - return MultiByteToWideChar(CP_UTF8, - 0, - utf8Buffer, - -1, - utf16Buffer, - utf16Size); -} - - int uv_exepath(char* buffer, size_t* size_ptr) { int utf8_len, utf16_buffer_len, utf16_len; WCHAR* utf16_buffer; @@ -210,7 +186,7 @@ int uv_cwd(char* buffer, size_t* size) { if (r == 0) { return uv_translate_sys_error(GetLastError()); } else if (r > (int) *size) { - *size = r -1; + *size = r; return UV_ENOBUFS; } @@ -384,7 +360,7 @@ int uv_set_process_title(const char* title) { uv__once_init(); /* Find out how big the buffer for the wide-char title must be */ - length = uv_utf8_to_utf16(title, NULL, 0); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); if (!length) { err = GetLastError(); goto done; @@ -396,7 +372,7 @@ int uv_set_process_title(const char* title) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - length = uv_utf8_to_utf16(title, title_w, length); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); if (!length) { err = GetLastError(); goto done; @@ -434,7 +410,7 @@ static int uv__get_process_title() { } /* Find out what the size of the buffer is that we need */ - length = uv_utf16_to_utf8(title_w, -1, NULL, 0); + length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); if (!length) { return -1; } @@ -446,7 +422,14 @@ static int uv__get_process_title() { } /* Do utf16 -> utf8 conversion here */ - if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) { + if (!WideCharToMultiByte(CP_UTF8, + 0, + title_w, + -1, + process_title, + length, + NULL, + NULL)) { uv__free(process_title); return -1; } @@ -1169,7 +1152,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_os_homedir(char* buffer, size_t* size) { - HANDLE token; + uv_passwd_t pwd; wchar_t path[MAX_PATH]; DWORD bufsize; size_t len; @@ -1183,6 +1166,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len == 0) { r = GetLastError(); + /* Don't return an error if USERPROFILE was not found */ if (r != ERROR_ENVVAR_NOT_FOUND) return uv_translate_sys_error(r); @@ -1190,43 +1174,219 @@ int uv_os_homedir(char* buffer, size_t* size) { /* This should not be possible */ return UV_EIO; } else { - goto convert_buffer; + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; } - /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */ - if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) - return uv_translate_sys_error(GetLastError()); + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); - bufsize = MAX_PATH; - if (!GetUserProfileDirectoryW(token, path, &bufsize)) { - r = GetLastError(); - CloseHandle(token); + if (r != 0) { + return r; + } - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_EIO; + len = strlen(pwd.homedir); - return uv_translate_sys_error(r); + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; } - CloseHandle(token); + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} -convert_buffer: + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } /* Check how much space we need */ - bufsize = uv_utf16_to_utf8(path, -1, NULL, 0); + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + if (bufsize == 0) { return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { - *size = bufsize - 1; + *size = bufsize; return UV_ENOBUFS; } /* Convert to UTF-8 */ - bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + if (bufsize == 0) return uv_translate_sys_error(GetLastError()); *size = bufsize - 1; return 0; } + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer */ + *utf8 = uv__malloc(bufsize); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + -1, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + return uv_translate_sys_error(GetLastError()); + } + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = sizeof(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = sizeof(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 2264d1e89d5fae..2405fa878c0805 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -226,7 +226,7 @@ int process_wait(process_info_t* vec, int n, int timeout) { tv = timebase; for (;;) { /* Check that gettimeofday() doesn't jump back in time. */ - assert(tv.tv_sec == timebase.tv_sec || + assert(tv.tv_sec > timebase.tv_sec || (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec)); elapsed_ms = diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index d18c1daa364702..96cc6377cb1fa6 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -108,10 +108,10 @@ typedef enum { /* This macro cleans up the main loop. This is used to avoid valgrind * warnings about memory being "leaked" by the main event loop. */ -#define MAKE_VALGRIND_HAPPY() \ - do { \ - close_loop(uv_default_loop()); \ - uv_loop_delete(uv_default_loop()); \ +#define MAKE_VALGRIND_HAPPY() \ + do { \ + close_loop(uv_default_loop()); \ + ASSERT(0 == uv_loop_close(uv_default_loop())); \ } while (0) /* Just sugar for wrapping the main() for a task or helper. */ @@ -207,7 +207,7 @@ UNUSED static int can_ipv6(void) { int i; if (uv_interface_addresses(&addr, &count)) - return 1; /* Assume IPv6 support on failure. */ + return 0; /* Assume no IPv6 support on failure. */ supported = 0; for (i = 0; supported == 0 && i < count; i += 1) diff --git a/deps/uv/test/test-condvar.c b/deps/uv/test/test-condvar.c index dbacdba384d158..83b28494adbb3f 100644 --- a/deps/uv/test/test-condvar.c +++ b/deps/uv/test/test-condvar.c @@ -25,24 +25,33 @@ #include #include -typedef struct { +typedef struct worker_config { uv_mutex_t mutex; uv_cond_t cond; - int delay; + int signal_delay; + int wait_delay; int use_broadcast; - volatile int posted; + volatile int posted_1; + volatile int posted_2; + void (*signal_cond)(struct worker_config* c, volatile int* flag); + void (*wait_cond)(struct worker_config* c, const volatile int* flag); } worker_config; static void worker(void* arg) { worker_config* c = arg; + c->signal_cond(c, &c->posted_1); + c->wait_cond(c, &c->posted_2); +} + - if (c->delay) - uv_sleep(c->delay); +static void condvar_signal(worker_config* c, volatile int* flag) { + if (c->signal_delay) + uv_sleep(c->signal_delay); uv_mutex_lock(&c->mutex); - ASSERT(c->posted == 0); - c->posted = 1; + ASSERT(*flag == 0); + *flag = 1; if (c->use_broadcast) uv_cond_broadcast(&c->cond); else @@ -51,21 +60,33 @@ static void worker(void* arg) { } +static void condvar_wait(worker_config* c, const volatile int* flag) { + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + uv_cond_wait(&c->cond, &c->mutex); + } + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_1) { uv_thread_t thread; worker_config wc; memset(&wc, 0, sizeof(wc)); + wc.wait_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -80,15 +101,16 @@ TEST_IMPL(condvar_2) { worker_config wc; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_cond_wait(&wc.cond, &wc.mutex); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -98,22 +120,35 @@ TEST_IMPL(condvar_2) { } +static void condvar_timedwait(worker_config* c, const volatile int* flag) { + int r; + + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0); + } + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_3) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6)); - ASSERT(r == UV_ETIMEDOUT); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -126,19 +161,18 @@ TEST_IMPL(condvar_3) { TEST_IMPL(condvar_4) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -154,16 +188,16 @@ TEST_IMPL(condvar_5) { memset(&wc, 0, sizeof(wc)); wc.use_broadcast = 1; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); diff --git a/deps/uv/test/test-eintr-handling.c b/deps/uv/test/test-eintr-handling.c new file mode 100644 index 00000000000000..1aaf623b789b6e --- /dev/null +++ b/deps/uv/test/test-eintr-handling.c @@ -0,0 +1,94 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 + +TEST_IMPL(eintr_handling) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + iov = uv_buf_init(buf, sizeof(buf)); + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); + + ASSERT(nread == sizeof(test_buf)); + ASSERT(0 == strcmp(buf, test_buf)); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index e02ff2fda5e5d9..35583529e57507 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -531,6 +531,33 @@ TEST_IMPL(fs_event_watch_file_current_dir) { return 0; } +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_file_root_dir) { + uv_loop_t* loop; + int r; + + const char* sys_drive = getenv("SystemDrive"); + char path[] = "\\\\?\\X:\\bootsect.bak"; + + ASSERT(sys_drive != NULL); + strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fail_cb, path, 0); + if (r == UV_ENOENT) + RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &fs_event, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + TEST_IMPL(fs_event_no_callback_after_close) { uv_loop_t* loop = uv_default_loop(); int r; @@ -792,6 +819,7 @@ TEST_IMPL(fs_event_getpath) { r = uv_fs_event_getpath(&fs_event, buf, &len); ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, "watch_dir", len) == 0); r = uv_fs_event_stop(&fs_event); ASSERT(r == 0); diff --git a/deps/uv/test/test-fs-poll.c b/deps/uv/test/test-fs-poll.c index dbc1515b0b1b93..737d50dfd26937 100644 --- a/deps/uv/test/test-fs-poll.c +++ b/deps/uv/test/test-fs-poll.c @@ -173,6 +173,7 @@ TEST_IMPL(fs_poll_getpath) { len = sizeof buf; ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len)); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(0 == memcmp(buf, FIXTURE, len)); uv_close((uv_handle_t*) &poll_handle, close_cb); diff --git a/deps/uv/test/test-get-passwd.c b/deps/uv/test/test-get-passwd.c new file mode 100644 index 00000000000000..58d9c73c691cf3 --- /dev/null +++ b/deps/uv/test/test-get-passwd.c @@ -0,0 +1,80 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +TEST_IMPL(get_passwd) { + uv_passwd_t pwd; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + len = strlen(pwd.username); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.shell == NULL); +#else + len = strlen(pwd.shell); + ASSERT(len > 0); +#endif + + len = strlen(pwd.homedir); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.homedir[len - 1] != '\\'); +#else + ASSERT(pwd.homedir[len - 1] != '/'); +#endif + +#ifdef _WIN32 + ASSERT(pwd.uid == -1); + ASSERT(pwd.gid == -1); +#else + ASSERT(pwd.uid >= 0); + ASSERT(pwd.gid >= 0); +#endif + + /* Test uv_os_free_passwd() */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test a double free */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test invalid input */ + r = uv_os_get_passwd(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-homedir.c b/deps/uv/test/test-homedir.c index cbc47566c55e42..5027d44c1ea358 100644 --- a/deps/uv/test/test-homedir.c +++ b/deps/uv/test/test-homedir.c @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "uv.h" #include "task.h" #include diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 858a20af49c291..8b10f1a5f68507 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -44,6 +44,7 @@ TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) TEST_DECLARE (tty_file) +TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ip6_pton) TEST_DECLARE (ipc_listen_before_write) @@ -154,6 +155,7 @@ TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) TEST_DECLARE (timer_from_check) TEST_DECLARE (timer_null_callback) +TEST_DECLARE (timer_early_check) TEST_DECLARE (idle_starvation) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) @@ -191,12 +193,15 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) +TEST_DECLARE (get_passwd) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) @@ -267,6 +272,9 @@ TEST_DECLARE (fs_event_watch_dir_recursive) TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_twice) TEST_DECLARE (fs_event_watch_file_current_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_file_root_dir) +#endif TEST_DECLARE (fs_event_no_callback_after_close) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) @@ -292,6 +300,7 @@ TEST_DECLARE (threadpool_cancel_work) TEST_DECLARE (threadpool_cancel_fs) TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (thread_local_storage) +TEST_DECLARE (thread_stack_size) TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock_trylock) @@ -301,6 +310,7 @@ TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) +TEST_DECLARE (poll_bad_fdtype) TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) @@ -378,6 +388,7 @@ TASK_LIST_START TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) TEST_ENTRY (tty_file) + TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) TEST_ENTRY (ipc_listen_before_write) @@ -522,6 +533,7 @@ TASK_LIST_START TEST_ENTRY (timer_run_once) TEST_ENTRY (timer_from_check) TEST_ENTRY (timer_null_callback) + TEST_ENTRY (timer_early_check) TEST_ENTRY (idle_starvation) @@ -566,6 +578,7 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) + TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) @@ -575,12 +588,16 @@ TASK_LIST_START TEST_ENTRY (get_memory) + TEST_ENTRY (get_passwd) + TEST_ENTRY (get_loadavg) TEST_ENTRY (handle_fileno) TEST_ENTRY (homedir) + TEST_ENTRY (tmpdir) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) @@ -600,6 +617,7 @@ TASK_LIST_START TEST_ENTRY (poll_duplex) TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) + TEST_ENTRY (poll_bad_fdtype) TEST_ENTRY (socket_buffer_size) @@ -688,6 +706,9 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_twice) TEST_ENTRY (fs_event_watch_file_current_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_file_root_dir) +#endif TEST_ENTRY (fs_event_no_callback_after_close) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) @@ -706,13 +727,21 @@ TASK_LIST_START TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) +#if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */ + /* pthread_join takes a while, especially on AIX. + * Therefore being gratuitous with timeout. + */ + TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 120000) +#else TEST_ENTRY (threadpool_multiple_event_loops) +#endif TEST_ENTRY (threadpool_cancel_getaddrinfo) TEST_ENTRY (threadpool_cancel_getnameinfo) TEST_ENTRY (threadpool_cancel_work) TEST_ENTRY (threadpool_cancel_fs) TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (thread_local_storage) + TEST_ENTRY (thread_stack_size) TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock_trylock) diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c index ee8bb2a9a8bc38..4ab14789a3858b 100644 --- a/deps/uv/test/test-pipe-close-stdout-read-stdin.c +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { int pid; int fd[2]; int status; + char buf; uv_pipe_t stdin_pipe; r = pipe(fd); @@ -64,6 +65,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { * The write side will be closed by the parent process. */ close(fd[1]); + /* block until write end of pipe is closed */ + read(fd[0], &buf, 1); close(0); r = dup(fd[0]); ASSERT(r != -1); diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 5e036f9d528a58..58041c02668271 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -114,6 +114,7 @@ TEST_IMPL(pipe_getsockname) { ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); len = sizeof buf; diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 76495e14fd87c3..2c4740550a198c 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -32,6 +32,7 @@ TEST_IMPL(platform_output) { uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; + uv_passwd_t pwd; int count; int i; int err; @@ -122,5 +123,15 @@ TEST_IMPL(platform_output) { } uv_free_interface_addresses(interfaces, count); + err = uv_os_get_passwd(&pwd); + ASSERT(err == 0); + + printf("uv_os_get_passwd:\n"); + printf(" euid: %ld\n", pwd.uid); + printf(" gid: %ld\n", pwd.gid); + printf(" username: %s\n", pwd.username); + printf(" shell: %s\n", pwd.shell); + printf(" home directory: %s\n", pwd.homedir); + return 0; } diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index be8b00c32ca99b..bfb75af13355ab 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -21,7 +21,9 @@ #include -#ifndef _WIN32 +#ifdef _WIN32 +# include +#else # include # include #endif @@ -49,7 +51,7 @@ typedef struct connection_context_s { size_t read, sent; int is_server_connection; int open_handles; - int got_fin, sent_fin; + int got_fin, sent_fin, got_disconnect; unsigned int events, delayed_events; } connection_context_t; @@ -70,6 +72,8 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +static int disconnects = 0; + static int got_eagain(void) { #ifdef _WIN32 @@ -140,6 +144,7 @@ static connection_context_t* create_connection_context( context->delayed_events = 0; context->got_fin = 0; context->sent_fin = 0; + context->got_disconnect = 0; r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); context->open_handles++; @@ -373,7 +378,13 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } } - if (context->got_fin && context->sent_fin) { + if (events & UV_DISCONNECT) { + context->got_disconnect = 1; + ++disconnects; + new_events &= ~UV_DISCONNECT; + } + + if (context->got_fin && context->sent_fin && context->got_disconnect) { /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -461,9 +472,9 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) { #endif connection_context = create_connection_context(sock, 1); - connection_context->events = UV_READABLE | UV_WRITABLE; + connection_context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&connection_context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -505,9 +516,9 @@ static void start_client(void) { sock = create_bound_socket(addr); context = create_connection_context(sock, 0); - context->events = UV_READABLE | UV_WRITABLE; + context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -541,6 +552,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); + ASSERT(disconnects == NUM_CLIENTS * 2); MAKE_VALGRIND_HAPPY(); } @@ -558,3 +570,29 @@ TEST_IMPL(poll_unidirectional) { start_poll_test(); return 0; } + + +/* Windows won't let you open a directory so we open a file instead. + * OS X lets you poll a file so open the $PWD instead. Both fail + * on Linux so it doesn't matter which one we pick. Both succeed + * on FreeBSD, Solaris and AIX so skip the test on those platforms. + */ +TEST_IMPL(poll_bad_fdtype) { +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ + !defined(_AIX) + uv_poll_t poll_handle; + int fd; + +#if defined(_WIN32) + fd = open("test/fixtures/empty_file", O_RDONLY); +#else + fd = open(".", O_RDONLY); +#endif + ASSERT(fd != -1); + ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == close(fd)); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tcp-close-while-connecting.c b/deps/uv/test/test-tcp-close-while-connecting.c index 2c39b652b61078..60df7a574409aa 100644 --- a/deps/uv/test/test-tcp-close-while-connecting.c +++ b/deps/uv/test/test-tcp-close-while-connecting.c @@ -72,7 +72,7 @@ TEST_IMPL(tcp_close_while_connecting) { RETURN_SKIP("Network unreachable."); ASSERT(r == 0); ASSERT(0 == uv_timer_init(loop, &timer1_handle)); - ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0)); + ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 1, 0)); ASSERT(0 == uv_timer_init(loop, &timer2_handle)); ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0)); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); diff --git a/deps/uv/test/test-thread.c b/deps/uv/test/test-thread.c index 7f3321aa06d2c0..10bec3fe6c6587 100644 --- a/deps/uv/test/test-thread.c +++ b/deps/uv/test/test-thread.c @@ -209,3 +209,24 @@ TEST_IMPL(thread_local_storage) { uv_key_delete(&tls_key); return 0; } + + +#if defined(__APPLE__) +static void thread_check_stack(void* arg) { + /* 512KB is the default stack size of threads other than the main thread + * on OSX. */ + ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); +} +#endif + + +TEST_IMPL(thread_stack_size) { +#if defined(__APPLE__) + uv_thread_t thread; + ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT(0 == uv_thread_join(&thread)); + return 0; +#else + RETURN_SKIP("OSX only test"); +#endif +} diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c index aba050fd64c72a..080a73005ee3c2 100644 --- a/deps/uv/test/test-timer.c +++ b/deps/uv/test/test-timer.c @@ -301,3 +301,30 @@ TEST_IMPL(timer_null_callback) { MAKE_VALGRIND_HAPPY(); return 0; } + + +static uint64_t timer_early_check_expected_time; + + +static void timer_early_check_cb(uv_timer_t* handle) { + uint64_t hrtime = uv_hrtime() / 1000000; + ASSERT(hrtime >= timer_early_check_expected_time); +} + + +TEST_IMPL(timer_early_check) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tmpdir.c b/deps/uv/test/test-tmpdir.c new file mode 100644 index 00000000000000..29e8055f1d5d91 --- /dev/null +++ b/deps/uv/test/test-tmpdir.c @@ -0,0 +1,71 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index b844959d526340..461d1941359018 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -28,6 +28,13 @@ #else /* Unix */ # include # include +# if defined(__linux__) +# include +# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# include +# elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# endif #endif #include @@ -182,3 +189,35 @@ TEST_IMPL(tty_file) { #endif return 0; } + +TEST_IMPL(tty_pty) { +# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + int master_fd, slave_fd; + struct winsize w; + uv_loop_t loop; + uv_tty_t master_tty, slave_tty; + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w)); + ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + /* Check if the file descriptor was reopened. If it is, + * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + */ + ASSERT(0 == (slave_tty.flags & 0x80)); + /* The master_fd of a pty should never be reopened. + */ + ASSERT(master_tty.flags & 0x80); + ASSERT(0 == close(slave_fd)); + uv_close((uv_handle_t*) &slave_tty, NULL); + ASSERT(0 == close(master_fd)); + uv_close((uv_handle_t*) &master_tty, NULL); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); +#endif + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 635a234ea6eee8..757540193dd7a2 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -92,6 +92,7 @@ 'src/win/req.c', 'src/win/req-inl.h', 'src/win/signal.c', + 'src/win/snprintf.c', 'src/win/stream.c', 'src/win/stream-inl.h', 'src/win/tcp.c', @@ -104,13 +105,6 @@ 'src/win/winsock.c', 'src/win/winsock.h', ], - 'conditions': [ - ['MSVS_VERSION < "2015"', { - 'sources': [ - 'src/win/snprintf.c' - ] - }] - ], 'link_settings': { 'libraries': [ '-ladvapi32', @@ -247,6 +241,7 @@ '_ALL_SOURCE', '_XOPEN_SOURCE=500', '_LINUX_SOURCE_COMPAT', + '_THREAD_SAFE', ], 'link_settings': { 'libraries': [ @@ -300,6 +295,7 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', + 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', @@ -308,6 +304,7 @@ 'test/test-fs-event.c', 'test/test-get-currentexe.c', 'test/test-get-memory.c', + 'test/test-get-passwd.c', 'test/test-getaddrinfo.c', 'test/test-getnameinfo.c', 'test/test-getsockname.c', @@ -386,6 +383,7 @@ 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', 'test/test-thread-equal.c', + 'test/test-tmpdir.c', 'test/test-mutexes.c', 'test/test-thread.c', 'test/test-barrier.c', @@ -417,7 +415,8 @@ [ 'OS=="win"', { 'sources': [ 'test/runner-win.c', - 'test/runner-win.h' + 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX @@ -427,6 +426,11 @@ 'test/runner-unix.h', ], }], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE 'defines': [ '__EXTENSIONS__', @@ -485,6 +489,7 @@ 'sources': [ 'test/runner-win.c', 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 696f0db30e15ad..9a7ed4b8c512e0 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -49,6 +49,7 @@ if not defined VS140COMNTOOLS goto vc-set-2013 if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013 call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2015 +echo Using Visual Studio 2015 goto select-target :vc-set-2013 @@ -57,6 +58,7 @@ if not defined VS120COMNTOOLS goto vc-set-2012 if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2013 +echo Using Visual Studio 2013 goto select-target :vc-set-2012 @@ -65,6 +67,7 @@ if not defined VS110COMNTOOLS goto vc-set-2010 if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2012 +echo Using Visual Studio 2012 goto select-target :vc-set-2010 @@ -73,6 +76,7 @@ if not defined VS100COMNTOOLS goto vc-set-2008 if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008 call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2010 +echo Using Visual Studio 2010 goto select-target :vc-set-2008 @@ -81,6 +85,7 @@ if not defined VS90COMNTOOLS goto vc-set-notfound if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2008 +echo Using Visual Studio 2008 goto select-target :vc-set-notfound From e2bc22e63061fe7707a78c02e0c40f7470cdb989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 17 May 2016 00:25:23 +0200 Subject: [PATCH 2/6] deps: upgrade libuv to 1.9.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/nodejs/node/issues/4002 Fixes: https://github.com/nodejs/node/issues/5384 Fixes: https://github.com/nodejs/node/issues/6563 Refs: https://github.com/nodejs/node/issues/2680#issuecomment-213521708 PR-URL: https://github.com/nodejs/node/pull/6796 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Johan Bergström Reviewed-By: Myles Borins --- deps/uv/AUTHORS | 4 + deps/uv/ChangeLog | 89 ++++++++++ deps/uv/Makefile.am | 13 +- deps/uv/Makefile.mingw | 1 + deps/uv/README.md | 5 + deps/uv/android-configure | 4 +- deps/uv/appveyor.yml | 2 +- deps/uv/common.gypi | 7 - deps/uv/configure.ac | 5 +- deps/uv/docs/src/poll.rst | 6 + deps/uv/include/pthread-barrier.h | 64 +++++++ deps/uv/include/uv-unix.h | 21 +-- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv-win.h | 3 +- deps/uv/src/unix/aix.c | 82 +++++---- deps/uv/src/unix/async.c | 4 +- deps/uv/src/unix/core.c | 10 +- deps/uv/src/unix/freebsd.c | 8 +- deps/uv/src/unix/fs.c | 15 +- deps/uv/src/unix/internal.h | 58 ++----- deps/uv/src/unix/kqueue.c | 38 +++-- deps/uv/src/unix/linux-core.c | 69 +++++--- deps/uv/src/unix/linux-inotify.c | 2 +- deps/uv/src/unix/linux-syscalls.h | 8 - deps/uv/src/unix/openbsd.c | 4 +- deps/uv/src/unix/pipe.c | 4 +- deps/uv/src/unix/poll.c | 14 +- deps/uv/src/unix/pthread-barrier.c | 120 ++++++++++++++ deps/uv/src/unix/pthread-fixes.c | 70 ++------ deps/uv/src/unix/signal.c | 2 +- deps/uv/src/unix/stream.c | 70 ++++---- deps/uv/src/unix/sunos.c | 20 ++- deps/uv/src/unix/tcp.c | 4 +- deps/uv/src/unix/thread.c | 109 +++++------- deps/uv/src/unix/udp.c | 20 +-- deps/uv/src/uv-common.c | 29 +++- deps/uv/src/win/fs-event.c | 61 +++---- deps/uv/src/win/fs.c | 18 +- deps/uv/src/win/internal.h | 3 +- deps/uv/src/win/tty.c | 174 +++++++++++++++----- deps/uv/src/win/util.c | 108 +++++------- deps/uv/test/test-emfile.c | 7 + deps/uv/test/test-fs-event.c | 11 +- deps/uv/test/test-fs.c | 4 + deps/uv/test/test-get-passwd.c | 10 +- deps/uv/test/test-homedir.c | 14 +- deps/uv/test/test-list.h | 6 + deps/uv/test/test-platform-output.c | 5 + deps/uv/test/test-poll.c | 11 +- deps/uv/test/test-tcp-create-socket-early.c | 3 + deps/uv/test/test-tcp-write-queue-order.c | 2 + deps/uv/test/test-tty.c | 69 ++++++++ deps/uv/test/test-udp-create-socket-early.c | 3 + deps/uv/uv.gyp | 7 +- deps/uv/vcbuild.bat | 10 +- 55 files changed, 962 insertions(+), 550 deletions(-) create mode 100644 deps/uv/include/pthread-barrier.h create mode 100644 deps/uv/src/unix/pthread-barrier.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 9a9e9c2a2204b8..7acee7c5333388 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -253,3 +253,7 @@ Robert Chiras Kári Tristan Helgason Krishnaraj Bhat Enno Boland +Michael Fero +Robert Jefe Lindstaedt +Myles Borins +Tony Theodore diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 85d40113e4f052..3f376de6bae6c3 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,92 @@ +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c + +Changes since version 1.9.0: + +* test: handle root home directories (cjihrig) + +* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) + +* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) + +* win: fix var declaration to be C89 compliant (Michael Fero) + +* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) + +* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) + +* Revert "win,build: remove unused build defines" (cjihrig) + +* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) + +* linux: don't abort on malformed /proc/stat (Ben Noordhuis) + +* linux: fix long lines in linux-core.c (Ben Noordhuis) + +* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) + +* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) + +* unix: delay signal handling until after normal i/o (Ben Noordhuis) + +* android: pthread_sigmask() does not set errno (Oguz Bastemur) + +* win: work around sharepoint scandir bug (Ben Noordhuis) + +* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) + +* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) + +* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) + +* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) + +* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) + +* unix: error on realpath if PATH_MAX is undefined (Myles Borins) + +* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) + +* build: bump android ndk version (Kári Tristan Helgason) + +* build: always compile with -fvisibility=hidden (Ben Noordhuis) + +* test: fix -Wformat warnings in platform test (Ben Noordhuis) + +* win: clarify fsevents handling code (Saúl Ibarra Corretgé) + +* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) + +* build, mingw: set LIBS in configure.ac (Tony Theodore) + +* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) + +* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* darwin: work around condition variable kernel bug (Ben Noordhuis) + +* darwin: make thread stack multiple of page size (Ben Noordhuis) + +* build,win: rename platform to msbuild_platform (João Reis) + +* gitignore: ignore VS temporary database files (João Reis) + +* test: skip emfile on AIX (Imran Iqbal) + +* unix: use system allocator for scandir() (cjihrig) + +* common: release uv_fs_scandir() array (cjihrig) + +* win: call uv__fs_scandir_cleanup() (cjihrig) + +* win,tty: fix read stop in line mode (João Reis) + +* win,tty: don't duplicate handle for line reads (João Reis) + +* win,tty: restore cursor after canceling line read (Alexis Campailla) + + 2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 Changes since version 1.8.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index dfd4353a31b649..05ccd58ac9612b 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -43,8 +43,8 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 -LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ @@ -290,20 +290,23 @@ endif if ANDROID include_HEADERS += include/android-ifaddrs.h \ - include/pthread-fixes.h + include/pthread-barrier.h libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c + src/unix/pthread-fixes.c \ + src/unix/pthread-barrier.c endif if DARWIN -include_HEADERS += include/uv-darwin.h +include_HEADERS += include/uv-darwin.h \ + include/pthread-barrier.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/darwin.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ - src/unix/proctitle.c + src/unix/proctitle.c \ + src/unix/pthread-barrier.c test_run_tests_LDFLAGS += -lutil endif diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 3130bac473d30c..156f15dab159f1 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -20,6 +20,7 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 17304a7ab57125..e94fcc902f9981 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -60,6 +60,11 @@ Build documentation as HTML: $ make html +Build documentation as HTML and live reload it when it changes (this requires +sphinx-autobuild to be installed and is only supported on Unix): + + $ make livehtml + Build documentation as man pages: $ make man diff --git a/deps/uv/android-configure b/deps/uv/android-configure index e0b250fb6348e2..7ffc035c1bfbfc 100755 --- a/deps/uv/android-configure +++ b/deps/uv/android-configure @@ -3,7 +3,7 @@ export TOOLCHAIN=$PWD/android-toolchain mkdir -p $TOOLCHAIN $1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.8 \ + --toolchain=arm-linux-androideabi-4.9 \ --arch=arm \ --install-dir=$TOOLCHAIN \ --platform=android-21 @@ -14,7 +14,7 @@ export CXX=arm-linux-androideabi-g++ export LINK=arm-linux-androideabi-g++ export PLATFORM=android -if [ $2 -a $2 == 'gyp' ] +if [[ $2 == 'gyp' ]] then ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android fi diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index 835730b924c8ff..c7ea736502b2ac 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.9.0.build{build} +version: v1.9.1.build{build} install: - cinst -y nsis diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 7cebcde5f89137..56bca2948db6d9 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -1,6 +1,5 @@ { 'variables': { - 'visibility%': 'hidden', # V8's visibility setting 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds @@ -156,9 +155,6 @@ 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'visibility=="hidden"', { - 'cflags': [ '-fvisibility=hidden' ], - }], ], }], ['OS=="mac"', { @@ -170,9 +166,6 @@ 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'PREBINDING': 'NO', # No -Wl,-prebind 'USE_HEADERMAP': 'NO', diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 2d5a3b9de5eb6d..d9251f31985427 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.9.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.1], [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]) @@ -58,6 +58,9 @@ AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) +AS_CASE([$host_os],[mingw*], [ + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" +]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst index 69d45be6d32b29..004ff4b92e5ea5 100644 --- a/deps/uv/docs/src/poll.rst +++ b/deps/uv/docs/src/poll.rst @@ -31,6 +31,8 @@ closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`. On windows only sockets can be polled with poll handles. On Unix any file descriptor that would be accepted by :man:`poll(2)` can be used. +.. note:: + On AIX, watching for disconnection is not supported. Data types ---------- @@ -101,6 +103,10 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. note:: + Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set + on the `events` field in the callback. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. .. c:function:: int uv_poll_stop(uv_poll_t* poll) diff --git a/deps/uv/include/pthread-barrier.h b/deps/uv/include/pthread-barrier.h new file mode 100644 index 00000000000000..084e1c2d556e3e --- /dev/null +++ b/deps/uv/include/pthread-barrier.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _UV_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#include /* sem_t */ + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index 82d193bdca4fe2..a852c40e49baa5 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -38,9 +38,6 @@ #include #include -#ifdef __ANDROID__ -#include "pthread-fixes.h" -#endif #include #include "uv-threadpool.h" @@ -60,6 +57,10 @@ # include "uv-bsd.h" #endif +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.h" +#endif + #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif @@ -136,22 +137,8 @@ typedef pthread_rwlock_t uv_rwlock_t; typedef UV_PLATFORM_SEM_T uv_sem_t; typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; - -#if defined(__APPLE__) && defined(__MACH__) - -typedef struct { - unsigned int n; - unsigned int count; - uv_mutex_t mutex; - uv_sem_t turnstile1; - uv_sem_t turnstile2; -} uv_barrier_t; - -#else /* defined(__APPLE__) && defined(__MACH__) */ - typedef pthread_barrier_t uv_barrier_t; -#endif /* defined(__APPLE__) && defined(__MACH__) */ /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index cb666182892dea..08ad0edaa748e0 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,7 +32,7 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 -#define UV_VERSION_PATCH 0 +#define UV_VERSION_PATCH 1 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 6b537fed0d9019..a75dba8d1c5afa 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -483,7 +483,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); union { \ struct { \ /* Used for readable TTY handles */ \ - HANDLE read_line_handle; \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index bcaa5ee50bc203..2276985fc0dd95 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -118,6 +118,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { uv__io_t* w; uint64_t base; uint64_t diff; + int have_signals; int nevents; int count; int nfds; @@ -225,6 +226,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -255,13 +257,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } - w->cb(loop, w, pe->revents); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + nevents++; } + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -782,53 +797,30 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* filename, unsigned int flags) { #ifdef HAVE_SYS_AHAFS_EVPRODS_H - int fd, rc, i = 0, res = 0; + int fd, rc, str_offset = 0; char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; - char fname[PATH_MAX]; - char *p; + char readlink_cwd[PATH_MAX]; - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - cwd[i] = 0; - absolute_path[i] = 0; - fname[i] = 0; - } - i = 0; /* Figure out whether filename is absolute or not */ if (filename[0] == '/') { - /* We have absolute pathname, create the relative pathname*/ - sprintf(absolute_path, filename); - p = strrchr(filename, '/'); - p++; + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); } else { - if (filename[0] == '.' && filename[1] == '/') { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - p++; - } else { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - } - /* Copy to filename buffer */ - while(filename[i] != NULL) { - *p = filename[i]; - i++; - p++; - } + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); } if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ @@ -845,7 +837,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->path = uv__strdup(filename); handle->cb = cb; - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; #else @@ -1036,14 +1028,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, } if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } ifc.ifc_req = (struct ifreq*)uv__malloc(size); ifc.ifc_len = size; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } @@ -1062,7 +1054,7 @@ 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) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 184b598126eb2c..393cdebd4ea3fc 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -223,7 +223,7 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { return err; uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &wa->io_watcher, UV__POLLIN); + uv__io_start(loop, &wa->io_watcher, POLLIN); wa->wfd = pipefd[1]; wa->cb = cb; @@ -241,7 +241,7 @@ void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { wa->wfd = -1; } - uv__io_stop(loop, &wa->io_watcher, UV__POLLIN); + uv__io_stop(loop, &wa->io_watcher, POLLIN); uv__close(wa->io_watcher.fd); wa->io_watcher.fd = -1; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 9aaca84187001e..cdcd0b504f32f4 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -762,7 +762,7 @@ static int uv__run_pending(uv_loop_t* loop) { QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, pending_queue); - w->cb(loop, w, UV__POLLOUT); + w->cb(loop, w, POLLOUT); } return 1; @@ -833,7 +833,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -866,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -898,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -913,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index b747abdf5bc46e..adc95235ceefdf 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -292,7 +292,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(cpuspeed); if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -301,7 +301,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -314,8 +314,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(cp_times)); - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(cp_times); + uv__free(*cpu_infos); return -errno; } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 8936ad9d837095..085970a06d9e7b 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -33,6 +33,7 @@ #include #include #include +#include /* PATH_MAX */ #include #include @@ -205,6 +206,13 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { # else return futimes(req->file, tv); # endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); #else errno = ENOSYS; return -1; @@ -362,9 +370,10 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { if (dents != NULL) { int i; + /* Memory was allocated using the system allocator, so use free() here. */ for (i = 0; i < n; i++) - uv__free(dents[i]); - uv__free(dents); + free(dents[i]); + free(dents); } errno = saved_errno; @@ -383,7 +392,7 @@ static ssize_t uv__fs_pathmax_size(const char* path) { #if defined(PATH_MAX) return PATH_MAX; #else - return 4096; +#error "PATH_MAX undefined in the current platform" #endif } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 938e76f1d18d88..670b14bc2a2aa5 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -44,15 +44,25 @@ #endif /* __sun */ #if defined(_AIX) -#define reqevents events -#define rtnevents revents -#include +# define reqevents events +# define rtnevents revents +# include +#else +# include #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE # include #endif +#if defined(__ANDROID__) +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); +# ifdef pthread_sigmask +# undef pthread_sigmask +# endif +# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset) +#endif + #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) @@ -89,43 +99,11 @@ # define UV_UNUSED(declaration) declaration #endif -#if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP -# define UV__POLLRDHUP UV__EPOLLRDHUP -#endif - -#if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP -#endif - -#ifndef UV__POLLIN -# define UV__POLLIN 1 -#endif - -#ifndef UV__POLLOUT -# define UV__POLLOUT 2 -#endif - -#ifndef UV__POLLERR -# define UV__POLLERR 4 -#endif - -#ifndef UV__POLLHUP -# define UV__POLLHUP 8 -#endif - -#ifndef UV__POLLRDHUP -# ifdef POLLRDHUP -# define UV__POLLRDHUP POLLRDHUP -# else -# define UV__POLLRDHUP 0x200 -# endif +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 #endif #if !defined(O_CLOEXEC) && defined(__FreeBSD__) diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 400b4a4b7c6842..fffd4626f17579 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -78,6 +78,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t set; uint64_t base; uint64_t diff; + int have_signals; int filter; int fflags; int count; @@ -103,7 +104,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); - if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { + if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; @@ -124,7 +125,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } - if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { + if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { @@ -192,6 +193,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -219,8 +221,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_VNODE) { - assert(w->events == UV__POLLIN); - assert(w->pevents == UV__POLLIN); + assert(w->events == POLLIN); + assert(w->pevents == POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; @@ -229,8 +231,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents = 0; if (ev->filter == EVFILT_READ) { - if (w->pevents & UV__POLLIN) { - revents |= UV__POLLIN; + if (w->pevents & POLLIN) { + revents |= POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ @@ -243,8 +245,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_WRITE) { - if (w->pevents & UV__POLLOUT) { - revents |= UV__POLLOUT; + if (w->pevents & POLLOUT) { + revents |= POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ @@ -257,7 +259,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->flags & EV_ERROR) - revents |= UV__POLLERR; + revents |= POLLERR; if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) revents |= UV__POLLRDHUP; @@ -265,12 +267,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (revents == 0) continue; - w->cb(loop, w, revents); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + nevents++; } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -409,7 +425,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* defined(__APPLE__) */ - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index fb8ac3f2379851..b48a1111701753 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -18,6 +18,11 @@ * IN THE SOFTWARE. */ +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + #include "uv.h" #include "internal.h" @@ -69,7 +74,9 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static unsigned long read_cpufreq(unsigned int cpunum); @@ -102,7 +109,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { void uv__platform_loop_delete(uv_loop_t* loop) { if (loop->inotify_fd == -1) return; - uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); uv__close(loop->inotify_fd); loop->inotify_fd = -1; } @@ -144,7 +151,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { struct uv__epoll_event e; int rc; - e.events = UV__EPOLLIN; + e.events = POLLIN; e.data = -1; rc = 0; @@ -181,6 +188,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t sigset; uint64_t sigmask; uint64_t base; + int have_signals; int nevents; int count; int nfds; @@ -308,6 +316,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -341,7 +350,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * the current watcher. Also, filters out events that users has not * requested us to watch. */ - pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; + pe->events &= w->pevents | POLLERR | POLLHUP; /* Work around an epoll quirk where it sometimes reports just the * EPOLLERR or EPOLLHUP event. In order to force the event loop to @@ -358,17 +367,31 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * needs to remember the error/hangup event. We should get that for * free when we switch over to edge-triggered I/O. */ - if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP) - pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { - w->cb(loop, w, pe->events); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + nevents++; } } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -557,7 +580,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { char buf[1024]; if (!fgets(buf, sizeof(buf), statfile_fp)) - abort(); + return -EIO; num = 0; while (fgets(buf, sizeof(buf), statfile_fp)) { @@ -566,6 +589,9 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { num++; } + if (num == 0) + return -EIO; + *numcpus = num; return 0; } @@ -586,26 +612,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = uv__cpu_num(statfile_fp, &numcpus); if (err < 0) - return err; - - assert(numcpus != (unsigned int) -1); - assert(numcpus != 0); + goto out; + err = -ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) - return -ENOMEM; + goto out; err = read_models(numcpus, ci); if (err == 0) err = read_times(statfile_fp, numcpus, ci); - if (fclose(statfile_fp)) - if (errno != EINTR && errno != EINPROGRESS) - abort(); - if (err) { uv_free_cpu_info(ci, numcpus); - return err; + goto out; } /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. @@ -616,8 +636,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = ci; *count = numcpus; + err = 0; - return 0; +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; } @@ -727,7 +754,9 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index 282912115d8120..4708c051d3b540 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -102,7 +102,7 @@ static int init_inotify(uv_loop_t* loop) { loop->inotify_fd = err; uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 4260df111f3ae4..4c095e9b537996 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -72,14 +72,6 @@ #define UV__EPOLL_CTL_DEL 2 #define UV__EPOLL_CTL_MOD 3 -#define UV__EPOLLIN 1 -#define UV__EPOLLOUT 4 -#define UV__EPOLLERR 8 -#define UV__EPOLLHUP 16 -#define UV__EPOLLRDHUP 0x2000 -#define UV__EPOLLONESHOT 0x40000000 -#define UV__EPOLLET 0x80000000 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 6a3909a666c1d0..8c40bde40f69ad 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -247,7 +247,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -258,7 +258,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[2] = i; size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index d4fdfa9d5a5480..c8d163dcc796d5 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -102,7 +102,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { handle->connection_cb = cb; handle->io_watcher.cb = uv__server_io; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); return 0; } @@ -185,7 +185,7 @@ void uv_pipe_connect(uv_connect_t* req, } if (err == 0) - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); out: handle->delayed_error = err; diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index e5efb17160ff95..0d5944b0afb8ba 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -33,17 +33,17 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + if (events & POLLERR) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; } pevents = 0; - if (events & UV__POLLIN) + if (events & POLLIN) pevents |= UV_READABLE; - if (events & UV__POLLOUT) + if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) pevents |= UV_DISCONNECT; @@ -79,7 +79,7 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -104,9 +104,9 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) - events |= UV__POLLIN; + events |= POLLIN; if (pevents & UV_WRITABLE) - events |= UV__POLLOUT; + events |= POLLOUT; if (pevents & UV_DISCONNECT) events |= UV__POLLRDHUP; diff --git a/deps/uv/src/unix/pthread-barrier.c b/deps/uv/src/unix/pthread-barrier.c new file mode 100644 index 00000000000000..f57bf25080c4e1 --- /dev/null +++ b/deps/uv/src/unix/pthread-barrier.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "uv-common.h" +#include "pthread-barrier.h" + +#include +#include + +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + assert(pthread_cond_signal(&b->cond) == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} diff --git a/deps/uv/src/unix/pthread-fixes.c b/deps/uv/src/unix/pthread-fixes.c index 3a71eb5aae743f..fb179958467231 100644 --- a/deps/uv/src/unix/pthread-fixes.c +++ b/deps/uv/src/unix/pthread-fixes.c @@ -29,76 +29,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Android versions < 4.1 have a broken pthread_sigmask. - * Note that this block of code must come before any inclusion of - * pthread-fixes.h so that the real pthread_sigmask can be referenced. - * */ +/* Android versions < 4.1 have a broken pthread_sigmask. */ #include #include #include int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { static int workaround; + int err; if (workaround) { return sigprocmask(how, set, oset); - } else if (pthread_sigmask(how, set, oset)) { - if (errno == EINVAL && sigprocmask(how, set, oset) == 0) { - workaround = 1; - return 0; - } else { - return -1; - } } else { - return 0; - } -} - -/*Android doesn't provide pthread_barrier_t for now.*/ -#ifndef PTHREAD_BARRIER_SERIAL_THREAD - -#include "pthread-fixes.h" - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - barrier->count = count; - pthread_mutex_init(&barrier->mutex, NULL); - pthread_cond_init(&barrier->cond, NULL); - return 0; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - /* Lock the mutex*/ - pthread_mutex_lock(&barrier->mutex); - /* Decrement the count. If this is the first thread to reach 0, wake up - waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/ - if (--barrier->count == 0) { - /* First thread to reach the barrier */ - pthread_cond_broadcast(&barrier->cond); - pthread_mutex_unlock(&barrier->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } } - /* Otherwise, wait for other threads until the count reaches 0, then - return 0 to indicate this is not the first thread.*/ - do { - pthread_cond_wait(&barrier->cond, &barrier->mutex); - } while (barrier->count > 0); - - pthread_mutex_unlock(&barrier->mutex); - return 0; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier) { - barrier->count = 0; - pthread_cond_destroy(&barrier->cond); - pthread_mutex_destroy(&barrier->mutex); - return 0; -} - -#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ -int pthread_yield(void) { - sched_yield(); return 0; } diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index edd9085d3f352f..d82b9b7cf83ca1 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -222,7 +222,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { uv__io_init(&loop->signal_io_watcher, uv__signal_event, loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN); + uv__io_start(loop, &loop->signal_io_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9043664dfcaf9a..7dbc556f74e0bc 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -159,9 +159,9 @@ static void uv__stream_osx_select(void* arg) { memset(s->sread, 0, s->sread_sz); memset(s->swrite, 0, s->swrite_sz); - if (uv__io_active(&stream->io_watcher, UV__POLLIN)) + if (uv__io_active(&stream->io_watcher, POLLIN)) FD_SET(fd, s->sread); - if (uv__io_active(&stream->io_watcher, UV__POLLOUT)) + if (uv__io_active(&stream->io_watcher, POLLOUT)) FD_SET(fd, s->swrite); FD_SET(s->int_fd, s->sread); @@ -202,9 +202,9 @@ static void uv__stream_osx_select(void* arg) { /* Handle events */ events = 0; if (FD_ISSET(fd, s->sread)) - events |= UV__POLLIN; + events |= POLLIN; if (FD_ISSET(fd, s->swrite)) - events |= UV__POLLOUT; + events |= POLLOUT; assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); if (events != 0) { @@ -233,14 +233,14 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { ACCESS_ONCE(int, s->events) = 0; assert(events != 0); - assert(events == (events & (UV__POLLIN | UV__POLLOUT))); + assert(events == (events & (POLLIN | POLLOUT))); /* Invoke callback on event-loop */ - if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN); + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); - if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT); + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); if (stream->flags & UV_CLOSING) return; @@ -437,7 +437,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { - assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); assert(stream->flags & UV_CLOSED); if (stream->connect_req) { @@ -511,11 +511,11 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; stream = container_of(w, uv_stream_t, io_watcher); - assert(events == UV__POLLIN); + assert(events == POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_CLOSING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); /* connection_cb can close the server socket while we're * in the loop so check it on each iteration. @@ -552,7 +552,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (stream->accepted_fd != -1) { /* The user hasn't yet accepted called uv_accept() */ - uv__io_stop(loop, &stream->io_watcher, UV__POLLIN); + uv__io_stop(loop, &stream->io_watcher, POLLIN); return; } @@ -626,7 +626,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { } else { server->accepted_fd = -1; if (err == 0) - uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); + uv__io_start(server->loop, &server->io_watcher, POLLIN); } return err; } @@ -660,7 +660,7 @@ static void uv__drain(uv_stream_t* stream) { int err; assert(QUEUE_EMPTY(&stream->write_queue)); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); /* Shutdown? */ @@ -846,8 +846,8 @@ static void uv__write(uv_stream_t* stream) { /* Error */ req->error = -errno; uv__write_req_finish(req); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); - if (!uv__io_active(&stream->io_watcher, UV__POLLIN)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); return; @@ -910,7 +910,7 @@ static void uv__write(uv_stream_t* stream) { assert(!(stream->flags & UV_STREAM_BLOCKING)); /* We're not done. */ - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); /* Notify select() thread about state change */ uv__stream_osx_interrupt_select(stream); @@ -989,8 +989,8 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags |= UV_STREAM_READ_EOF; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); @@ -1159,7 +1159,7 @@ static void uv__read(uv_stream_t* stream) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ if (stream->flags & UV_STREAM_READING) { - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } stream->read_cb(stream, 0, &buf); @@ -1168,8 +1168,8 @@ static void uv__read(uv_stream_t* stream) { stream->read_cb(stream, -errno, &buf); if (stream->flags & UV_STREAM_READING) { stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); } @@ -1230,7 +1230,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->shutdown_req = req; stream->flags |= UV_STREAM_SHUTTING; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); return 0; @@ -1255,7 +1255,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ - if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) + if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); if (uv__stream_fd(stream) == -1) @@ -1267,7 +1267,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * have to do anything. If the partial read flag is not set, we can't * report the EOF yet because there is still data to read. */ - if ((events & UV__POLLHUP) && + if ((events & POLLHUP) && (stream->flags & UV_STREAM_READING) && (stream->flags & UV_STREAM_READ_PARTIAL) && !(stream->flags & UV_STREAM_READ_EOF)) { @@ -1278,7 +1278,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ - if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { + if (events & (POLLOUT | POLLERR | POLLHUP)) { uv__write(stream); uv__write_callbacks(stream); @@ -1327,7 +1327,7 @@ static void uv__stream_connect(uv_stream_t* stream) { uv__req_unregister(stream->loop, req); if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); } if (req->cb) @@ -1422,7 +1422,7 @@ int uv_write2(uv_write_t* req, * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1461,7 +1461,7 @@ int uv_try_write(uv_stream_t* stream, if (stream->connect_req != NULL || stream->write_queue_size != 0) return -EAGAIN; - has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); + has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); if (r != 0) @@ -1485,7 +1485,7 @@ int uv_try_write(uv_stream_t* stream, /* Do not poll for writable, if we wasn't before calling this */ if (!has_pollout) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1520,7 +1520,7 @@ int uv_read_start(uv_stream_t* stream, stream->read_cb = read_cb; stream->alloc_cb = alloc_cb; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__handle_start(stream); uv__stream_osx_interrupt_select(stream); @@ -1533,8 +1533,8 @@ int uv_read_stop(uv_stream_t* stream) { return 0; stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); @@ -1621,7 +1621,7 @@ void uv__stream_close(uv_stream_t* handle) { handle->queued_fds = NULL; } - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 9a6cc42b5bf3fd..e67be8fcf81ec4 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -140,6 +140,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { unsigned int nfds; unsigned int i; int saved_errno; + int have_signals; int nevents; int count; int err; @@ -230,6 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -252,7 +254,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w == NULL) continue; - w->cb(loop, w, pe->portev_events); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->portev_events); + nevents++; if (w != loop->watchers[fd]) @@ -262,9 +271,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -456,7 +472,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (first_run) { uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); } return 0; diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 6d213a497787d8..793e4c7d60b543 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -181,7 +181,7 @@ int uv__tcp_connect(uv_connect_t* req, QUEUE_INIT(&req->queue); handle->connect_req = req; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); if (handle->delayed_error) uv__io_feed(handle->loop, &handle->io_watcher); @@ -273,7 +273,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { /* Start listening for connections. */ tcp->io_watcher.cb = uv__server_io; - uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN); + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index c35bc926bf0fac..236f5913936650 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -28,13 +28,13 @@ #include #include /* getrlimit() */ +#include /* getpagesize() */ #include #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) - struct thread_ctx { void (*entry)(void* arg); void* arg; @@ -82,10 +82,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { if (pthread_attr_init(attr)) abort(); - if (lim.rlim_cur != RLIM_INFINITY && - lim.rlim_cur >= PTHREAD_STACK_MIN) { - if (pthread_attr_setstacksize(attr, lim.rlim_cur)) - abort(); + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); } #else attr = NULL; @@ -393,6 +396,35 @@ int uv_cond_init(uv_cond_t* cond) { #endif /* defined(__APPLE__) && defined(__MACH__) */ void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + if (pthread_cond_destroy(cond)) abort(); } @@ -448,72 +480,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -#if defined(__APPLE__) && defined(__MACH__) - -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - int err; - - barrier->n = count; - barrier->count = 0; - - err = uv_mutex_init(&barrier->mutex); - if (err) - return -err; - - err = uv_sem_init(&barrier->turnstile1, 0); - if (err) - goto error2; - - err = uv_sem_init(&barrier->turnstile2, 1); - if (err) - goto error; - - return 0; - -error: - uv_sem_destroy(&barrier->turnstile1); -error2: - uv_mutex_destroy(&barrier->mutex); - return -err; - -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - uv_sem_destroy(&barrier->turnstile2); - uv_sem_destroy(&barrier->turnstile1); - uv_mutex_destroy(&barrier->mutex); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int serial_thread; - - uv_mutex_lock(&barrier->mutex); - if (++barrier->count == barrier->n) { - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile1); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile1); - - uv_mutex_lock(&barrier->mutex); - serial_thread = (--barrier->count == 0); - if (serial_thread) { - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile2); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile2); - return serial_thread; -} - -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { return -pthread_barrier_init(barrier, NULL, count); } @@ -532,7 +498,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) { return r == PTHREAD_BARRIER_SERIAL_THREAD; } -#endif /* defined(__APPLE__) && defined(__MACH__) */ int uv_key_create(uv_key_t* key) { return -pthread_key_create(key, NULL); diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 39ade8de338afc..4527bba1f1931c 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -61,7 +61,7 @@ void uv__udp_finish_close(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); assert(handle->io_watcher.fd == -1); while (!QUEUE_EMPTY(&handle->write_queue)) { @@ -120,8 +120,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { if (QUEUE_EMPTY(&handle->write_queue)) { /* Pending queue and completion queue empty, stop watcher. */ - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT); - if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) + uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); + if (!uv__io_active(&handle->io_watcher, POLLIN)) uv__handle_stop(handle); } @@ -135,10 +135,10 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { handle = container_of(w, uv_udp_t, io_watcher); assert(handle->type == UV_UDP); - if (revents & UV__POLLIN) + if (revents & POLLIN) uv__udp_recvmsg(handle); - if (revents & UV__POLLOUT) { + if (revents & POLLOUT) { uv__udp_sendmsg(handle); uv__udp_run_completed(handle); } @@ -424,7 +424,7 @@ int uv__udp_send(uv_udp_send_t* req, if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { uv__udp_sendmsg(handle); } else { - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } return 0; @@ -843,7 +843,7 @@ int uv__udp_recv_start(uv_udp_t* handle, if (alloc_cb == NULL || recv_cb == NULL) return -EINVAL; - if (uv__io_active(&handle->io_watcher, UV__POLLIN)) + if (uv__io_active(&handle->io_watcher, POLLIN)) return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); @@ -853,7 +853,7 @@ int uv__udp_recv_start(uv_udp_t* handle, handle->alloc_cb = alloc_cb; handle->recv_cb = recv_cb; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); uv__handle_start(handle); return 0; @@ -861,9 +861,9 @@ int uv__udp_recv_start(uv_udp_t* handle, int uv__udp_recv_stop(uv_udp_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); - if (!uv__io_active(&handle->io_watcher, UV__POLLOUT)) + if (!uv__io_active(&handle->io_watcher, POLLOUT)) uv__handle_stop(handle); handle->alloc_cb = NULL; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 6b8c584fbe75b1..ba26446915a39c 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -22,10 +22,11 @@ #include "uv.h" #include "uv-common.h" -#include #include +#include #include #include /* NULL */ +#include #include /* malloc */ #include /* memset */ @@ -75,7 +76,14 @@ void* uv__malloc(size_t size) { } void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; uv__allocator.local_free(ptr); + errno = saved_errno; } void* uv__calloc(size_t count, size_t size) { @@ -475,6 +483,16 @@ static unsigned int* uv__get_nbufs(uv_fs_t* req) { #endif } +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#endif + void uv__fs_scandir_cleanup(uv_fs_t* req) { uv__dirent_t** dents; @@ -484,7 +502,10 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { if (*nbufs > 0 && *nbufs != (unsigned int) req->result) (*nbufs)--; for (; *nbufs < (unsigned int) req->result; (*nbufs)++) - uv__free(dents[*nbufs]); + uv__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; } @@ -498,11 +519,11 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { /* Free previous entity */ if (*nbufs > 0) - uv__free(dents[*nbufs - 1]); + uv__fs_scandir_free(dents[*nbufs - 1]); /* End was already reached */ if (*nbufs == (unsigned int) req->result) { - uv__free(dents); + uv__fs_scandir_free(dents); req->ptr = NULL; return UV_EOF; } diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 77c935a2d8c8fe..e79a48d0e99686 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -66,11 +66,12 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, static void uv_relative_path(const WCHAR* filename, const WCHAR* dir, WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); size_t dirlen = wcslen(dir); if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - size_t filenamelen = wcslen(filename); - size_t relpathlen = filenamelen - dirlen - 1; + relpathlen = filenamelen - dirlen - 1; *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); @@ -348,7 +349,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, FILE_NOTIFY_INFORMATION* file_info; int err, sizew, size; char* filename = NULL; - WCHAR* filenamew, *long_filenamew = NULL; + WCHAR* filenamew = NULL; + WCHAR* long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); @@ -373,6 +375,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, do { file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); assert(!filename); + assert(!filenamew); assert(!long_filenamew); /* @@ -437,14 +440,17 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv__free(long_filenamew); long_filenamew = filenamew; sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); } - } - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { + } else { + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } @@ -454,38 +460,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, sizew = -1; } - if (filenamew) { - /* Convert the filename to utf8. */ - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - NULL, - 0, - NULL, - NULL); - if (size) { - filename = (char*)uv__malloc(size + 1); - if (!filename) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - filename, - size, - NULL, - NULL); - if (size) { - filename[size] = '\0'; - } else { - uv__free(filename); - filename = NULL; - } - } - } + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); switch (file_info->Action) { case FILE_ACTION_ADDED: @@ -504,6 +480,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, filename = NULL; uv__free(long_filenamew); long_filenamew = NULL; + filenamew = NULL; } offset = file_info->NextEntryOffset; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 16e3ae7cf1b416..54dfea7240864e 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -901,7 +901,15 @@ void fs__scandir(uv_fs_t* req) { /* Compute the length of the filename in WCHARs. */ wchar_len = info->FileNameLength / sizeof info->FileName[0]; - /* Skip over '.' and '..' entries. */ + /* Skip over '.' and '..' entries. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; if (wchar_len == 1 && info->FileName[0] == L'.') continue; if (wchar_len == 2 && info->FileName[0] == L'.' && @@ -1870,8 +1878,12 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->flags & UV_FS_FREE_PATHS) uv__free(req->file.pathw); - if (req->flags & UV_FS_FREE_PTR) - uv__free(req->ptr); + if (req->flags & UV_FS_FREE_PTR) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } req->path = NULL; req->file.pathw = NULL; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index c724793bf05a41..0a7c9404fa3faf 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -83,6 +83,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #define UV_HANDLE_ZERO_READ 0x00080000 #define UV_HANDLE_EMULATE_IOCP 0x00100000 #define UV_HANDLE_BLOCKING_WRITES 0x00200000 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 /* Used by uv_tcp_t and uv_udp_t handles */ #define UV_HANDLE_IPV6 0x01000000 @@ -329,7 +330,7 @@ int uv_parent_pid(); int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); -int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); /* diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 1b27f60a6f0c9c..9b9637784401d8 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -57,11 +57,23 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); /* Null uv_buf_t */ static const uv_buf_t uv_null_buf_ = { 0, NULL }; +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + /* * The console virtual window. @@ -173,7 +185,8 @@ 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->tty.rd.read_line_handle = NULL; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = NULL; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -398,6 +411,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { DWORD bytes, read_bytes; WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; DWORD chars, read_chars; + LONG status; + COORD pos; assert(data); @@ -419,7 +434,15 @@ 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->tty.rd.read_line_handle, + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + if (ReadConsoleW(handle->handle, (void*) utf16, chars, &read_chars, @@ -438,6 +461,33 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { SET_REQ_ERROR(req, GetLastError()); } + InterlockedExchange(&uv__read_console_status, COMPLETED); + + /* If we canceled the read by sending a VK_RETURN event, restore the screen + state to undo the visual effect of the VK_RETURN*/ + if (InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by + one line. The right position to reset the cursor to is therefore one + line higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -463,25 +513,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { } 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->tty.rd.read_line_handle == NULL) { - HANDLE this_process = GetCurrentProcess(); - r = DuplicateHandle(this_process, - handle->handle, - this_process, - &handle->tty.rd.read_line_handle, - 0, - 0, - DUPLICATE_SAME_ACCESS); - if (!r) { - handle->tty.rd.read_line_handle = NULL; - SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); - goto out; - } - } - + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; r = QueueUserWorkItem(uv_tty_line_read_thread, (void*) req, WT_EXECUTELONGFUNCTION); @@ -490,7 +526,6 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { uv_insert_pending_req(loop, (uv_req_t*)req); } - out: handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } @@ -857,8 +892,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, if (!REQ_SUCCESS(req)) { /* Read was not successful */ - if ((handle->flags & UV_HANDLE_READING) && - handle->tty.rd.read_line_handle != NULL) { + if (handle->flags & UV_HANDLE_READING) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -871,10 +905,15 @@ 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->u.io.overlapped.InternalHigh; - handle->read_cb((uv_stream_t*) handle, bytes, &buf); + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->u.io.overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } } /* Wait for more input events. */ @@ -937,30 +976,82 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); - /* Cancel raw read */ - if ((handle->flags & UV_HANDLE_READ_PENDING) && - (handle->flags & UV_HANDLE_TTY_RAW)) { + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ /* Write some bullshit event to force the console wait to return. */ - INPUT_RECORD record; - DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + return 0; } - /* Cancel line-buffered read */ - if (handle->tty.rd.read_line_handle != NULL) { - /* Closing this handle will cancel the ReadConsole operation */ - CloseHandle(handle->tty.rd.read_line_handle); - handle->tty.rd.read_line_handle = NULL; + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); } + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); - return 0; + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; } @@ -2045,11 +2136,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if (handle->flags & UV__HANDLE_CLOSING && handle->reqs_pending == 0) { - /* The console handle duplicate used for line reading should be destroyed */ - /* by uv_tty_read_stop. */ - assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || - 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) || diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 1788b1780e9bba..4cebad390818cd 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -124,7 +124,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) { utf16_buffer, -1, buffer, - *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr, + (int) *size_ptr, NULL, NULL); if (utf8_len == 0) { @@ -403,36 +403,13 @@ int uv_set_process_title(const char* title) { static int uv__get_process_title() { WCHAR title_w[MAX_TITLE_LENGTH]; - int length; if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { return -1; } - /* Find out what the size of the buffer is that we need */ - length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); - if (!length) { - return -1; - } - - assert(!process_title); - process_title = (char*)uv__malloc(length); - if (!process_title) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - /* Do utf16 -> utf8 conversion here */ - if (!WideCharToMultiByte(CP_UTF8, - 0, - title_w, - -1, - process_title, - length, - NULL, - NULL)) { - uv__free(process_title); + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) return -1; - } return 0; } @@ -704,43 +681,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; - - len = WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, + uv__convert_utf16_to_utf8(cpu_brand, cpu_brand_size / sizeof(WCHAR), - NULL, - 0, - NULL, - NULL); - if (len == 0) { - err = GetLastError(); - goto error; - } - - assert(len > 0); - - /* Allocate 1 extra byte for the null terminator. */ - cpu_info->model = uv__malloc(len + 1); - if (cpu_info->model == NULL) { - err = ERROR_OUTOFMEMORY; - goto error; - } - - if (WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, - cpu_brand_size / sizeof(WCHAR), - cpu_info->model, - len, - NULL, - NULL) == 0) { - err = GetLastError(); - goto error; - } - - /* Ensure that cpu_info->model is null terminated. */ - cpu_info->model[len] = '\0'; + &(cpu_info->model)); } uv__free(sppi); @@ -1118,6 +1061,7 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME createTime, exitTime, kernelTime, userTime; SYSTEMTIME kernelSystemTime, userSystemTime; + PROCESS_MEMORY_COUNTERS memCounters; int ret; ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); @@ -1135,6 +1079,13 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return uv_translate_sys_error(GetLastError()); } + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + memset(uv_rusage, 0, sizeof(*uv_rusage)); uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + @@ -1147,6 +1098,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { kernelSystemTime.wSecond; uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + return 0; } @@ -1288,20 +1242,36 @@ void uv_os_free_passwd(uv_passwd_t* pwd) { } -int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { DWORD bufsize; if (utf16 == NULL) return UV_EINVAL; /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); if (bufsize == 0) return uv_translate_sys_error(GetLastError()); - /* Allocate the destination buffer */ - *utf8 = uv__malloc(bufsize); + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); if (*utf8 == NULL) return UV_ENOMEM; @@ -1310,7 +1280,7 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, - -1, + utf16len, *utf8, bufsize, NULL, @@ -1318,9 +1288,11 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { if (bufsize == 0) { uv__free(*utf8); + *utf8 = NULL; return uv_translate_sys_error(GetLastError()); } + (*utf8)[bufsize] = '\0'; return 0; } @@ -1366,13 +1338,13 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { } pwd->homedir = NULL; - r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); if (r != 0) return r; pwd->username = NULL; - r = uv__convert_utf16_to_utf8(username, &pwd->username); + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); if (r != 0) { uv__free(pwd->homedir); diff --git a/deps/uv/test/test-emfile.c b/deps/uv/test/test-emfile.c index dd35f785b46352..5f4dd9efdf7e77 100644 --- a/deps/uv/test/test-emfile.c +++ b/deps/uv/test/test-emfile.c @@ -38,6 +38,13 @@ static uv_tcp_t client_handle; TEST_IMPL(emfile) { +#ifdef _AIX + /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket + * which causes uv__emfile_trick to not work as intended and this test + * to fail. + */ + RETURN_SKIP("uv__emfile_trick does not work on AIX"); +#endif struct sockaddr_in addr; struct rlimit limits; uv_connect_t connect_req; diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 35583529e57507..353c43b0de4e07 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -511,7 +511,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_touch, 10, 0); + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); @@ -698,18 +698,19 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } -#if defined(HAVE_KQUEUE) +#if defined(HAVE_KQUEUE) || defined(_AIX) /* kqueue doesn't register fs events if you don't have an active watcher. * The file descriptor needs to be part of the kqueue set of interest and * that's not the case until we actually enter the event loop. + * This is also observed on AIX with ahafs. */ TEST_IMPL(fs_event_close_in_callback) { - fprintf(stderr, "Skipping test, doesn't work with kqueue.\n"); + fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n"); return 0; } -#else /* !HAVE_KQUEUE */ +#else /* !HAVE_KQUEUE || !_AIX */ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { @@ -766,7 +767,7 @@ TEST_IMPL(fs_event_close_in_callback) { return 0; } -#endif /* HAVE_KQUEUE */ +#endif /* HAVE_KQUEUE || _AIX */ TEST_IMPL(fs_event_start_and_close) { uv_loop_t* loop; diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index cf37ac4909ca12..1cc1a7c064107f 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -2033,6 +2033,9 @@ TEST_IMPL(fs_stat_root) { TEST_IMPL(fs_futime) { +#if defined(_AIX) && !defined(_AIX71) + RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); +#else utime_check_t checkme; const char* path = "test_file"; double atime; @@ -2087,6 +2090,7 @@ TEST_IMPL(fs_futime) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } diff --git a/deps/uv/test/test-get-passwd.c b/deps/uv/test/test-get-passwd.c index 58d9c73c691cf3..8e16fb83c8f1b6 100644 --- a/deps/uv/test/test-get-passwd.c +++ b/deps/uv/test/test-get-passwd.c @@ -45,9 +45,15 @@ TEST_IMPL(get_passwd) { ASSERT(len > 0); #ifdef _WIN32 - ASSERT(pwd.homedir[len - 1] != '\\'); + if (len == 3 && pwd.homedir[1] == ':') + ASSERT(pwd.homedir[2] == '\\'); + else + ASSERT(pwd.homedir[len - 1] != '\\'); #else - ASSERT(pwd.homedir[len - 1] != '/'); + if (len == 1) + ASSERT(pwd.homedir[0] == '/'); + else + ASSERT(pwd.homedir[len - 1] != '/'); #endif #ifdef _WIN32 diff --git a/deps/uv/test/test-homedir.c b/deps/uv/test/test-homedir.c index 5027d44c1ea358..856534a40ceaa9 100644 --- a/deps/uv/test/test-homedir.c +++ b/deps/uv/test/test-homedir.c @@ -29,7 +29,6 @@ TEST_IMPL(homedir) { char homedir[PATHMAX]; size_t len; - char last; int r; /* Test the normal case */ @@ -42,14 +41,17 @@ TEST_IMPL(homedir) { ASSERT(len > 0); ASSERT(homedir[len] == '\0'); - if (len > 1) { - last = homedir[len - 1]; #ifdef _WIN32 - ASSERT(last != '\\'); + if (len == 3 && homedir[1] == ':') + ASSERT(homedir[2] == '\\'); + else + ASSERT(homedir[len - 1] != '\\'); #else - ASSERT(last != '/'); + if (len == 1) + ASSERT(homedir[0] == '/'); + else + ASSERT(homedir[len - 1] != '/'); #endif - } /* Test the case where the buffer is too small */ len = SMALLPATH; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 8b10f1a5f68507..c93f081992a481 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -43,6 +43,9 @@ TEST_DECLARE (semaphore_1) TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) +#ifdef _WIN32 +TEST_DECLARE (tty_raw) +#endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) @@ -387,6 +390,9 @@ TASK_LIST_START #endif TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) +#ifdef _WIN32 + TEST_ENTRY (tty_raw) +#endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 2c4740550a198c..bd61454fa7c742 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -61,6 +61,8 @@ TEST_IMPL(platform_output) { ASSERT(rusage.ru_utime.tv_usec >= 0); ASSERT(rusage.ru_stime.tv_sec >= 0); ASSERT(rusage.ru_stime.tv_usec >= 0); + ASSERT(rusage.ru_majflt >= 0); + ASSERT(rusage.ru_maxrss >= 0); printf("uv_getrusage:\n"); printf(" user: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_utime.tv_sec, @@ -68,6 +70,9 @@ TEST_IMPL(platform_output) { printf(" system: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_stime.tv_sec, (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); err = uv_cpu_info(&cpus, &count); ASSERT(err == 0); diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index bfb75af13355ab..f3cfe7977753c4 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -72,8 +72,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +#ifndef _AIX static int disconnects = 0; - +#endif /* !_AIX */ static int got_eagain(void) { #ifdef _WIN32 @@ -377,7 +378,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } - +#ifndef _AIX if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -385,6 +386,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { +#else /* _AIX */ + if (context->got_fin && context->sent_fin) { +#endif /* !_AIx */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -552,8 +556,9 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); +#ifndef _AIX ASSERT(disconnects == NUM_CLIENTS * 2); - +#endif MAKE_VALGRIND_HAPPY(); } diff --git a/deps/uv/test/test-tcp-create-socket-early.c b/deps/uv/test/test-tcp-create-socket-early.c index 65650adcc27919..1a508e474aa700 100644 --- a/deps/uv/test/test-tcp-create-socket-early.c +++ b/deps/uv/test/test-tcp-create-socket-early.c @@ -139,6 +139,9 @@ TEST_IMPL(tcp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6); diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c index aa4d2acc24ab30..8a98ab83667934 100644 --- a/deps/uv/test/test-tcp-write-queue-order.c +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -107,6 +107,7 @@ static void start_server(void) { TEST_IMPL(tcp_write_queue_order) { uv_connect_t connect_req; struct sockaddr_in addr; + int buffer_size = 16 * 1024; start_server(); @@ -117,6 +118,7 @@ TEST_IMPL(tcp_write_queue_order) { &client, (struct sockaddr*) &addr, connect_cb)); + ASSERT(0 == uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0)); diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index 461d1941359018..55cc016752d31b 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -146,6 +146,75 @@ TEST_IMPL(tty) { } +#ifdef _WIN32 +static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + +static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + ASSERT(nread == 1); + ASSERT(buf->base[0] == ' '); + uv_close((uv_handle_t*) tty_in, NULL); + } else { + ASSERT(nread == 0); + } +} + +TEST_IMPL(tty_raw) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop = uv_default_loop(); + HANDLE handle; + INPUT_RECORD record; + DWORD written; + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT(ttyin_fd >= 0); + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ + Sleep(100); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); + ASSERT(r == 0); + + /* Write ' ' that should be read in raw mode */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; + record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L' '; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle, &record, 1, &written); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(tty_file) { #ifndef _WIN32 uv_loop_t loop; diff --git a/deps/uv/test/test-udp-create-socket-early.c b/deps/uv/test/test-udp-create-socket-early.c index 3d0152428b8bc9..3f3027404700f4 100644 --- a/deps/uv/test/test-udp-create-socket-early.c +++ b/deps/uv/test/test-udp-create-socket-early.c @@ -79,6 +79,9 @@ TEST_IMPL(udp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 757540193dd7a2..2fdd59ac784300 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -17,6 +17,7 @@ }], ], 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ], 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], } @@ -111,12 +112,14 @@ '-liphlpapi', '-lpsapi', '-lshell32', + '-luser32', '-luserenv', '-lws2_32' ], }, }, { # Not Windows i.e. POSIX 'cflags': [ + '-fvisibility=hidden', '-g', '--std=gnu89', '-pedantic', @@ -184,6 +187,7 @@ 'src/unix/darwin.c', 'src/unix/fsevents.c', 'src/unix/darwin-proctitle.c', + 'src/unix/pthread-barrier.c' ], 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', @@ -214,7 +218,8 @@ 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', 'src/unix/pthread-fixes.c', - 'src/unix/android-ifaddrs.c' + 'src/unix/android-ifaddrs.c', + 'src/unix/pthread-barrier.c' ], 'link_settings': { 'libraries': [ '-ldl' ], diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 9a7ed4b8c512e0..91f45b72195301 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -19,7 +19,7 @@ set nobuild= set run= set target_arch=ia32 set vs_toolset=x86 -set platform=WIN32 +set msbuild_platform=WIN32 set library=static_library :next-arg @@ -31,9 +31,9 @@ if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok if /i "%1"=="clean" set target=Clean&goto arg-ok if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok if /i "%1"=="nobuild" set nobuild=1&goto arg-ok -if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok +if /i "%1"=="x86" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="ia32" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="x64" set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64&goto arg-ok if /i "%1"=="shared" set library=shared_library&goto arg-ok if /i "%1"=="static" set library=static_library&goto arg-ok :arg-ok @@ -132,7 +132,7 @@ goto run @rem Build the sln with msbuild. :msbuild-found -msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo if errorlevel 1 exit /b 1 :run From 9eedea9033a74a3a7a9787fdef9eade3c3684240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 18 May 2016 15:13:04 +0100 Subject: [PATCH 3/6] unix,stream: fix getting the correct fd for a handle On OSX it's possible that the fd is replaced, so use the proper libuv API to get the correct fd. PR-URL: https://github.com/nodejs/node/pull/6753 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/stream_wrap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index e6236a6e529864..7118a9e573f4c2 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -91,7 +91,7 @@ int StreamWrap::GetFD() { int fd = -1; #if !defined(_WIN32) if (stream() != nullptr) - fd = stream()->io_watcher.fd; + uv_fileno(reinterpret_cast(stream()), &fd); #endif return fd; } From 13103c2d030fe79ae83a58059d5b6d76852deab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sat, 21 May 2016 00:01:48 +0200 Subject: [PATCH 4/6] udp: use libuv API to get file descriptor Refs: https://github.com/nodejs/node/pull/6838 PR-URL: https://github.com/nodejs/node/pull/6908 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/udp_wrap.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 8c460ebac6ff22..e395ee85e0852e 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -136,12 +136,14 @@ void UDPWrap::New(const FunctionCallbackInfo& args) { void UDPWrap::GetFD(Local, const PropertyCallbackInfo& args) { + int fd = -1; #if !defined(_WIN32) HandleScope scope(args.GetIsolate()); UDPWrap* wrap = Unwrap(args.Holder()); - int fd = (wrap == nullptr) ? -1 : wrap->handle_.io_watcher.fd; - args.GetReturnValue().Set(fd); + if (wrap != nullptr) + uv_fileno(reinterpret_cast(&wrap->handle_), &fd); #endif + args.GetReturnValue().Set(fd); } From 9eb7dc898e7163c660dc9331e68fb4349c7ffa17 Mon Sep 17 00:00:00 2001 From: Jeremiah Senkpiel Date: Fri, 20 May 2016 10:20:08 -0400 Subject: [PATCH 5/6] tty: use blocking mode on OS X OS X has a tiny 1kb hard-coded buffer size for stdout / stderr to TTYs (terminals). Output larger than that causes chunking, which ends up having some (very small but existent) delay past the first chunk. That causes two problems: 1. When output is written to stdout and stderr at similar times, the two can become mixed together (interleaved). This is especially problematic when using control characters, such as \r. With interleaving, chunked output will often have lines or characters erased unintentionally, or in the wrong spots, leading to broken output. CLI apps often extensively use such characters for things such as progress bars. 2. Output can be lost if the process is exited before chunked writes are finished flushing. This usually happens in applications that use `process.exit()`, which isn't infrequent. See https://github.com/nodejs/node/issues/6980 for more info. This became an issue as result of the Libuv 1.9.0 upgrade. A fix to an unrelated issue broke a hack previously required for the OS X implementation. This resulted in an unexpected behavior change in node. The 1.9.0 upgrade was done in c3cec1eefc9f3b55a3fb7bd623b3d921f493870d, which was included in v6.0.0. Full details of the Libuv issue that induced this are at https://github.com/nodejs/node/issues/6456#issuecomment-219974514 Refs: https://github.com/nodejs/node/pull/1771 Refs: https://github.com/nodejs/node/issues/6456 Refs: https://github.com/nodejs/node/pull/6773 Refs: https://github.com/nodejs/node/pull/6816 PR-URL: https://github.com/nodejs/node/pull/6895 Reviewed-By: Rod Vagg Reviewed-By: Anna Henningsen --- doc/api/console.md | 6 +++++- doc/api/process.md | 10 +++++++++- lib/tty.js | 7 +++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/doc/api/console.md b/doc/api/console.md index 67d82a3ed55eab..ead2c3607011a5 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -53,11 +53,15 @@ duplicate the browser's functionality exactly. ## Asynchronous vs Synchronous Consoles -The console functions are asynchronous unless the destination is a file. +The console functions are usually asynchronous unless the destination is a file. Disks are fast and operating systems normally employ write-back caching; it should be a very rare occurrence indeed that a write blocks, but it is possible. +Additionally, console functions are blocking when outputting to TTYs +(terminals) on OS X as a workaround for the OS's very small, 1kb buffer size. +This is to prevent interleaving between `stdout` and `stderr`. + ## Class: Console diff --git a/doc/api/process.md b/doc/api/process.md index c7f2567ccf5aff..97cabdf8ad18b0 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -953,6 +953,10 @@ event and that writes can block when output is redirected to a file (although disks are fast and operating systems normally employ write-back caching so it should be a very rare occurrence indeed.) +Additionally, `process.stderr` and `process.stdout` are blocking when outputting +to TTYs (terminals) on OS X as a workaround for the OS's very small, 1kb +buffer size. This is to prevent interleaving between `stdout` and `stderr`. + ## process.stdin A `Readable Stream` for stdin (on fd `0`). @@ -1003,6 +1007,10 @@ event and that writes can block when output is redirected to a file (although disks are fast and operating systems normally employ write-back caching so it should be a very rare occurrence indeed.) +Additionally, `process.stderr` and `process.stdout` are blocking when outputting +to TTYs (terminals) on OS X as a workaround for the OS's very small, 1kb +buffer size. This is to prevent interleaving between `stdout` and `stderr`. + To check if Node.js is being run in a TTY context, read the `isTTY` property on `process.stderr`, `process.stdout`, or `process.stdin`: @@ -1098,4 +1106,4 @@ Will print something like: [Signal Events]: #process_signal_events [Stream compatibility]: stream.html#stream_compatibility_with_older_node_js_versions [the tty docs]: tty.html#tty_tty -[`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify \ No newline at end of file +[`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify diff --git a/lib/tty.js b/lib/tty.js index f3f84ca5a6e9f7..54a7b756ec9544 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -59,6 +59,13 @@ function WriteStream(fd) { writable: true }); + // Prevents interleaved stdout/stderr output in OS X terminals. + // As noted in the following reference, local TTYs tend to be quite fast and + // this behaviour has become expected due historical functionality on OS X, + // even though it was originally intended to change in v1.0.2 (Libuv 1.2.1). + // Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671 + if (process.platform === 'darwin') this._handle.setBlocking(true); + var winSize = []; var err = this._handle.getWindowSize(winSize); if (!err) { From ded6af537b4bf81f8227e4e86f138aad36ed0a50 Mon Sep 17 00:00:00 2001 From: Jeremiah Senkpiel Date: Fri, 20 May 2016 19:05:54 -0400 Subject: [PATCH 6/6] test: test TTY problems by fakeing a TTY using openpty Many thanks to thefourtheye and addaleax who helped make the python bits of this possible. See https://github.com/nodejs/node/issues/6980 for more info regarding the related TTY issues. Refs: https://github.com/nodejs/node/issues/6456 Refs: https://github.com/nodejs/node/pull/6773 Refs: https://github.com/nodejs/node/pull/6816 PR-URL: https://github.com/nodejs/node/pull/6895 Reviewed-By: Rod Vagg Reviewed-By: Anna Henningsen --- Makefile | 4 +- test/pseudo-tty/no_dropped_stdio.js | 15 +++ test/pseudo-tty/no_dropped_stdio.out | 21 +++ test/pseudo-tty/no_interleaved_stdio.js | 17 +++ test/pseudo-tty/no_interleaved_stdio.out | 21 +++ test/pseudo-tty/testcfg.py | 161 +++++++++++++++++++++++ tools/test.py | 67 ++++++++-- 7 files changed, 292 insertions(+), 14 deletions(-) create mode 100644 test/pseudo-tty/no_dropped_stdio.js create mode 100644 test/pseudo-tty/no_dropped_stdio.out create mode 100644 test/pseudo-tty/no_interleaved_stdio.js create mode 100644 test/pseudo-tty/no_interleaved_stdio.out create mode 100644 test/pseudo-tty/testcfg.py diff --git a/Makefile b/Makefile index 55107392d35f11..5c16b9b66c5a35 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ v8: $(MAKE) -C deps/v8 $(V8_ARCH) $(V8_BUILD_OPTIONS) test: | cctest # Depends on 'all'. - $(PYTHON) tools/test.py --mode=release doctool message parallel sequential -J + $(PYTHON) tools/test.py --mode=release doctool message pseudo-tty parallel sequential -J $(MAKE) jslint $(MAKE) cpplint @@ -167,7 +167,7 @@ test-all-valgrind: test-build $(PYTHON) tools/test.py --mode=debug,release --valgrind CI_NATIVE_SUITES := addons -CI_JS_SUITES := doctool message parallel sequential +CI_JS_SUITES := doctool message parallel pseudo-tty sequential # Build and test addons without building anything else test-ci-native: | test/addons/.buildstamp diff --git a/test/pseudo-tty/no_dropped_stdio.js b/test/pseudo-tty/no_dropped_stdio.js new file mode 100644 index 00000000000000..1a20889073ce06 --- /dev/null +++ b/test/pseudo-tty/no_dropped_stdio.js @@ -0,0 +1,15 @@ +// https://github.com/nodejs/node/issues/6456#issuecomment-219320599 +// https://gist.github.com/isaacs/1495b91ec66b21d30b10572d72ad2cdd +'use strict'; +require('../common'); + +// 1000 bytes wrapped at 50 columns +// \n turns into a double-byte character +// (48 + {2}) * 20 = 1000 +var out = ('o'.repeat(48) + '\n').repeat(20); +// Add the remaining 24 bytes and terminate with an 'O'. +// This results in 1025 bytes, just enough to overflow the 1kb OS X TTY buffer. +out += 'o'.repeat(24) + 'O'; + +process.stdout.write(out); +process.exit(0); diff --git a/test/pseudo-tty/no_dropped_stdio.out b/test/pseudo-tty/no_dropped_stdio.out new file mode 100644 index 00000000000000..78d2b7a36523a2 --- /dev/null +++ b/test/pseudo-tty/no_dropped_stdio.out @@ -0,0 +1,21 @@ +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +ooooooooooooooooooooooooO diff --git a/test/pseudo-tty/no_interleaved_stdio.js b/test/pseudo-tty/no_interleaved_stdio.js new file mode 100644 index 00000000000000..778b2c09583b90 --- /dev/null +++ b/test/pseudo-tty/no_interleaved_stdio.js @@ -0,0 +1,17 @@ +// https://github.com/nodejs/node/issues/6456#issuecomment-219320599 +// https://gist.github.com/isaacs/1495b91ec66b21d30b10572d72ad2cdd +'use strict'; +require('../common'); + +// 1000 bytes wrapped at 50 columns +// \n turns into a double-byte character +// (48 + {2}) * 20 = 1000 +var out = ('o'.repeat(48) + '\n').repeat(20); +// Add the remaining 24 bytes and terminate with an 'O'. +// This results in 1025 bytes, just enough to overflow the 1kb OS X TTY buffer. +out += 'o'.repeat(24) + 'O'; + +const err = '__This is some stderr__'; + +process.stdout.write(out); +process.stderr.write(err); diff --git a/test/pseudo-tty/no_interleaved_stdio.out b/test/pseudo-tty/no_interleaved_stdio.out new file mode 100644 index 00000000000000..f39b87ff466725 --- /dev/null +++ b/test/pseudo-tty/no_interleaved_stdio.out @@ -0,0 +1,21 @@ +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +oooooooooooooooooooooooooooooooooooooooooooooooo +ooooooooooooooooooooooooO__This is some stderr__ diff --git a/test/pseudo-tty/testcfg.py b/test/pseudo-tty/testcfg.py new file mode 100644 index 00000000000000..469903152101c1 --- /dev/null +++ b/test/pseudo-tty/testcfg.py @@ -0,0 +1,161 @@ +# Copyright 2008 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import test +import os +from os.path import join, exists, basename, isdir +import re +import utils + +FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") + +class TTYTestCase(test.TestCase): + + def __init__(self, path, file, expected, arch, mode, context, config): + super(TTYTestCase, self).__init__(context, path, arch, mode) + self.file = file + self.expected = expected + self.config = config + self.arch = arch + self.mode = mode + + def IgnoreLine(self, str): + """Ignore empty lines and valgrind output.""" + if not str.strip(): return True + else: return str.startswith('==') or str.startswith('**') + + def IsFailureOutput(self, output): + f = file(self.expected) + # Convert output lines to regexps that we can match + env = { 'basename': basename(self.file) } + patterns = [ ] + for line in f: + if not line.strip(): + continue + pattern = re.escape(line.rstrip() % env) + pattern = pattern.replace('\\*', '.*') + pattern = '^%s$' % pattern + patterns.append(pattern) + # Compare actual output with the expected + raw_lines = (output.stdout + output.stderr).split('\n') + outlines = [ s.strip() for s in raw_lines if not self.IgnoreLine(s) ] + if len(outlines) != len(patterns): + print "length differs." + print "expect=%d" % len(patterns) + print "actual=%d" % len(outlines) + print "patterns:" + for i in xrange(len(patterns)): + print "pattern = %s" % patterns[i] + print "outlines:" + for i in xrange(len(outlines)): + print "outline = %s" % outlines[i] + return True + for i in xrange(len(patterns)): + if not re.match(patterns[i], outlines[i]): + print "match failed" + print "line=%d" % i + print "expect=%s" % patterns[i] + print "actual=%s" % outlines[i] + return True + return False + + def GetLabel(self): + return "%s %s" % (self.mode, self.GetName()) + + def GetName(self): + return self.path[-1] + + def GetCommand(self): + result = [self.config.context.GetVm(self.arch, self.mode)] + source = open(self.file).read() + flags_match = FLAGS_PATTERN.search(source) + if flags_match: + result += flags_match.group(1).strip().split() + result.append(self.file) + return result + + def GetSource(self): + return (open(self.file).read() + + "\n--- expected output ---\n" + + open(self.expected).read()) + + def RunCommand(self, command, env): + full_command = self.context.processor(command) + output = test.Execute(full_command, + self.context, + self.context.GetTimeout(self.mode), + env, + True) + self.Cleanup() + return test.TestOutput(self, + full_command, + output, + self.context.store_unexpected_output) + + +class TTYTestConfiguration(test.TestConfiguration): + + def __init__(self, context, root): + super(TTYTestConfiguration, self).__init__(context, root) + + def Ls(self, path): + if isdir(path): + return [f[:-3] for f in os.listdir(path) if f.endswith('.js')] + else: + return [] + + def ListTests(self, current_path, path, arch, mode): + all_tests = [current_path + [t] for t in self.Ls(self.root)] + result = [] + # Skip these tests on Windows, as pseudo terminals are not available + if utils.IsWindows(): + print ("Skipping pseudo-tty tests, as pseudo terminals are not available" + " on Windows.") + return result + for test in all_tests: + if self.Contains(path, test): + file_prefix = join(self.root, reduce(join, test[1:], "")) + file_path = file_prefix + ".js" + output_path = file_prefix + ".out" + if not exists(output_path): + print "Could not find %s" % output_path + continue + result.append(TTYTestCase(test, file_path, output_path, + arch, mode, self.context, self)) + return result + + def GetBuildRequirements(self): + return ['sample', 'sample=shell'] + + def GetTestStatus(self, sections, defs): + status_file = join(self.root, 'message.status') + if exists(status_file): + test.ReadConfigurationInto(status_file, sections, defs) + + +def GetConfiguration(context, root): + return TTYTestConfiguration(context, root) diff --git a/tools/test.py b/tools/test.py index 8b66b3136769b7..d50fd5b4662c36 100755 --- a/tools/test.py +++ b/tools/test.py @@ -575,11 +575,17 @@ def RunProcess(context, timeout, args, **rest): error_mode = SEM_NOGPFAULTERRORBOX; prev_error_mode = Win32SetErrorMode(error_mode); Win32SetErrorMode(error_mode | prev_error_mode); + + faketty = rest.pop('faketty', False) + pty_out = rest.pop('pty_out') + process = subprocess.Popen( shell = utils.IsWindows(), args = popen_args, **rest ) + if faketty: + os.close(rest['stdout']) if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE: Win32SetErrorMode(prev_error_mode) # Compute the end time - if the process crosses this limit we @@ -591,6 +597,29 @@ def RunProcess(context, timeout, args, **rest): # loop and keep track of whether or not it times out. exit_code = None sleep_time = INITIAL_SLEEP_TIME + output = '' + if faketty: + while True: + if time.time() >= end_time: + # Kill the process and wait for it to exit. + KillProcessWithID(process.pid) + exit_code = process.wait() + timed_out = True + break + + # source: http://stackoverflow.com/a/12471855/1903116 + # related: http://stackoverflow.com/q/11165521/1903116 + try: + data = os.read(pty_out, 9999) + except OSError as e: + if e.errno != errno.EIO: + raise + break # EIO means EOF on some systems + else: + if not data: # EOF + break + output += data + while exit_code is None: if (not end_time is None) and (time.time() >= end_time): # Kill the process and wait for it to exit. @@ -603,7 +632,7 @@ def RunProcess(context, timeout, args, **rest): sleep_time = sleep_time * SLEEP_TIME_FACTOR if sleep_time > MAX_SLEEP_TIME: sleep_time = MAX_SLEEP_TIME - return (process, exit_code, timed_out) + return (process, exit_code, timed_out, output) def PrintError(str): @@ -625,29 +654,43 @@ def CheckedUnlink(name): PrintError("os.unlink() " + str(e)) break -def Execute(args, context, timeout=None, env={}): - (fd_out, outname) = tempfile.mkstemp() - (fd_err, errname) = tempfile.mkstemp() +def Execute(args, context, timeout=None, env={}, faketty=False): + if faketty: + import pty + (out_master, fd_out) = pty.openpty() + fd_err = fd_out + pty_out = out_master + else: + (fd_out, outname) = tempfile.mkstemp() + (fd_err, errname) = tempfile.mkstemp() + pty_out = None # Extend environment env_copy = os.environ.copy() for key, value in env.iteritems(): env_copy[key] = value - (process, exit_code, timed_out) = RunProcess( + (process, exit_code, timed_out, output) = RunProcess( context, timeout, args = args, stdout = fd_out, stderr = fd_err, - env = env_copy + env = env_copy, + faketty = faketty, + pty_out = pty_out ) - os.close(fd_out) - os.close(fd_err) - output = file(outname).read() - errors = file(errname).read() - CheckedUnlink(outname) - CheckedUnlink(errname) + if faketty: + os.close(out_master) + errors = '' + else: + os.close(fd_out) + os.close(fd_err) + output = file(outname).read() + errors = file(errname).read() + CheckedUnlink(outname) + CheckedUnlink(errname) + return CommandOutput(exit_code, timed_out, output, errors)