diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5974d9d3..f2f3db5a 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -12,6 +12,8 @@ libuv is currently managed by the following individuals: - 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) diff --git a/Makefile.am b/Makefile.am index 93675f8d..135b33be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,7 +126,11 @@ 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 test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ @@ -277,10 +281,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=600 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 @@ -351,6 +374,28 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 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/README.md b/README.md index 29b94db1..284dfb47 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ 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). diff --git a/common.gypi b/common.gypi index 56bca294..44db701d 100644 --- a/common.gypi +++ b/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/configure.ac b/configure.ac index 06df36b5..cfed372e 100644 --- a/configure.ac +++ b/configure.ac @@ -24,10 +24,12 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O +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=gnu99]) -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/docs/src/fs.rst b/docs/src/fs.rst index aa38143f..273c5ade 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -288,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 `_. .. versionadded:: 1.8.0 diff --git a/docs/src/handle.rst b/docs/src/handle.rst index 6ba597a2..b0a123cf 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -24,12 +24,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`. diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 3b7f31aa..95237f49 100644 --- a/docs/src/misc.rst +++ b/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. @@ -205,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/docs/src/tcp.rst b/docs/src/tcp.rst index ca0c9b4a..a1a58245 100644 --- a/docs/src/tcp.rst +++ b/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/include/uv-errno.h b/include/uv-errno.h index 53f30296..f1371517 100644 --- a/include/uv-errno.h +++ b/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/include/uv-os390.h b/include/uv-os390.h new file mode 100644 index 00000000..b0b068f4 --- /dev/null +++ b/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/include/uv-unix.h b/include/uv-unix.h index a852c40e..bca27144 100644 --- a/include/uv-unix.h +++ b/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/libuv.pc.in b/libuv.pc.in index 2933ec22..9174fe15 100644 --- a/libuv.pc.in +++ b/libuv.pc.in @@ -1,5 +1,5 @@ prefix=@prefix@ -exec_prefix=@prefix@ +exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 84e47183..815e3552 100644 --- a/src/unix/atomic-ops.h +++ b/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/src/unix/core.c b/src/unix/core.c index 5be878dd..a91132cf 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -55,7 +55,9 @@ # endif #endif -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) # include # include # include @@ -71,6 +73,10 @@ # 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. */ @@ -912,6 +918,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; @@ -926,6 +933,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/src/unix/fs.c b/src/unix/fs.c index ac28869c..5d88a6fa 100644 --- a/src/unix/fs.c +++ b/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 @@ -193,6 +194,7 @@ skip: #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__sun) @@ -213,6 +215,14 @@ skip: ts[1].tv_sec = req->mtime; 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; @@ -336,22 +346,23 @@ done: } -#if defined(__OpenBSD__) -static int uv__fs_scandir_filter(uv__dirent_t* dent) { -#else static int uv__fs_scandir_filter(const uv__dirent_t* dent) { -#endif return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; } +static int uv__fs_scandir_sort(const uv__dirent_t** a, const uv__dirent_t** 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 +606,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 +622,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 +791,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) || \ diff --git a/src/unix/internal.h b/src/unix/internal.h index 710595b9..bb5dc007 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -128,7 +128,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,6 +153,7 @@ struct uv__stream_queued_fds_s { defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__linux__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl diff --git a/src/unix/os390.c b/src/unix/os390.c new file mode 100644 index 00000000..bcdbc4b6 --- /dev/null +++ b/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/src/unix/pipe.c b/src/unix/pipe.c index c8d163dc..b73994cb 100644 --- a/src/unix/pipe.c +++ b/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/src/unix/process.c b/src/unix/process.c index 8a010edc..45f5b452 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -40,7 +40,7 @@ extern char **environ; #endif -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) # include #endif diff --git a/src/unix/stream.c b/src/unix/stream.c index 5dc2f83f..d20d0bcb 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -604,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) { diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 46d8cd25..c423dcb1 100644 --- a/src/unix/tcp.c +++ b/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; @@ -272,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/src/unix/thread.c b/src/unix/thread.c index 236f5913..52989f7f 100644 --- a/src/unix/thread.c +++ b/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/src/unix/timer.c b/src/unix/timer.c index ca3ec3db..f46bdf4b 100644 --- a/src/unix/timer.c +++ b/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/src/unix/tty.c b/src/unix/tty.c index a56afe18..b2d37f4c 100644 --- a/src/unix/tty.c +++ b/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; @@ -168,7 +172,7 @@ skip: 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. diff --git a/src/unix/udp.c b/src/unix/udp.c index f5d7ed14..1cd49257 100644 --- a/src/unix/udp.c +++ b/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 @@ -332,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: @@ -508,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; } @@ -551,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; } @@ -669,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; @@ -701,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, @@ -729,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, @@ -752,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/src/win/tty.c b/src/win/tty.c index b8ba9ff6..15ad4fe7 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -52,6 +52,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); @@ -103,7 +106,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; @@ -116,9 +123,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(); } @@ -156,7 +172,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 */ @@ -168,7 +187,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 +313,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!SetConsoleMode(tty->handle, flags)) { - return uv_translate_sys_error(GetLastError()); - } - /* If currently reading, stop, and restart reading. */ if (tty->flags & UV_HANDLE_READING) { was_reading = 1; @@ -311,6 +326,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; @@ -340,9 +363,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; @@ -411,6 +434,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); @@ -440,11 +464,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, @@ -459,33 +485,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 (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--; + /* 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); + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } } + uv_sem_post(&uv_tty_output_lock); } - POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -673,14 +702,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; } @@ -1014,11 +1043,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; } @@ -1603,12 +1637,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]; @@ -2013,7 +2074,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; @@ -2166,3 +2227,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/src/win/util.c b/src/win/util.c index a5850a97..7c5033bd 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1006,6 +1006,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); @@ -1030,6 +1031,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 + @@ -1045,6 +1051,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/test/run-tests.c b/test/run-tests.c index b4be01f6..1e344f05 100644 --- a/test/run-tests.c +++ b/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/test/runner-unix.c b/test/runner-unix.c index 0edd671b..2ff18ce7 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -201,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); @@ -372,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/test/runner.c b/test/runner.c index 5e22c18f..4f54f85e 100644 --- a/test/runner.c +++ b/test/runner.c @@ -145,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; @@ -274,6 +274,8 @@ out: /* Show error and output from processes if the test failed. */ if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { + if (strlen(errmsg) > 0) + fprintf(stderr, "# %s\n", errmsg); fprintf(stderr, "# "); fflush(stderr); diff --git a/test/test-embed.c b/test/test-embed.c index 145819a6..6f3cd113 100644 --- a/test/test-embed.c +++ b/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/test/test-emfile.c b/test/test-emfile.c index 5f4dd9ef..8e44ac5c 100644 --- a/test/test-emfile.c +++ b/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/test/test-fs-event.c b/test/test-fs-event.c index 25eef07b..df8dc4c2 100644 --- a/test/test-fs-event.c +++ b/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; @@ -151,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)); } } @@ -262,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); @@ -376,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; @@ -455,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; @@ -495,6 +521,11 @@ 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; @@ -530,6 +561,9 @@ TEST_IMPL(fs_event_watch_file_exact_path) { } 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; @@ -551,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; @@ -621,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; @@ -655,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; @@ -702,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; @@ -724,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; @@ -754,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); @@ -780,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; @@ -858,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/test/test-fs.c b/test/test-fs.c index 8f9f578e..894741ae 100644 --- a/test/test-fs.c +++ b/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 @@ -1123,7 +1123,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) || \ diff --git a/test/test-poll.c b/test/test-poll.c index 33d0761a..6c1f98b7 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -82,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 @@ -388,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; @@ -396,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); @@ -566,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(); @@ -594,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; diff --git a/test/test-process-title.c b/test/test-process-title.c index 00f164a4..21ab0ed4 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -60,7 +60,7 @@ static void uv_get_process_title_edge_cases() { 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. */ diff --git a/test/test-ref.c b/test/test-ref.c index ddaa1738..39f4b0fc 100644 --- a/test/test-ref.c +++ b/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/test/test-spawn.c b/test/test-spawn.c index 31a2ea19..c2f54b4b 100644 --- a/test/test-spawn.c +++ b/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; @@ -1223,21 +1225,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); @@ -1428,6 +1435,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]; @@ -1497,6 +1507,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/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 60df7a57..90a31f31 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/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/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index 6cfe2ebb..7206fdc2 100644 --- a/test/test-tcp-writealot.c +++ b/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/test/test-tty.c b/test/test-tty.c index c93fe75a..d03f07a4 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,7 +28,7 @@ #else /* Unix */ # include # include -# if defined(__linux__) && !defined(__ANDROID__) +# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) # include # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include @@ -260,8 +260,13 @@ TEST_IMPL(tty_file) { } TEST_IMPL(tty_pty) { -# if defined(__linux__) && !defined(__ANDROID__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) +#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; diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 1b0db78b..a65f09e0 100644 --- a/test/test-udp-ipv6.c +++ b/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/test/test-udp-multicast-interface6.c b/test/test-udp-multicast-interface6.c index d3881e83..40b05536 100644 --- a/test/test-udp-multicast-interface6.c +++ b/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/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index f635bdb9..2eb9e920 100644 --- a/test/test-udp-multicast-join6.c +++ b/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/test/test-udp-options.c b/test/test-udp-options.c index 0da1786f..8f913675 100644 --- a/test/test-udp-options.c +++ b/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/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c index 910ed0fb..6ff48d44 100644 --- a/test/test-watcher-cross-stop.c +++ b/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/uv.gyp b/uv.gyp index 1f608188..754c7f24 100644 --- a/uv.gyp +++ b/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' ], + }] ], }], ], @@ -117,15 +133,6 @@ ], }, }, { # Not Windows i.e. POSIX - 'cflags': [ - '-fvisibility=hidden', - '-g', - '--std=gnu99', - '-pedantic', - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - ], 'sources': [ 'include/uv-unix.h', 'include/uv-linux.h', @@ -160,16 +167,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 @@ -180,6 +196,17 @@ [ 'OS in "linux mac ios android"', { 'sources': [ 'src/unix/proctitle.c' ], }], + [ 'OS != "zos"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu99', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ], + }], [ 'OS in "mac ios"', { 'sources': [ 'src/unix/darwin.c', @@ -192,7 +219,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' ], @@ -272,6 +299,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' + ] + }], ] }, @@ -427,12 +461,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' ], @@ -451,7 +493,12 @@ ], }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': { @@ -506,7 +553,12 @@ ] }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': {