diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index ef5c2b2feaae9f..aa97506dbc6923 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -165,5 +165,5 @@ not send out notifications when you add commits. [issue tracker]: https://github.com/libuv/libuv/issues [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 +[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html [project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/deps/uv/LICENSE b/deps/uv/LICENSE index 4d411670e3fa10..41ba44c2857a49 100644 --- a/deps/uv/LICENSE +++ b/deps/uv/LICENSE @@ -1,5 +1,29 @@ -libuv is part of the Node project: http://nodejs.org/ -libuv may be distributed alone under Node's license: +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +==== + +This license applies to parts of libuv originating from the +https://github.com/joyent/libuv repository: ==== diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 2f0e618ca24149..f2f3db5a1c75a9 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -7,8 +7,13 @@ libuv is currently managed by the following individuals: - 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)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) +* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) + - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) +* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) + - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul) @@ -34,4 +39,3 @@ be garbage collected since nothing references it, so we'll create a tag for it: Commit the changes and push: $ git push origin pubkey-saghul - diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 05ccd58ac9612b..c232b6dbdc8cca 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -36,7 +36,7 @@ libuv_la_SOURCES = src/fs-poll.c \ if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. -libuv_la_CFLAGS += -pthread +libuv_la_CFLAGS += -pthreads endif if WINNT @@ -48,6 +48,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \ libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ + src/win/detect-wakeup.c \ src/win/dl.c \ src/win/error.c \ src/win/fs-event.c \ @@ -128,7 +129,18 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests +if OS390 test_run_tests_CFLAGS = +else +test_run_tests_CFLAGS = -Wno-long-long +endif + +if SUNOS +# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers +# on other platforms complain that the argument is unused during compilation. +test_run_tests_CFLAGS += -pthreads +endif + test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ @@ -215,6 +227,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-socket-buffer-size.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ + test/test-tcp-alloc-cb-fail.c \ test/test-tcp-bind-error.c \ test/test-tcp-bind6-error.c \ test/test-tcp-close-accept.c \ @@ -246,6 +259,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer.c \ test/test-tmpdir.c \ test/test-tty.c \ + test/test-udp-alloc-cb-fail.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ test/test-udp-dgram-too-big.c \ @@ -277,10 +291,29 @@ if AIX test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT endif +if LINUX +test_run_tests_CFLAGS += -D_GNU_SOURCE +endif + if SUNOS test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 endif +if OS390 +test_run_tests_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_FILE_EXT \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +endif if AIX libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE @@ -312,6 +345,7 @@ endif if DRAGONFLY include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c test_run_tests_LDFLAGS += -lutil endif @@ -350,6 +384,28 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 libuv_la_SOURCES += src/unix/sunos.c endif +if OS390 +include_HEADERS += include/pthread-fixes.h include/pthread-barrier.h +libuv_la_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_SYS_FILE_EXT \ + -DUV_PLATFORM_SEM_T=int \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +libuv_la_LDFLAGS += -qXPLINK +libuv_la_SOURCES += src/unix/pthread-fixes.c \ + src/unix/pthread-barrier.c +libuv_la_SOURCES += src/unix/os390.c +endif + if HAVE_PKG_CONFIG pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 156f15dab159f1..8139138fccf654 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -48,6 +48,7 @@ OBJS = src/fs-poll.o \ src/version.o \ src/win/async.o \ src/win/core.o \ + src/win/detect-wakeup.o \ src/win/dl.o \ src/win/error.o \ src/win/fs-event.o \ diff --git a/deps/uv/README.md b/deps/uv/README.md index e94fcc902f9981..284dfb47c3d951 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -39,6 +39,12 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve scheme. The API change and backwards compatibility rules are those indicated by SemVer. libuv will keep a stable ABI across major releases. +The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/). + +## Licensing + +libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). + ## Community * [Mailing list](http://groups.google.com/group/libuv) @@ -220,18 +226,7 @@ Run: ## Supported Platforms -Microsoft Windows operating systems since Windows XP SP2. It can be built -with either Visual Studio or MinGW. Consider using -[Visual Studio Express 2010][] or later if you do not have a full Visual -Studio license. - -Linux using the GCC toolchain. - -OS X using the GCC or XCode toolchain. - -Solaris 121 and later using GCC toolchain. - -AIX 6 and later using GCC toolchain (see notes). +Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). ### AIX Notes @@ -250,7 +245,6 @@ See the [guidelines for contributing][]. [node.js]: http://nodejs.org/ [GYP]: http://code.google.com/p/gyp/ [Python]: https://www.python.org/downloads/ -[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/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md new file mode 100644 index 00000000000000..bff1050d6331c0 --- /dev/null +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -0,0 +1,70 @@ +# Supported platforms + +| System | Support type | Supported versions | Notes | +|---|---|---|---| +| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | | +| macOS | Tier 1 | macOS >= 10.7 | | +| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported | +| FreeBSD | Tier 1 | >= 9 (see note) | | +| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | +| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | +| Linux with musl | Tier 2 | musl >= 1.0 | | +| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos | +| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| Other | Tier 3 | N/A | | + +#### Note on FreeBSD 9 + +While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until +it reaches end of life, in December 2016. + +## Support types + +* **Tier 1**: Officially supported and tested with CI. Any contributed patch + MUST NOT break such systems. These are supported by @libuv/collaborators. + +* **Tier 2**: Officially supported, but not necessarily tested with CI. These + systems are maintained to the best of @libuv/collaborators ability, + without being a top priority. + +* **Tier 3**: Community maintained. These systems may inadvertently break and the + community and interested parties are expected to help with the maintenance. + +## Adding support for a new platform + +**IMPORTANT**: Before attempting to add support for a new platform please open +an issue about it for discussion. + +### Unix + +I/O handling is abstracted by an internal `uv__io_t` handle. The new platform +will need to implement some of the functions, the prototypes are in +``src/unix/internal.h``. + +If the new platform requires extra fields for any handle structure, create a +new include file in ``include/`` with the name ``uv-theplatform.h`` and add +the appropriate defines there. + +All functionality related to the new platform must be implemented in its own +file inside ``src/unix/`` unless it's already done in a common file, in which +case adding an `ifdef` is fine. + +Two build systems are supported: autotools and GYP. Ideally both need to be +supported, but if GYP does not support the new platform it can be left out. + +### Windows + +Windows is treated as a single platform, so adding support for a new platform +would mean adding support for a new version. + +Compilation and runtime must succeed for the minimum supported version. If a +new API is to be used, it must be done optionally, only in supported versions. + +### Common + +Some common notes when adding support for new platforms: + +* Generally libuv tries to avoid compile time checks. Do not add any to the + autotools based build system or use version checking macros. + Dynamically load functions and symbols if they are not supported by the + minimum supported version. diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 56bca2948db6d9..44db701d68df61 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -11,7 +11,7 @@ 'configurations': { 'Debug': { 'defines': [ 'DEBUG', '_DEBUG' ], - 'cflags': [ '-g', '-O0', '-fwrapv' ], + 'cflags': [ '-g' ], 'msvs_settings': { 'VCCLCompilerTool': { 'target_conditions': [ @@ -35,6 +35,9 @@ 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ + ['OS != "zos"', { + 'cflags': [ '-O0', '-fwrapv' ] + }], ['OS == "android"', { 'cflags': [ '-fPIE' ], 'ldflags': [ '-fPIE', '-pie' ] @@ -151,7 +154,7 @@ 'cflags': [ '-pthreads' ], 'ldflags': [ '-pthreads' ], }], - [ 'OS not in "solaris android"', { + [ 'OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index d9251f31985427..90335b4acfed0b 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -24,10 +24,12 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O -CC_CHECK_CFLAGS_APPEND([-fvisibility=hidden]) +AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) +]) +CC_FLAG_VISIBILITY #[-fvisibility=hidden] CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-std=gnu89]) -CC_CHECK_CFLAGS_APPEND([-pedantic]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) @@ -52,10 +54,11 @@ AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false]) AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])]) AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])]) AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])]) -AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[freebsd*], [true], [false])]) +AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])]) AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) +AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [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*], [ diff --git a/deps/uv/docs/src/errors.rst b/deps/uv/docs/src/errors.rst index cec25f5187e1ce..2ebaf1e41df18a 100644 --- a/deps/uv/docs/src/errors.rst +++ b/deps/uv/docs/src/errors.rst @@ -8,6 +8,9 @@ In libuv errors are negative numbered constants. As a rule of thumb, whenever there is a status parameter, or an API functions returns an integer, a negative number will imply an error. +When a function which takes a callback returns an error, the callback will never +be called. + .. note:: Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on Windows they are defined by libuv to arbitrary negative numbers. diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 69e283f4c67fc6..8e4a98f2dbff54 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -91,7 +91,8 @@ Data types UV_FS_SYMLINK, UV_FS_READLINK, UV_FS_CHOWN, - UV_FS_FCHOWN + UV_FS_FCHOWN, + UV_FS_REALPATH } uv_fs_type; .. c:type:: uv_dirent_t @@ -258,6 +259,12 @@ API Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively. + .. note:: + AIX: This function only works for AIX 7.1 and newer. It can still be called on older + versions but will return ``UV_ENOSYS``. + + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows + .. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) Equivalent to :man:`link(2)`. @@ -281,7 +288,26 @@ API .. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) - Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``. + Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle `_. + + .. warning:: + This function has certain platform specific caveats that were discovered when used in Node. + + * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are + found while resolving the given path. This limit is hardcoded and cannot be sidestepped. + * Windows: while this function works in the common case, there are a number of corner cases + where it doesn't: + + - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) + cannot be resolved. + - Inconsistent casing when using drive letters. + - Resolved path bypasses subst'd drives. + + While this function can still be used, it's not recommended if scenarios such as the + above need to be supported. + + The background story and some more details on these issues can be checked + `here `_. .. note:: This function is not implemented on Windows XP and Windows Server 2003. diff --git a/deps/uv/docs/src/fs_event.rst b/deps/uv/docs/src/fs_event.rst index c2d7f520236856..c08ade2ef597be 100644 --- a/deps/uv/docs/src/fs_event.rst +++ b/deps/uv/docs/src/fs_event.rst @@ -8,6 +8,20 @@ FS Event handles allow the user to monitor a given path for changes, for example if the file was renamed or there was a generic change in it. This handle uses the best backend for the job on each platform. +.. note:: + For AIX, the non default IBM bos.ahafs package has to be installed. + The AIX Event Infrastructure file system (ahafs) has some limitations: + + - ahafs tracks monitoring per process and is not thread safe. A separate process + must be spawned for each monitor for the same event. + - Events for file modification (writing to a file) are not received if only the + containing folder is watched. + + See documentation_ for more details. + + .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ + + Data types ---------- diff --git a/deps/uv/docs/src/handle.rst b/deps/uv/docs/src/handle.rst index 6ba597a21ab996..14aec51fff1692 100644 --- a/deps/uv/docs/src/handle.rst +++ b/deps/uv/docs/src/handle.rst @@ -17,6 +17,34 @@ Data types The base libuv handle type. +.. c:type:: uv_handle_type + + The kind of the libuv handle. + + :: + + typedef enum { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX + } uv_handle_type; + .. c:type:: uv_any_handle Union of all handle types. @@ -24,12 +52,28 @@ Data types .. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) Type definition for callback passed to :c:func:`uv_read_start` and - :c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t` - structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment) - is provided, but it doesn't need to be honored. Setting the buffer's length to 0 - will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or + :c:func:`uv_udp_recv_start`. The user must allocate memory and fill the supplied + :c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length, + a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the :c:type:`uv_read_cb` callback. + A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, + not related in any way to the pending data to be read. The user is free to allocate the amount + of memory they decide. + + As an example, applications with custom allocation schemes such as using freelists, allocation + pools or slab based allocators may decide to use a different size which matches the memory + chunks they already have. + + Example: + + :: + + static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; + } + .. c:type:: void (*uv_close_cb)(uv_handle_t* handle) Type definition for callback passed to :c:func:`uv_close`. @@ -42,6 +86,10 @@ Public members Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly. +.. c:member:: uv_loop_t* uv_handle_t.type + + Pointer to the :c:type:`uv_handle_type`. Readonly. + .. c:member:: void* uv_handle_t.data Space for user-defined arbitrary data. libuv does not use this field. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index f32af48ff9e92d..95237f49c7ba61 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -17,11 +17,11 @@ Data types .. c:member:: char* uv_buf_t.base - Pointer to the base of the buffer. Readonly. + Pointer to the base of the buffer. .. c:member:: size_t uv_buf_t.len - Total bytes in the buffer. Readonly. + Total bytes in the buffer. .. note:: On Windows this field is ULONG. @@ -69,21 +69,24 @@ Data types uv_timeval_t ru_utime; /* user CPU time used */ uv_timeval_t ru_stime; /* system CPU time used */ uint64_t ru_maxrss; /* maximum resident set size */ - uint64_t ru_ixrss; /* integral shared memory size */ - uint64_t ru_idrss; /* integral unshared data size */ - uint64_t ru_isrss; /* integral unshared stack size */ - uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_ixrss; /* integral shared memory size (X) */ + uint64_t ru_idrss; /* integral unshared data size (X) */ + uint64_t ru_isrss; /* integral unshared stack size (X) */ + uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */ uint64_t ru_majflt; /* page faults (hard page faults) */ - uint64_t ru_nswap; /* swaps */ + uint64_t ru_nswap; /* swaps (X) */ uint64_t ru_inblock; /* block input operations */ uint64_t ru_oublock; /* block output operations */ - uint64_t ru_msgsnd; /* IPC messages sent */ - uint64_t ru_msgrcv; /* IPC messages received */ - uint64_t ru_nsignals; /* signals received */ - uint64_t ru_nvcsw; /* voluntary context switches */ - uint64_t ru_nivcsw; /* involuntary context switches */ + uint64_t ru_msgsnd; /* IPC messages sent (X) */ + uint64_t ru_msgrcv; /* IPC messages received (X) */ + uint64_t ru_nsignals; /* signals received (X) */ + uint64_t ru_nvcsw; /* voluntary context switches (X) */ + uint64_t ru_nivcsw; /* involuntary context switches (X) */ } uv_rusage_t; + Members marked with `(X)` are unsupported on Windows. + See :man:`getrusage(2)` for supported fields on Unix + .. c:type:: uv_cpu_info_t Data type for CPU information. @@ -183,7 +186,9 @@ API .. c:function:: int uv_get_process_title(char* buffer, size_t size) - Gets the title of the current process. + Gets the title of the current process. If `buffer` is `NULL` or `size` is + zero, `UV_EINVAL` is returned. If `size` cannot accommodate the process + title and terminating `NULL` character, the function returns `UV_ENOBUFS`. .. c:function:: int uv_set_process_title(const char* title) @@ -203,6 +208,7 @@ API .. note:: On Windows not all fields are set, the unsupported fields are filled with zeroes. + See :c:type:`uv_rusage_t` for more details. .. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index ed0c79d0045616..7989cd4f884c35 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -26,7 +26,11 @@ Data types .. c:type:: uv_write_t - Write request type. + Write request type. Careful attention must be paid when reusing objects of + this type. When a stream is in non-blocking mode, write requests sent + with ``uv_write`` will be queued. Reusing objects at this point is undefined + behaviour. It is safe to reuse the ``uv_write_t`` object only after the + callback passed to ``uv_write`` is fired. .. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) @@ -61,7 +65,7 @@ Data types .. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) - Callback called after s shutdown request has been completed. `status` will + Callback called after a shutdown request has been completed. `status` will be 0 in case of success, < 0 otherwise. .. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status) @@ -92,7 +96,7 @@ Public members .. c:member:: uv_stream_t* uv_write_t.send_handle - Pointer to the stream being sent using this write request.. + Pointer to the stream being sent using this write request. .. seealso:: The :c:type:`uv_handle_t` members also apply. diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index ca0c9b4ac5af4c..a1a5824561add9 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -53,7 +53,7 @@ API .. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable) - Enable / disable Nagle's algorithm. + Enable `TCP_NODELAY`, which disables Nagle's algorithm. .. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) diff --git a/deps/uv/include/pthread-barrier.h b/deps/uv/include/pthread-barrier.h index 084e1c2d556e3e..3e01705d9c31b8 100644 --- a/deps/uv/include/pthread-barrier.h +++ b/deps/uv/include/pthread-barrier.h @@ -39,6 +39,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2 * sizeof(sem_t) + \ 2 * sizeof(unsigned int) - \ sizeof(void *) +#else +# define UV_BARRIER_STRUCT_PADDING 0 #endif typedef struct { diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv-errno.h index 53f30296c1cdc4..f1371517cc32fe 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv-errno.h @@ -408,6 +408,7 @@ #elif defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) # define UV__EHOSTDOWN (-64) diff --git a/deps/uv/include/uv-os390.h b/deps/uv/include/uv-os390.h new file mode 100644 index 00000000000000..b0b068f44e86af --- /dev/null +++ b/deps/uv/include/uv-os390.h @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#endif /* UV_MVS_H */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index a852c40e49baa5..bca271447677f4 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -50,9 +50,10 @@ # include "uv-sunos.h" #elif defined(__APPLE__) # include "uv-darwin.h" -#elif defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ defined(__NetBSD__) # include "uv-bsd.h" #endif diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 08ad0edaa748e0..3cb9b5fdd1cafd 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 2 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ diff --git a/deps/uv/libuv.pc.in b/deps/uv/libuv.pc.in index 2933ec22526861..9174fe151d7421 100644 --- a/deps/uv/libuv.pc.in +++ b/deps/uv/libuv.pc.in @@ -1,5 +1,5 @@ prefix=@prefix@ -exec_prefix=@prefix@ +exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 2276985fc0dd95..652cd980f513ab 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -156,7 +156,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { pqry.fd = pc.fd; rc = pollset_query(loop->backend_fd, &pqry); switch (rc) { - case -1: + case -1: assert(0 && "Failed to query pollset for file descriptor"); abort(); case 0: @@ -333,20 +333,20 @@ int uv_exepath(char* buffer, size_t* size) { pi.pi_pid = getpid(); res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) + if (res < 0) return -EINVAL; /* * Possibilities for args: * i) an absolute path such as: /home/user/myprojects/nodejs/node * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable + * iii) a bare filename such as "node", after exporting PATH variable * to its location. */ /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) + if (realpath(args, abspath) != abspath) return -errno; abspath_size = strlen(abspath); @@ -360,7 +360,7 @@ int uv_exepath(char* buffer, size_t* size) { return 0; } else { - /* Case iii). Search PATH environment variable */ + /* Case iii). Search PATH environment variable */ char trypath[PATH_MAX]; char *clonedpath = NULL; char *token = NULL; @@ -376,7 +376,7 @@ int uv_exepath(char* buffer, size_t* size) { token = strtok(clonedpath, ":"); while (token != NULL) { snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { + if (realpath(trypath, abspath) == abspath) { /* Check the match is executable */ if (access(abspath, X_OK) == 0) { abspath_size = strlen(abspath); @@ -452,7 +452,7 @@ static char *uv__rawname(char *cp) { } -/* +/* * Determine whether given pathname is a directory * Returns 0 if the path is a directory, -1 if not * @@ -472,7 +472,7 @@ static int uv__path_is_a_directory(char* filename) { } -/* +/* * Check whether AHAFS is mounted. * Returns 0 if AHAFS is mounted, or an error code < 0 on failure */ @@ -547,7 +547,7 @@ static int uv__makedir_p(const char *dir) { return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); } -/* +/* * Creates necessary subdirectories in the AIX Event Infrastructure * file system for monitoring the object specified. * Returns code from mkdir call @@ -665,7 +665,7 @@ static int uv__skip_lines(char **p, int n) { /* * Parse the event occurrence data to figure out what event just occurred * and take proper action. - * + * * The buf is a pointer to the buffer containing the event occurrence data * Returns 0 on success, -1 if unrecoverable error in parsing * @@ -891,9 +891,10 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; return 0; } diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h index 84e471838bede7..815e355238b121 100644 --- a/deps/uv/src/unix/atomic-ops.h +++ b/deps/uv/src/unix/atomic-ops.h @@ -42,6 +42,9 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { const int out = (*(volatile int*) ptr); __compare_and_swap(ptr, &oldval, newval); return out; +#elif defined(__MVS__) + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -63,6 +66,14 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { __compare_and_swap(ptr, &oldval, newval); # endif /* if defined(__64BIT__) */ return out; +#elif defined (__MVS__) +# ifdef _LP64 + return __plo_CSGR(ptr, (unsigned long long*) ptr, + oldval, (unsigned long long*) &newval); +# else + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); +# endif #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index cdcd0b504f32f4..d88fc1de8f048b 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -40,11 +41,8 @@ #include /* getrusage */ #include -#ifdef __linux__ -# include -#endif - #ifdef __sun +# include # include # include #endif @@ -52,16 +50,16 @@ #ifdef __APPLE__ # include /* _NSGetExecutablePath */ # include -# include # if defined(O_CLOEXEC) # define UV__O_CLOEXEC O_CLOEXEC # endif #endif -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) # include # include -# include # include # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 @@ -74,14 +72,14 @@ # endif #endif -#ifdef _AIX -#include -#endif - #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 # include /* for dlsym */ #endif +#if defined(__MVS__) +#include +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -508,8 +506,8 @@ int uv__close_nocheckstdio(int fd) { rc = close(fd); if (rc == -1) { rc = -errno; - if (rc == -EINTR) - rc = -EINPROGRESS; /* For platform/libc consistency. */ + if (rc == -EINTR || rc == -EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ errno = saved_errno; } @@ -523,10 +521,7 @@ int uv__close(int fd) { } -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__) - -int uv__nonblock(int fd, int set) { +int uv__nonblock_ioctl(int fd, int set) { int r; do @@ -540,7 +535,7 @@ int uv__nonblock(int fd, int set) { } -int uv__cloexec(int fd, int set) { +int uv__cloexec_ioctl(int fd, int set) { int r; do @@ -553,10 +548,8 @@ int uv__cloexec(int fd, int set) { return 0; } -#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__)) */ -int uv__nonblock(int fd, int set) { +int uv__nonblock_fcntl(int fd, int set) { int flags; int r; @@ -587,7 +580,7 @@ int uv__nonblock(int fd, int set) { } -int uv__cloexec(int fd, int set) { +int uv__cloexec_fcntl(int fd, int set) { int flags; int r; @@ -617,9 +610,6 @@ int uv__cloexec(int fd, int set) { return 0; } -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__) */ - /* This function is not execve-safe, there is a race window * between the call to dup() and fcntl(FD_CLOEXEC). @@ -931,6 +921,7 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; +#if !defined(__MVS__) rusage->ru_maxrss = usage.ru_maxrss; rusage->ru_ixrss = usage.ru_ixrss; rusage->ru_idrss = usage.ru_idrss; @@ -945,6 +936,7 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_nsignals = usage.ru_nsignals; rusage->ru_nvcsw = usage.ru_nvcsw; rusage->ru_nivcsw = usage.ru_nivcsw; +#endif return 0; } diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index adc95235ceefdf..cba44a3e0b078e 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -196,14 +196,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 085970a06d9e7b..3d478b790e6c5a 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -46,9 +46,10 @@ #include #include -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_PREADV 1 #else @@ -151,9 +152,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { goto skip; ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; r = uv__utimesat(req->file, NULL, ts, 0); if (r == 0) @@ -167,9 +168,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { skip: tv[0].tv_sec = req->atime; - tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); r = utimes(path, tv); @@ -193,14 +194,15 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__sun) struct timeval tv[2]; tv[0].tv_sec = req->atime; - tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; # if defined(__sun) return futimesat(req->file, NULL, tv); # else @@ -209,10 +211,18 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { #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[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); #else errno = ENOSYS; return -1; @@ -251,7 +261,7 @@ static ssize_t uv__fs_open(uv_fs_t* req) { */ if (r >= 0 && uv__cloexec(r, 1) != 0) { r = uv__close(r); - if (r != 0 && r != -EINPROGRESS) + if (r != 0) abort(); r = -1; } @@ -336,22 +346,30 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } -#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) -static int uv__fs_scandir_filter(uv__dirent_t* dent) { +#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) +#define UV_CONST_DIRENT uv__dirent_t #else -static int uv__fs_scandir_filter(const uv__dirent_t* dent) { +#define UV_CONST_DIRENT const uv__dirent_t #endif + + +static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) { return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; } +static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { + return strcmp((*a)->d_name, (*b)->d_name); +} + + static ssize_t uv__fs_scandir(uv_fs_t* req) { uv__dirent_t **dents; int saved_errno; int n; dents = NULL; - n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort); + n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort); /* NOTE: We will use nbufs as an index field */ req->nbufs = 0; @@ -595,7 +613,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { return -1; } -#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) { off_t len; ssize_t r; @@ -608,6 +629,15 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { #if defined(__FreeBSD__) || defined(__DragonFly__) len = 0; r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); +#elif defined(__FreeBSD_kernel__) + len = 0; + r = bsd_sendfile(in_fd, + out_fd, + req->off, + req->bufsml[0].len, + NULL, + &len, + 0); #else /* The darwin sendfile takes len as an input for the length to send, * so make sure to initialize it with the caller's value. */ @@ -768,6 +798,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ + defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ @@ -810,8 +841,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { static int uv__fs_stat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = stat(path, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } @@ -819,8 +853,11 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) { static int uv__fs_lstat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = lstat(path, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } @@ -828,8 +865,11 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) { static int uv__fs_fstat(int fd, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = fstat(fd, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 670b14bc2a2aa5..c7b6019ed2527a 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -132,7 +132,8 @@ enum { UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ - UV_UDP_PROCESSING = 0x20000 /* Handle is running the send callback queue. */ + UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ }; /* loop flags */ @@ -152,11 +153,26 @@ struct uv__stream_queued_fds_s { }; +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + /* core */ -int uv__nonblock(int fd, int set); +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(int fd, int set); +int uv__nonblock_ioctl(int fd, int set); +int uv__nonblock_fcntl(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); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index b48a1111701753..58dd813ddf132c 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (nfds == 0) { assert(timeout != -1); - timeout = real_timeout - timeout; - if (timeout > 0) - continue; + if (timeout == 0) + return; - return; + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; } if (nfds == -1) { @@ -484,12 +486,20 @@ int uv_exepath(char* buffer, size_t* size) { uint64_t uv_get_free_memory(void) { - return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; } uint64_t uv_get_total_memory(void) { - return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 92e96f09ed0100..bd63c2f9d1d24a 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -28,11 +28,15 @@ #include int uv_loop_init(uv_loop_t* loop) { + void* saved_data; int err; uv__signal_global_once_init(); + saved_data = loop->data; memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->active_reqs); diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index ca48550f9d99d4..4a9e6cbc17c783 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -147,14 +147,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 8c40bde40f69ad..909288cc888893 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -169,14 +169,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c new file mode 100644 index 00000000000000..bcdbc4b6a80542 --- /dev/null +++ b/deps/uv/src/unix/os390.c @@ -0,0 +1,42 @@ +/* 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 "internal.h" + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index c8d163dcc796d5..b73994cb8de365 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -80,6 +80,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } /* Success. */ + handle->flags |= UV_HANDLE_BOUND; handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->io_watcher.fd = sockfd; return 0; @@ -97,6 +98,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { if (uv__stream_fd(handle) == -1) return -EINVAL; +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + if (listen(uv__stream_fd(handle), backlog)) return -errno; diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 0d5944b0afb8ba..4c0d478eee1a1f 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -59,7 +59,14 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { if (err) return err; + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ err = uv__nonblock(fd, 1); + if (err == -ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(fd, 1); + if (err) return err; diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index ef10a3422dc518..45f5b4526b9774 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -40,7 +40,7 @@ extern char **environ; #endif -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) # include #endif @@ -232,7 +232,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container, return 0; err = uv__close(pipefds[1]); - if (err != 0 && err != -EINPROGRESS) + if (err != 0) abort(); pipefds[1] = -1; diff --git a/deps/uv/src/unix/proctitle.c b/deps/uv/src/unix/proctitle.c index 19214e5ec9743d..08d875f7af4112 100644 --- a/deps/uv/src/unix/proctitle.c +++ b/deps/uv/src/unix/proctitle.c @@ -87,10 +87,13 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (process_title.len > 0) - strncpy(buffer, process_title.str, size); - else if (size > 0) - buffer[0] = '\0'; + if (buffer == NULL || size == 0) + return -EINVAL; + else if (size <= process_title.len) + return -ENOBUFS; + + memcpy(buffer, process_title.str, process_title.len + 1); + buffer[process_title.len] = '\0'; return 0; } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 7dbc556f74e0bc..d20d0bcb33004e 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -291,7 +291,10 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { timeout.tv_sec = 0; timeout.tv_nsec = 1; - ret = kevent(kq, filter, 1, events, 1, &timeout); + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + uv__close(kq); if (ret == -1) @@ -571,7 +574,6 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_accept(uv_stream_t* server, uv_stream_t* client) { int err; - /* TODO document this */ assert(server->loop == client->loop); if (server->accepted_fd == -1) @@ -602,6 +604,8 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { return -EINVAL; } + client->flags |= UV_HANDLE_BOUND; + done: /* Process queued fds */ if (server->queued_fds != NULL) { @@ -962,8 +966,8 @@ 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 +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly 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. */ @@ -1122,8 +1126,9 @@ static void uv__read(uv_stream_t* stream) { && (count-- > 0)) { assert(stream->alloc_cb != NULL); + buf = uv_buf_init(NULL, 0); stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { /* User indicates it can't or won't handle the read. */ stream->read_cb(stream, UV_ENOBUFS, &buf); return; diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index e67be8fcf81ec4..3e7a7592d911e5 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -33,6 +33,8 @@ #endif #include #include +#include +#include #include #include @@ -540,9 +542,10 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; return 0; } @@ -692,13 +695,57 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return -errno; + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return -errno; + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifdef SUNOS_NO_IFADDRS return -ENOSYS; #else uv_interface_address_t* address; - struct sockaddr_dl* sa_addr; struct ifaddrs* addrs; struct ifaddrs* ent; int i; @@ -751,28 +798,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || (ent->ifa_flags & IFF_LOOPBACK)); + uv__set_phys_addr(address, ent); address++; } - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { - continue; - } - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - freeifaddrs(addrs); return 0; diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 793e4c7d60b543..c423dcb15fe11d 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -115,6 +115,10 @@ int uv__tcp_bind(uv_tcp_t* tcp, IPV6_V6ONLY, &on, sizeof on) == -1) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return -EINVAL; +#endif return -errno; } } @@ -130,6 +134,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, } tcp->delayed_error = -errno; + tcp->flags |= UV_HANDLE_BOUND; if (addr->sa_family == AF_INET6) tcp->flags |= UV_HANDLE_IPV6; @@ -158,11 +163,17 @@ int uv__tcp_connect(uv_connect_t* req, handle->delayed_error = 0; - do + do { + errno = 0; r = connect(uv__stream_fd(handle), addr, addrlen); - while (r == -1 && errno == EINTR); + } while (r == -1 && errno == EINTR); - if (r == -1) { + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { if (errno == EINPROGRESS) ; /* not an error */ else if (errno == ECONNREFUSED) @@ -266,10 +277,32 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { if (err) return err; +#ifdef __MVS__ + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + + if (!(tcp->flags & UV_HANDLE_BOUND)) { + struct sockaddr_storage saddr; + socklen_t slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + + if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) + return -errno; + + if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) + return -errno; + + tcp->flags |= UV_HANDLE_BOUND; + } +#endif + if (listen(tcp->io_watcher.fd, backlog)) return -errno; tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; /* Start listening for connections. */ tcp->io_watcher.cb = uv__server_io; diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 236f5913936650..52989f7f03b61c 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -32,6 +32,11 @@ #include +#ifdef __MVS__ +#include +#include +#endif + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -302,6 +307,85 @@ int uv_sem_trywait(uv_sem_t* sem) { return -EINVAL; /* Satisfy the compiler. */ } +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + struct sembuf buf; + int err; + + buf.sem_num = 0; + buf.sem_op = value; + buf.sem_flg = 0; + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return -errno; + + if (-1 == semop(semid, &buf, 1)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return -err; + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + #else /* !(defined(__APPLE__) && defined(__MACH__)) */ int uv_sem_init(uv_sem_t* sem, unsigned int value) { @@ -354,7 +438,7 @@ int uv_sem_trywait(uv_sem_t* sem) { #endif /* defined(__APPLE__) && defined(__MACH__) */ -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) int uv_cond_init(uv_cond_t* cond) { return -pthread_cond_init(cond, NULL); diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/unix/timer.c index ca3ec3db957433..f46bdf4bf52e61 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/unix/timer.c @@ -31,8 +31,8 @@ static int timer_less_than(const struct heap_node* ha, const uv_timer_t* a; const uv_timer_t* b; - a = container_of(ha, const uv_timer_t, heap_node); - b = container_of(hb, const uv_timer_t, heap_node); + a = container_of(ha, uv_timer_t, heap_node); + b = container_of(hb, uv_timer_t, heap_node); if (a->timeout < b->timeout) return 1; @@ -135,7 +135,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (heap_node == NULL) return -1; /* block indefinitely */ - handle = container_of(heap_node, const uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, heap_node); if (handle->timeout <= loop->time) return 0; diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 32fa37eac96307..b2d37f4c2c1e5b 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -30,13 +30,17 @@ #include #include +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + 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__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) int dummy; result = ioctl(fd, TIOCGPTN, &dummy) != 0; @@ -57,6 +61,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { int flags; int newfd; int r; + int saved_flags; char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. @@ -113,6 +118,22 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { fd = newfd; } +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return -errno; + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); @@ -120,13 +141,20 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ + if (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + #if defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { + int rc = r; if (newfd != -1) uv__close(newfd); QUEUE_REMOVE(&tty->handle_queue); - return r; + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; } #endif @@ -135,9 +163,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { else flags |= UV_STREAM_WRITABLE; - if (!(flags & UV_STREAM_BLOCKING)) - uv__nonblock(fd, 1); - uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; @@ -147,7 +172,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { static void uv__tty_make_raw(struct termios* tio) { assert(tio != NULL); -#ifdef __sun +#if defined __sun || defined __MVS__ /* * This implementation of cfmakeraw for Solaris and derivatives is taken from * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html. @@ -268,14 +293,14 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_UDP; if (type == SOCK_STREAM) { -#if defined(_AIX) - /* on AIX the getsockname call returns an empty sa structure +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly the getsockname call returns an empty sa structure * for sockets of type AF_UNIX. For all other types it will * return a properly filled in structure. */ if (len == 0) return UV_NAMED_PIPE; -#endif /* defined(_AIX) */ +#endif /* defined(_AIX) || defined(__DragonFly__) */ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) return UV_TCP; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 4527bba1f1931c..1cd49257865d0f 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -27,6 +27,9 @@ #include #include #include +#if defined(__MVS__) +#include +#endif #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -165,8 +168,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { h.msg_name = &peer; do { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); return; } @@ -331,6 +335,8 @@ int uv__udp_bind(uv_udp_t* handle, if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; + handle->flags |= UV_HANDLE_BOUND; + return 0; out: @@ -507,6 +513,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle, optname, &mreq, sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif return -errno; } @@ -550,6 +560,10 @@ static int uv__udp_set_membership6(uv_udp_t* handle, optname, &mreq, sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif return -errno; } @@ -668,7 +682,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option4, int option6, int val) { -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) char arg = val; #elif defined(__OpenBSD__) unsigned char arg = val; @@ -700,19 +714,27 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { if (ttl < 1 || ttl > 255) return -EINVAL; +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + /* * On Solaris and derivatives such as SmartOS, the length of socket options * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS, * so hardcode the size of these options on this platform, * and use the general uv__setsockopt_maybe_char call on other platforms. */ -#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) + return uv__setsockopt(handle, IP_TTL, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */ +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_TTL, @@ -728,14 +750,14 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -751,14 +773,14 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP, &on, sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index ba26446915a39c..434a5029cda7dc 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -613,6 +613,7 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; + void* saved_data; if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; @@ -626,7 +627,9 @@ int uv_loop_close(uv_loop_t* loop) { uv__loop_close(loop); #ifndef NDEBUG + saved_data = loop->data; memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; #endif if (loop == default_loop_ptr) default_loop_ptr = NULL; diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index ba306ebc083fbb..9d00afc6b2fac7 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -31,6 +31,7 @@ #include "uv.h" #include "internal.h" +#include "queue.h" #include "handle-inl.h" #include "req-inl.h" @@ -80,6 +81,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression, } #endif +static uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init() { + uv_mutex_init(&uv__loops_lock); + uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*)); + if (!uv__loops) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + uv__loops_size = 0; + uv__loops_capacity = UV__LOOPS_CHUNK_SIZE; +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops() { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} static void uv_init(void) { /* Tell Windows that we will handle critical errors. */ @@ -101,6 +194,9 @@ static void uv_init(void) { _CrtSetReportHook(uv__crt_dbg_report_handler); #endif + /* Initialize tracking of all uv loops */ + uv__loops_init(); + /* Fetch winapi function pointers. This must be done first because other * initialization code might need these function pointers to be loaded. */ @@ -120,6 +216,9 @@ static void uv_init(void) { /* Initialize utilities */ uv__util_init(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); } @@ -178,6 +277,10 @@ int uv_loop_init(uv_loop_t* loop) { uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV__HANDLE_INTERNAL; + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + return 0; fail_async_init: @@ -199,6 +302,8 @@ void uv__once_init(void) { void uv__loop_close(uv_loop_t* loop) { size_t i; + uv__loops_remove(loop); + /* close the async handle without needing an extra loop iteration */ assert(!loop->wq_async.async_sent); loop->wq_async.close_cb = NULL; @@ -323,9 +428,13 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { 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); + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } } /* Some time might have passed waiting for I/O, diff --git a/deps/uv/src/win/detect-wakeup.c b/deps/uv/src/win/detect-wakeup.c new file mode 100644 index 00000000000000..a12179f7981d13 --- /dev/null +++ b/deps/uv/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(); + +void uv__init_detect_system_wakeup() { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback() { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index e79a48d0e99686..03e4adc058f9f3 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { } +static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) { + int str_len; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; @@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, * or if the filename filter matches. */ if (handle->dirw || - _wcsnicmp(handle->filew, file_info->FileName, - file_info->FileNameLength / sizeof(WCHAR)) == 0 || - _wcsnicmp(handle->short_filew, file_info->FileName, - file_info->FileNameLength / sizeof(WCHAR)) == 0) { + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 0) { if (handle->dirw) { /* @@ -407,7 +425,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, - file_info->FileNameLength / sizeof(WCHAR), + file_info->FileNameLength / (DWORD)sizeof(WCHAR), file_info->FileName); filenamew[size - 1] = L'\0'; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 54dfea7240864e..6a4157bfe59b4e 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -94,7 +94,7 @@ #define TIME_T_TO_FILETIME(time, filetime_ptr) \ do { \ - uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \ + uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \ 116444736000000000ULL; \ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ @@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, req->fs.info.new_pathw = NULL; } - if (!copy_path) { - req->path = path; - } else if (path) { + req->path = path; + if (path != NULL && copy_path) { memcpy(pos, path, path_len); assert(path_len == buf_sz - (pos - buf)); req->path = pos; - } else { - req->path = NULL; } req->flags |= UV_FS_FREE_PATHS; @@ -1091,17 +1088,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { statbuf->st_mode = 0; if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - statbuf->st_mode |= S_IFLNK; - if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + /* + * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have + * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets + * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode + * calculated below will indicate a normal directory or file, as if + * FILE_ATTRIBUTE_REPARSE_POINT was not present. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { + statbuf->st_mode |= S_IFLNK; + } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { return -1; + } + } - } else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - statbuf->st_mode |= _S_IFDIR; - statbuf->st_size = 0; - - } else { - statbuf->st_mode |= _S_IFREG; - statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + if (statbuf->st_mode == 0) { + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + statbuf->st_size = 0; + } else { + statbuf->st_mode |= _S_IFREG; + statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + } } if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) @@ -1429,8 +1437,8 @@ static void fs__fchmod(uv_fs_t* req) { INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { FILETIME filetime_a, filetime_m; - TIME_T_TO_FILETIME((time_t) atime, &filetime_a); - TIME_T_TO_FILETIME((time_t) mtime, &filetime_m); + TIME_T_TO_FILETIME(atime, &filetime_a); + TIME_T_TO_FILETIME(mtime, &filetime_m); if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { return -1; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 0a7c9404fa3faf..b8cfde90e81f8b 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -381,4 +381,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6; extern struct sockaddr_in uv_addr_ip4_any_; extern struct sockaddr_in6 uv_addr_ip6_any_; +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(); + #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index a784325c589474..2442be7301ebf8 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle); static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { - snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); } @@ -1634,8 +1634,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, } } + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, avail, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); break; } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 0f5654863e9790..0709696ff9afed 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -496,8 +496,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { */ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); - if (handle->tcp.conn.read_buffer.len == 0) { + if (handle->tcp.conn.read_buffer.base == NULL || + handle->tcp.conn.read_buffer.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer); return; } @@ -1004,8 +1006,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, /* Do nonblocking reads until the buffer is empty */ while (handle->flags & UV_HANDLE_READING) { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); break; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 9b9637784401d8..18d68d09433fbe 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -40,6 +40,9 @@ #include "stream-inl.h" #include "req-inl.h" +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif #define UNICODE_REPLACEMENT_CHARACTER (0xfffd) @@ -54,6 +57,9 @@ #define MAX_INPUT_BUFFER_LENGTH 8192 +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); @@ -105,7 +111,11 @@ static int uv_tty_virtual_offset = -1; static int uv_tty_virtual_height = -1; static int uv_tty_virtual_width = -1; -static CRITICAL_SECTION uv_tty_output_lock; +/* We use a semaphore rather than a mutex or critical section because in some + cases (uv__cancel_read_console) we need take the lock in the main thread and + release it in another thread. Using a semaphore ensures that in such + scenario the main thread will still block when trying to acquire the lock. */ +static uv_sem_t uv_tty_output_lock; static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; @@ -118,9 +128,18 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { - InitializeCriticalSection(&uv_tty_output_lock); + if (uv_sem_init(&uv_tty_output_lock, 1)) + abort(); } @@ -158,7 +177,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* Obtain the the tty_output_lock because the virtual window state is */ /* shared between all uv_tty_t handles. */ - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); + + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); /* Store the global tty output handle. This handle is used by TTY read */ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ @@ -170,7 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { uv_tty_update_virtual_window(&screen_buffer_info); - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); } @@ -294,10 +316,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { break; case UV_TTY_MODE_IO: return UV_ENOTSUP; - } - - if (!SetConsoleMode(tty->handle, flags)) { - return uv_translate_sys_error(GetLastError()); + default: + return UV_EINVAL; } /* If currently reading, stop, and restart reading. */ @@ -313,6 +333,14 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { was_reading = 0; } + uv_sem_wait(&uv_tty_output_lock); + if (!SetConsoleMode(tty->handle, flags)) { + err = uv_translate_sys_error(GetLastError()); + uv_sem_post(&uv_tty_output_lock); + return err; + } + uv_sem_post(&uv_tty_output_lock); + /* Update flag. */ tty->flags &= ~UV_HANDLE_TTY_RAW; tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; @@ -342,9 +370,9 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { return uv_translate_sys_error(GetLastError()); } - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); uv_tty_update_virtual_window(&info); - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); *width = uv_tty_virtual_width; *height = uv_tty_virtual_height; @@ -413,6 +441,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { DWORD chars, read_chars; LONG status; COORD pos; + BOOL read_console_success; assert(data); @@ -442,11 +471,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { return 0; } - if (ReadConsoleW(handle->handle, - (void*) utf16, - chars, - &read_chars, - NULL)) { + read_console_success = ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL); + + if (read_console_success) { read_bytes = WideCharToMultiByte(CP_UTF8, 0, utf16, @@ -461,33 +492,36 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { SET_REQ_ERROR(req, GetLastError()); } - InterlockedExchange(&uv__read_console_status, COMPLETED); + status = 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$", + if (status == TRAP_REQUESTED) { + /* 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 (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer; + 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); + 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); + } } + uv_sem_post(&uv_tty_output_lock); } - POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -504,8 +538,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { req = &handle->read_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); - if (handle->tty.rd.read_line_buffer.len == 0) { + if (handle->tty.rd.read_line_buffer.base == NULL || + handle->tty.rd.read_line_buffer.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tty.rd.read_line_buffer); @@ -673,14 +709,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { CONSOLE_SCREEN_BUFFER_INFO info; - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); if (uv_tty_output_handle != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { uv_tty_update_virtual_window(&info); } - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); continue; } @@ -828,8 +864,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) { /* Allocate a buffer if needed */ if (buf_used == 0) { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); goto out; } @@ -1013,11 +1050,16 @@ static int uv__cancel_read_console(uv_tty_t* handle) { assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + /* Hold the output lock during the cancellation, to ensure that further + writes don't interfere with the screen state. It will be the ReadConsole + thread's responsibility to release the lock. */ + uv_sem_wait(&uv_tty_output_lock); 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. */ + uv_sem_post(&uv_tty_output_lock); return 0; } @@ -1602,12 +1644,39 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* state. */ *error = ERROR_SUCCESS; - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); for (i = 0; i < nbufs; i++) { uv_buf_t buf = bufs[i]; unsigned int j; + if (uv__vterm_state == UV_SUPPORTED) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buf, + utf16_buf_used)) { + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + continue; + } + for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2012,7 +2081,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, handle->tty.wr.previous_eol = previous_eol; handle->tty.wr.ansi_parser_state = ansi_parser_state; - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); if (*error == STATUS_SUCCESS) { return 0; @@ -2165,3 +2234,24 @@ int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; } + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 24792ec067ef2f..9bf1453e536d9a 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -289,8 +289,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { if (loop->active_udp_streams < uv_active_udp_streams_threshold) { handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->recv_buffer = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); - if (handle->recv_buffer.len == 0) { + if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); return; } @@ -506,8 +507,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, /* Do a nonblocking receive */ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); goto done; } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 4cebad390818cd..050058afaa9a90 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -54,6 +54,10 @@ /* The number of nanoseconds in one second. */ #define UV__NANOSEC 1000000000 +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; @@ -416,6 +420,11 @@ static int uv__get_process_title() { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + uv__once_init(); EnterCriticalSection(&process_title_lock); @@ -429,7 +438,14 @@ int uv_get_process_title(char* buffer, size_t size) { } assert(process_title); - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); LeaveCriticalSection(&process_title_lock); return 0; @@ -1062,6 +1078,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME createTime, exitTime, kernelTime, userTime; SYSTEMTIME kernelSystemTime, userSystemTime; PROCESS_MEMORY_COUNTERS memCounters; + IO_COUNTERS ioCounters; int ret; ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); @@ -1086,6 +1103,11 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return uv_translate_sys_error(GetLastError()); } + ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + 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 + @@ -1101,6 +1123,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + return 0; } diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 26bd0648668742..1fa179b5724ed0 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -49,9 +49,14 @@ sCancelSynchronousIo pCancelSynchronousIo; sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + + void uv_winapi_init() { HMODULE ntdll_module; HMODULE kernel32_module; + HMODULE powrprof_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -143,4 +148,12 @@ void uv_winapi_init() { pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 122198a6d481ac..16d9365cc4b651 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4684,6 +4684,40 @@ typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) DWORD cchFilePath, DWORD dwFlags); +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + + /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; @@ -4707,4 +4741,8 @@ extern sWakeConditionVariable pWakeConditionVariable; extern sCancelSynchronousIo pCancelSynchronousIo; extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + #endif /* UV_WIN_WINAPI_H_ */ diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index b4be01f6f95927..1e344f05002ac6 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -56,6 +56,7 @@ int main(int argc, char **argv) { case 1: return run_tests(0); case 2: return maybe_run_test(argc, argv); case 3: return run_test_part(argv[1], argv[2]); + case 4: return maybe_run_test(argc, argv); default: fprintf(stderr, "Too many arguments.\n"); fflush(stderr); @@ -177,5 +178,17 @@ static int maybe_run_test(int argc, char **argv) { return spawn_stdin_stdout(); } +#ifndef _WIN32 + if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) { + uv_uid_t uid = atoi(argv[2]); + uv_gid_t gid = atoi(argv[3]); + + ASSERT(uid == getuid()); + ASSERT(gid == getgid()); + + return 1; + } +#endif /* !_WIN32 */ + return run_test(argv[1], 0, 1); } diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 2405fa878c0805..2ff18ce75647fe 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -43,11 +43,6 @@ /* Do platform-specific initialization. */ int platform_init(int argc, char **argv) { - const char* tap; - - tap = getenv("UV_TAP_OUTPUT"); - tap_output = (tap != NULL && atoi(tap) > 0); - /* Disable stdio output buffering. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); @@ -206,7 +201,11 @@ int process_wait(process_info_t* vec, int n, int timeout) { if (pthread_attr_init(&attr)) abort(); +#if defined(__MVS__) + if (pthread_attr_setstacksize(&attr, 1024 * 1024)) +#else if (pthread_attr_setstacksize(&attr, 256 * 1024)) +#endif abort(); r = pthread_create(&tid, &attr, dowait, &args); @@ -294,8 +293,7 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ -int process_copy_output(process_info_t *p, int fd) { - ssize_t nwritten; +int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; int r; @@ -306,20 +304,8 @@ int process_copy_output(process_info_t *p, int fd) { } /* TODO: what if the line is longer than buf */ - while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) { - /* TODO: what if write doesn't write the whole buffer... */ - nwritten = 0; - - if (tap_output) - nwritten += write(fd, "#", 1); - - nwritten += write(fd, buf, strlen(buf)); - - if (nwritten < 0) { - perror("write"); - return -1; - } - } + while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) + print_lines(buf, strlen(buf), stream); if (ferror(p->stdout_file)) { perror("read"); @@ -390,11 +376,23 @@ void process_cleanup(process_info_t *p) { /* Move the console cursor one line up and back to the first column. */ void rewind_cursor(void) { +#if defined(__MVS__) + fprintf(stderr, "\047[2K\r"); +#else fprintf(stderr, "\033[2K\r"); +#endif } /* Pause the calling thread for a number of milliseconds. */ void uv_sleep(int msec) { - usleep(msec * 1000); + int sec; + int usec; + + sec = msec / 1000; + usec = (msec % 1000) * 1000; + if (sec > 0) + sleep(sec); + if (usec > 0) + usleep(usec); } diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 97ef7599eb8e52..1b4a569aef54dd 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -44,11 +44,6 @@ /* Do platform-specific initialization. */ int platform_init(int argc, char **argv) { - const char* tap; - - tap = getenv("UV_TAP_OUTPUT"); - tap_output = (tap != NULL && atoi(tap) > 0); - /* Disable the "application crashed" popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -213,10 +208,9 @@ long int process_output_size(process_info_t *p) { } -int process_copy_output(process_info_t *p, int fd) { +int process_copy_output(process_info_t* p, FILE* stream) { DWORD read; char buf[1024]; - char *line, *start; if (SetFilePointer(p->stdio_out, 0, @@ -225,29 +219,8 @@ int process_copy_output(process_info_t *p, int fd) { return -1; } - if (tap_output) - write(fd, "#", 1); - - while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) && - read > 0) { - if (tap_output) { - start = buf; - - while ((line = strchr(start, '\n')) != NULL) { - write(fd, start, line - start + 1); - write(fd, "#", 1); - start = line + 1; - } - - if (start < buf + read) - write(fd, start, buf + read - start); - } else { - write(fd, buf, read); - } - } - - if (tap_output) - write(fd, "\n", 1); + while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0) + print_lines(buf, read, stream); if (GetLastError() != ERROR_HANDLE_EOF) return -1; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index c616d176445db1..4f54f85e2305f1 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -28,31 +28,6 @@ char executable_path[sizeof(executable_path)]; -int tap_output = 0; - - -static void log_progress(int total, - int passed, - int failed, - int todos, - int skipped, - const char* name) { - int progress; - - if (total == 0) - total = 1; - - progress = 100 * (passed + failed + skipped + todos) / total; - fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s", - progress, - passed, - failed, - todos, - skipped, - name); - fflush(stderr); -} - const char* fmt(double d) { static char buf[1024]; @@ -95,7 +70,6 @@ int run_tests(int benchmark_output) { int total; int passed; int failed; - int todos; int skipped; int current; int test_result; @@ -109,15 +83,12 @@ int run_tests(int benchmark_output) { } } - if (tap_output) { - fprintf(stderr, "1..%d\n", total); - fflush(stderr); - } + fprintf(stderr, "1..%d\n", total); + fflush(stderr); /* Run all tests. */ passed = 0; failed = 0; - todos = 0; skipped = 0; current = 1; for (task = TASKS; task->main; task++) { @@ -125,30 +96,15 @@ int run_tests(int benchmark_output) { continue; } - if (!tap_output) - rewind_cursor(); - - if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, todos, skipped, task->task_name); - } - test_result = run_test(task->task_name, benchmark_output, current); switch (test_result) { case TEST_OK: passed++; break; - case TEST_TODO: todos++; break; case TEST_SKIP: skipped++; break; default: failed++; } current++; } - if (!tap_output) - rewind_cursor(); - - if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, todos, skipped, "Done.\n"); - } - return failed; } @@ -166,10 +122,6 @@ void log_tap_result(int test_count, result = "ok"; directive = ""; break; - case TEST_TODO: - result = "not ok"; - directive = " # TODO "; - break; case TEST_SKIP: result = "ok"; directive = " # SKIP "; @@ -179,8 +131,7 @@ void log_tap_result(int test_count, directive = ""; } - if ((status == TEST_SKIP || status == TEST_TODO) && - process_output_size(process) > 0) { + if (status == TEST_SKIP && process_output_size(process) > 0) { process_read_last_line(process, reason, sizeof reason); } else { reason[0] = '\0'; @@ -194,7 +145,7 @@ void log_tap_result(int test_count, int run_test(const char* test, int benchmark_output, int test_count) { - char errmsg[1024] = "no error"; + char errmsg[1024] = ""; process_info_t processes[1024]; process_info_t *main_proc; task_entry_t* task; @@ -319,22 +270,13 @@ int run_test(const char* test, FATAL("process_wait failed"); } - if (tap_output) - log_tap_result(test_count, test, status, &processes[i]); + log_tap_result(test_count, test, status, &processes[i]); /* Show error and output from processes if the test failed. */ - if (status != 0 || task->show_output) { - if (tap_output) { - fprintf(stderr, "#"); - } else if (status == TEST_TODO) { - fprintf(stderr, "\n`%s` todo\n", test); - } else if (status == TEST_SKIP) { - fprintf(stderr, "\n`%s` skipped\n", test); - } else if (status != 0) { - fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg); - } else { - fprintf(stderr, "\n"); - } + if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { + if (strlen(errmsg) > 0) + fprintf(stderr, "# %s\n", errmsg); + fprintf(stderr, "# "); fflush(stderr); for (i = 0; i < process_count; i++) { @@ -354,15 +296,11 @@ int run_test(const char* test, default: fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i])); fflush(stderr); - process_copy_output(&processes[i], fileno(stderr)); + process_copy_output(&processes[i], stderr); break; } } - if (!tap_output) { - fprintf(stderr, "=============================================================\n"); - } - /* In benchmark mode show concise output from the main process. */ } else if (benchmark_output) { switch (process_output_size(main_proc)) { @@ -378,7 +316,7 @@ int run_test(const char* test, default: for (i = 0; i < process_count; i++) { - process_copy_output(&processes[i], fileno(stderr)); + process_copy_output(&processes[i], stderr); } break; } @@ -464,3 +402,21 @@ void print_tests(FILE* stream) { } } } + + +void print_lines(const char* buffer, size_t size, FILE* stream) { + const char* start; + const char* end; + + start = buffer; + while ((end = memchr(start, '\n', &buffer[size] - start))) { + fprintf(stream, "# %.*s\n", (int) (end - start), start); + fflush(stream); + start = end + 1; + } + + if (start < &buffer[size]) { + fprintf(stream, "# %s\n", start); + fflush(stream); + } +} diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 78f3c880a981fc..555f2f8eb72075 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -126,6 +126,8 @@ int run_test_part(const char* test, const char* part); */ void print_tests(FILE* stream); +/* Print lines in |buffer| as TAP diagnostics to |stream|. */ +void print_lines(const char* buffer, size_t size, FILE* stream); /* * Stuff that should be implemented by test-runner-.h @@ -148,8 +150,8 @@ int process_wait(process_info_t *vec, int n, int timeout); /* Returns the number of bytes in the stdio output buffer for process `p`. */ long int process_output_size(process_info_t *p); -/* Copy the contents of the stdio output buffer to `fd`. */ -int process_copy_output(process_info_t *p, int fd); +/* Copy the contents of the stdio output buffer to `stream`. */ +int process_copy_output(process_info_t* p, FILE* stream); /* Copy the last line of the stdio output buffer to `buffer` */ int process_read_last_line(process_info_t *p, @@ -172,7 +174,4 @@ void process_cleanup(process_info_t *p); /* Move the console cursor one line up and back to the first column. */ void rewind_cursor(void); -/* trigger output as tap */ -extern int tap_output; - #endif /* RUNNER_H_ */ diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index 96cc6377cb1fa6..65a1132e49865d 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -136,7 +136,6 @@ const char* fmt(double d); /* Reserved test exit codes. */ enum test_status { TEST_OK = 0, - TEST_TODO, TEST_SKIP }; @@ -145,13 +144,6 @@ enum test_status { return TEST_OK; \ } while (0) -#define RETURN_TODO(explanation) \ - do { \ - fprintf(stderr, "%s\n", explanation); \ - fflush(stderr); \ - return TEST_TODO; \ - } while (0) - #define RETURN_SKIP(explanation) \ do { \ fprintf(stderr, "%s\n", explanation); \ diff --git a/deps/uv/test/test-embed.c b/deps/uv/test/test-embed.c index 06137456f8b8ff..c6ddceb149d9c1 100644 --- a/deps/uv/test/test-embed.c +++ b/deps/uv/test/test-embed.c @@ -29,6 +29,7 @@ # if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_KQUEUE 1 diff --git a/deps/uv/test/test-emfile.c b/deps/uv/test/test-emfile.c index 5f4dd9efdf7e77..8e44ac5c77877d 100644 --- a/deps/uv/test/test-emfile.c +++ b/deps/uv/test/test-emfile.c @@ -38,12 +38,12 @@ static uv_tcp_t client_handle; TEST_IMPL(emfile) { -#ifdef _AIX +#if defined(_AIX) || defined(__MVS__) /* 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"); + RETURN_SKIP("uv__emfile_trick does not work on this OS"); #endif struct sockaddr_in addr; struct rlimit limits; diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 353c43b0de4e07..df8dc4c2f700fd 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -29,12 +29,19 @@ # if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_KQUEUE 1 # endif #endif +#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */ +# define CREATE_TIMEOUT 100 +#else +# define CREATE_TIMEOUT 1 +#endif + static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; @@ -53,6 +60,14 @@ static char fs_event_filename[PATH_MAX]; static char fs_event_filename[1024]; #endif /* defined(PATH_MAX) */ static int timer_cb_touch_called; +static int timer_cb_exact_called; + +static void fs_event_fail(uv_fs_event_t* handle, + const char* filename, + int events, + int status) { + ASSERT(0 && "should never be called"); +} static void create_dir(const char* name) { int r; @@ -143,7 +158,10 @@ static void fs_event_create_files(uv_timer_t* handle) { if (++fs_event_created < fs_event_file_count) { /* Create another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0)); + ASSERT(0 == uv_timer_start(&timer, + fs_event_create_files, + CREATE_TIMEOUT, + 0)); } } @@ -254,6 +272,14 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, const char* filename, int events, int status) { +#ifdef _WIN32 + /* Each file created (or deleted) will cause this callback to be called twice + * under Windows: once with the name of the file, and second time with the + * name of the directory. We will ignore the callback for the directory + * itself. */ + if (filename && strcmp(filename, file_prefix_in_subdir) == 0) + return; +#endif fs_event_cb_called++; ASSERT(handle == &fs_event); ASSERT(status == 0); @@ -345,6 +371,21 @@ static void timer_cb_touch(uv_timer_t* timer) { timer_cb_touch_called++; } +static void timer_cb_exact(uv_timer_t* handle) { + int r; + + if (timer_cb_exact_called == 0) { + touch_file("watch_dir/file.js"); + } else { + uv_close((uv_handle_t*)handle, NULL); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, NULL); + } + + ++timer_cb_exact_called; +} + static void timer_cb_watch_twice(uv_timer_t* handle) { uv_fs_event_t* handles = handle->data; uv_close((uv_handle_t*) (handles + 0), NULL); @@ -353,6 +394,10 @@ static void timer_cb_watch_twice(uv_timer_t* handle) { } TEST_IMPL(fs_event_watch_dir) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -432,6 +477,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) { TEST_IMPL(fs_event_watch_file) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -467,7 +516,54 @@ TEST_IMPL(fs_event_watch_file) { return 0; } +TEST_IMPL(fs_event_watch_file_exact_path) { + /* + This test watches a file named "file.jsx" and modifies a file named + "file.js". The test verifies that no events occur for file.jsx. + */ + +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + create_dir("watch_dir"); + create_file("watch_dir/file.js"); + create_file("watch_dir/file.jsx"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_exact, 100, 100); + ASSERT(r == 0); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_cb_exact_called == 2); + + /* Cleanup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_event_watch_file_twice) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif const char path[] = "test/fixtures/empty_file"; uv_fs_event_t watchers[2]; uv_timer_t timer; @@ -489,6 +585,9 @@ TEST_IMPL(fs_event_watch_file_twice) { } TEST_IMPL(fs_event_watch_file_current_dir) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_timer_t timer; uv_loop_t* loop; int r; @@ -559,6 +658,10 @@ TEST_IMPL(fs_event_watch_file_root_dir) { #endif TEST_IMPL(fs_event_no_callback_after_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -593,6 +696,10 @@ TEST_IMPL(fs_event_no_callback_after_close) { } TEST_IMPL(fs_event_no_callback_on_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -626,12 +733,6 @@ TEST_IMPL(fs_event_no_callback_on_close) { } -static void fs_event_fail(uv_fs_event_t* handle, const char* filename, - int events, int status) { - ASSERT(0 && "should never be called"); -} - - static void timer_cb(uv_timer_t* handle) { int r; @@ -646,6 +747,9 @@ static void timer_cb(uv_timer_t* handle) { TEST_IMPL(fs_event_immediate_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_timer_t timer; uv_loop_t* loop; int r; @@ -668,6 +772,9 @@ TEST_IMPL(fs_event_immediate_close) { TEST_IMPL(fs_event_close_with_pending_event) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; int r; @@ -698,20 +805,6 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } -#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 and AIX.\n"); - return 0; -} - -#else /* !HAVE_KQUEUE || !_AIX */ - static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { ASSERT(status == 0); @@ -724,52 +817,49 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, } } - TEST_IMPL(fs_event_close_in_callback) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; int r; loop = uv_default_loop(); + fs_event_unlink_files(NULL); create_dir("watch_dir"); - create_file("watch_dir/file1"); - create_file("watch_dir/file2"); - create_file("watch_dir/file3"); - create_file("watch_dir/file4"); - create_file("watch_dir/file5"); r = uv_fs_event_init(loop, &fs_event); ASSERT(r == 0); r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0); ASSERT(r == 0); - /* Generate a couple of fs events. */ - touch_file("watch_dir/file1"); - touch_file("watch_dir/file2"); - touch_file("watch_dir/file3"); - touch_file("watch_dir/file4"); - touch_file("watch_dir/file5"); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, fs_event_create_files, 100, 0); + ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + uv_close((uv_handle_t*)&timer, close_cb); + + uv_run(loop, UV_RUN_ONCE); + + ASSERT(close_cb_called == 2); ASSERT(fs_event_cb_called == 3); /* Clean up */ - remove("watch_dir/file1"); - remove("watch_dir/file2"); - remove("watch_dir/file3"); - remove("watch_dir/file4"); - remove("watch_dir/file5"); + fs_event_unlink_files(NULL); remove("watch_dir/"); MAKE_VALGRIND_HAPPY(); return 0; } -#endif /* HAVE_KQUEUE || _AIX */ - TEST_IMPL(fs_event_start_and_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; uv_fs_event_t fs_event1; uv_fs_event_t fs_event2; @@ -802,6 +892,9 @@ TEST_IMPL(fs_event_start_and_close) { } TEST_IMPL(fs_event_getpath) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop = uv_default_loop(); int r; char buf[1024]; diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 1cc1a7c064107f..74abaf349f9b8f 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -29,7 +29,7 @@ /* FIXME we shouldn't need to branch in this file */ #if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) #include /* unlink, rmdir, etc. */ #else # include @@ -662,8 +662,8 @@ static void check_utime(const char* path, double atime, double mtime) { ASSERT(req.result == 0); s = &req.statbuf; - ASSERT(s->st_atim.tv_sec == atime); - ASSERT(s->st_mtim.tv_sec == mtime); + ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime); + ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime); uv_fs_req_cleanup(&req); } @@ -1134,7 +1134,15 @@ TEST_IMPL(fs_fstat) { ASSERT(s->st_mtim.tv_nsec == 0); ASSERT(s->st_ctim.tv_sec == t.st_ctime); ASSERT(s->st_ctim.tv_nsec == 0); +#elif defined(__ANDROID__) + ASSERT(s->st_atim.tv_sec == t.st_atime); + ASSERT(s->st_atim.tv_nsec == t.st_atimensec); + ASSERT(s->st_mtim.tv_sec == t.st_mtime); + ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec); + ASSERT(s->st_ctim.tv_sec == t.st_ctime); + ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec); #elif defined(__sun) || \ + defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ @@ -1968,6 +1976,15 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); ASSERT(r == 0); ASSERT(req.result == 0); @@ -2055,6 +2072,15 @@ TEST_IMPL(fs_futime) { atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c index c445483fa089e3..133ae901493728 100644 --- a/deps/uv/test/test-ipc-send-recv.c +++ b/deps/uv/test/test-ipc-send-recv.c @@ -68,8 +68,8 @@ static struct echo_ctx ctx2; /* Used in write2_cb to decide if we need to cleanup or not */ static int is_child_process; static int is_in_process; -static int read_cb_called; -static int recv_cb_called; +static int read_cb_count; +static int recv_cb_count; static int write2_cb_called; @@ -91,43 +91,46 @@ static void recv_cb(uv_stream_t* handle, int r; union handles* recv; - if (++recv_cb_called == 1) { - recv = &ctx.recv; - } else { - recv = &ctx.recv2; - } - pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx.channel); - /* Depending on the OS, the final recv_cb can be called after the child - * process has terminated which can result in nread being UV_EOF instead of - * the number of bytes read. Since the other end of the pipe has closed this - * UV_EOF is an acceptable value. */ - if (nread == UV_EOF) { - /* UV_EOF is only acceptable for the final recv_cb call */ - ASSERT(recv_cb_called == 2); - } else { - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &recv->tcp); - else - abort(); - ASSERT(r == 0); - - r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); - } + do { + if (++recv_cb_count == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } + + /* Depending on the OS, the final recv_cb can be called after + * the child process has terminated which can result in nread + * being UV_EOF instead of the number of bytes read. Since + * the other end of the pipe has closed this UV_EOF is an + * acceptable value. */ + if (nread == UV_EOF) { + /* UV_EOF is only acceptable for the final recv_cb call */ + ASSERT(recv_cb_count == 2); + } else { + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == ctx.expected_type); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + } + } while (uv_pipe_pending_count(pipe) > 0); /* Close after two writes received */ - if (recv_cb_called == 2) { + if (recv_cb_count == 2) { uv_close((uv_handle_t*)&ctx.channel, NULL); } } @@ -186,7 +189,7 @@ static int run_test(int inprocess) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - ASSERT(recv_cb_called == 2); + ASSERT(recv_cb_count == 2); if (inprocess) { r = uv_thread_join(&tid); @@ -293,41 +296,43 @@ static void read_cb(uv_stream_t* handle, return; } - if (++read_cb_called == 2) { - recv = &ctx2.recv; - write_req = &ctx2.write_req; - } else { - recv = &ctx2.recv2; - write_req = &ctx2.write_req2; - } - pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx2.channel); - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); - else - abort(); - ASSERT(r == 0); + do { + if (++read_cb_count == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } + + ASSERT(pipe == &ctx2.channel); + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); - r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - wrbuf = uv_buf_init(".", 1); - r = uv_write2(write_req, - (uv_stream_t*)&ctx2.channel, - &wrbuf, - 1, - &recv->stream, - write2_cb); - ASSERT(r == 0); + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + + wrbuf = uv_buf_init(".", 1); + r = uv_write2(write_req, + (uv_stream_t*)&ctx2.channel, + &wrbuf, + 1, + &recv->stream, + write2_cb); + ASSERT(r == 0); + } while (uv_pipe_pending_count(pipe) > 0); } static void send_recv_start() { diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index c93f081992a481..2f19b3279098ac 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -19,6 +19,8 @@ * IN THE SOFTWARE. */ +#include "uv.h" + TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (close_order) @@ -59,6 +61,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess) TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) +TEST_DECLARE (tcp_alloc_cb_fail) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) TEST_DECLARE (pipe_ping_pong) @@ -104,6 +107,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) TEST_DECLARE (tcp_bind6_error_inval) TEST_DECLARE (tcp_bind6_localhost_ok) +TEST_DECLARE (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_create_early) @@ -273,6 +277,7 @@ TEST_DECLARE (fs_read_file_eof) TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_dir_recursive) TEST_DECLARE (fs_event_watch_file) +TEST_DECLARE (fs_event_watch_file_exact_path) TEST_DECLARE (fs_event_watch_file_twice) TEST_DECLARE (fs_event_watch_file_current_dir) #ifdef _WIN32 @@ -314,13 +319,19 @@ TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) TEST_DECLARE (poll_bad_fdtype) +#ifdef __linux__ +TEST_DECLARE (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE +TEST_DECLARE (poll_nested_kqueue) +#endif TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) -#ifdef _WIN32 TEST_DECLARE (poll_close_doesnt_corrupt_stack) TEST_DECLARE (poll_closesocket) +#ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) #if !defined(USING_UV_SHARED) TEST_DECLARE (argument_escaping) @@ -407,6 +418,8 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) + TEST_ENTRY (tcp_alloc_cb_fail) + TEST_ENTRY (tcp_ping_pong) TEST_HELPER (tcp_ping_pong, tcp4_echo_server) @@ -474,6 +487,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind6_error_inval) TEST_ENTRY (tcp_bind6_localhost_ok) + TEST_ENTRY (udp_alloc_cb_fail) TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_create_early) @@ -624,6 +638,12 @@ TASK_LIST_START TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) TEST_ENTRY (poll_bad_fdtype) +#ifdef __linux__ + TEST_ENTRY (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE + TEST_ENTRY (poll_nested_kqueue) +#endif TEST_ENTRY (socket_buffer_size) @@ -655,9 +675,9 @@ TASK_LIST_START TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) -#ifdef _WIN32 TEST_ENTRY (poll_close_doesnt_corrupt_stack) TEST_ENTRY (poll_closesocket) +#ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) #if !defined(USING_UV_SHARED) TEST_ENTRY (argument_escaping) @@ -710,6 +730,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_dir) TEST_ENTRY (fs_event_watch_dir_recursive) TEST_ENTRY (fs_event_watch_file) + TEST_ENTRY (fs_event_watch_file_exact_path) TEST_ENTRY (fs_event_watch_file_twice) TEST_ENTRY (fs_event_watch_file_current_dir) #ifdef _WIN32 diff --git a/deps/uv/test/test-loop-close.c b/deps/uv/test/test-loop-close.c index 5aec234ed039bc..971c9d725bec02 100644 --- a/deps/uv/test/test-loop-close.c +++ b/deps/uv/test/test-loop-close.c @@ -34,7 +34,9 @@ TEST_IMPL(loop_close) { int r; uv_loop_t loop; + loop.data = &loop; ASSERT(0 == uv_loop_init(&loop)); + ASSERT(loop.data == (void*) &loop); uv_timer_init(&loop, &timer_handle); uv_timer_start(&timer_handle, timer_cb, 100, 100); @@ -47,7 +49,9 @@ TEST_IMPL(loop_close) { r = uv_run(&loop, UV_RUN_DEFAULT); ASSERT(r == 0); + ASSERT(loop.data == (void*) &loop); ASSERT(0 == uv_loop_close(&loop)); + ASSERT(loop.data == (void*) &loop); return 0; } diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 58041c02668271..4b4ceccc45ced5 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -231,7 +231,7 @@ TEST_IMPL(pipe_getsockname_blocking) { len1 = sizeof buf1; r = uv_pipe_getsockname(&pipe_client, buf1, &len1); ASSERT(r == 0); - ASSERT(buf1[len1 - 1] != 0); + ASSERT(len1 == 0); /* It's an annonymous pipe. */ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL); ASSERT(r == 0); @@ -240,7 +240,7 @@ TEST_IMPL(pipe_getsockname_blocking) { len2 = sizeof buf2; r = uv_pipe_getsockname(&pipe_client, buf2, &len2); ASSERT(r == 0); - ASSERT(buf2[len2 - 1] != 0); + ASSERT(len2 == 0); /* It's an annonymous pipe. */ r = uv_read_stop((uv_stream_t*)&pipe_client); ASSERT(r == 0); @@ -255,7 +255,6 @@ TEST_IMPL(pipe_getsockname_blocking) { ASSERT(pipe_close_cb_called == 1); - _close(readfd); CloseHandle(writeh); #endif diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index bd61454fa7c742..b8955080104756 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -61,8 +61,6 @@ 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, diff --git a/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c b/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c index fc2cc004f16ae7..1dfc80e352b5cc 100644 --- a/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c +++ b/deps/uv/test/test-poll-close-doesnt-corrupt-stack.c @@ -19,8 +19,6 @@ * IN THE SOFTWARE. */ -#ifdef _WIN32 - #include #include @@ -37,6 +35,7 @@ uv_os_sock_t sock; uv_poll_t handle; +#ifdef _WIN32 static int close_cb_called = 0; @@ -69,9 +68,13 @@ static void NO_INLINE close_socket_and_verify_stack() { for (i = 0; i < ARRAY_SIZE(data); i++) ASSERT(data[i] == MARKER); } +#endif TEST_IMPL(poll_close_doesnt_corrupt_stack) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else struct WSAData wsa_data; int r; unsigned long on; @@ -109,6 +112,5 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } - -#endif /* _WIN32 */ diff --git a/deps/uv/test/test-poll-closesocket.c b/deps/uv/test/test-poll-closesocket.c index 4db74a01f63989..ecaa9e54a223c0 100644 --- a/deps/uv/test/test-poll-closesocket.c +++ b/deps/uv/test/test-poll-closesocket.c @@ -19,7 +19,6 @@ * IN THE SOFTWARE. */ -#ifdef _WIN32 #include @@ -29,6 +28,7 @@ uv_os_sock_t sock; uv_poll_t handle; +#ifdef _WIN32 static int close_cb_called = 0; @@ -50,9 +50,13 @@ static void poll_cb(uv_poll_t* h, int status, int events) { uv_close((uv_handle_t*) &handle, close_cb); } +#endif TEST_IMPL(poll_closesocket) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else struct WSAData wsa_data; int r; unsigned long on; @@ -85,5 +89,5 @@ TEST_IMPL(poll_closesocket) { MAKE_VALGRIND_HAPPY(); return 0; -} #endif +} diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index f3cfe7977753c4..6c1f98b7eff552 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -31,6 +31,16 @@ #include "uv.h" #include "task.h" +#ifdef __linux__ +# include +#endif + +#ifdef UV_HAVE_KQUEUE +# include +# include +# include +#endif + #define NUM_CLIENTS 5 #define TRANSFER_BYTES (1 << 16) @@ -72,9 +82,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) static int disconnects = 0; -#endif /* !_AIX */ +#endif /* !_AIX && !__MVS__ */ static int got_eagain(void) { #ifdef _WIN32 @@ -378,7 +388,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -386,9 +396,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 */ +#else /* _AIX && __MVS__ */ if (context->got_fin && context->sent_fin) { -#endif /* !_AIx */ +#endif /* !_AIX && !__MVS__ */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -556,7 +566,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) ASSERT(disconnects == NUM_CLIENTS * 2); #endif MAKE_VALGRIND_HAPPY(); @@ -584,7 +594,7 @@ TEST_IMPL(poll_unidirectional) { */ TEST_IMPL(poll_bad_fdtype) { #if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ - !defined(_AIX) + !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) uv_poll_t poll_handle; int fd; @@ -601,3 +611,47 @@ TEST_IMPL(poll_bad_fdtype) { MAKE_VALGRIND_HAPPY(); return 0; } + + +#ifdef __linux__ +TEST_IMPL(poll_nested_epoll) { + uv_poll_t poll_handle; + int fd; + + fd = epoll_create(1); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* __linux__ */ + + +#ifdef UV_HAVE_KQUEUE +TEST_IMPL(poll_nested_kqueue) { + uv_poll_t poll_handle; + int fd; + + fd = kqueue(); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* UV_HAVE_KQUEUE */ diff --git a/deps/uv/test/test-process-title.c b/deps/uv/test/test-process-title.c index 42ade44160416f..21ab0ed4fde8c8 100644 --- a/deps/uv/test/test-process-title.c +++ b/deps/uv/test/test-process-title.c @@ -41,13 +41,35 @@ static void set_title(const char* title) { } +static void uv_get_process_title_edge_cases() { + char buffer[512]; + int r; + + /* Test a NULL buffer */ + r = uv_get_process_title(NULL, 100); + ASSERT(r == UV_EINVAL); + + /* Test size of zero */ + r = uv_get_process_title(buffer, 0); + ASSERT(r == UV_EINVAL); + + /* Test for insufficient buffer size */ + r = uv_get_process_title(buffer, 1); + ASSERT(r == UV_ENOBUFS); +} + + TEST_IMPL(process_title) { -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"); set_title("new title"); + + /* Check uv_get_process_title() edge cases */ + uv_get_process_title_edge_cases(); + return 0; #endif } diff --git a/deps/uv/test/test-ref.c b/deps/uv/test/test-ref.c index ddaa17380830e9..39f4b0fc739174 100644 --- a/deps/uv/test/test-ref.c +++ b/deps/uv/test/test-ref.c @@ -194,6 +194,9 @@ TEST_IMPL(timer_ref2) { TEST_IMPL(fs_event_ref) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_fs_event_t h; uv_fs_event_init(uv_default_loop(), &h); uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0); diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index eba54ae7054976..53a036969b6252 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -46,7 +46,7 @@ static uv_timer_t timer; static uv_process_options_t options; static char exepath[1024]; static size_t exepath_size = 1024; -static char* args[3]; +static char* args[5]; static int no_term_signal; static int timer_counter; @@ -147,6 +147,8 @@ static void init_process_options(char* test, uv_exit_cb exit_cb) { args[0] = exepath; args[1] = test; args[2] = NULL; + args[3] = NULL; + args[4] = NULL; options.file = exepath; options.args = args; options.exit_cb = exit_cb; @@ -1226,21 +1228,26 @@ TEST_IMPL(spawn_with_an_odd_path) { TEST_IMPL(spawn_setuid_setgid) { int r; struct passwd* pw; + char uidstr[10]; + char gidstr[10]; /* if not root, then this will fail. */ uv_uid_t uid = getuid(); if (uid != 0) { - fprintf(stderr, "spawn_setuid_setgid skipped: not root\n"); - return 0; + RETURN_SKIP("It should be run as root user"); } - init_process_options("spawn_helper1", exit_cb); + init_process_options("spawn_helper_setuid_setgid", exit_cb); /* become the "nobody" user. */ pw = getpwnam("nobody"); ASSERT(pw != NULL); options.uid = pw->pw_uid; options.gid = pw->pw_gid; + snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); + snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); + options.args[2] = uidstr; + options.args[3] = gidstr; options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID; r = uv_spawn(uv_default_loop(), &process, &options); @@ -1431,6 +1438,9 @@ TEST_IMPL(spawn_fs_open) { #ifndef _WIN32 TEST_IMPL(closed_fd_events) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_stdio_container_t stdio[3]; uv_pipe_t pipe_handle; int fd[2]; @@ -1500,6 +1510,8 @@ TEST_IMPL(spawn_reads_child_path) { */ #if defined(__APPLE__) static const char dyld_path_var[] = "DYLD_LIBRARY_PATH"; +#elif defined __MVS__ + static const char dyld_path_var[] = "LIBPATH"; #else static const char dyld_path_var[] = "LD_LIBRARY_PATH"; #endif diff --git a/deps/uv/test/test-tcp-alloc-cb-fail.c b/deps/uv/test/test-tcp-alloc-cb-fail.c new file mode 100644 index 00000000000000..61ca667acbcab3 --- /dev/null +++ b/deps/uv/test/test-tcp-alloc-cb-fail.c @@ -0,0 +1,123 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "uv.h" +#include "task.h" + +static uv_tcp_t server; +static uv_tcp_t client; +static uv_tcp_t incoming; +static int connect_cb_called; +static int close_cb_called; +static int connection_cb_called; +static uv_write_t write_req; + +static char hello[] = "HELLO!"; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); +} + +static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + /* Do nothing, read_cb should be called with UV_ENOBUFS. */ +} + +static void conn_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == UV_ENOBUFS); + ASSERT(buf->base == NULL); + ASSERT(buf->len == 0); + + uv_close((uv_handle_t*) &incoming, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &server, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t buf; + + ASSERT(status == 0); + connect_cb_called++; + + buf = uv_buf_init(hello, sizeof(hello)); + r = uv_write(&write_req, req->handle, &buf, 1, write_cb); + ASSERT(r == 0); +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT(status == 0); + + ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); + ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, + conn_alloc_cb, + conn_read_cb)); + + connection_cb_called++; +} + + +static void start_server(void) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); +} + + +TEST_IMPL(tcp_alloc_cb_fail) { + uv_connect_t connect_req; + struct sockaddr_in addr; + + start_server(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(connection_cb_called == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tcp-close-accept.c b/deps/uv/test/test-tcp-close-accept.c index 5517aaf99e6649..e4878398c8b98e 100644 --- a/deps/uv/test/test-tcp-close-accept.c +++ b/deps/uv/test/test-tcp-close-accept.c @@ -40,6 +40,7 @@ static unsigned int got_connections; static unsigned int close_cb_called; static unsigned int write_cb_called; static unsigned int read_cb_called; +static unsigned int pending_incoming; static void close_cb(uv_handle_t* handle) { close_cb_called++; @@ -58,8 +59,11 @@ static void connect_cb(uv_connect_t* req, int status) { if (req == &tcp_check_req) { ASSERT(status != 0); - /* Close check and incoming[0], time to finish test */ - uv_close((uv_handle_t*) &tcp_incoming[0], close_cb); + /* + * Time to finish the test: close both the check and pending incoming + * connections + */ + uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], close_cb); uv_close((uv_handle_t*) &tcp_check, close_cb); return; } @@ -84,8 +88,8 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { uv_loop_t* loop; unsigned int i; - /* Only first stream should receive read events */ - ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]); + pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; + ASSERT(pending_incoming < got_connections); ASSERT(0 == uv_read_stop(stream)); ASSERT(1 == nread); @@ -93,8 +97,13 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { read_cb_called++; /* Close all active incomings, except current one */ - for (i = 1; i < got_connections; i++) - uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + for (i = 0; i < got_connections; i++) { + if (i != pending_incoming) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + } + + /* Close server, so no one will connect to it */ + uv_close((uv_handle_t*) &tcp_server, close_cb); /* Create new fd that should be one of the closed incomings */ ASSERT(0 == uv_tcp_init(loop, &tcp_check)); @@ -103,9 +112,6 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { (const struct sockaddr*) &addr, connect_cb)); ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); - - /* Close server, so no one will connect to it */ - uv_close((uv_handle_t*) &tcp_server, close_cb); } static void connection_cb(uv_stream_t* server, int status) { diff --git a/deps/uv/test/test-tcp-close-while-connecting.c b/deps/uv/test/test-tcp-close-while-connecting.c index 60df7a574409aa..90a31f31941047 100644 --- a/deps/uv/test/test-tcp-close-while-connecting.c +++ b/deps/uv/test/test-tcp-close-while-connecting.c @@ -37,7 +37,7 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == UV_ECANCELED); + ASSERT(status == UV_ECANCELED || status == 0); uv_timer_stop(&timer2_handle); connect_cb_called++; } diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c index 8a98ab83667934..d50289c3c26fe1 100644 --- a/deps/uv/test/test-tcp-write-queue-order.c +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -46,13 +46,13 @@ static void close_cb(uv_handle_t* handle) { close_cb_called++; } -void timer_cb(uv_timer_t* handle) { +static void timer_cb(uv_timer_t* handle) { uv_close((uv_handle_t*) &client, close_cb); uv_close((uv_handle_t*) &server, close_cb); uv_close((uv_handle_t*) &incoming, close_cb); } -void write_cb(uv_write_t* req, int status) { +static void write_cb(uv_write_t* req, int status) { if (status == 0) write_callbacks++; else if (status == UV_ECANCELED) diff --git a/deps/uv/test/test-tcp-writealot.c b/deps/uv/test/test-tcp-writealot.c index 6cfe2ebb18d41a..7206fdc2f60eb5 100644 --- a/deps/uv/test/test-tcp-writealot.c +++ b/deps/uv/test/test-tcp-writealot.c @@ -26,7 +26,11 @@ #define WRITES 3 +#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ +#define CHUNKS_PER_WRITE 2048 +#else #define CHUNKS_PER_WRITE 4096 +#endif #define CHUNK_SIZE 10024 /* 10 kb */ #define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE) diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index 55cc016752d31b..d03f07a4418e49 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -28,7 +28,7 @@ #else /* Unix */ # include # include -# if defined(__linux__) +# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) # include # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include @@ -260,16 +260,24 @@ TEST_IMPL(tty_file) { } TEST_IMPL(tty_pty) { -# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) - int master_fd, slave_fd; +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + (defined(__linux__) && !defined(__ANDROID__)) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) + int master_fd, slave_fd, r; 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)); + r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); + if (r != 0) + RETURN_SKIP("No pty available, skipping."); + 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, diff --git a/deps/uv/test/test-udp-alloc-cb-fail.c b/deps/uv/test/test-udp-alloc-cb-fail.c new file mode 100644 index 00000000000000..05b871e921c094 --- /dev/null +++ b/deps/uv/test/test-udp-alloc-cb-fail.c @@ -0,0 +1,197 @@ +/* Copyright libuv project and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int cl_send_cb_called; +static int cl_recv_cb_called; + +static int sv_send_cb_called; +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void sv_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void cl_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* Do nothing, recv_cb should be called with UV_ENOBUFS. */ +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(1 == uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + ASSERT(flags == 0); + ASSERT(nread == UV_ENOBUFS); + + cl_recv_cb_called++; + + uv_close((uv_handle_t*) handle, close_cb); +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + int r; + + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb); + ASSERT(r == 0); + + cl_send_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + uv_close((uv_handle_t*) req->handle, close_cb); + free(req); + + sv_send_cb_called++; +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + uv_udp_send_t* req; + uv_buf_t sndbuf; + int r; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards sv_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(!memcmp("PING", rcvbuf->base, nread)); + + r = uv_udp_recv_stop(handle); + ASSERT(r == 0); + + req = malloc(sizeof *req); + ASSERT(req != NULL); + + sndbuf = uv_buf_init("PONG", 4); + r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb); + ASSERT(r == 0); + + sv_recv_cb_called++; +} + + +TEST_IMPL(udp_alloc_cb_fail) { + struct sockaddr_in addr; + uv_udp_send_t req; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + buf = uv_buf_init("PING", 4); + r = uv_udp_send(&req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + cl_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(cl_send_cb_called == 0); + ASSERT(cl_recv_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + ASSERT(sv_recv_cb_called == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(cl_send_cb_called == 1); + ASSERT(cl_recv_cb_called == 1); + ASSERT(sv_send_cb_called == 1); + ASSERT(sv_recv_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 1b0db78b8efcea..a65f09e0c6d765 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -26,7 +26,7 @@ #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #endif @@ -47,7 +47,7 @@ static int send_cb_called; static int recv_cb_called; static int close_cb_called; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int can_ipv6_ipv4_dual() { int v6only; size_t size = sizeof(int); @@ -166,7 +166,7 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #endif diff --git a/deps/uv/test/test-udp-multicast-interface6.c b/deps/uv/test/test-udp-multicast-interface6.c index d3881e83bb1565..40b05536dc7430 100644 --- a/deps/uv/test/test-udp-multicast-interface6.c +++ b/deps/uv/test/test-udp-multicast-interface6.c @@ -72,7 +72,7 @@ TEST_IMPL(udp_multicast_interface6) { r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); ASSERT(r == 0); -#if defined(__APPLE__) || defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) r = uv_udp_set_multicast_interface(&server, "::1%lo0"); #else r = uv_udp_set_multicast_interface(&server, NULL); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index f635bdb9e14ee2..2eb9e920e7f2f5 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -119,7 +119,10 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* join the multicast channel */ -#if defined(__APPLE__) || defined(_AIX) +#if defined(__APPLE__) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__FreeBSD_kernel__) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); diff --git a/deps/uv/test/test-udp-options.c b/deps/uv/test/test-udp-options.c index 0da1786f506fc4..8f91367590388b 100644 --- a/deps/uv/test/test-udp-options.c +++ b/deps/uv/test/test-udp-options.c @@ -52,7 +52,14 @@ static int udp_options_test(const struct sockaddr* addr) { /* values 1-255 should work */ for (i = 1; i <= 255; i++) { r = uv_udp_set_ttl(&h, i); +#if defined(__MVS__) + if (addr->sa_family == AF_INET6) + ASSERT(r == 0); + else + ASSERT(r == UV_ENOTSUP); +#else ASSERT(r == 0); +#endif } for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) { @@ -113,7 +120,11 @@ TEST_IMPL(udp_no_autobind) { ASSERT(0 == uv_udp_init(loop, &h)); ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32)); ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1)); +#if defined(__MVS__) + ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); +#else ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); +#endif ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1)); ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0")); diff --git a/deps/uv/test/test-watcher-cross-stop.c b/deps/uv/test/test-watcher-cross-stop.c index 910ed0fb6134f5..6ff48d44c88178 100644 --- a/deps/uv/test/test-watcher-cross-stop.c +++ b/deps/uv/test/test-watcher-cross-stop.c @@ -59,6 +59,9 @@ static void close_cb(uv_handle_t* handle) { TEST_IMPL(watcher_cross_stop) { +#if defined(__MVS__) + RETURN_SKIP("zOS does not allow address or port reuse when using UDP sockets"); +#endif uv_loop_t* loop = uv_default_loop(); unsigned int i; struct sockaddr_in addr; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 2fdd59ac784300..b969a8cd5dad20 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -10,9 +10,25 @@ ['OS=="solaris"', { 'cflags': [ '-pthreads' ], }], - ['OS not in "solaris android"', { + ['OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], }], + ['OS in "zos"', { + 'defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_IPV6', + '_OPEN_MSGQ_EXT', + '_XOPEN_SOURCE_EXTENDED', + '_ALL_SOURCE', + '_LARGE_TIME_API', + '_OPEN_SYS_FILE_EXT', + '_AE_BIMODAL', + 'PATH_MAX=255' + ], + 'cflags': [ '-qxplink' ], + }] ], }], ], @@ -75,6 +91,7 @@ 'src/win/async.c', 'src/win/atomicops-inl.h', 'src/win/core.c', + 'src/win/detect-wakeup.c', 'src/win/dl.c', 'src/win/error.c', 'src/win/fs.c', @@ -118,15 +135,6 @@ ], }, }, { # Not Windows i.e. POSIX - 'cflags': [ - '-fvisibility=hidden', - '-g', - '--std=gnu89', - '-pedantic', - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - ], 'sources': [ 'include/uv-unix.h', 'include/uv-linux.h', @@ -162,16 +170,25 @@ ['OS=="solaris"', { 'ldflags': [ '-pthreads' ], }], - ['OS != "solaris" and OS != "android"', { + [ 'OS=="zos" and uv_library=="shared_library"', { + 'ldflags': [ '-Wl,DLL' ], + }], + ['OS != "solaris" and OS != "android" and OS != "zos"', { 'ldflags': [ '-pthread' ], }], ], }, 'conditions': [ ['uv_library=="shared_library"', { - 'cflags': [ '-fPIC' ], + 'conditions': [ + ['OS=="zos"', { + 'cflags': [ '-qexportall' ], + }, { + 'cflags': [ '-fPIC' ], + }], + ], }], - ['uv_library=="shared_library" and OS!="mac"', { + ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR # in include/uv-version.h @@ -182,6 +199,17 @@ [ 'OS in "linux mac ios android"', { 'sources': [ 'src/unix/proctitle.c' ], }], + [ 'OS != "zos"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ], + }], [ 'OS in "mac ios"', { 'sources': [ 'src/unix/darwin.c', @@ -194,7 +222,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac"', { + [ 'OS!="mac" and OS!="zos"', { # Enable on all platforms except OS X. The antique gcc/clang that # ships with Xcode emits waaaay too many false positives. 'cflags': [ '-Wstrict-aliasing' ], @@ -274,6 +302,13 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], + ['OS=="zos"', { + 'sources': [ + 'src/unix/pthread-fixes.c', + 'src/unix/pthread-barrier.c' + 'src/unix/os390.c' + ] + }], ] }, @@ -363,6 +398,7 @@ 'test/test-spawn.c', 'test/test-fs-poll.c', 'test/test-stdio-over-pipes.c', + 'test/test-tcp-alloc-cb-fail.c', 'test/test-tcp-bind-error.c', 'test/test-tcp-bind6-error.c', 'test/test-tcp-close.c', @@ -397,6 +433,7 @@ 'test/test-timer-from-check.c', 'test/test-timer.c', 'test/test-tty.c', + 'test/test-udp-alloc-cb-fail.c', 'test/test-udp-bind.c', 'test/test-udp-create-socket-early.c', 'test/test-udp-dgram-too-big.c', @@ -425,12 +462,20 @@ ], 'libraries': [ '-lws2_32' ] }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], 'sources': [ 'test/runner-unix.c', 'test/runner-unix.h', ], - }], + 'conditions': [ + [ 'OS != "zos"', { + 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], + 'xcode_settings': { + 'WARNING_CFLAGS': [ '-Wno-long-long' ] + } + }], + ]}, + ], [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { 'link_settings': { 'libraries': [ '-lutil' ], @@ -449,7 +494,12 @@ ], }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': { @@ -505,7 +555,12 @@ ] }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': {