From 6033f48b479f8b3bb4801cfbe0fa96e527a7c05b Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 25 Feb 2017 14:30:35 -0800 Subject: [PATCH] Update libuv --- common/net/daybreak_connection.cpp | 8 +- common/net/eqstream.cpp | 11 +- libs/libuv/.mailmap | 1 + libs/libuv/AUTHORS | 27 + libs/libuv/CMakeLists.txt | 1 + libs/libuv/CONTRIBUTING.md | 2 +- libs/libuv/ChangeLog | 308 ++++++- libs/libuv/LICENSE | 28 +- libs/libuv/MAINTAINERS.md | 7 +- libs/libuv/Makefile.am | 66 +- libs/libuv/Makefile.mingw | 1 + libs/libuv/README.md | 20 +- libs/libuv/SUPPORTED_PLATFORMS.md | 70 ++ libs/libuv/appveyor.yml | 2 +- libs/libuv/common.gypi | 7 +- libs/libuv/configure.ac | 11 +- libs/libuv/docs/src/conf.py | 6 +- libs/libuv/docs/src/errors.rst | 13 + libs/libuv/docs/src/fs.rst | 32 +- libs/libuv/docs/src/fs_event.rst | 14 + libs/libuv/docs/src/handle.rst | 56 +- libs/libuv/docs/src/misc.rst | 38 +- libs/libuv/docs/src/stream.rst | 14 +- libs/libuv/docs/src/tcp.rst | 2 +- libs/libuv/docs/src/timer.rst | 3 + libs/libuv/include/pthread-barrier.h | 4 + libs/libuv/include/uv-errno.h | 1 + libs/libuv/include/uv-os390.h | 30 + libs/libuv/include/uv-unix.h | 11 +- libs/libuv/include/uv-version.h | 4 +- libs/libuv/include/uv-win.h | 11 +- libs/libuv/include/uv.h | 2 + libs/libuv/libuv.pc.in | 2 +- libs/libuv/src/unix/aix.c | 111 ++- libs/libuv/src/unix/atomic-ops.h | 20 + libs/libuv/src/unix/core.c | 53 +- libs/libuv/src/unix/freebsd.c | 18 +- libs/libuv/src/unix/fs.c | 137 ++- libs/libuv/src/unix/internal.h | 28 +- libs/libuv/src/unix/linux-core.c | 22 +- libs/libuv/src/unix/loop.c | 4 + libs/libuv/src/unix/netbsd.c | 18 +- libs/libuv/src/unix/openbsd.c | 18 +- libs/libuv/src/unix/os390-syscalls.c | 334 +++++++ libs/libuv/src/unix/os390-syscalls.h | 69 ++ libs/libuv/src/unix/os390.c | 865 ++++++++++++++++++ libs/libuv/src/unix/pipe.c | 9 + libs/libuv/src/unix/poll.c | 11 +- libs/libuv/src/unix/process.c | 8 +- libs/libuv/src/unix/proctitle.c | 17 +- libs/libuv/src/unix/pthread-barrier.c | 3 +- libs/libuv/src/unix/signal.c | 8 +- libs/libuv/src/unix/stream.c | 46 +- libs/libuv/src/unix/sunos.c | 86 +- libs/libuv/src/unix/tcp.c | 39 +- libs/libuv/src/unix/thread.c | 118 ++- libs/libuv/src/unix/timer.c | 6 +- libs/libuv/src/unix/tty.c | 43 +- libs/libuv/src/unix/udp.c | 38 +- libs/libuv/src/uv-common.c | 17 +- libs/libuv/src/win/core.c | 119 ++- libs/libuv/src/win/detect-wakeup.c | 35 + libs/libuv/src/win/error.c | 1 + libs/libuv/src/win/fs-event.c | 28 +- libs/libuv/src/win/fs.c | 51 +- libs/libuv/src/win/getaddrinfo.c | 3 +- libs/libuv/src/win/internal.h | 10 + libs/libuv/src/win/pipe.c | 5 +- libs/libuv/src/win/process-stdio.c | 1 + libs/libuv/src/win/process.c | 2 +- libs/libuv/src/win/signal.c | 118 +-- libs/libuv/src/win/tcp.c | 7 +- libs/libuv/src/win/tty.c | 207 ++++- libs/libuv/src/win/udp.c | 6 +- libs/libuv/src/win/util.c | 27 +- libs/libuv/src/win/winapi.c | 13 + libs/libuv/src/win/winapi.h | 46 +- libs/libuv/test/run-tests.c | 13 + libs/libuv/test/runner-unix.c | 42 +- libs/libuv/test/runner-win.c | 33 +- libs/libuv/test/runner.c | 102 +-- libs/libuv/test/runner.h | 9 +- libs/libuv/test/task.h | 8 - libs/libuv/test/test-embed.c | 1 + libs/libuv/test/test-emfile.c | 4 +- libs/libuv/test/test-error.c | 23 + libs/libuv/test/test-fs-event.c | 175 +++- libs/libuv/test/test-fs.c | 97 +- libs/libuv/test/test-getaddrinfo.c | 7 + libs/libuv/test/test-ipc-send-recv.c | 129 +-- libs/libuv/test/test-list.h | 35 +- libs/libuv/test/test-loop-close.c | 4 + libs/libuv/test/test-pipe-getsockname.c | 5 +- libs/libuv/test/test-platform-output.c | 2 - .../test-poll-close-doesnt-corrupt-stack.c | 10 +- libs/libuv/test/test-poll-closesocket.c | 8 +- libs/libuv/test/test-poll.c | 68 +- libs/libuv/test/test-process-title.c | 24 +- libs/libuv/test/test-ref.c | 3 + libs/libuv/test/test-signal.c | 35 +- libs/libuv/test/test-spawn.c | 20 +- libs/libuv/test/test-tcp-alloc-cb-fail.c | 123 +++ libs/libuv/test/test-tcp-close-accept.c | 24 +- .../test/test-tcp-close-while-connecting.c | 13 +- libs/libuv/test/test-tcp-write-queue-order.c | 4 +- libs/libuv/test/test-tcp-writealot.c | 4 + libs/libuv/test/test-threadpool-cancel.c | 105 +-- libs/libuv/test/test-tty.c | 108 ++- libs/libuv/test/test-udp-alloc-cb-fail.c | 197 ++++ libs/libuv/test/test-udp-ipv6.c | 6 +- .../test/test-udp-multicast-interface6.c | 2 +- libs/libuv/test/test-udp-multicast-join6.c | 5 +- libs/libuv/test/test-udp-options.c | 11 + libs/libuv/test/test-watcher-cross-stop.c | 3 + libs/libuv/uv.gyp | 97 +- 115 files changed, 4304 insertions(+), 893 deletions(-) create mode 100644 libs/libuv/SUPPORTED_PLATFORMS.md create mode 100644 libs/libuv/include/uv-os390.h create mode 100644 libs/libuv/src/unix/os390-syscalls.c create mode 100644 libs/libuv/src/unix/os390-syscalls.h create mode 100644 libs/libuv/src/unix/os390.c create mode 100644 libs/libuv/src/win/detect-wakeup.c create mode 100644 libs/libuv/test/test-tcp-alloc-cb-fail.c create mode 100644 libs/libuv/test/test-udp-alloc-cb-fail.c diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index 26381fec6..a4b793a45 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -185,6 +185,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend() void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, uint64_t size) { + Log.OutF(Logs::Detail, Logs::Netcode, "Recv {0:#x} from {1}:{2}.", data[1], endpoint, port); if (m_options.simulated_in_packet_loss && m_options.simulated_in_packet_loss >= m_rand.Int(0, 100)) { Log.OutF(Logs::Detail, Logs::Netcode, "Dropped a packet from {0}:{1} because of simulated packet loss", endpoint, port); return; @@ -241,13 +242,15 @@ void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr, { DaybreakDisconnect header; header.zero = 0; - header.opcode = OP_SessionDisconnect; + header.opcode = OP_OutOfSession; header.connect_code = 0; DynamicPacket out; out.PutSerialize(0, header); uv_udp_send_t *send_req = new uv_udp_send_t; + memset(send_req, 0, sizeof(*send_req)); + sockaddr_in send_addr; uv_ip4_addr(addr.c_str(), port, &send_addr); uv_buf_t send_buffers[1]; @@ -1229,6 +1232,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) uv_udp_send_t *send_req = new uv_udp_send_t; memset(send_req, 0, sizeof(*send_req)); + sockaddr_in send_addr; uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr); uv_buf_t send_buffers[1]; @@ -1251,6 +1255,8 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) } uv_udp_send_t *send_req = new uv_udp_send_t; + memset(send_req, 0, sizeof(*send_req)); + sockaddr_in send_addr; uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr); uv_buf_t send_buffers[1]; diff --git a/common/net/eqstream.cpp b/common/net/eqstream.cpp index b323e6323..cc7816518 100644 --- a/common/net/eqstream.cpp +++ b/common/net/eqstream.cpp @@ -119,7 +119,16 @@ EQApplicationPacket *EQ::Net::EQStream::PopPacket() { } EmuOpcode emu_op = (*m_opcode_manager)->EQToEmu(opcode); - EQApplicationPacket *ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->m_options.opcode_size, p->Length() - m_owner->m_options.opcode_size); + auto sz = p->Length() - m_owner->m_options.opcode_size; + EQApplicationPacket *ret = nullptr; + + if (sz > 0) { + ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->m_options.opcode_size, sz); + } + else { + ret = new EQApplicationPacket(emu_op); + } + ret->SetProtocolOpcode(opcode); m_packet_queue.pop_front(); return ret; diff --git a/libs/libuv/.mailmap b/libs/libuv/.mailmap index 4966caf5f..8acf8fecd 100644 --- a/libs/libuv/.mailmap +++ b/libs/libuv/.mailmap @@ -1,6 +1,7 @@ Aaron Bieber Alan Gutierrez Andrius Bentkus +Bert Belder Bert Belder Bert Belder Brandon Philips diff --git a/libs/libuv/AUTHORS b/libs/libuv/AUTHORS index 7acee7c53..4719d2368 100644 --- a/libs/libuv/AUTHORS +++ b/libs/libuv/AUTHORS @@ -257,3 +257,30 @@ Michael Fero Robert Jefe Lindstaedt Myles Borins Tony Theodore +Jason Ginchereau +Nicolas Cavallari +Pierre-Marie de Rodat +Brian Maher +neevek +John Barboza +liuxiaobo +Michele Caini +Bartosz Sosnowski +Matej Knopp +sunjin.lee +Matt Clarkson +Jeffrey Clark +Bart Robinson +Vit Gottwald +Vladimír Čunát +Alex Hultman +Brad King +Philippe Laferriere +Will Speak +Hitesh Kanwathirtha +Eric Sciple +jBarz +muflub +Daniel Bevenius +Howard Hellyer +Chris Araman diff --git a/libs/libuv/CMakeLists.txt b/libs/libuv/CMakeLists.txt index 075c8af76..149cd80f4 100644 --- a/libs/libuv/CMakeLists.txt +++ b/libs/libuv/CMakeLists.txt @@ -78,6 +78,7 @@ else() list(APPEND libuv_sources src/win/async.c src/win/core.c + src/win/detect-wakeup.c src/win/dl.c src/win/error.c src/win/fs-event.c diff --git a/libs/libuv/CONTRIBUTING.md b/libs/libuv/CONTRIBUTING.md index ef5c2b2fe..aa97506db 100644 --- a/libs/libuv/CONTRIBUTING.md +++ b/libs/libuv/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/libs/libuv/ChangeLog b/libs/libuv/ChangeLog index 30cdf7a67..a795a4d22 100644 --- a/libs/libuv/ChangeLog +++ b/libs/libuv/ChangeLog @@ -1,4 +1,310 @@ -2016.05.17, Version 1.9.1 (Stable) +2017.02.02, Version 1.11.0 (Stable) + +Changes since version 1.10.2: + +* Now working on version 1.10.3 (cjihrig) + +* win: added fcntl.h to uv-win.h (Michele Caini) + +* unix: move function call out of assert (jBarz) + +* fs: cleanup uv__fs_scandir (Santiago Gimeno) + +* fs: fix crash in uv_fs_scandir_next (muflub) + +* win,signal: fix potential deadlock (Bartosz Sosnowski) + +* unix: use async-signal safe functions between fork and exec (jBarz) + +* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) + +* zos: make platform functional (John Barboza) + +* doc: add repitition qualifier to version regexs (Daniel Bevenius) + +* zos: use gyp OS label "os390" on z/OS (John Barboza) + +* aix: enable uv_get/set_process_title (Howard Hellyer) + +* zos: use built-in proctitle implementation (John Barboza) + +* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) + +* win,test: don't write uninitialized buffer to tty (Bert Belder) + +* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) + +* aix: re-enable fs watch facility (Gireesh Punathil) + + +2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 + +Changes since version 1.10.1: + +* Now working on version 1.10.2 (cjihrig) + +* darwin: fix fsync and fdatasync (Joran Dirk Greef) + +* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" + (Santiago Gimeno) + +* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) + +* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) + +* win: fix comment in quote_cmd_arg (Eric Sciple) + +* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) + +* win, tty: fix crash on restarting with pending data (Nicholas Vavilov) + +* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) + +* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) + +* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) + + +2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 + +Changes since version 1.10.0: + +* Now working on version 1.10.1 (cjihrig) + +* win: fix anonymous union syntax (Brad King) + +* unix: use uv__is_closing everywhere (Santiago Gimeno) + +* win: add missing break statement (cjihrig) + +* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) + +* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) + +* doc: add cjihrig alternative GPG ID (cjihrig) + +* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) + + +2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 + +Changes since version 1.9.1: + +* Now working on version 1.9.2 (Saúl Ibarra Corretgé) + +* doc: add cjihrig GPG ID (cjihrig) + +* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) + +* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra + Corretgé) + +* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) + +* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) + +* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) + +* license: libuv is no longer a Node project (Saúl Ibarra Corretgé) + +* license: add license text we've been using for a while (Saúl Ibarra Corretgé) + +* doc: add licensing information to README (Saúl Ibarra Corretgé) + +* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) + +* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) + +* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) + +* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) + +* doc: update docs with AIX related information (Imran Iqbal) + +* test: silence build warnings (Kári Tristan Helgason) + +* doc: add iWuzHere GPG ID (Imran Iqbal) + +* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) + +* build: fix build on DragonFly (Michael Neumann) + +* unix: correctly detect named pipes on DragonFly (Michael Neumann) + +* test: make tap output the default (Ben Noordhuis) + +* test: don't dump output for skipped tests (Ben Noordhuis) + +* test: improve formatting of diagnostic messages (Ben Noordhuis) + +* test: remove unused RETURN_TODO macro (Ben Noordhuis) + +* doc: fix stream typos (Pierre-Marie de Rodat) + +* doc: update coding style link (Imran Iqbal) + +* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) + +* build: check for warnings for -fvisibility=hidden (Imran Iqbal) + +* unix: remove unneeded TODO note (Saúl Ibarra Corretgé) + +* test: skip tty_pty test if pty is not available (Luca Bruno) + +* sunos: set phys_addr of interface_address using ARP (Brian Maher) + +* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) + +* unix: don't convert stat buffer when syscall fails (Ben Noordhuis) + +* win: compare entire filename in watch events (cjihrig) + +* doc: add a note on safe reuse of uv_write_t (neevek) + +* linux: fix potential event loop stall (Ben Noordhuis) + +* unix,win: make uv_get_process_title() stricter (cjihrig) + +* test: close server before initiating new connection (John Barboza) + +* test: account for multiple handles in one ipc read (John Barboza) + +* unix: fix errno and retval conflict (liuxiaobo) + +* doc: add missing entry in uv_fs_type enum (Michele Caini) + +* unix: preserve loop->data across loop init/done (Ben Noordhuis) + +* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) + +* win: simplify memory copy logic in fs.c (Ben Noordhuis) + +* win: fix compilation on mingw (Bartosz Sosnowski) + +* win: ensure 32-bit printf precision (Matej Knopp) + +* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) + +* test: fix OOB buffer access (Saúl Ibarra Corretgé) + +* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) + +* test: fix android build error. (sunjin.lee) + +* win: evaluate timers when system wakes up (Bartosz Sosnowski) + +* doc: add supported platforms description (Saúl Ibarra Corretgé) + +* win: fix lstat reparse point without link data (Jason Ginchereau) + +* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) + +* zos: add support for new platform (John Barboza) + +* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) + +* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) + +* build: GNU/kFreeBSD support (Jeffrey Clark) + +* zos: use PLO instruction for atomic operations (John Barboza) + +* zos: use pthread helper functions (John Barboza) + +* zos: implement uv__fs_futime (John Barboza) + +* unix: expand range of values for usleep (John Barboza) + +* zos: track unbound handles and bind before listen (John Barboza) + +* test: improve tap output on test failures (Santiago Gimeno) + +* test: refactor fs_event_close_in_callback (Julien Gilli) + +* zos: implement uv__io_check_fd (John Barboza) + +* unix: unneccessary use const qualifier in container_of (John Barboza) + +* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) + +* doc: add santigimeno to maintainers (Santiago Gimeno) + +* win: fix typo in type name (Saúl Ibarra Corretgé) + +* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) + +* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) + +* win: add disk read/write count to uv_getrusage (Imran Iqbal) + +* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) + +* test: improve spawn_setuid_setgid test (Santiago Gimeno) + +* test: fix building pty test on Android (Saúl Ibarra Corretgé) + +* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) + +* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) + +* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) + +* doc: update supported fields for uv_rusage_t (Imran Iqbal) + +* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) + +* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) + +* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) + +* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) + +* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) + +* doc: add ABI tracker link to README (Saúl Ibarra Corretgé) + +* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) + +* test: fix fs_fstat on Android (Vit Gottwald) + +* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) + +* doc: add description of uv_handle_type (Vit Gottwald) + +* build: use -pthreads for tests with autotools (Julien Gilli) + +* win: fix leaky fs request buffer (Jason Ginchereau) + +* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) + +* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) + +* win: fix winapi function pointer typedef syntax (Brad King) + +* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) + +* test: make threadpool_cancel_single deterministic (Ben Noordhuis) + +* test: make threadpool saturation reliable (Ben Noordhuis) + +* unix: don't malloc in uv_thread_create() (Ben Noordhuis) + +* unix: don't include CoreServices globally on macOS (Brad King) + +* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) + +* win: remove unused static variables (Ben Noordhuis) + +* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) + +* signal: replace pthread_once with uv_once (Santiago Gimeno) + +* test: fix sign-compare warning (Will Speak) + +* common: fix unused variable warning (Brad King) + + +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c Changes since version 1.9.0: diff --git a/libs/libuv/LICENSE b/libs/libuv/LICENSE index 4d411670e..41ba44c28 100644 --- a/libs/libuv/LICENSE +++ b/libs/libuv/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/libs/libuv/MAINTAINERS.md b/libs/libuv/MAINTAINERS.md index 2f0e618ca..27a3523ea 100644 --- a/libs/libuv/MAINTAINERS.md +++ b/libs/libuv/MAINTAINERS.md @@ -7,8 +7,14 @@ 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) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **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 +40,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/libs/libuv/Makefile.am b/libs/libuv/Makefile.am index 05ccd58ac..036464e71 100644 --- a/libs/libuv/Makefile.am +++ b/libs/libuv/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,13 +291,36 @@ 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 +libuv_la_CFLAGS += -D_ALL_SOURCE \ + -D_XOPEN_SOURCE=500 \ + -D_LINUX_SOURCE_COMPAT \ + -D_THREAD_SAFE \ + -DHAVE_SYS_AHAFS_EVPRODS_H include_HEADERS += include/uv-aix.h libuv_la_SOURCES += src/unix/aix.c endif @@ -312,6 +349,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 +388,30 @@ 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 \ + src/unix/os390.c \ + src/unix/os390-syscalls.c \ + src/unix/proctitle.c +endif + if HAVE_PKG_CONFIG pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/libs/libuv/Makefile.mingw b/libs/libuv/Makefile.mingw index 156f15dab..8139138fc 100644 --- a/libs/libuv/Makefile.mingw +++ b/libs/libuv/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/libs/libuv/README.md b/libs/libuv/README.md index e94fcc902..284dfb47c 100644 --- a/libs/libuv/README.md +++ b/libs/libuv/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/libs/libuv/SUPPORTED_PLATFORMS.md b/libs/libuv/SUPPORTED_PLATFORMS.md new file mode 100644 index 000000000..bff1050d6 --- /dev/null +++ b/libs/libuv/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/libs/libuv/appveyor.yml b/libs/libuv/appveyor.yml index c7ea73650..e8e79f051 100644 --- a/libs/libuv/appveyor.yml +++ b/libs/libuv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.9.1.build{build} +version: v1.11.0.build{build} install: - cinst -y nsis diff --git a/libs/libuv/common.gypi b/libs/libuv/common.gypi index 56bca2948..470b73385 100644 --- a/libs/libuv/common.gypi +++ b/libs/libuv/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 != "os390"', { + '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 os390"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], diff --git a/libs/libuv/configure.ac b/libs/libuv/configure.ac index d9251f319..360652198 100644 --- a/libs/libuv/configure.ac +++ b/libs/libuv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.9.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.11.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -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/libs/libuv/docs/src/conf.py b/libs/libuv/docs/src/conf.py index b9eaa1374..3f8689d2e 100644 --- a/libs/libuv/docs/src/conf.py +++ b/libs/libuv/docs/src/conf.py @@ -21,11 +21,11 @@ def get_libuv_version(): with open('../../include/uv-version.h') as f: data = f.read() try: - m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_MAJOR (\d+)$""", data, re.MULTILINE) major = int(m.group(1)) - m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_MINOR (\d+)$""", data, re.MULTILINE) minor = int(m.group(1)) - m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_PATCH (\d+)$""", data, re.MULTILINE) patch = int(m.group(1)) m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE) is_release = int(m.group(1)) diff --git a/libs/libuv/docs/src/errors.rst b/libs/libuv/docs/src/errors.rst index cec25f518..4e30447bf 100644 --- a/libs/libuv/docs/src/errors.rst +++ b/libs/libuv/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. @@ -329,3 +332,13 @@ API Returns the error name for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. + +.. c:function:: int uv_translate_sys_error(int sys_errno) + + Returns the libuv error code equivalent to the given platform dependent error + code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error + codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`). + + If `sys_errno` is already a libuv error, it is simply returned. + + .. versionchanged:: 1.10.0 function declared public. diff --git a/libs/libuv/docs/src/fs.rst b/libs/libuv/docs/src/fs.rst index 69e283f4c..192ecc705 100644 --- a/libs/libuv/docs/src/fs.rst +++ b/libs/libuv/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 @@ -222,7 +223,7 @@ API .. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) .. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) - Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively. + Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`lstat(2)` respectively. .. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) @@ -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/libs/libuv/docs/src/fs_event.rst b/libs/libuv/docs/src/fs_event.rst index c2d7f5202..c08ade2ef 100644 --- a/libs/libuv/docs/src/fs_event.rst +++ b/libs/libuv/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/libs/libuv/docs/src/handle.rst b/libs/libuv/docs/src/handle.rst index 6ba597a21..14aec51ff 100644 --- a/libs/libuv/docs/src/handle.rst +++ b/libs/libuv/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/libs/libuv/docs/src/misc.rst b/libs/libuv/docs/src/misc.rst index f32af48ff..719346946 100644 --- a/libs/libuv/docs/src/misc.rst +++ b/libs/libuv/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,11 +186,17 @@ 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) - Sets the current process title. + Sets the current process title. On platforms with a fixed size buffer for the + process title the contents of `title` will be copied to the buffer and + truncated if larger than the available space. Other platforms will return + `UV_ENOMEM` if they cannot allocate enough space to duplicate the contents of + `title`. .. c:function:: int uv_resident_set_memory(size_t* rss) @@ -203,6 +212,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/libs/libuv/docs/src/stream.rst b/libs/libuv/docs/src/stream.rst index ed0c79d00..de492b357 100644 --- a/libs/libuv/docs/src/stream.rst +++ b/libs/libuv/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. @@ -169,6 +173,10 @@ API uv_write(&req1, stream, a, 2, cb); uv_write(&req2, stream, b, 2, cb); + .. note:: + The memory pointed to by the buffers must remain valid until the callback gets called. + This also holds for :c:func:`uv_write2`. + .. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) Extended write function for sending handles over a pipe. The pipe must be diff --git a/libs/libuv/docs/src/tcp.rst b/libs/libuv/docs/src/tcp.rst index ca0c9b4ac..a1a582456 100644 --- a/libs/libuv/docs/src/tcp.rst +++ b/libs/libuv/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/libs/libuv/docs/src/timer.rst b/libs/libuv/docs/src/timer.rst index 31d733efc..8e11f257f 100644 --- a/libs/libuv/docs/src/timer.rst +++ b/libs/libuv/docs/src/timer.rst @@ -42,6 +42,9 @@ API If `repeat` is non-zero, the callback fires first after `timeout` milliseconds and then repeatedly after `repeat` milliseconds. + .. note:: + Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. + .. c:function:: int uv_timer_stop(uv_timer_t* handle) Stop the timer, the callback will not be called anymore. diff --git a/libs/libuv/include/pthread-barrier.h b/libs/libuv/include/pthread-barrier.h index 084e1c2d5..900ebedd3 100644 --- a/libs/libuv/include/pthread-barrier.h +++ b/libs/libuv/include/pthread-barrier.h @@ -18,7 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define _UV_PTHREAD_BARRIER_ #include #include +#if !defined(__MVS__) #include /* sem_t */ +#endif #define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 @@ -39,6 +41,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/libs/libuv/include/uv-errno.h b/libs/libuv/include/uv-errno.h index 53f30296c..f1371517c 100644 --- a/libs/libuv/include/uv-errno.h +++ b/libs/libuv/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/libs/libuv/include/uv-os390.h b/libs/libuv/include/uv-os390.h new file mode 100644 index 000000000..58f926111 --- /dev/null +++ b/libs/libuv/include/uv-os390.h @@ -0,0 +1,30 @@ +/* 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 + +#define UV_PLATFORM_LOOP_FIELDS \ + void* ep; \ + +#endif /* UV_MVS_H */ diff --git a/libs/libuv/include/uv-unix.h b/libs/libuv/include/uv-unix.h index a852c40e4..3030f719a 100644 --- a/libs/libuv/include/uv-unix.h +++ b/libs/libuv/include/uv-unix.h @@ -36,7 +36,9 @@ #include #include +#if !defined(__MVS__) #include +#endif #include #include @@ -44,15 +46,18 @@ #if defined(__linux__) # include "uv-linux.h" +#elif defined (__MVS__) +# include "uv-os390.h" #elif defined(_AIX) # include "uv-aix.h" #elif defined(__sun) # 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/libs/libuv/include/uv-version.h b/libs/libuv/include/uv-version.h index 08ad0edaa..cf0004879 100644 --- a/libs/libuv/include/uv-version.h +++ b/libs/libuv/include/uv-version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 9 -#define UV_VERSION_PATCH 1 +#define UV_VERSION_MINOR 11 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/libs/libuv/include/uv-win.h b/libs/libuv/include/uv-win.h index a75dba8d1..9677ff164 100644 --- a/libs/libuv/include/uv-win.h +++ b/libs/libuv/include/uv-win.h @@ -49,6 +49,7 @@ typedef struct pollfd { #include #include +#include #include #if defined(_MSC_VER) && _MSC_VER < 1600 @@ -116,7 +117,7 @@ typedef struct pollfd { {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - typedef BOOL PASCAL (*LPFN_ACCEPTEX) + typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, @@ -126,7 +127,7 @@ typedef struct pollfd { LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped); - typedef BOOL PASCAL (*LPFN_CONNECTEX) + typedef BOOL (PASCAL *LPFN_CONNECTEX) (SOCKET s, const struct sockaddr* name, int namelen, @@ -135,7 +136,7 @@ typedef struct pollfd { LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped); - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS) (PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, @@ -145,13 +146,13 @@ typedef struct pollfd { LPSOCKADDR* RemoteSockaddr, LPINT RemoteSockaddrLength); - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + typedef BOOL (PASCAL *LPFN_DISCONNECTEX) (SOCKET hSocket, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD reserved); - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + typedef BOOL (PASCAL *LPFN_TRANSMITFILE) (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, diff --git a/libs/libuv/include/uv.h b/libs/libuv/include/uv.h index baa0b2812..31f09f0f6 100644 --- a/libs/libuv/include/uv.h +++ b/libs/libuv/include/uv.h @@ -363,6 +363,8 @@ typedef enum { } uv_membership; +UV_EXTERN int uv_translate_sys_error(int sys_errno); + UV_EXTERN const char* uv_strerror(int err); UV_EXTERN const char* uv_err_name(int err); diff --git a/libs/libuv/libuv.pc.in b/libs/libuv/libuv.pc.in index 2933ec225..9174fe151 100644 --- a/libs/libuv/libuv.pc.in +++ b/libs/libuv/libuv.pc.in @@ -1,5 +1,5 @@ prefix=@prefix@ -exec_prefix=@prefix@ +exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ diff --git a/libs/libuv/src/unix/aix.c b/libs/libuv/src/unix/aix.c index 2276985fc..1d2cd4a80 100644 --- a/libs/libuv/src/unix/aix.c +++ b/libs/libuv/src/unix/aix.c @@ -64,6 +64,11 @@ #define RDWR_BUF_SIZE 4096 #define EQ(a,b) (strcmp(a,b) == 0) +static void* args_mem = NULL; +static char** process_argv = NULL; +static int process_argc = 0; +static char* process_title_ptr = NULL; + int uv__platform_loop_init(uv_loop_t* loop) { loop->fs_fd = -1; @@ -156,7 +161,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 +338,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 +365,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 +381,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 +457,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 +477,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 +552,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 +670,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 * @@ -753,6 +758,13 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); + /* In file / directory move cases, AIX Event infrastructure + * produces a second event with no data. + * Ignore it and return gracefully. + */ + if(bytes == 0) + return; + /* Parse the data */ if(bytes > 0) rc = uv__parse_data(result_data, &events, handle); @@ -881,23 +893,94 @@ void uv__fs_event_close(uv_fs_event_t* handle) { char** uv_setup_args(int argc, char** argv) { - return argv; + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Save the original pointer to argv. + * AIX uses argv to read the process name. + * (Not the memory pointed to by argv[0..n] as on Linux.) + */ + process_argv = argv; + process_argc = argc; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); + + new_argv = uv__malloc(size); + if (new_argv == NULL) + return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; + } + new_argv[i] = NULL; + + return new_argv; } int uv_set_process_title(const char* title) { + char* new_title; + + /* We cannot free this pointer when libuv shuts down, + * the process may still be using it. + */ + new_title = uv__strdup(title); + if (new_title == NULL) + return -ENOMEM; + + /* If this is the first time this is set, + * don't free and set argv[1] to NULL. + */ + if (process_title_ptr != NULL) + uv__free(process_title_ptr); + + process_title_ptr = new_title; + + process_argv[0] = process_title_ptr; + if (process_argc > 1) + process_argv[1] = NULL; + return 0; } int uv_get_process_title(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } + size_t len; + len = strlen(process_argv[0]); + if (buffer == NULL || size == 0) + return -EINVAL; + else if (size <= len) + return -ENOBUFS; + + memcpy(buffer, process_argv[0], len + 1); + return 0; } +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} + + int uv_resident_set_memory(size_t* rss) { char pp[64]; psinfo_t psinfo; diff --git a/libs/libuv/src/unix/atomic-ops.h b/libs/libuv/src/unix/atomic-ops.h index 84e471838..9dac2557f 100644 --- a/libs/libuv/src/unix/atomic-ops.h +++ b/libs/libuv/src/unix/atomic-ops.h @@ -42,6 +42,13 @@ 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__) + unsigned int op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) + return oldval; + else + return op4; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -63,6 +70,19 @@ 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 + unsigned long long op4; + if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, + (unsigned long long*) ptr, *ptr, &op4)) +#else + unsigned long op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) +#endif + return oldval; + else + return op4; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/libs/libuv/src/unix/core.c b/libs/libuv/src/unix/core.c index cdcd0b504..1ec549ccc 100644 --- a/libs/libuv/src/unix/core.c +++ b/libs/libuv/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. */ @@ -100,7 +98,7 @@ uint64_t uv_hrtime(void) { void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); handle->flags |= UV_CLOSING; handle->close_cb = close_cb; @@ -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; } @@ -519,14 +517,14 @@ int uv__close_nocheckstdio(int fd) { int uv__close(int fd) { assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ +#if defined(__MVS__) + epoll_file_close(fd); +#endif return uv__close_nocheckstdio(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 +538,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 +551,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 +583,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 +613,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 +924,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 +939,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; } @@ -1244,3 +1239,9 @@ void uv_os_free_passwd(uv_passwd_t* pwd) { int uv_os_get_passwd(uv_passwd_t* pwd) { return uv__getpwuid_r(pwd); } + + +int uv_translate_sys_error(int sys_errno) { + /* If < 0 then it's already a libuv error. */ + return sys_errno <= 0 ? sys_errno : -sys_errno; +} diff --git a/libs/libuv/src/unix/freebsd.c b/libs/libuv/src/unix/freebsd.c index adc95235c..cba44a3e0 100644 --- a/libs/libuv/src/unix/freebsd.c +++ b/libs/libuv/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/libs/libuv/src/unix/fs.c b/libs/libuv/src/unix/fs.c index 085970a06..f9513ea55 100644 --- a/libs/libuv/src/unix/fs.c +++ b/libs/libuv/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 @@ -128,8 +129,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { #if defined(__linux__) || defined(__sun) || defined(__NetBSD__) return fdatasync(req->file); -#elif defined(__APPLE__) && defined(SYS_fdatasync) - return syscall(SYS_fdatasync, req->file); +#elif defined(__APPLE__) + /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache + * to the drive platters. This is in contrast to Linux's fdatasync and fsync + * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent + * for flushing buffered data to permanent storage. + */ + return fcntl(req->file, F_FULLFSYNC); +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) + /* See the comment in uv__fs_fdatasync. */ + return fcntl(req->file, F_FULLFSYNC); #else return fsync(req->file); #endif @@ -151,9 +167,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 +183,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 +209,15 @@ skip: #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 +226,18 @@ skip: #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 +276,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,49 +361,45 @@ done: } -#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; - if (n == 0) - goto out; /* osx still needs to deallocate some memory */ - else if (n == -1) + if (n == 0) { + /* OS X still needs to deallocate some memory. + * Memory was allocated using the system allocator, so use free() here. + */ + free(dents); + dents = NULL; + } else if (n == -1) { return n; + } req->ptr = dents; - return n; - -out: - saved_errno = errno; - if (dents != NULL) { - int i; - - /* Memory was allocated using the system allocator, so use free() here. */ - for (i = 0; i < n; i++) - free(dents[i]); - free(dents); - } - errno = saved_errno; - - req->ptr = NULL; - return n; } @@ -595,7 +616,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 +632,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 +801,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ @@ -778,9 +816,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; dst->st_ctim.tv_sec = src->st_ctim.tv_sec; dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; -# if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +# if defined(__FreeBSD__) || \ defined(__NetBSD__) dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec; dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec; @@ -810,8 +846,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 +858,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 +870,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; } @@ -905,7 +950,7 @@ static void uv__fs_work(struct uv__work* w) { X(FCHOWN, fchown(req->file, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); - X(FSYNC, fsync(req->file)); + X(FSYNC, uv__fs_fsync(req)); X(FTRUNCATE, ftruncate(req->file, req->off)); X(FUTIME, uv__fs_futime(req)); X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); diff --git a/libs/libuv/src/unix/internal.h b/libs/libuv/src/unix/internal.h index 670b14bc2..1188e8fe7 100644 --- a/libs/libuv/src/unix/internal.h +++ b/libs/libuv/src/unix/internal.h @@ -38,6 +38,10 @@ # include "linux-syscalls.h" #endif /* __linux__ */ +#if defined(__MVS__) +# include "os390-syscalls.h" +#endif /* __MVS__ */ + #if defined(__sun) # include # include @@ -52,7 +56,7 @@ #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE -# include +# include #endif #if defined(__ANDROID__) @@ -132,7 +136,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 +157,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/libs/libuv/src/unix/linux-core.c b/libs/libuv/src/unix/linux-core.c index b48a11117..58dd813dd 100644 --- a/libs/libuv/src/unix/linux-core.c +++ b/libs/libuv/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/libs/libuv/src/unix/loop.c b/libs/libuv/src/unix/loop.c index 92e96f09e..bd63c2f9d 100644 --- a/libs/libuv/src/unix/loop.c +++ b/libs/libuv/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/libs/libuv/src/unix/netbsd.c b/libs/libuv/src/unix/netbsd.c index ca48550f9..4a9e6cbc1 100644 --- a/libs/libuv/src/unix/netbsd.c +++ b/libs/libuv/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/libs/libuv/src/unix/openbsd.c b/libs/libuv/src/unix/openbsd.c index 8c40bde40..909288cc8 100644 --- a/libs/libuv/src/unix/openbsd.c +++ b/libs/libuv/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/libs/libuv/src/unix/os390-syscalls.c b/libs/libuv/src/unix/os390-syscalls.c new file mode 100644 index 000000000..2bf3b7381 --- /dev/null +++ b/libs/libuv/src/unix/os390-syscalls.c @@ -0,0 +1,334 @@ +/* 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 "os390-syscalls.h" +#include +#include +#include +#include + +#define CW_CONDVAR 32 + +#pragma linkage(BPX4CTW, OS) +#pragma linkage(BPX1CTW, OS) + +static int number_of_epolls; +static QUEUE global_epoll_queue; +static uv_mutex_t global_epoll_lock; +static uv_once_t once = UV_ONCE_INIT; + +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent*), + int (*compar)(const struct dirent**, + const struct dirent **)) { + struct dirent** nl; + struct dirent* dirent; + unsigned count; + size_t allocated; + DIR* mdir; + + nl = NULL; + count = 0; + allocated = 0; + mdir = opendir(maindir); + if (!mdir) + return -1; + + while (1) { + dirent = readdir(mdir); + if (!dirent) + break; + if (!filter || filter(dirent)) { + struct dirent* copy; + copy = uv__malloc(sizeof(*copy)); + if (!copy) { + while (count) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; + } + memcpy(copy, dirent, sizeof(*copy)); + + nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); + nl[count++] = copy; + } + } + + qsort(nl, count, sizeof(struct dirent *), + (int (*)(const void *, const void *)) compar); + + closedir(mdir); + + *namelist = nl; + return count; +} + + +static unsigned int next_power_of_two(unsigned int val) { + val -= 1; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val += 1; + return val; +} + + +static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { + unsigned int newsize; + unsigned int i; + struct pollfd* newlst; + + if (len <= lst->size) + return; + + newsize = next_power_of_two(len); + newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); + + if (newlst == NULL) + abort(); + for (i = lst->size; i < newsize; ++i) + newlst[i].fd = -1; + + lst->items = newlst; + lst->size = newsize; +} + + +static void epoll_init() { + QUEUE_INIT(&global_epoll_queue); + if (uv_mutex_init(&global_epoll_lock)) + abort(); +} + + +uv__os390_epoll* epoll_create1(int flags) { + uv__os390_epoll* lst; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + lst = uv__malloc(sizeof(*lst)); + if (lst == -1) + return NULL; + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + + /* initialize list */ + lst->size = 0; + lst->items = NULL; + return lst; +} + + +int epoll_ctl(uv__os390_epoll* lst, + int op, + int fd, + struct epoll_event *event) { + if(op == EPOLL_CTL_DEL) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + errno = ENOENT; + return -1; + } + lst->items[fd].fd = -1; + } else if(op == EPOLL_CTL_ADD) { + maybe_resize(lst, fd + 1); + if (lst->items[fd].fd != -1) { + errno = EEXIST; + return -1; + } + lst->items[fd].fd = fd; + lst->items[fd].events = event->events; + } else if(op == EPOLL_CTL_MOD) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + errno = ENOENT; + return -1; + } + lst->items[fd].events = event->events; + } else + abort(); + + return 0; +} + + +int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, + int maxevents, int timeout) { + size_t size; + struct pollfd* pfds; + int pollret; + int reventcount; + + uv_mutex_lock(&global_epoll_lock); + uv_mutex_unlock(&global_epoll_lock); + size = lst->size; + pfds = lst->items; + pollret = poll(pfds, size, timeout); + if(pollret == -1) + return pollret; + + reventcount = 0; + for (int i = 0; i < lst->size && i < maxevents; ++i) { + struct epoll_event ev; + + ev.events = 0; + ev.fd = pfds[i].fd; + if(!pfds[i].revents) + continue; + + if(pfds[i].revents & POLLRDNORM) + ev.events = ev.events | POLLIN; + + if(pfds[i].revents & POLLWRNORM) + ev.events = ev.events | POLLOUT; + + if(pfds[i].revents & POLLHUP) + ev.events = ev.events | POLLHUP; + + pfds[i].revents = 0; + events[reventcount++] = ev; + } + + return reventcount; +} + + +int epoll_file_close(int fd) { + QUEUE* q; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_FOREACH(q, &global_epoll_queue) { + uv__os390_epoll* lst; + + lst = QUEUE_DATA(q, uv__os390_epoll, member); + if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) + lst->items[fd].fd = -1; + } + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + +void epoll_queue_close(uv__os390_epoll* lst) { + uv_mutex_lock(&global_epoll_lock); + QUEUE_REMOVE(&lst->member); + uv_mutex_unlock(&global_epoll_lock); + uv__free(lst->items); + lst->items = NULL; +} + + +int nanosleep(const struct timespec* req, struct timespec* rem) { + unsigned nano; + unsigned seconds; + unsigned events; + unsigned secrem; + unsigned nanorem; + int rv; + int rc; + int rsn; + + nano = (int)req->tv_nsec; + seconds = req->tv_sec; + events = CW_CONDVAR; + +#if defined(_LP64) + BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#else + BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#endif + + assert(rv == -1 && errno == EAGAIN); + + if(rem != NULL) { + rem->tv_nsec = nanorem; + rem->tv_sec = secrem; + } + + return 0; +} + + +char* mkdtemp(char* path) { + static const char* tempchars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + char *ep, *cp; + unsigned int tries, i; + size_t len; + uint64_t v; + int fd; + int retval; + int saved_errno; + + len = strlen(path); + ep = path + len; + if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { + errno = EINVAL; + return NULL; + } + + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + return NULL; + + tries = TMP_MAX; + retval = -1; + do { + if (read(fd, &v, sizeof(v)) != sizeof(v)) + break; + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (mkdir(path, S_IRWXU) == 0) { + retval = 0; + break; + } + else if (errno != EEXIST) + break; + } while (--tries); + + saved_errno = errno; + uv__close(fd); + if (tries == 0) { + errno = EEXIST; + return NULL; + } + + if (retval == -1) { + errno = saved_errno; + return NULL; + } + + return path; +} diff --git a/libs/libuv/src/unix/os390-syscalls.h b/libs/libuv/src/unix/os390-syscalls.h new file mode 100644 index 000000000..61a7cee83 --- /dev/null +++ b/libs/libuv/src/unix/os390-syscalls.h @@ -0,0 +1,69 @@ +/* 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_OS390_SYSCALL_H_ +#define UV_OS390_SYSCALL_H_ + +#include "uv.h" +#include "internal.h" +#include +#include +#include + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 +#define MAX_EPOLL_INSTANCES 256 +#define MAX_ITEMS_PER_EPOLL 1024 + +#define UV__O_CLOEXEC 0x80000 +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD +#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL +#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD + +struct epoll_event { + int events; + int fd; +}; + +typedef struct { + QUEUE member; + struct pollfd* items; + unsigned long size; +} uv__os390_epoll; + +/* epoll api */ +uv__os390_epoll* epoll_create1(int flags); +int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event); +int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout); +int epoll_file_close(int fd); + +/* utility functions */ +int nanosleep(const struct timespec* req, struct timespec* rem); +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); +char *mkdtemp(char* path); + +#endif /* UV_OS390_SYSCALL_H_ */ diff --git a/libs/libuv/src/unix/os390.c b/libs/libuv/src/unix/os390.c new file mode 100644 index 000000000..be325a923 --- /dev/null +++ b/libs/libuv/src/unix/os390.c @@ -0,0 +1,865 @@ +/* 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" +#include +#include +#include +#include +#include +#if defined(__clang__) +#include "csrsic.h" +#else +#include "//'SYS1.SAMPLIB(CSRSIC)'" +#endif + +#define CVT_PTR 0x10 +#define CSD_OFFSET 0x294 + +/* + Long-term average CPU service used by this logical partition, + in millions of service units per hour. If this value is above + the partition's defined capacity, the partition will be capped. + It is calculated using the physical CPU adjustment factor + (RCTPCPUA) so it may not match other measures of service which + are based on the logical CPU adjustment factor. It is available + if the hardware supports LPAR cluster. +*/ +#define RCTLACS_OFFSET 0xC4 + +/* 32-bit count of alive CPUs. This includes both CPs and IFAs */ +#define CSD_NUMBER_ONLINE_CPUS 0xD4 + +/* Address of system resources manager (SRM) control table */ +#define CVTOPCTP_OFFSET 0x25C + +/* Address of the RCT table */ +#define RMCTRCT_OFFSET 0xE4 + +/* Address of the rsm control and enumeration area. */ +#define CVTRCEP_OFFSET 0x490 + +/* + Number of frames currently available to system. + Excluded are frames backing perm storage, frames offline, and bad frames. +*/ +#define RCEPOOL_OFFSET 0x004 + +/* Total number of frames currently on all available frame queues. */ +#define RCEAFC_OFFSET 0x088 + +/* CPC model length from the CSRSI Service. */ +#define CPCMODEL_LENGTH 16 + +/* Thread Entry constants */ +#define PGTH_CURRENT 1 +#define PGTH_LEN 26 +#define PGTHAPATH 0x20 +#pragma linkage(BPX4GTH, OS) +#pragma linkage(BPX1GTH, OS) + +typedef unsigned data_area_ptr_assign_type; + +typedef union { + struct { +#if defined(_LP64) + data_area_ptr_assign_type lower; +#endif + data_area_ptr_assign_type assign; + }; + char* deref; +} data_area_ptr; + + +void uv_loadavg(double avg[3]) { + /* TODO: implement the following */ + avg[0] = 0; + avg[1] = 0; + avg[2] = 0; +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + uv__os390_epoll* ep; + + ep = epoll_create1(UV__EPOLL_CLOEXEC); + loop->ep = ep; + if (ep == NULL) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->ep != NULL) { + epoll_queue_close(loop->ep); + loop->ep = NULL; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timeval time; + gettimeofday(&time, NULL); + return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3; +} + + +/* + Get the exe path using the thread entry information + in the address space. +*/ +static int getexe(const int pid, char* buf, size_t len) { + struct { + int pid; + int thid[2]; + char accesspid; + char accessthid; + char asid[2]; + char loginname[8]; + char flag; + char len; + } Input_data; + + union { + struct { + char gthb[4]; + int pid; + int thid[2]; + char accesspid; + char accessthid[3]; + int lenused; + int offsetProcess; + int offsetConTTY; + int offsetPath; + int offsetCommand; + int offsetFileData; + int offsetThread; + } Output_data; + char buf[2048]; + } Output_buf; + + struct Output_path_type { + char gthe[4]; + short int len; + char path[1024]; + }; + + int Input_length; + int Output_length; + void* Input_address; + void* Output_address; + struct Output_path_type* Output_path; + int rv; + int rc; + int rsn; + + Input_length = PGTH_LEN; + Output_length = sizeof(Output_buf); + Output_address = &Output_buf; + Input_address = &Input_data; + memset(&Input_data, 0, sizeof Input_data); + Input_data.flag |= PGTHAPATH; + Input_data.pid = pid; + Input_data.accesspid = PGTH_CURRENT; + +#ifdef _LP64 + BPX4GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#else + BPX1GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#endif + + if (rv == -1) { + errno = rc; + return -1; + } + + /* Check highest byte to ensure data availability */ + assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); + + /* Get the offset from the lowest 3 bytes */ + Output_path = (char*)(&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + + if (Output_path->len >= len) { + errno = ENOBUFS; + return -1; + } + + strncpy(buf, Output_path->path, len); + + return 0; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in zOS - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + int pid; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + pid = getpid(); + res = getexe(pid, args, sizeof(args)); + 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 + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char* clonedpath = NULL; + char* token = NULL; + char* path = getenv("PATH"); + + if (path == NULL) + return -EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + uint64_t freeram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; + return freeram; +} + + +uint64_t uv_get_total_memory(void) { + uint64_t totalram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4; + return totalram; +} + + +int uv_resident_set_memory(size_t* rss) { + W_PSPROC buf; + + memset(&buf, 0, sizeof(buf)); + if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1) + return -EINVAL; + + *rss = buf.ps_size; + return 0; +} + + +int uv_uptime(double* uptime) { + struct utmpx u ; + struct utmpx *v; + time64_t t; + + u.ut_type = BOOT_TIME; + v = getutxid(&u); + if (v == NULL) + return -1; + *uptime = difftime64(time64(&t), v->ut_tv.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + int result; + int idx; + siv1v2 info; + data_area_ptr cvt = {0}; + data_area_ptr csd = {0}; + data_area_ptr rmctrct = {0}; + data_area_ptr cvtopctp = {0}; + int cpu_usage_avg; + + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + + csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET)); + cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET)); + rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET)); + + *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS)); + cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET)); + + *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) + return -ENOMEM; + + cpu_info = *cpu_infos; + idx = 0; + while (idx < *count) { + cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability); + cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1); + memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1); + memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH); + cpu_info->cpu_times.user = cpu_usage_avg; + /* TODO: implement the following */ + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + ++cpu_info; + ++idx; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + for (int i = 0; i < count; ++i) + uv__free(cpu_infos[i].model); + uv__free(cpu_infos); +} + + +static int uv__interface_addresses_v6(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + __net_ifconf6header_t ifc; + __net_ifconf6entry_t* ifr; + __net_ifconf6entry_t* p; + __net_ifconf6entry_t flg; + + *count = 0; + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) + return -errno; + + ifc.__nif6h_version = 1; + ifc.__nif6h_buflen = maxsize; + ifc.__nif6h_buffer = uv__calloc(1, maxsize);; + + if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + + + *count = 0; + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + ++(*count); + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->__nif6e_name); + + if (p->__nif6e_addr.sin6_family == AF_INET6) + address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr); + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; + + address++; + } + + uv__close(sockfd); + return 0; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + struct ifconf ifc; + struct ifreq flg; + struct ifreq* ifr; + struct ifreq* p; + int count_v6; + + /* get the ipv6 addresses first */ + uv_interface_address_t* addresses_v6; + uv__interface_addresses_v6(&addresses_v6, &count_v6); + + /* now get the ipv4 addresses */ + *count = 0; + + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (0 > sockfd) + return -errno; + + ifc.ifc_req = uv__calloc(1, maxsize); + ifc.ifc_len = maxsize; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -errno; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc((*count + count_v6) * + sizeof(uv_interface_address_t)); + + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + /* copy over the ipv6 addresses */ + memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); + address += count_v6; + *count += count_v6; + uv__free(addresses_v6); + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->ifr_name); + + if (p->ifr_addr.sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + } + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + address++; + } + +#undef ADDR_SIZE +#undef MAX + + uv__close(sockfd); + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + for (i = 0; i < count; ++i) + uv__free(addresses[i].name); + uv__free(addresses); +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct epoll_event* events; + struct epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the epoll. */ + if (loop->ep != NULL) + epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); +} + + +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; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + static const int max_safe_timeout = 1789569; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + uint64_t base; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + uv_stream_t* stream; + + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + + assert(w->pevents != 0); + assert(w->fd >= 0); + + stream= container_of(w, uv_stream_t, io_watcher); + + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.fd = w->fd; + + if (w->events == 0) + op = UV__EPOLL_CTL_ADD; + else + op = UV__EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (epoll_ctl(loop->ep, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == UV__EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + int nevents = 0; + + nfds = 0; + for (;;) { + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + nfds = epoll_wait(loop->ep, events, + ARRAY_SIZE(events), timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + base = loop->time; + SAVE_ERRNO(uv__update_time(loop)); + if (nfds == 0) { + assert(timeout != -1); + timeout = real_timeout - timeout; + if (timeout > 0) + continue; + + return; + } + + if (nfds == -1) { + + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | POLLERR | POLLHUP; + + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + if (pe->events != 0) { + w->cb(loop, w, pe->events); + nevents++; + } + } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + real_timeout -= (loop->time - base); + if (real_timeout <= 0) + return; + + timeout = real_timeout; + } +} + +void uv__set_process_title(const char* title) { + /* do nothing */ +} diff --git a/libs/libuv/src/unix/pipe.c b/libs/libuv/src/unix/pipe.c index c8d163dcc..b73994cb8 100644 --- a/libs/libuv/src/unix/pipe.c +++ b/libs/libuv/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/libs/libuv/src/unix/poll.c b/libs/libuv/src/unix/poll.c index 0d5944b0a..370994bd5 100644 --- a/libs/libuv/src/unix/poll.c +++ b/libs/libuv/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; @@ -85,7 +92,7 @@ static void uv__poll_stop(uv_poll_t* handle) { int uv_poll_stop(uv_poll_t* handle) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__poll_stop(handle); return 0; } @@ -95,7 +102,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__poll_stop(handle); diff --git a/libs/libuv/src/unix/process.c b/libs/libuv/src/unix/process.c index ef10a3422..f2fe30521 100644 --- a/libs/libuv/src/unix/process.c +++ b/libs/libuv/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; @@ -323,7 +323,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (fd == use_fd) - uv__cloexec(use_fd, 0); + uv__cloexec_fcntl(use_fd, 0); else fd = dup2(use_fd, fd); @@ -333,7 +333,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (fd <= 2) - uv__nonblock(fd, 0); + uv__nonblock_fcntl(fd, 0); if (close_fd >= stdio_count) uv__close(close_fd); diff --git a/libs/libuv/src/unix/proctitle.c b/libs/libuv/src/unix/proctitle.c index 19214e5ec..9160f7eaf 100644 --- a/libs/libuv/src/unix/proctitle.c +++ b/libs/libuv/src/unix/proctitle.c @@ -48,9 +48,15 @@ char** uv_setup_args(int argc, char** argv) { for (i = 0; i < argc; i++) size += strlen(argv[i]) + 1; +#if defined(__MVS__) + /* argv is not adjacent. So just use argv[0] */ + process_title.str = argv[0]; + process_title.len = strlen(argv[0]); +#else process_title.str = argv[0]; process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ +#endif /* Add space for the argv pointers. */ size += (argc + 1) * sizeof(char*); @@ -87,10 +93,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/libs/libuv/src/unix/pthread-barrier.c b/libs/libuv/src/unix/pthread-barrier.c index f57bf2508..b6e604d46 100644 --- a/libs/libuv/src/unix/pthread-barrier.c +++ b/libs/libuv/src/unix/pthread-barrier.c @@ -73,7 +73,8 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) { if (++b->in == b->threshold) { b->in = 0; b->out = b->threshold - 1; - assert(pthread_cond_signal(&b->cond) == 0); + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); pthread_mutex_unlock(&b->mutex); return PTHREAD_BARRIER_SERIAL_THREAD; diff --git a/libs/libuv/src/unix/signal.c b/libs/libuv/src/unix/signal.c index d82b9b7cf..dbd8f8644 100644 --- a/libs/libuv/src/unix/signal.c +++ b/libs/libuv/src/unix/signal.c @@ -43,7 +43,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); -static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT; +static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); static int uv__signal_lock_pipefd[2]; @@ -64,7 +64,7 @@ static void uv__signal_global_init(void) { void uv__signal_global_once_init(void) { - pthread_once(&uv__signal_global_init_guard, uv__signal_global_init); + uv_once(&uv__signal_global_init_guard, uv__signal_global_init); } @@ -290,7 +290,7 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { sigset_t saved_sigmask; int err; - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); /* If the user supplies signum == 0, then return an error already. If the * signum is otherwise invalid then uv__signal_register will find out @@ -434,7 +434,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { int uv_signal_stop(uv_signal_t* handle) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__signal_stop(handle); return 0; } diff --git a/libs/libuv/src/unix/stream.c b/libs/libuv/src/unix/stream.c index 7dbc556f7..7059df16a 100644 --- a/libs/libuv/src/unix/stream.c +++ b/libs/libuv/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) @@ -387,7 +390,7 @@ failed_malloc: int uv__stream_open(uv_stream_t* stream, int fd, int flags) { -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__MVS__) int enable; #endif @@ -406,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { return -errno; } -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__MVS__) enable = 1; if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && @@ -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; @@ -1189,6 +1194,30 @@ static void uv__read(uv_stream_t* stream) { return; } } + +#if defined(__MVS__) + if (is_ipc && msg.msg_controllen > 0) { + uv_buf_t blankbuf; + int nread; + struct iovec *old; + + blankbuf.base = 0; + blankbuf.len = 0; + old = msg.msg_iov; + msg.msg_iov = (struct iovec*) &blankbuf; + nread = 0; + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + msg.msg_iov = old; + return; + } + } while (nread == 0 && msg.msg_controllen > 0); + msg.msg_iov = old; + } +#endif stream->read_cb(stream, nread, &buf); /* Return if we didn't fill the buffer, there is no more data to read. */ @@ -1216,8 +1245,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { if (!(stream->flags & UV_STREAM_WRITABLE) || stream->flags & UV_STREAM_SHUT || stream->flags & UV_STREAM_SHUTTING || - stream->flags & UV_CLOSED || - stream->flags & UV_CLOSING) { + uv__is_closing(stream)) { return -ENOTCONN; } diff --git a/libs/libuv/src/unix/sunos.c b/libs/libuv/src/unix/sunos.c index e67be8fcf..a43f7f1b1 100644 --- a/libs/libuv/src/unix/sunos.c +++ b/libs/libuv/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,59 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +#ifdef SUNOS_NO_IFADDRS +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + return -ENOSYS; +} +#else /* SUNOS_NO_IFADDRS */ +/* + * 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,34 +800,15 @@ 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; -#endif /* SUNOS_NO_IFADDRS */ } - +#endif /* SUNOS_NO_IFADDRS */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { diff --git a/libs/libuv/src/unix/tcp.c b/libs/libuv/src/unix/tcp.c index 793e4c7d6..c423dcb15 100644 --- a/libs/libuv/src/unix/tcp.c +++ b/libs/libuv/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/libs/libuv/src/unix/thread.c b/libs/libuv/src/unix/thread.c index 236f59139..a9b5e4c02 100644 --- a/libs/libuv/src/unix/thread.c +++ b/libs/libuv/src/unix/thread.c @@ -32,31 +32,16 @@ #include +#ifdef __MVS__ +#include +#include +#endif + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) -struct thread_ctx { - void (*entry)(void* arg); - void* arg; -}; - - -static void* uv__thread_start(void *arg) -{ - struct thread_ctx *ctx_p; - struct thread_ctx ctx; - - ctx_p = arg; - ctx = *ctx_p; - uv__free(ctx_p); - ctx.entry(ctx.arg); - - return 0; -} - int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - struct thread_ctx* ctx; int err; pthread_attr_t* attr; #if defined(__APPLE__) @@ -64,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct rlimit lim; #endif - ctx = uv__malloc(sizeof(*ctx)); - if (ctx == NULL) - return UV_ENOMEM; - - ctx->entry = entry; - ctx->arg = arg; - /* On OSX threads other than the main thread are created with a reduced stack * size by default, adjust it to RLIMIT_STACK. */ @@ -94,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { attr = NULL; #endif - err = pthread_create(tid, attr, uv__thread_start, ctx); + err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); if (attr != NULL) pthread_attr_destroy(attr); - if (err) - uv__free(ctx); - return -err; } @@ -302,6 +277,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 +408,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/libs/libuv/src/unix/timer.c b/libs/libuv/src/unix/timer.c index ca3ec3db9..f46bdf4bf 100644 --- a/libs/libuv/src/unix/timer.c +++ b/libs/libuv/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/libs/libuv/src/unix/tty.c b/libs/libuv/src/unix/tty.c index 32fa37eac..b2d37f4c2 100644 --- a/libs/libuv/src/unix/tty.c +++ b/libs/libuv/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 @@ skip: * 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 @@ skip: 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 @@ 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. @@ -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/libs/libuv/src/unix/udp.c b/libs/libuv/src/unix/udp.c index 4527bba1f..1cd492578 100644 --- a/libs/libuv/src/unix/udp.c +++ b/libs/libuv/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/libs/libuv/src/uv-common.c b/libs/libuv/src/uv-common.c index ba2644691..bc7d1379d 100644 --- a/libs/libuv/src/uv-common.c +++ b/libs/libuv/src/uv-common.c @@ -512,8 +512,18 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { uv__dirent_t** dents; uv__dirent_t* dent; + unsigned int* nbufs; - unsigned int* nbufs = uv__get_nbufs(req); + /* Check to see if req passed */ + if (req->result < 0) + return req->result; + + /* Ptr will be null if req was canceled or no files found */ + if (!req->ptr) + return UV_EOF; + + nbufs = uv__get_nbufs(req); + assert(nbufs); dents = req->ptr; @@ -613,6 +623,9 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; +#ifndef NDEBUG + void* saved_data; +#endif if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; @@ -626,7 +639,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/libs/libuv/src/win/core.c b/libs/libuv/src/win/core.c index ba306ebc0..e84186d4e 100644 --- a/libs/libuv/src/win/core.c +++ b/libs/libuv/src/win/core.c @@ -31,13 +31,10 @@ #include "uv.h" #include "internal.h" +#include "queue.h" #include "handle-inl.h" #include "req-inl.h" - -static uv_loop_t default_loop_struct; -static uv_loop_t* default_loop_ptr; - /* uv_once initialization guards */ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; @@ -80,6 +77,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 +190,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 +212,9 @@ static void uv_init(void) { /* Initialize utilities */ uv__util_init(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); } @@ -178,6 +273,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 +298,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 +424,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/libs/libuv/src/win/detect-wakeup.c b/libs/libuv/src/win/detect-wakeup.c new file mode 100644 index 000000000..a12179f79 --- /dev/null +++ b/libs/libuv/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/libs/libuv/src/win/error.c b/libs/libuv/src/win/error.c index c512f35af..642d1112e 100644 --- a/libs/libuv/src/win/error.c +++ b/libs/libuv/src/win/error.c @@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) { switch (sys_errno) { case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; + case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff --git a/libs/libuv/src/win/fs-event.c b/libs/libuv/src/win/fs-event.c index e79a48d0e..03e4adc05 100644 --- a/libs/libuv/src/win/fs-event.c +++ b/libs/libuv/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/libs/libuv/src/win/fs.c b/libs/libuv/src/win/fs.c index 54dfea724..6902d4f1a 100644 --- a/libs/libuv/src/win/fs.c +++ b/libs/libuv/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; \ @@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, const char* new_path, const int copy_path) { char* buf; char* pos; - ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0; + ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0; /* new_path can only be set if path is also set. */ assert(new_path == NULL || path != NULL); @@ -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; @@ -233,6 +230,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, req->ptr = NULL; req->path = NULL; req->cb = cb; + memset(&req->fs, 0, sizeof(req->fs)); } @@ -405,7 +403,6 @@ void fs__open(uv_fs_t* req) { switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { case _O_RDONLY: access = FILE_GENERIC_READ; - attributes |= FILE_FLAG_BACKUP_SEMANTICS; break; case _O_WRONLY: access = FILE_GENERIC_WRITE; @@ -420,7 +417,6 @@ void fs__open(uv_fs_t* req) { if (flags & _O_APPEND) { access &= ~FILE_WRITE_DATA; access |= FILE_APPEND_DATA; - attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; } /* @@ -1091,17 +1087,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 +1436,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; @@ -1885,9 +1892,13 @@ void uv_fs_req_cleanup(uv_fs_t* req) { uv__free(req->ptr); } + if (req->fs.info.bufs != req->fs.info.bufsml) + uv__free(req->fs.info.bufs); + req->path = NULL; req->file.pathw = NULL; req->fs.info.new_pathw = NULL; + req->fs.info.bufs = NULL; req->ptr = NULL; req->flags |= UV_FS_CLEANEDUP; diff --git a/libs/libuv/src/win/getaddrinfo.c b/libs/libuv/src/win/getaddrinfo.c index 744f8e026..c13bfec35 100644 --- a/libs/libuv/src/win/getaddrinfo.c +++ b/libs/libuv/src/win/getaddrinfo.c @@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop, int err; if (req == NULL || (node == NULL && service == NULL)) { - err = WSAEINVAL; - goto error; + return UV_EINVAL; } uv_req_init(loop, (uv_req_t*)req); diff --git a/libs/libuv/src/win/internal.h b/libs/libuv/src/win/internal.h index 0a7c9404f..b8cfde90e 100644 --- a/libs/libuv/src/win/internal.h +++ b/libs/libuv/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/libs/libuv/src/win/pipe.c b/libs/libuv/src/win/pipe.c index a784325c5..2442be730 100644 --- a/libs/libuv/src/win/pipe.c +++ b/libs/libuv/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/libs/libuv/src/win/process-stdio.c b/libs/libuv/src/win/process-stdio.c index e3c06f57d..032e30935 100644 --- a/libs/libuv/src/win/process-stdio.c +++ b/libs/libuv/src/win/process-stdio.c @@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop, case FILE_TYPE_PIPE: CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + break; case FILE_TYPE_CHAR: case FILE_TYPE_REMOTE: diff --git a/libs/libuv/src/win/process.c b/libs/libuv/src/win/process.c index 855c37408..bdf88d2cd 100644 --- a/libs/libuv/src/win/process.c +++ b/libs/libuv/src/win/process.c @@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { * input : hello\\"world * output: "hello\\\\\"world" * input : hello world\ - * output: "hello world\" + * output: "hello world\\" */ *(target++) = L'"'; diff --git a/libs/libuv/src/win/signal.c b/libs/libuv/src/win/signal.c index 2c64a55dc..af7974c36 100644 --- a/libs/libuv/src/win/signal.c +++ b/libs/libuv/src/win/signal.c @@ -30,12 +30,14 @@ RB_HEAD(uv_signal_tree_s, uv_signal_s); static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); -static ssize_t volatile uv__signal_control_handler_refs = 0; static CRITICAL_SECTION uv__signal_lock; +static BOOL WINAPI uv__signal_control_handler(DWORD type); void uv_signals_init() { InitializeCriticalSection(&uv__signal_lock); + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + abort(); } @@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { } -static int uv__signal_register_control_handler() { - /* When this function is called, the uv__signal_lock must be held. */ - - /* If the console control handler has already been hooked, just add a */ - /* reference. */ - if (uv__signal_control_handler_refs > 0) { - uv__signal_control_handler_refs++; - return 0; - } - - if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) - return GetLastError(); - - uv__signal_control_handler_refs++; - - return 0; -} - - -static void uv__signal_unregister_control_handler() { - /* When this function is called, the uv__signal_lock must be held. */ - BOOL r; - - /* Don't unregister if the number of console control handlers exceeds one. */ - /* Just remove a reference in that case. */ - if (uv__signal_control_handler_refs > 1) { - uv__signal_control_handler_refs--; - return; - } - - assert(uv__signal_control_handler_refs == 1); - - r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); - /* This should never fail; if it does it is probably a bug in libuv. */ - assert(r); - - uv__signal_control_handler_refs--; -} - - -static int uv__signal_register(int signum) { - switch (signum) { - case SIGINT: - case SIGBREAK: - case SIGHUP: - return uv__signal_register_control_handler(); - - case SIGWINCH: - /* SIGWINCH is generated in tty.c. No need to register anything. */ - return 0; - - case SIGILL: - case SIGABRT_COMPAT: - case SIGFPE: - case SIGSEGV: - case SIGTERM: - case SIGABRT: - /* Signal is never raised. */ - return 0; - - default: - /* Invalid signal. */ - return ERROR_INVALID_PARAMETER; - } -} - - -static void uv__signal_unregister(int signum) { - switch (signum) { - case SIGINT: - case SIGBREAK: - case SIGHUP: - uv__signal_unregister_control_handler(); - return; - - case SIGWINCH: - /* SIGWINCH is generated in tty.c. No need to unregister anything. */ - return; - - case SIGILL: - case SIGABRT_COMPAT: - case SIGFPE: - case SIGSEGV: - case SIGTERM: - case SIGABRT: - /* Nothing is registered for this signal. */ - return; - - default: - /* Libuv bug. */ - assert(0 && "Invalid signum"); - return; - } -} - - int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { uv_req_t* req; @@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) { EnterCriticalSection(&uv__signal_lock); - uv__signal_unregister(handle->signum); - removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); assert(removed_handle == handle); @@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) { int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { - int err; - - /* If the user supplies signum == 0, then return an error already. If the */ - /* signum is otherwise invalid then uv__signal_register will find out */ - /* eventually. */ - if (signum == 0) { + /* Test for invalid signal values. */ + if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) return UV_EINVAL; - } /* Short circuit: if the signal watcher is already watching {signum} don't */ /* go through the process of deregistering and registering the handler. */ @@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { EnterCriticalSection(&uv__signal_lock); - err = uv__signal_register(signum); - if (err) { - /* Uh-oh, didn't work. */ - LeaveCriticalSection(&uv__signal_lock); - return uv_translate_sys_error(err); - } - handle->signum = signum; RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); diff --git a/libs/libuv/src/win/tcp.c b/libs/libuv/src/win/tcp.c index 0f5654863..0709696ff 100644 --- a/libs/libuv/src/win/tcp.c +++ b/libs/libuv/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/libs/libuv/src/win/tty.c b/libs/libuv/src/win/tty.c index 9b9637784..1b7adf64f 100644 --- a/libs/libuv/src/win/tty.c +++ b/libs/libuv/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) @@ -53,7 +56,11 @@ #define ANSI_BACKSLASH_SEEN 0x80 #define MAX_INPUT_BUFFER_LENGTH 8192 +#define MAX_CONSOLE_CHAR 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 +112,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 +129,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 +178,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 +193,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 +317,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 +334,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 +371,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 +442,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 +472,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 +493,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; } @@ -504,8 +539,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 +710,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 +865,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; } @@ -966,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, if (handle->tty.rd.last_key_len > 0) { SET_REQ_SUCCESS(&handle->read_req); uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); + /* Make sure no attempt is made to insert it again until it's handled. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; return 0; } @@ -1013,11 +1054,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; } @@ -1574,17 +1620,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle, DWORD* error) { /* We can only write 8k characters at a time. Windows can't handle */ /* much more characters in a single console write anyway. */ - WCHAR utf16_buf[8192]; + WCHAR utf16_buf[MAX_CONSOLE_CHAR]; + WCHAR* utf16_buffer; DWORD utf16_buf_used = 0; - unsigned int i; + unsigned int i, len, max_len, pos; + int allocate = 0; -#define FLUSH_TEXT() \ - do { \ - if (utf16_buf_used > 0) { \ - uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ - utf16_buf_used = 0; \ - } \ - } while (0) +#define FLUSH_TEXT() \ + do { \ + pos = 0; \ + do { \ + len = utf16_buf_used - pos; \ + if (len > MAX_CONSOLE_CHAR) \ + len = MAX_CONSOLE_CHAR; \ + uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \ + pos += len; \ + } while (pos < utf16_buf_used); \ + if (allocate) { \ + uv__free(utf16_buffer); \ + allocate = 0; \ + utf16_buffer = utf16_buf; \ + } \ + utf16_buf_used = 0; \ + } while (0) #define ENSURE_BUFFER_SPACE(wchars_needed) \ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \ @@ -1602,12 +1660,48 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* state. */ *error = ERROR_SUCCESS; - EnterCriticalSection(&uv_tty_output_lock); + utf16_buffer = utf16_buf; + + 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 && buf.len > 0) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + max_len = (utf16_buf_used + 1) * sizeof(WCHAR); + allocate = max_len > MAX_CONSOLE_CHAR; + if (allocate) + utf16_buffer = uv__malloc(max_len); + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buffer, + utf16_buf_used)) { + if (allocate) + uv__free(utf16_buffer); + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + + continue; + } + for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2012,7 +2106,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 +2259,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/libs/libuv/src/win/udp.c b/libs/libuv/src/win/udp.c index 24792ec06..9bf1453e5 100644 --- a/libs/libuv/src/win/udp.c +++ b/libs/libuv/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/libs/libuv/src/win/util.c b/libs/libuv/src/win/util.c index 4cebad390..050058afa 100644 --- a/libs/libuv/src/win/util.c +++ b/libs/libuv/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/libs/libuv/src/win/winapi.c b/libs/libuv/src/win/winapi.c index 26bd06486..1fa179b57 100644 --- a/libs/libuv/src/win/winapi.c +++ b/libs/libuv/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/libs/libuv/src/win/winapi.h b/libs/libuv/src/win/winapi.h index 122198a6d..9401676fb 100644 --- a/libs/libuv/src/win/winapi.h +++ b/libs/libuv/src/win/winapi.h @@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; - } DUMMYUNIONNAME; + }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif @@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; - } DUMMYUNIONNAME; + }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; @@ -4606,6 +4606,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) #endif /* from winerror.h */ +#ifndef ERROR_ELEVATION_REQUIRED +# define ERROR_ELEVATION_REQUIRED 740 +#endif + #ifndef ERROR_SYMLINK_NOT_SUPPORTED # define ERROR_SYMLINK_NOT_SUPPORTED 1464 #endif @@ -4684,6 +4688,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 +4745,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/libs/libuv/test/run-tests.c b/libs/libuv/test/run-tests.c index b4be01f6f..1e344f050 100644 --- a/libs/libuv/test/run-tests.c +++ b/libs/libuv/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/libs/libuv/test/runner-unix.c b/libs/libuv/test/runner-unix.c index 2405fa878..2ff18ce75 100644 --- a/libs/libuv/test/runner-unix.c +++ b/libs/libuv/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/libs/libuv/test/runner-win.c b/libs/libuv/test/runner-win.c index 97ef7599e..1b4a569ae 100644 --- a/libs/libuv/test/runner-win.c +++ b/libs/libuv/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/libs/libuv/test/runner.c b/libs/libuv/test/runner.c index c616d1764..4f54f85e2 100644 --- a/libs/libuv/test/runner.c +++ b/libs/libuv/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 @@ out: 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 @@ out: 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 @@ out: 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/libs/libuv/test/runner.h b/libs/libuv/test/runner.h index 78f3c880a..555f2f8eb 100644 --- a/libs/libuv/test/runner.h +++ b/libs/libuv/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/libs/libuv/test/task.h b/libs/libuv/test/task.h index 96cc6377c..65a1132e4 100644 --- a/libs/libuv/test/task.h +++ b/libs/libuv/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/libs/libuv/test/test-embed.c b/libs/libuv/test/test-embed.c index 06137456f..c6ddceb14 100644 --- a/libs/libuv/test/test-embed.c +++ b/libs/libuv/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/libs/libuv/test/test-emfile.c b/libs/libuv/test/test-emfile.c index 5f4dd9efd..8e44ac5c7 100644 --- a/libs/libuv/test/test-emfile.c +++ b/libs/libuv/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/libs/libuv/test/test-error.c b/libs/libuv/test/test-error.c index eb337e66f..a2d559a4e 100644 --- a/libs/libuv/test/test-error.c +++ b/libs/libuv/test/test-error.c @@ -21,6 +21,9 @@ #include "uv.h" #include "task.h" +#if defined(_WIN32) +# include "../src/win/winapi.h" +#endif #include #include @@ -48,3 +51,23 @@ TEST_IMPL(error_message) { return 0; } + + +TEST_IMPL(sys_error) { +#if defined(_WIN32) + ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); + ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); + ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); +#else + ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM); + ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE); + ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL); +#endif + ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL); + ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE); + ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES); + ASSERT(uv_translate_sys_error(0) == 0); + + return 0; +} diff --git a/libs/libuv/test/test-fs-event.c b/libs/libuv/test/test-fs-event.c index 353c43b0d..df8dc4c2f 100644 --- a/libs/libuv/test/test-fs-event.c +++ b/libs/libuv/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/libs/libuv/test/test-fs.c b/libs/libuv/test/test-fs.c index 1cc1a7c06..030245ead 100644 --- a/libs/libuv/test/test-fs.c +++ b/libs/libuv/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 @@ -510,6 +510,18 @@ static void empty_scandir_cb(uv_fs_t* req) { scandir_cb_count++; } +static void non_existent_scandir_cb(uv_fs_t* req) { + uv_dirent_t dent; + + ASSERT(req == &scandir_req); + ASSERT(req->fs_type == UV_FS_SCANDIR); + ASSERT(req->result == UV_ENOENT); + ASSERT(req->ptr == NULL); + ASSERT(UV_ENOENT == uv_fs_scandir_next(req, &dent)); + uv_fs_req_cleanup(req); + scandir_cb_count++; +} + static void file_scandir_cb(uv_fs_t* req) { ASSERT(req == &scandir_req); @@ -662,8 +674,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,10 +1146,22 @@ 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(__sun) || \ - defined(_BSD_SOURCE) || \ - defined(_SVID_SOURCE) || \ - defined(_XOPEN_SOURCE) || \ +#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(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || \ + defined(_XOPEN_SOURCE) || \ defined(_DEFAULT_SOURCE) ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec); ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec); @@ -1145,10 +1169,8 @@ TEST_IMPL(fs_fstat) { ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec); ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec); ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec); -# if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) +# if defined(__FreeBSD__) || \ + defined(__NetBSD__) ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec); ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec); ASSERT(s->st_flags == t.st_flags); @@ -1968,6 +1990,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 +2086,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); @@ -2147,6 +2187,39 @@ TEST_IMPL(fs_scandir_empty_dir) { } +TEST_IMPL(fs_scandir_non_existent_dir) { + const char* path; + uv_fs_t req; + uv_dirent_t dent; + int r; + + path = "./non_existent_dir/"; + loop = uv_default_loop(); + + uv_fs_rmdir(NULL, &req, path, NULL); + uv_fs_req_cleanup(&req); + + /* Fill the req to ensure that required fields are cleaned up */ + memset(&req, 0xdb, sizeof(req)); + + r = uv_fs_scandir(NULL, &req, path, 0, NULL); + ASSERT(r == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + ASSERT(req.ptr == NULL); + ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent)); + uv_fs_req_cleanup(&req); + + r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb); + ASSERT(r == 0); + + ASSERT(scandir_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(scandir_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_scandir_file) { const char* path; int r; @@ -2605,7 +2678,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, offset, NULL); ASSERT(r >= 0); - ASSERT(read_req.result == sizeof(test_buf) * iovcount); + ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); for (index = 0; index < iovcount; ++index) ASSERT(strncmp(buffer + index * sizeof(test_buf), diff --git a/libs/libuv/test/test-getaddrinfo.c b/libs/libuv/test/test-getaddrinfo.c index 6b644a8d4..03dc12695 100644 --- a/libs/libuv/test/test-getaddrinfo.c +++ b/libs/libuv/test/test-getaddrinfo.c @@ -83,6 +83,13 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, TEST_IMPL(getaddrinfo_fail) { uv_getaddrinfo_t req; + ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), + &req, + (uv_getaddrinfo_cb) abort, + NULL, + NULL, + NULL)); + /* Use a FQDN by ending in a period */ ASSERT(0 == uv_getaddrinfo(uv_default_loop(), &req, diff --git a/libs/libuv/test/test-ipc-send-recv.c b/libs/libuv/test/test-ipc-send-recv.c index c445483fa..133ae9014 100644 --- a/libs/libuv/test/test-ipc-send-recv.c +++ b/libs/libuv/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)); + do { + if (++recv_cb_count == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); + /* 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); - 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); + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == ctx.expected_type); - r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); - } + 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)); + do { + if (++read_cb_count == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); + ASSERT(pipe == &ctx2.channel); + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 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); + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - r = uv_accept(handle, &recv->stream); - 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); - wrbuf = uv_buf_init(".", 1); - r = uv_write2(write_req, - (uv_stream_t*)&ctx2.channel, - &wrbuf, - 1, - &recv->stream, - write2_cb); - 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/libs/libuv/test/test-list.h b/libs/libuv/test/test-list.h index c93f08199..3a1e82a91 100644 --- a/libs/libuv/test/test-list.h +++ b/libs/libuv/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) @@ -45,6 +47,8 @@ TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) #ifdef _WIN32 TEST_DECLARE (tty_raw) +TEST_DECLARE (tty_empty_write) +TEST_DECLARE (tty_large_write) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) @@ -59,6 +63,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 +109,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) @@ -148,6 +154,7 @@ TEST_DECLARE (shutdown_eof) TEST_DECLARE (shutdown_twice) TEST_DECLARE (callback_stack) TEST_DECLARE (error_message) +TEST_DECLARE (sys_error) TEST_DECLARE (timer) TEST_DECLARE (timer_init) TEST_DECLARE (timer_again) @@ -273,6 +280,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 @@ -287,6 +295,7 @@ TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) TEST_DECLARE (fs_event_getpath) TEST_DECLARE (fs_scandir_empty_dir) +TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) TEST_DECLARE (fs_open_dir) TEST_DECLARE (fs_rename_to_existing_file) @@ -314,13 +323,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) @@ -331,6 +346,7 @@ TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (ipc_listen_after_bind_twice) +TEST_DECLARE (win32_signum_number) #else TEST_DECLARE (emfile) TEST_DECLARE (close_fd) @@ -392,6 +408,8 @@ TASK_LIST_START TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) + TEST_ENTRY (tty_empty_write) + TEST_ENTRY (tty_large_write) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) @@ -407,6 +425,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 +494,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) @@ -528,6 +549,7 @@ TASK_LIST_START TEST_HELPER (callback_stack, tcp4_echo_server) TEST_ENTRY (error_message) + TEST_ENTRY (sys_error) TEST_ENTRY (timer) TEST_ENTRY (timer_init) @@ -624,6 +646,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 +683,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) @@ -668,6 +696,7 @@ TASK_LIST_START TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (ipc_listen_after_bind_twice) + TEST_ENTRY (win32_signum_number) #else TEST_ENTRY (emfile) TEST_ENTRY (close_fd) @@ -710,6 +739,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 @@ -724,6 +754,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_error_reporting) TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_scandir_empty_dir) + TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file) TEST_ENTRY (fs_open_dir) TEST_ENTRY (fs_rename_to_existing_file) diff --git a/libs/libuv/test/test-loop-close.c b/libs/libuv/test/test-loop-close.c index 5aec234ed..971c9d725 100644 --- a/libs/libuv/test/test-loop-close.c +++ b/libs/libuv/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/libs/libuv/test/test-pipe-getsockname.c b/libs/libuv/test/test-pipe-getsockname.c index 58041c026..4b4ceccc4 100644 --- a/libs/libuv/test/test-pipe-getsockname.c +++ b/libs/libuv/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/libs/libuv/test/test-platform-output.c b/libs/libuv/test/test-platform-output.c index bd61454fa..b89550801 100644 --- a/libs/libuv/test/test-platform-output.c +++ b/libs/libuv/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/libs/libuv/test/test-poll-close-doesnt-corrupt-stack.c b/libs/libuv/test/test-poll-close-doesnt-corrupt-stack.c index fc2cc004f..1dfc80e35 100644 --- a/libs/libuv/test/test-poll-close-doesnt-corrupt-stack.c +++ b/libs/libuv/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/libs/libuv/test/test-poll-closesocket.c b/libs/libuv/test/test-poll-closesocket.c index 4db74a01f..ecaa9e54a 100644 --- a/libs/libuv/test/test-poll-closesocket.c +++ b/libs/libuv/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/libs/libuv/test/test-poll.c b/libs/libuv/test/test-poll.c index f3cfe7977..6c1f98b7e 100644 --- a/libs/libuv/test/test-poll.c +++ b/libs/libuv/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/libs/libuv/test/test-process-title.c b/libs/libuv/test/test-process-title.c index 42ade4416..5d5ede9d6 100644 --- a/libs/libuv/test/test-process-title.c +++ b/libs/libuv/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) 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/libs/libuv/test/test-ref.c b/libs/libuv/test/test-ref.c index ddaa17380..39f4b0fc7 100644 --- a/libs/libuv/test/test-ref.c +++ b/libs/libuv/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/libs/libuv/test/test-signal.c b/libs/libuv/test/test-signal.c index fcdd8e4d2..c0424c60a 100644 --- a/libs/libuv/test/test-signal.c +++ b/libs/libuv/test/test-signal.c @@ -19,13 +19,40 @@ * IN THE SOFTWARE. */ - -/* This test does not pretend to be cross-platform. */ -#ifndef _WIN32 - #include "uv.h" #include "task.h" +/* For Windows we test only signum handling */ +#ifdef _WIN32 +static void signum_test_cb(uv_signal_t* handle, int signum) { + FATAL("signum_test_cb should not be called"); +} + +TEST_IMPL(win32_signum_number) { + uv_signal_t signal; + uv_loop_t* loop; + + loop = uv_default_loop(); + uv_signal_init(loop, &signal); + + ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); + MAKE_VALGRIND_HAPPY(); + return 0; +} +#else #include #include #include diff --git a/libs/libuv/test/test-spawn.c b/libs/libuv/test/test-spawn.c index eba54ae70..53a036969 100644 --- a/libs/libuv/test/test-spawn.c +++ b/libs/libuv/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/libs/libuv/test/test-tcp-alloc-cb-fail.c b/libs/libuv/test/test-tcp-alloc-cb-fail.c new file mode 100644 index 000000000..61ca667ac --- /dev/null +++ b/libs/libuv/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/libs/libuv/test/test-tcp-close-accept.c b/libs/libuv/test/test-tcp-close-accept.c index 5517aaf99..e4878398c 100644 --- a/libs/libuv/test/test-tcp-close-accept.c +++ b/libs/libuv/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/libs/libuv/test/test-tcp-close-while-connecting.c b/libs/libuv/test/test-tcp-close-while-connecting.c index 60df7a574..8d0b82706 100644 --- a/libs/libuv/test/test-tcp-close-while-connecting.c +++ b/libs/libuv/test/test-tcp-close-while-connecting.c @@ -29,6 +29,7 @@ static uv_tcp_t tcp_handle; static int connect_cb_called; static int timer1_cb_called; static int close_cb_called; +static int netunreach_errors; static void close_cb(uv_handle_t* handle) { @@ -37,9 +38,15 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == UV_ECANCELED); + /* The expected error is UV_ECANCELED but the test tries to connect to what + * is basically an arbitrary address in the expectation that no network path + * exists, so UV_ENETUNREACH is an equally plausible outcome. + */ + ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH); uv_timer_stop(&timer2_handle); connect_cb_called++; + if (status == UV_ENETUNREACH) + netunreach_errors++; } @@ -82,5 +89,9 @@ TEST_IMPL(tcp_close_while_connecting) { ASSERT(close_cb_called == 2); MAKE_VALGRIND_HAPPY(); + + if (netunreach_errors > 0) + RETURN_SKIP("Network unreachable."); + return 0; } diff --git a/libs/libuv/test/test-tcp-write-queue-order.c b/libs/libuv/test/test-tcp-write-queue-order.c index 8a98ab836..d50289c3c 100644 --- a/libs/libuv/test/test-tcp-write-queue-order.c +++ b/libs/libuv/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/libs/libuv/test/test-tcp-writealot.c b/libs/libuv/test/test-tcp-writealot.c index 6cfe2ebb1..7206fdc2f 100644 --- a/libs/libuv/test/test-tcp-writealot.c +++ b/libs/libuv/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/libs/libuv/test/test-threadpool-cancel.c b/libs/libuv/test/test-threadpool-cancel.c index 784c1739f..917f5f475 100644 --- a/libs/libuv/test/test-threadpool-cancel.c +++ b/libs/libuv/test/test-threadpool-cancel.c @@ -37,77 +37,45 @@ struct cancel_info { uv_timer_t timer_handle; }; -static uv_cond_t signal_cond; -static uv_mutex_t signal_mutex; -static uv_mutex_t wait_mutex; -static unsigned num_threads; static unsigned fs_cb_called; -static unsigned work_cb_called; static unsigned done_cb_called; static unsigned done2_cb_called; static unsigned timer_cb_called; +static uv_work_t pause_reqs[4]; +static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)]; static void work_cb(uv_work_t* req) { - uv_mutex_lock(&signal_mutex); - uv_cond_signal(&signal_cond); - uv_mutex_unlock(&signal_mutex); - - uv_mutex_lock(&wait_mutex); - uv_mutex_unlock(&wait_mutex); - - work_cb_called++; + uv_sem_wait(pause_sems + (req - pause_reqs)); } static void done_cb(uv_work_t* req, int status) { - done_cb_called++; - free(req); + uv_sem_destroy(pause_sems + (req - pause_reqs)); } static void saturate_threadpool(void) { - uv_work_t* req; + uv_loop_t* loop; + char buf[64]; + size_t i; - ASSERT(0 == uv_cond_init(&signal_cond)); - ASSERT(0 == uv_mutex_init(&signal_mutex)); - ASSERT(0 == uv_mutex_init(&wait_mutex)); + snprintf(buf, sizeof(buf), "UV_THREADPOOL_SIZE=%zu", ARRAY_SIZE(pause_reqs)); + putenv(buf); - uv_mutex_lock(&signal_mutex); - uv_mutex_lock(&wait_mutex); - - for (num_threads = 0; /* empty */; num_threads++) { - req = malloc(sizeof(*req)); - ASSERT(req != NULL); - ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb)); - - /* Expect to get signalled within 350 ms, otherwise assume that - * the thread pool is saturated. As with any timing dependent test, - * this is obviously not ideal. - */ - if (uv_cond_timedwait(&signal_cond, - &signal_mutex, - (uint64_t) (350 * 1e6))) { - ASSERT(0 == uv_cancel((uv_req_t*) req)); - break; - } + loop = uv_default_loop(); + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) { + ASSERT(0 == uv_sem_init(pause_sems + i, 0)); + ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); } } static void unblock_threadpool(void) { - uv_mutex_unlock(&signal_mutex); - uv_mutex_unlock(&wait_mutex); -} + size_t i; - -static void cleanup_threadpool(void) { - ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */ - ASSERT(work_cb_called == num_threads); - - uv_cond_destroy(&signal_cond); - uv_mutex_destroy(&signal_mutex); - uv_mutex_destroy(&wait_mutex); + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) + uv_sem_post(pause_sems + i); } @@ -166,12 +134,9 @@ static void timer_cb(uv_timer_t* handle) { } -static void nop_work_cb(uv_work_t* req) { -} - - static void nop_done_cb(uv_work_t* req, int status) { - req->data = "OK"; + ASSERT(status == UV_ECANCELED); + done_cb_called++; } @@ -203,8 +168,6 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -241,8 +204,6 @@ TEST_IMPL(threadpool_cancel_getnameinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -267,8 +228,6 @@ TEST_IMPL(threadpool_cancel_work) { ASSERT(1 == timer_cb_called); ASSERT(ARRAY_SIZE(reqs) == done2_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -322,7 +281,6 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(n == fs_cb_called); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); MAKE_VALGRIND_HAPPY(); return 0; @@ -332,30 +290,15 @@ TEST_IMPL(threadpool_cancel_fs) { TEST_IMPL(threadpool_cancel_single) { uv_loop_t* loop; uv_work_t req; - int cancelled; - int i; + saturate_threadpool(); loop = uv_default_loop(); - for (i = 0; i < 5000; i++) { - req.data = NULL; - ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb)); - - cancelled = uv_cancel((uv_req_t*) &req); - if (cancelled == 0) - break; - - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - } - - if (cancelled != 0) { - fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n", - stderr); - return 1; - } - - ASSERT(req.data == NULL); + ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); + ASSERT(0 == uv_cancel((uv_req_t*) &req)); + ASSERT(0 == done_cb_called); + unblock_threadpool(); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */ + ASSERT(1 == done_cb_called); MAKE_VALGRIND_HAPPY(); return 0; diff --git a/libs/libuv/test/test-tty.c b/libs/libuv/test/test-tty.c index 55cc01675..6fc2c95c9 100644 --- a/libs/libuv/test/test-tty.c +++ b/libs/libuv/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 @@ -212,6 +212,96 @@ TEST_IMPL(tty_raw) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tty_empty_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[1]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + bufs[0].len = 0; + bufs[0].base = &dummy; + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tty_large_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[10000]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + memset(dummy, '.', sizeof(dummy) - 1); + dummy[sizeof(dummy) - 1] = '\n'; + + bufs[0] = uv_buf_init(dummy, sizeof(dummy)); + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 10000); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif @@ -260,16 +350,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/libs/libuv/test/test-udp-alloc-cb-fail.c b/libs/libuv/test/test-udp-alloc-cb-fail.c new file mode 100644 index 000000000..05b871e92 --- /dev/null +++ b/libs/libuv/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/libs/libuv/test/test-udp-ipv6.c b/libs/libuv/test/test-udp-ipv6.c index 1b0db78b8..a65f09e0c 100644 --- a/libs/libuv/test/test-udp-ipv6.c +++ b/libs/libuv/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/libs/libuv/test/test-udp-multicast-interface6.c b/libs/libuv/test/test-udp-multicast-interface6.c index d3881e83b..40b05536d 100644 --- a/libs/libuv/test/test-udp-multicast-interface6.c +++ b/libs/libuv/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/libs/libuv/test/test-udp-multicast-join6.c b/libs/libuv/test/test-udp-multicast-join6.c index f635bdb9e..2eb9e920e 100644 --- a/libs/libuv/test/test-udp-multicast-join6.c +++ b/libs/libuv/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/libs/libuv/test/test-udp-options.c b/libs/libuv/test/test-udp-options.c index 0da1786f5..8f9136759 100644 --- a/libs/libuv/test/test-udp-options.c +++ b/libs/libuv/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/libs/libuv/test/test-watcher-cross-stop.c b/libs/libuv/test/test-watcher-cross-stop.c index 910ed0fb6..6ff48d44c 100644 --- a/libs/libuv/test/test-watcher-cross-stop.c +++ b/libs/libuv/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/libs/libuv/uv.gyp b/libs/libuv/uv.gyp index 2fdd59ac7..49d5d22f9 100644 --- a/libs/libuv/uv.gyp +++ b/libs/libuv/uv.gyp @@ -10,9 +10,27 @@ ['OS=="solaris"', { 'cflags': [ '-pthreads' ], }], - ['OS not in "solaris android"', { + ['OS not in "solaris android os390"', { 'cflags': [ '-pthread' ], }], + ['OS in "os390"', { + 'defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_UNIX03_WITHDRAWN', + '_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' ], + 'ldflags': [ '-qxplink' ], + }] ], }], ], @@ -75,6 +93,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 +137,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 +172,25 @@ ['OS=="solaris"', { 'ldflags': [ '-pthreads' ], }], - ['OS != "solaris" and OS != "android"', { + [ 'OS=="os390" and uv_library=="shared_library"', { + 'ldflags': [ '-Wl,DLL' ], + }], + ['OS != "solaris" and OS != "android" and OS != "os390"', { 'ldflags': [ '-pthread' ], }], ], }, 'conditions': [ ['uv_library=="shared_library"', { - 'cflags': [ '-fPIC' ], + 'conditions': [ + ['OS=="os390"', { + 'cflags': [ '-qexportall' ], + }, { + 'cflags': [ '-fPIC' ], + }], + ], }], - ['uv_library=="shared_library" and OS!="mac"', { + ['uv_library=="shared_library" and OS!="mac" and OS!="os390"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR # in include/uv-version.h @@ -179,9 +198,20 @@ }], ], }], - [ 'OS in "linux mac ios android"', { + [ 'OS in "linux mac ios android os390"', { 'sources': [ 'src/unix/proctitle.c' ], }], + [ 'OS != "os390"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ], + }], [ 'OS in "mac ios"', { 'sources': [ 'src/unix/darwin.c', @@ -194,7 +224,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac"', { + [ 'OS!="mac" and OS!="os390"', { # Enable on all platforms except OS X. The antique gcc/clang that # ships with Xcode emits waaaay too many false positives. 'cflags': [ '-Wstrict-aliasing' ], @@ -247,6 +277,7 @@ '_XOPEN_SOURCE=500', '_LINUX_SOURCE_COMPAT', '_THREAD_SAFE', + 'HAVE_SYS_AHAFS_EVPRODS_H', ], 'link_settings': { 'libraries': [ @@ -274,6 +305,14 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], + ['OS=="os390"', { + 'sources': [ + 'src/unix/pthread-fixes.c', + 'src/unix/pthread-barrier.c', + 'src/unix/os390.c', + 'src/unix/os390-syscalls.c' + ] + }], ] }, @@ -363,6 +402,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 +437,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 +466,20 @@ ], 'libraries': [ '-lws2_32' ] }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], 'sources': [ 'test/runner-unix.c', 'test/runner-unix.h', ], - }], + 'conditions': [ + [ 'OS != "os390"', { + '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 +498,12 @@ ], }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "os390"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': { @@ -505,7 +559,12 @@ ] }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "os390"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': {