From ae83f0f993cbcde82fcc60b0e1e236d3bd4d6c6e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 11 Mar 2020 12:36:48 -0400 Subject: [PATCH] deps: upgrade to libuv 1.35.0 Notable changes: - The UV_UDP_MMSG_CHUNK UDP flag has been added. - Support has been dropped for FreeBSD < 10. - The FreeBSD and Linux system call logic has been simplified to assume the presence of features covered by libuv's minimum system requirements. - Listening on IPC pipes is no longer allowed. - Fix iOS and Android builds. PR-URL: https://github.com/nodejs/node/pull/32204 Reviewed-By: Anna Henningsen Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- deps/uv/AUTHORS | 5 + deps/uv/CMakeLists.txt | 428 +++-- deps/uv/CONTRIBUTING.md | 4 +- deps/uv/ChangeLog | 101 + deps/uv/MAINTAINERS.md | 2 + deps/uv/Makefile.am | 1 + deps/uv/README.md | 7 + deps/uv/configure.ac | 2 +- deps/uv/docs/src/misc.rst | 9 + deps/uv/docs/src/pipe.rst | 6 +- .../src/static/diagrams.key/Data/st0-311.jpg | Bin 19328 -> 14413 bytes .../src/static/diagrams.key/Data/st1-475.jpg | Bin 12655 -> 8284 bytes deps/uv/docs/src/tcp.rst | 5 + deps/uv/docs/src/udp.rst | 13 +- deps/uv/include/uv.h | 8 +- deps/uv/include/uv/version.h | 4 +- deps/uv/include/uv/win.h | 2 +- deps/uv/src/timer.c | 2 +- deps/uv/src/unix/async.c | 84 +- deps/uv/src/unix/core.c | 143 +- deps/uv/src/unix/freebsd.c | 25 + deps/uv/src/unix/ibmi.c | 17 +- deps/uv/src/unix/internal.h | 31 +- deps/uv/src/unix/linux-inotify.c | 67 +- deps/uv/src/unix/linux-syscalls.c | 191 +- deps/uv/src/unix/linux-syscalls.h | 79 - deps/uv/src/unix/openbsd.c | 10 +- deps/uv/src/unix/os390-syscalls.c | 31 +- deps/uv/src/unix/pipe.c | 6 +- deps/uv/src/unix/process.c | 78 +- deps/uv/src/unix/proctitle.c | 65 +- deps/uv/src/unix/signal.c | 23 +- deps/uv/src/unix/tcp.c | 12 +- deps/uv/src/unix/udp.c | 216 ++- deps/uv/src/win/pipe.c | 151 +- deps/uv/src/win/tcp.c | 23 +- deps/uv/src/win/tty.c | 337 ++-- deps/uv/test/benchmark-list.h | 1 + deps/uv/test/benchmark-multi-accept.c | 8 +- deps/uv/test/benchmark-ping-udp.c | 163 ++ deps/uv/test/echo-server.c | 55 +- deps/uv/test/run-tests.c | 11 + deps/uv/test/runner.c | 19 +- deps/uv/test/test-fs-copyfile.c | 3 + deps/uv/test/test-fs-event.c | 10 +- deps/uv/test/test-fs.c | 11 + deps/uv/test/test-get-memory.c | 11 +- deps/uv/test/test-get-passwd.c | 2 + deps/uv/test/test-list.h | 40 +- deps/uv/test/test-poll.c | 37 +- deps/uv/test/test-process-title.c | 59 + deps/uv/test/test-signal-pending-on-close.c | 27 +- deps/uv/test/test-spawn.c | 22 +- deps/uv/test/test-stdio-over-pipes.c | 135 +- .../test-tty-escape-sequence-processing.c | 1621 +++++++++++++++++ deps/uv/test/test-udp-connect.c | 4 + deps/uv/test/test-udp-ipv6.c | 59 +- deps/uv/test/test-watcher-cross-stop.c | 3 +- deps/uv/test/test.gyp | 2 + deps/uv/uv.gyp | 1 - 60 files changed, 3390 insertions(+), 1102 deletions(-) create mode 100644 deps/uv/test/benchmark-ping-udp.c create mode 100644 deps/uv/test/test-tty-escape-sequence-processing.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index f829778a21c1a5..491eded73d5c94 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -413,3 +413,8 @@ Carl Lei Stefan Bender nia virtualyw +Witold Kręcicki +Dominique Dumont +Manuel BACHMANN +Marek Vavrusa +TK-one diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 2ab6d17edddd72..03d889cf1dd8eb 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -2,22 +2,55 @@ cmake_minimum_required(VERSION 3.4) project(libuv LANGUAGES C) +cmake_policy(SET CMP0057 NEW) # Enable IN_LIST operator +cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + include(CMakePackageConfigHelpers) include(CMakeDependentOption) +include(CheckCCompilerFlag) include(GNUInstallDirs) include(CTest) +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_C_STANDARD 90) + cmake_dependent_option(LIBUV_BUILD_TESTS "Build the unit tests when BUILD_TESTING is enabled and we are the root project" ON "BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) +cmake_dependent_option(LIBUV_BUILD_BENCH + "Build the benchmarks when building unit tests and we are the root project" ON + "LIBUV_BUILD_TESTS" OFF) -if(MSVC) - list(APPEND uv_cflags /W4) -elseif(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") - list(APPEND uv_cflags -fvisibility=hidden --std=gnu89) - list(APPEND uv_cflags -Wall -Wextra -Wstrict-prototypes) - list(APPEND uv_cflags -Wno-unused-parameter) -endif() +# Compiler check +string(CONCAT is-msvc $, + $ +>) + +check_c_compiler_flag(/W4 UV_LINT_W4) +check_c_compiler_flag(-Wall UV_LINT_WALL) # DO NOT use this under MSVC + +# TODO: Place these into its own function +check_c_compiler_flag(-Wno-unused-parameter UV_LINT_NO_UNUSED_PARAMETER) +check_c_compiler_flag(-Wstrict-prototypes UV_LINT_STRICT_PROTOTYPES) +check_c_compiler_flag(-Wextra UV_LINT_EXTRA) + +set(lint-no-unused-parameter $<$:-Wno-unused-parameter>) +set(lint-strict-prototypes $<$:-Wstrict-prototypes>) +set(lint-extra $<$:-Wextra>) +set(lint-w4 $<$:/W4>) +# Unfortunately, this one is complicated because MSVC and clang-cl support -Wall +# but using it is like calling -Weverything +string(CONCAT lint-default $< + $,$>:-Wall +>) + +list(APPEND uv_cflags ${lint-strict-prototypes} ${lint-extra} ${lint-default} ${lint-w4}) +list(APPEND uv_cflags ${lint-no-unused-parameter}) set(uv_sources src/fs-poll.c @@ -31,172 +64,24 @@ set(uv_sources src/uv-data-getter-setters.c src/version.c) -set(uv_test_sources - test/blackhole-server.c - test/echo-server.c - test/run-tests.c - test/runner.c - test/test-active.c - test/test-async-null-cb.c - test/test-async.c - test/test-barrier.c - test/test-callback-order.c - test/test-callback-stack.c - test/test-close-fd.c - test/test-close-order.c - test/test-condvar.c - test/test-connect-unspecified.c - test/test-connection-fail.c - test/test-cwd-and-chdir.c - test/test-default-loop-close.c - test/test-delayed-accept.c - test/test-dlerror.c - test/test-eintr-handling.c - test/test-embed.c - test/test-emfile.c - test/test-env-vars.c - test/test-error.c - test/test-fail-always.c - test/test-fork.c - test/test-fs-copyfile.c - test/test-fs-event.c - test/test-fs-poll.c - test/test-fs.c - test/test-fs-readdir.c - test/test-fs-fd-hash.c - test/test-fs-open-flags.c - test/test-get-currentexe.c - test/test-get-loadavg.c - test/test-get-memory.c - test/test-get-passwd.c - test/test-getaddrinfo.c - test/test-gethostname.c - test/test-getnameinfo.c - test/test-getsockname.c - test/test-getters-setters.c - test/test-gettimeofday.c - test/test-handle-fileno.c - test/test-homedir.c - test/test-hrtime.c - test/test-idle.c - test/test-idna.c - test/test-ip4-addr.c - test/test-ip6-addr.c - test/test-ipc-heavy-traffic-deadlock-bug.c - test/test-ipc-send-recv.c - test/test-ipc.c - test/test-loop-alive.c - test/test-loop-close.c - test/test-loop-configure.c - test/test-loop-handles.c - test/test-loop-stop.c - test/test-loop-time.c - test/test-multiple-listen.c - test/test-mutexes.c - test/test-osx-select.c - test/test-pass-always.c - test/test-ping-pong.c - test/test-pipe-bind-error.c - test/test-pipe-close-stdout-read-stdin.c - test/test-pipe-connect-error.c - test/test-pipe-connect-multiple.c - test/test-pipe-connect-prepare.c - test/test-pipe-getsockname.c - test/test-pipe-pending-instances.c - test/test-pipe-sendmsg.c - test/test-pipe-server-close.c - test/test-pipe-set-fchmod.c - test/test-pipe-set-non-blocking.c - test/test-platform-output.c - test/test-poll-close-doesnt-corrupt-stack.c - test/test-poll-close.c - test/test-poll-closesocket.c - test/test-poll-oob.c - test/test-poll.c - test/test-process-priority.c - test/test-process-title-threadsafe.c - test/test-process-title.c - test/test-queue-foreach-delete.c - test/test-random.c - test/test-ref.c - test/test-run-nowait.c - test/test-run-once.c - test/test-semaphore.c - test/test-shutdown-close.c - test/test-shutdown-eof.c - test/test-shutdown-twice.c - test/test-signal-multiple-loops.c - test/test-signal-pending-on-close.c - test/test-signal.c - test/test-socket-buffer-size.c - test/test-spawn.c - test/test-stdio-over-pipes.c - test/test-strscpy.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 - test/test-tcp-close-while-connecting.c - test/test-tcp-close.c - test/test-tcp-close-reset.c - test/test-tcp-connect-error-after-write.c - test/test-tcp-connect-error.c - test/test-tcp-connect-timeout.c - test/test-tcp-connect6-error.c - test/test-tcp-create-socket-early.c - test/test-tcp-flags.c - test/test-tcp-oob.c - test/test-tcp-open.c - test/test-tcp-read-stop.c - test/test-tcp-shutdown-after-write.c - test/test-tcp-try-write.c - test/test-tcp-try-write-error.c - test/test-tcp-unexpected-read.c - test/test-tcp-write-after-connect.c - test/test-tcp-write-fail.c - test/test-tcp-write-queue-order.c - test/test-tcp-write-to-half-open-connection.c - test/test-tcp-writealot.c - test/test-thread-equal.c - test/test-thread.c - test/test-threadpool-cancel.c - test/test-threadpool.c - test/test-timer-again.c - test/test-timer-from-check.c - test/test-timer.c - test/test-tmpdir.c - test/test-tty-duplicate-key.c - test/test-tty.c - test/test-udp-alloc-cb-fail.c - test/test-udp-bind.c - test/test-udp-connect.c - test/test-udp-create-socket-early.c - test/test-udp-dgram-too-big.c - test/test-udp-ipv6.c - test/test-udp-multicast-interface.c - test/test-udp-multicast-interface6.c - test/test-udp-multicast-join.c - test/test-udp-multicast-join6.c - test/test-udp-multicast-ttl.c - test/test-udp-open.c - test/test-udp-options.c - test/test-udp-send-and-recv.c - test/test-udp-send-hang-loop.c - test/test-udp-send-immediate.c - test/test-udp-send-unreachable.c - test/test-udp-try-send.c - test/test-uname.c - test/test-walk-handles.c - test/test-watcher-cross-stop.c) - if(WIN32) - list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0600) + if (CMAKE_SYSTEM_VERSION VERSION_GREATER 10) # Windows 10 + set(windows-version 0x0A00) + elseif (CMAKE_SYSTEM_VERSION VERSION_GREATER 6.3) # Windows 8.1 + set(windows-version 0x0603) + elseif (CMAKE_SYSTEM_VERSION VERSION_GREATER 6.2) # Windows 8 + set(windows-version 0x0602) + elseif (CMAKE_SYSTEM_VERSION VERSION_GREATER 6.1) # Windows 7 + set(windows-version 0x0601) + elseif (CMAKE_SYSTEM_VERSION VERSION_GREATER 6.0) # Windows Vista + set(windows-version 0x0600) + else() + message(FATAL_ERROR "Windows Vista is the minimum version supported") + endif() + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=${windows-version}) list(APPEND uv_libraries - advapi32 + $<$:psapi> iphlpapi - psapi - shell32 - user32 userenv ws2_32) list(APPEND uv_sources @@ -230,6 +115,7 @@ if(WIN32) else() list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + # TODO: This should be replaced with find_package(Threads) if possible # Android has pthread as part of its c library, not as a separate # libpthread.so. list(APPEND uv_libraries pthread) @@ -275,6 +161,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") src/unix/linux-syscalls.c src/unix/procfs-exepath.c src/unix/pthread-fixes.c + src/unix/random-getentropy.c src/unix/random-getrandom.c src/unix/random-sysctl-linux.c src/unix/sysinfo-loadavg.c) @@ -367,19 +254,191 @@ endif() add_library(uv SHARED ${uv_sources}) target_compile_definitions(uv - INTERFACE USING_UV_SHARED=1 - PRIVATE ${uv_defines} BUILDING_UV_SHARED=1) + INTERFACE + USING_UV_SHARED=1 + PRIVATE + BUILDING_UV_SHARED=1 + ${uv_defines}) target_compile_options(uv PRIVATE ${uv_cflags}) -target_include_directories(uv PUBLIC include PRIVATE src) +target_include_directories(uv + PUBLIC + $ + $ + PRIVATE + $) target_link_libraries(uv ${uv_libraries}) add_library(uv_a STATIC ${uv_sources}) target_compile_definitions(uv_a PRIVATE ${uv_defines}) target_compile_options(uv_a PRIVATE ${uv_cflags}) -target_include_directories(uv_a PUBLIC include PRIVATE src) +target_include_directories(uv_a + PUBLIC + $ + $ + PRIVATE + $) target_link_libraries(uv_a ${uv_libraries}) if(LIBUV_BUILD_TESTS) + list(APPEND uv_test_sources + test/blackhole-server.c + test/echo-server.c + test/run-tests.c + test/runner.c + test/test-active.c + test/test-async-null-cb.c + test/test-async.c + test/test-barrier.c + test/test-callback-order.c + test/test-callback-stack.c + test/test-close-fd.c + test/test-close-order.c + test/test-condvar.c + test/test-connect-unspecified.c + test/test-connection-fail.c + test/test-cwd-and-chdir.c + test/test-default-loop-close.c + test/test-delayed-accept.c + test/test-dlerror.c + test/test-eintr-handling.c + test/test-embed.c + test/test-emfile.c + test/test-env-vars.c + test/test-error.c + test/test-fail-always.c + test/test-fork.c + test/test-fs-copyfile.c + test/test-fs-event.c + test/test-fs-poll.c + test/test-fs.c + test/test-fs-readdir.c + test/test-fs-fd-hash.c + test/test-fs-open-flags.c + test/test-get-currentexe.c + test/test-get-loadavg.c + test/test-get-memory.c + test/test-get-passwd.c + test/test-getaddrinfo.c + test/test-gethostname.c + test/test-getnameinfo.c + test/test-getsockname.c + test/test-getters-setters.c + test/test-gettimeofday.c + test/test-handle-fileno.c + test/test-homedir.c + test/test-hrtime.c + test/test-idle.c + test/test-idna.c + test/test-ip4-addr.c + test/test-ip6-addr.c + test/test-ipc-heavy-traffic-deadlock-bug.c + test/test-ipc-send-recv.c + test/test-ipc.c + test/test-loop-alive.c + test/test-loop-close.c + test/test-loop-configure.c + test/test-loop-handles.c + test/test-loop-stop.c + test/test-loop-time.c + test/test-multiple-listen.c + test/test-mutexes.c + test/test-osx-select.c + test/test-pass-always.c + test/test-ping-pong.c + test/test-pipe-bind-error.c + test/test-pipe-close-stdout-read-stdin.c + test/test-pipe-connect-error.c + test/test-pipe-connect-multiple.c + test/test-pipe-connect-prepare.c + test/test-pipe-getsockname.c + test/test-pipe-pending-instances.c + test/test-pipe-sendmsg.c + test/test-pipe-server-close.c + test/test-pipe-set-fchmod.c + test/test-pipe-set-non-blocking.c + test/test-platform-output.c + test/test-poll-close-doesnt-corrupt-stack.c + test/test-poll-close.c + test/test-poll-closesocket.c + test/test-poll-oob.c + test/test-poll.c + test/test-process-priority.c + test/test-process-title-threadsafe.c + test/test-process-title.c + test/test-queue-foreach-delete.c + test/test-random.c + test/test-ref.c + test/test-run-nowait.c + test/test-run-once.c + test/test-semaphore.c + test/test-shutdown-close.c + test/test-shutdown-eof.c + test/test-shutdown-twice.c + test/test-signal-multiple-loops.c + test/test-signal-pending-on-close.c + test/test-signal.c + test/test-socket-buffer-size.c + test/test-spawn.c + test/test-stdio-over-pipes.c + test/test-strscpy.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 + test/test-tcp-close-while-connecting.c + test/test-tcp-close.c + test/test-tcp-close-reset.c + test/test-tcp-connect-error-after-write.c + test/test-tcp-connect-error.c + test/test-tcp-connect-timeout.c + test/test-tcp-connect6-error.c + test/test-tcp-create-socket-early.c + test/test-tcp-flags.c + test/test-tcp-oob.c + test/test-tcp-open.c + test/test-tcp-read-stop.c + test/test-tcp-shutdown-after-write.c + test/test-tcp-try-write.c + test/test-tcp-try-write-error.c + test/test-tcp-unexpected-read.c + test/test-tcp-write-after-connect.c + test/test-tcp-write-fail.c + test/test-tcp-write-queue-order.c + test/test-tcp-write-to-half-open-connection.c + test/test-tcp-writealot.c + test/test-thread-equal.c + test/test-thread.c + test/test-threadpool-cancel.c + test/test-threadpool.c + test/test-timer-again.c + test/test-timer-from-check.c + test/test-timer.c + test/test-tmpdir.c + test/test-tty-duplicate-key.c + test/test-tty-escape-sequence-processing.c + test/test-tty.c + test/test-udp-alloc-cb-fail.c + test/test-udp-bind.c + test/test-udp-connect.c + test/test-udp-create-socket-early.c + test/test-udp-dgram-too-big.c + test/test-udp-ipv6.c + test/test-udp-multicast-interface.c + test/test-udp-multicast-interface6.c + test/test-udp-multicast-join.c + test/test-udp-multicast-join6.c + test/test-udp-multicast-ttl.c + test/test-udp-open.c + test/test-udp-options.c + test/test-udp-send-and-recv.c + test/test-udp-send-hang-loop.c + test/test-udp-send-immediate.c + test/test-udp-send-unreachable.c + test/test-udp-try-send.c + test/test-uname.c + test/test-walk-handles.c + test/test-watcher-cross-stop.c) + add_executable(uv_run_tests ${uv_test_sources}) target_compile_definitions(uv_run_tests PRIVATE ${uv_defines} USING_UV_SHARED=1) @@ -399,23 +458,26 @@ endif() if(UNIX) # Now for some gibbering horrors from beyond the stars... - foreach(x ${uv_libraries}) - set(LIBS "${LIBS} -l${x}") - endforeach(x) + foreach(lib IN LISTS uv_libraries) + list(APPEND LIBS "-l${lib}") + endforeach() + string(REPLACE ";" " " LIBS "${LIBS}") + # Consider setting project version via project() call? file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) - string(REGEX MATCH [0-9]+[.][0-9]+[.][0-9]+ PACKAGE_VERSION "${configure_ac}") - string(REGEX MATCH ^[0-9]+ UV_VERSION_MAJOR "${PACKAGE_VERSION}") + string(REGEX MATCH "([0-9]+)[.][0-9]+[.][0-9]+" PACKAGE_VERSION "${configure_ac}") + set(UV_VERSION_MAJOR "${CMAKE_MATCH_1}") # The version in the filename is mirroring the behaviour of autotools. - set_target_properties(uv PROPERTIES VERSION ${UV_VERSION_MAJOR}.0.0 - SOVERSION ${UV_VERSION_MAJOR}) + set_target_properties(uv PROPERTIES + VERSION ${UV_VERSION_MAJOR}.0.0 + SOVERSION ${UV_VERSION_MAJOR}) set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) set(prefix ${CMAKE_INSTALL_PREFIX}) - configure_file(libuv.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc @ONLY) + configure_file(libuv.pc.in libuv.pc @ONLY) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc + install(FILES ${PROJECT_BINARY_DIR}/libuv.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index f22e124e3b23b9..6f8c45affb7545 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -48,11 +48,11 @@ the [Google C/C++ style guide]. Some of the key points, as well as some additional guidelines, are enumerated below. * Code that is specific to unix-y platforms should be placed in `src/unix`, and - declarations go into `include/uv-unix.h`. + declarations go into `include/uv/unix.h`. * Source code that is Windows-specific goes into `src/win`, and related publicly exported types, functions and macro declarations should generally - be declared in `include/uv-win.h`. + be declared in `include/uv/win.h`. * Names should be descriptive and concise. diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 9c2146dab9da7e..f45ba985e51cb0 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,104 @@ +2020.03.12, Version 1.35.0 (Stable), e45f1ec38db882f8dc17b51f51a6684027034609 + +Changes since version 1.34.2: + +* src: android build fix (David Carlier) + +* build: make code compilable for iOS on Xcode (ssrlive) + +* ibmi: skip unsupported fs test cases (Xu Meng) + +* ibmi: ensure that pipe backlog is not zero (Xu Meng) + +* test,udp6: fix udp_ipv6 test flakiness (Jameson Nash) + +* test: fix fs_event_watch_dir_recursive flakiness (Santiago Gimeno) + +* pipe: disallow listening on an IPC pipe (Witold Kręcicki) + +* build,cmake: improve buil experience (Isabella Muerte) + +* unix: remove support for FreeBSD < 10 (Saúl Ibarra Corretgé) + +* linux: simplify uv__accept() (Ben Noordhuis) + +* linux: assume presence of SOCK_CLOEXEC flag (Ben Noordhuis) + +* linux: simplify uv__dup2_cloexec() (Ben Noordhuis) + +* freebsd,linux: simplify uv__make_socketpair() (Ben Noordhuis) + +* unix: fix error handling in uv__make_socketpair() (Ben Noordhuis) + +* freebsd,linux: simplify uv__make_pipe() (Ben Noordhuis) + +* unix: fix error handling in uv__make_pipe() (Ben Noordhuis) + +* linux: simplify uv__async_eventfd() (Ben Noordhuis) + +* linux: assume the presence of inotify system calls (Ben Noordhuis) + +* doc: strip ICC profile from 2 jpg files (Dominique Dumont) + +* unix: make uv_tcp_keepalive predictable (Manuel BACHMANN) + +* docs: uv_setup_args() may take ownership of argv (Ben Noordhuis) + +* unix: fix error path in uv_setup_args() (Ben Noordhuis) + +* unix: fix size check in uv_get_process_title() (Ben Noordhuis) + +* doc: add erw7 to maintainers (erw7) + +* test: fixed udp4_echo_server implementation (Marek Vavrusa) + +* test: added udp ping benchmark (1,10,100 pingers) (Marek Vavrusa) + +* freebsd,linux: add recvmmsg() + sendmmsg() udp implementation (Marek Vavrusa) + +* win,pipe: DRY/simplify some code paths (Jameson Nash) + +* win: address some style nits (Jameson Nash) + +* win,pipe: ensure `req->event_handle` is defined (Elliot Saba) + +* win,pipe: consolidate overlapped initialization (Elliot Saba) + +* win,pipe: erase event_handle after deleting pointer (Jameson Nash) + +* build: fix android cmake build, build missing file (Ben Noordhuis) + +* test: skip some UDP tests on IBMi (Xu Meng) + +* test: skip some spawn test cases on IBMi (Xu Meng) + +* src: fix wrong method name in comment (TK-one) + +* test: add UV_TIMEOUT_MULTIPLIER environment var (Ben Noordhuis) + +* unix: fix uv_cpu_info always returning UV_ENOTDIR on OpenBSD (Ben Davies) + +* test: skip the pwd_shell test on IBMi (Xu Meng) + +* win,tty: Change to restore cursor shape with uv_tty_reset() (erw7) + +* win,tty: Added set cursor style to CSI sequences (erw7) + +* test: handle EINTR, fix EOF check in poll test (Ben Noordhuis) + +* unix: use socklen_t instead of size_t (Ben Noordhuis) + +* doc: fix header file location (TK-one) + +* unix: fix signal handle closing deferral (Ben Noordhuis) + +* ibmi: set the amount of memory in use to zero (Xu Meng) + +* zos: return on realloc failure in scandir() (Milad Farazmand) + +* zos: fix scandir() error path NULL pointer deref (Ben Noordhuis) + + 2020.01.24, Version 1.34.2 (Stable), f868c9ab0c307525a16fff99fd21e32a6ebc3837 Changes since version 1.34.1: diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 0870b88eb6896b..268251e615a13d 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -17,6 +17,8 @@ libuv is currently managed by the following individuals: - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) * **John Barboza** ([@jbarz](https://github.com/jbarz)) +* **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) + - GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7) * **Richard Lau** ([@richardlau](https://github.com/richardlau)) - GPG key: C82F A3AE 1CBE DC6B E46B 9360 C43C EC45 C17A B93C (pubkey-richardlau) * **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 9a06b9ce4a73e4..68bef4c507cf2c 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -286,6 +286,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer.c \ test/test-tmpdir.c \ test/test-tty-duplicate-key.c \ + test/test-tty-escape-sequence-processing.c \ test/test-tty.c \ test/test-udp-alloc-cb-fail.c \ test/test-udp-bind.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index c040b4c18c8903..9c785da84294db 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -347,6 +347,13 @@ $ make -C out $ ./out/Debug/run-tests ``` +Some tests are timing sensitive. Relaxing test timeouts may be necessary +on slow or overloaded machines: + +```bash +$ env UV_TEST_TIMEOUT_MULTIPLIER=2 ./out/Debug/run-tests # 10s instead of 5s +``` + #### Run one test The list of all tests is in `test/test-list.h`. diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index fba960b6b33731..d05ec8726bbaff 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.34.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.35.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 7cfac85f571b94..d9bf3aef01e577 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -244,6 +244,15 @@ API .. c:function:: char** uv_setup_args(int argc, char** argv) Store the program arguments. Required for getting / setting the process title. + Libuv may take ownership of the memory that `argv` points to. This function + should be called exactly once, at program start-up. + + Example: + + :: + + argv = uv_setup_args(argc, argv); /* May return a copy of argv. */ + .. c:function:: int uv_get_process_title(char* buffer, size_t size) diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst index 5eac1b6df48e29..6437a9d9948148 100644 --- a/deps/uv/docs/src/pipe.rst +++ b/deps/uv/docs/src/pipe.rst @@ -24,6 +24,8 @@ Public members .. c:member:: int uv_pipe_t.ipc Whether this pipe is suitable for handle passing between processes. + Only a connected pipe that will be passing the handles should have this flag + set, not the listening pipe that uv_accept is called on. .. seealso:: The :c:type:`uv_stream_t` members also apply. @@ -35,7 +37,9 @@ API Initialize a pipe handle. The `ipc` argument is a boolean to indicate if this pipe will be used for handle passing between processes (which may - change the bytes on the wire). + change the bytes on the wire). Only a connected pipe that will be + passing the handles should have this flag set, not the listening pipe + that uv_accept is called on. .. c:function:: int uv_pipe_open(uv_pipe_t* handle, uv_file file) diff --git a/deps/uv/docs/src/static/diagrams.key/Data/st0-311.jpg b/deps/uv/docs/src/static/diagrams.key/Data/st0-311.jpg index 439f58109369c37760ce8f9b4710711c17993d8e..08f23a90b6ea37b207550368944f3f727a58e5e6 100644 GIT binary patch literal 14413 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 U{Vf@vRTq*L{vT{Dqk5SCA1ib~G5`Po literal 19328 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 diff --git a/deps/uv/docs/src/static/diagrams.key/Data/st1-475.jpg b/deps/uv/docs/src/static/diagrams.key/Data/st1-475.jpg index ffb21ff22457dac44441fb7e83272c72fbc4d59e..26e676a71a3c1d1c5b965e7db73a7553cd6bf71c 100644 GIT binary patch literal 8284 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 literal 12655 zcmb_>2UwF!*8iJ82vvG7LArG5AX24^2qGXTNRt{m(us9+Ip9@erurAz3k%Q38eu5q=%o6iH-)h#SKetcpm@-$N&=HJOJ3* z`+6B((>4XbqNk94O+)go+_!Rqq0)m+36g&NnMStV@9jl#U2c(As$a5;Qmjlw_6nB95 z(OrK>5EESnanxNG#{dwIfSAwSAL#;OEQlG9j<&u4Kumc`_j9y&2C*cFDSb>$G(oHk z0Hl;of5CQt!G4Z`pqv1p>FE{Z+dTP`X7>UBY9axEW#Ug7Up4?xKLmj4{=ewMbh=)g{rtR?BqRa? z0>oV$?Zrly^~Z}0$vjW|Hl&j1i@^a8~66adl9Ot1y=w|TovW(J(@JafeI@9Q4KVEb?1fA0&~C; zum+%kec%`ZfxsbD5PAqJ1OefPh(M$u3J?{D7UVL-1abp%8{!1J^mpqx+vs0362stz@PnnG_uouJ;(VCX|= z0`xgF2U-lRhJJ+hK)*rfpli@QB7lg3h>7Sdkr`1i{z%{uH^U0pOcr8cal$$ z?@&-s@K7jH7*n`V+@p9-@t)!{#XQ9!B^{+Or6%P~N`J}($^yz(%5lmaDk>@gDm5xg zDnF_OszR!Esu?Qm8TvEgXY|fEoI#z*I8%LQ=*%WH88tt(I<+-*Fm)<*1$965It>|( z0F5S%EloI022CB!7|k9nJ?(i~BU&VF9PK;WZrT+(IGq5U7M%m#L%LkLcDhA+B6?nW zO?rF!2>Lhlo%Bl#Bn*NKdJL`%u?!^)eGF(uIz|~rGsZy148|tLIVK_|0VX{rccw(9 za;8zHBW6x!b!JEA$IPY7L(B&(>?~?5jw~@OWh~!Vj##-_wOHL)lUQq5r`d?vgxQSQ z0@yOyI@#9Q8Q3qd+q1{8m$OfBKskgtOgKU~ayfcA_BgpXbvV5^UvRc_u5&SQsd2e- zJ>_cVT1C(!R1hwRr-&BBFK$L|b#8a==iD9K=(8MWb@klZ&vl*$JY_u7 zyyUzJymxq?^0x7!`4D`De4%_rd=va+{0jWe{Av7M{09Pp0_FnI0yP3Ff-Hi1g294C zf>T0NLaIXELODVs=Sa>eoO3((>fC@ZR9IHnSvW(uUj!;5C*mUVN@P$JCaNgvA(|sP zCPpcyE_PR}NNir5N&K?-1MwR1O$j~;ONk_jE(yG(tfaf-8_CJ@bm#TYKR921ep^ad z%3dl%YDAh!T3Z?=T`P@|5s`6}$&~pnOD}6E8!g)=dm<+<=Ob4tw<^yke_Q^g{FnlR z!c~Phh0lsGMGZxiVx!`rlAMyCQn}LB1+fcm7v5c1Q5IBoRDPqpc#-F#?Zwv@=Tx{= zZmVRg%&DGLwN=egT~Omyb5P4yTUI}(?y6p_zNsOp;iFNdaiFQB8K&8KiRhBfrI<^7 zT69|1wbHd_w0X3hw2QRSIfZQoSGG|_bOy3lq1>uqM#W;e|W%?`{jnJ1giSx8ufS@hgsyWw)9))H=MW|?of zXQgHJ%xdYT?9Hf~qqhWa1>WkmX0vv;ZnB}av9+nV4ZCfA``vAvt&wex?Vg>U-Ag;P zy{3Jd{hEWC!&8S<$BT~1j>~s0-buc*;&jm|#c9=9)j8F9-9^(S-38;S>zd_y;AZ4j z;6`vacP~SdB5xz>Jm@^!JUTqNJOe!ky+pjCyym=>yq|faeGGi^eIdTLd~5v}z+kG^ zU&uewfBvq@-Hf}~0JDIKK-xf$z}_I?pvOVW!P>!jA;cl}A#I^&L+^*qhpC6X4u^!> zg}0%2Q4di|_jK;Py-$AM?f%yXk`Iy}>_(VJ)Ia2Wc<`hmmLSA7$TYhZ*Nr6Yf z+*^~k9fk6Rh3`1tB^E)8{EJqLZx#=fTq>z86)SyR##9#j9(eEn{?~`wA4ba!%G)Xw zDoQK)D_>U8SH)CAs)MT0HO@72wKr-9>-6i|>Mzt+HHbG9G@fnDXku(iY$k7h*i2{% zZrN+~YF+>6^l`Dxrfss_qJ5;pxTCMrp!4%5?N9Ap>Rm0LFMe+9R_d<%qVT1rN3N&3 zSGKq6tL)dRKDoZ?e);~|0mXs(LFK{bA=ROe!MO&bkFg_TR|DzDrsKQ($>+{)4yhV-OL;e+w2`2?>ITTxcd6}-wg;13XXUf85RBL zaZGZ`(`Tt^&tIhH)C)>XOhgPn)e8a*I8~gM7qtm|EY?=JCuF|GZxEB!Os2|-|<^9+AaBYxV8Ue3^mV%_DBr*85B}= zDOPdqd7kRfy$gw0i|Ur?2-QUFAOWCY8asX;-m+*D*TSr!Oo<|teiW5~3ZA*WEfzmrNVWWK|GjG74ED9(%RvQ#P-&?`Qh)hRD7 z^EkZ6FRRhkj{T~H@)HHAAZz`68o42Xvn5AvSQi2S-`vrw6Ol;4DTVIhlaBuo!3jeE z*i`53CJ4Y?>M@)fI-bmIAxkXyb4rFLu)sq*<6##TW4eo6 z*_=98D@FF38?%faT=8}hTfV3Ozu?x&+@uSTV7uueu8{m$r7aL($m ziOVgqgUS5n1OgEK`J|ZuM8>+Ee3!-&fcRjl$bsha%Ep_>RM{u?194-E5^V@(>_K}t zMdc8lFEABBgMD!)DLrsAeO`mZ_EN&5jXtB^Gt&3G07Sv4HTx*eWu7`xsWb&c-#G(M zm>8YeUJw(%plxVuIRzviqCb0)eV$P3zdB`?$A01FC#m|TM5mlu1XikdoNo+wQ3<$svB`wZ9#$K$>#-bLjt7X+@LjdRW4}o7xJbL`5bxG!4 zk7*UI!pW6=(W17e6No z;&bo8fZ!#@#lnS8i6^ET%!=$rh&0Vx%h92Fo~5GilOKn$^a!o2oy=p=VG4T;kYO|U zBb>;5KlAte7YkwRMq{E(>QbHFEdJ)ez4nV|$XIs;YJSx6%;6suy_O%GyY5aXu0J8vMxjpt^x zczG9IW9<^E`=y)DSH?%g(Spl#0B-enWBvUww``)6ue+3e8mQp2d}=SHt)zh8J`PTp zO}dDf6r;>Enkb2Dc1o!U?0-=cJ{7!i_+gA=H=9}tK@?6)l!Y~)Ve3B$iP@bL5iykO z8#8)e{h;p?=_rfsV~sbux#aKQp!}qEvsd`w{?Kb^>rBl3LHU+<2Y< za8G6(lg<)=)tglV1N`rewHPS>C%^Ou?eKWfqd_1;HF_gJ=~B07bSB4=&QH~SSKL0f z{aDWpLDlH^+U2TBoS$@F|GOC-;fails(8$gHm8;v;SMMyK_sFs>U!Yp5&N+^R{k0W z5m{2zL_Xv8)kfbb?Q^_=GFp=B_En|#6UA`8$lDM;^JQ<$B@=g_RRKklpsw0H&mfiA zAK+%kYiX5uv=o&M8@ezyXiq@ff+2kKd>?z8ut>k|@8^qn2pXGjH%(aDFNFjtWpz(|9YY3qZYX z5U94R4G~-HUBD5Mjd^%)ChLgohM5gwrjsw2Kc^cOtH8S<{a$#p`Q5u4z5^As-wdzs zUh-Fo9l%Ql+FK9FY}}dE!lt>vdNr=cEVn7;=-=CSJXZX;UzUQG#EGgXVmu!=hM;#k zXC$z;i%471$`j4&iLFX`9XqT0gSw-+CnkwXqZ_^G3m&F)(_J+O>uX1FEd#yEV;TH1 z3hO_1$KAxrnRF@A|1U=e{O>K&nvmwDgialJ?LOGur=gMtNwLlcHlrY}ikv$n7{x ze_~=mrp{pbMzTzTn~$a;(Pzw?81hYXk-7kf(Dntycv>qn0)5}rX+i!WNt%n)2mJTJ z4aBjT{LpfRX|48zcw8VAlAV}__z5ttL46C0IhO8F5nWN?!&J8{Qm{{7EXglV_+nw! zZlX)MgrK|BcgDlY%bZd&S3wcQ6tQoIwMQ1O1}`;NESlC=G#NbSl}}pQ z=Vd#nypt)4Ys~pMi8C}FOs^Awuj6>8JMZpJ_HToJ+UD^=LA%l8bh(0T7q-NRsuGW1 z>{QiuNDZ>NCOuv)M03JComy|6#g=j1O?lzgS4Lc+RAb??zYbbhl<60meCIdof{>0L zw!`^#RR+h;Zw>wWVZh<@$TAT2QefWBw(&QDUVUF&;jIWeazHBEIDDTZk1l%XFz z#9?$f)hzV}8Q^HCb2s4Ex>2Fvt^n!T>L`(rz}yEjvZRk<7>(6hfiw3^zv=s2OI@?c zvPnx~$ar{@so&_?W)oLN?o$7Fdn=bJTCM_fMS?lhbflSoHPIKm?ek~#gfJN<&+1}c7Gs{hBV6eZP6C-l| z<$uLAEcIY2gW=+coceBAArgsnM`l-)*E|>+;-l?k&}HPk zD#-w8B^oNoxkoNkYTj9YfaBelJJ5O%oz~NRM1LYg^e(44WDGC2qQW%HH>#{t^4)pD zuA4(UD+zUj<$wpvPKR#{pA+$oEXY4&-yxu2*L$6%LRZOWtS5OHOQ z1=#env54XyU+b;9cU*C}hG>fc>PBk5A4Ca80|5x8Vx+)_n)(qWa#K7{(u%j%EK@E1 z>~;7S=cA4L;}*LlZ|bl`E{;g=kdQE>ixUGb0@YHfM;TA%g(qn z<5%ivrIXSR3tRE~a{K93jnyjrQDo^0-xhQ{*BcPEy^@P8iZ|n=j>byNV^D29Hiy6J z%5Dyo;%D=}TQ95lof8Ppm6?Q|Fc|Be328@cQ`HfG_wfV(|E%X0mG2A-0eFJ!KY8d$ z0Cr0)SDfj-gXakegRvIy?<(U?z=mom0cca53u8J6|2k3W?X*T&aAZEnoTlgKc5&pz z_ZW*4n0G~ByI!r0_yVawV(HjNR-7}@w#_G{ljwNA3?#eBh(EiP#a4+#jpbA$9n%Ac zXKI1tw|uTb)#0pVFJ!jvWl~k9jv0-F8mK;MWOo+`2@^D~GNd*H8V*OFRM?<%l&q&cv6Hy8X`iR* z0r+|XkfBP6b3*SJVVn~D5D1-xx1xI+vK!(^52s;#N|A11b=cBzJ2w!pwUQUb?k&Ayet+KwMD!(N@9mEOSx9CsSlzR4Y$jVw9jMN3~h z$-=X{sZOS)r9a)zSviK6;*@~L_}Ew4SXx;S|Ppf-I0 ze^Q1u0cTKazWK=GrRqjHD4lbW!O?NI+mz{%1lE2>8qefuw3|5EV%*F*9ahuIMb^}} zbwRH(O{F2{+KHP4o=%l&5C8Rd`<57>SX{Qh!pemU?~rCAuHC;8xBeE)rv53K8M`>2 zct|ou0KRJz00N-DR2p?(>_LoBwyhS!Rmi`oaQ?-fvJZhGodI=SDFssoSqJv^CnA`{ z1?orPJX3*N<`{U??zB;dJks9Pk39>k|7O^|GH8MRg^7i!f~QO)N`QR z(KA*HTp+sO5dm;xzo=u0X^F>~9vnrMJybTZxA&xKlgJ7_Nb1Sg-S^t6mga8^;Y{NV zpCf`R4n=gfRP+C=%5PKQnQ~E~OOi{gs~X}Td2Ny+TB4lPadtx0XEnZEooWccp#Bt1b=T z+%VT?H|`f=tKBw47CeeLOA^xFj<5EOS^C{Ir_=M!XSXUmYjAt}7LU~|^GtZ3GMY(l zwpx6%f1zsw_9oOB%^X=pO@poJ2&Zx@dg0IhpK^@p)_4H;Vou%?Yz5kS1&yUrW%M{AiE@6Y#%zBQr8&9P;*P-F9|4yLTkjCcv zz0ujF!)N{Ap<1?vXTjai>aeNiDp@cB)^fX;CX~(Ca;DbyrJIT@ZCo}OvL|nd3bQHJ zMf9ew_hl?Tv(;@c#+=w3%V5_QysOZ6QZT+2NT*K{#afhUSHzMw?WMRW?W>I$f-bzz zuA8h(ozgFxK%o0tAT2A*Ap{^oBnvNIS?PIimUtIwWAJTvT51*afsZ!D#;YizD1;>) z6~rPQz~PCO%}A@Q6PE*)w+M|vEk^$T&RPFQw(v95DPSK#hD|uW5Sno=uRni8@W{NQ z1zmY4xS@RFwrNARk`$QMKCv8KP@6i$zNS~gWzj0e;wNn36c_iiSrc4|3Y7#P=UEXw z0kA$t06GWY9WAWkO5p>RMjfxDY@(h_&0@K}jOk|XQwvF1Hy)+5`*OkFl%2EkD%m#j zTyoIG+u^E40yX#FVxt$f*t$HK?``cSMmM`N&3d$aXs)V%HA7L5Y|JspouKfeCPBG6 z;3Q9X0(zKr1J%x9i5k@Z)`EtqV(V4s6U0xh5P-=sutX!LYBCoS6e8RwNOZ>*VeN$H7w=x#$`0t+!10Cx-BnHDcLL8HG(^j;oX?wNAIOg$g`GZ$Fi=~ ztEraU`UkuCH_fBQb&Svlk9G~iZ4hp3iQh|e8Z5Nl>HL&ZxJ@<{_<1?uRhOknK!AYo zm)@hFF+y*oGtphR2oKacFNy%<`HX4a{HN%bxSCuj=YAxZQ=jJ5|EjWB3p5=O^hiK?#5|-<4n| z=N{@R95QcqEu0#ootSrMGZA1J*4fnZeA2wvdE8v^eK+Ibs_ObGrhcV$%u+DAlc&wH{`hU>@S!FVDgRMzY;=Dc6atk*hoBS(P{iT-BXz=}bb#VXbRGt^kvEqJTk~~RDprxKt7nVPjHei1EjQ$x z$@BT3ESHqjqo|jv(Lp-M*i*mZ?#0yd!82yvv$X1hM5HPOQuf?D)6PvD#++_Z4Y^0! z7UKGc?%g%{qqcGMXR|qKJ1LuM(jsW9-iPWLzpi04f}|#m=U5 zZwuT-v`b8!B?m+)B>goxG9;1U+4jZ;wwdnuV5hUZScs~L(*RfeA5s$Wc6II_9~W#F@4BkN_#QV(abzP zy}9KWf!*o!?x&7X;Rsd2aF{gc3D1V5d-F>1oJaoh(eGk=xo3Jc5HPznwyw1xvLQZp zsTr$|PT$hLAJOh4)|A^$@A0hs?KS70L5W1gLx=_UC$2O5N2rf2E9Z8XHpT%OtJdV+ydUw3Hv5jxGm3Ta9ze@-1 zW%xfwfOT7xsLyiC_%<*$Ju(;blOb~lQxGC>LxVZvzpm2$vBL!}0SB%3mo5!C98-=x z0hi!_b*9f)7>2f#zBODbME6c@{Vnm;+yq(CzBYkYz(-H^FbK>RoE~36Ef|&B#V1aRvEHT^YoxQD=_r>k*GExnw`=*RrgC| zL3*K|F6%I2?FAT3xTv<(BAA^M7hjock0|Tp1m^7b^^Ipt9qnFCghc`e$BU1)e+0amGb`WhR}CctdM_V|<*>KEtSkEGt;HH-|ybY;C^8&iL zLzig3mVYr&+lH|Qy+ZV+Uh7SEm^XcR(~}h6S14W>f=Id< zBU+pqIy0`kM~0Sc%l?{Z5;NUf*6#C%KFnRyv~}(6^M+nixGnDG z-6iv8y%fF@jS~#M8!U0Mrvrk3oaK{WI9l|ll4C=ha+MpEV250|pw*<9BAfXLYnoBL z&4-eX1PQ(uFETxote^oPgitB3fz z-)1N7ED7)9z0m{T&bbjFly6RwYX^^RdbS?!wWosv~$Cd||j^5ViGA z6$DMps$1rBUuPe+xJ}ayx2Ky&HVbyXQ|HPI?XJ=-zQeQC{V>Ro$n&Jgu`oId*)cQ;t0uK~zN&-d zaOAv^Y4EDGGbQE6vO)7Jzn0~40>E>4agQC>KUIdkvb(-(bNnk21Y27D$KSAqg@I-J z<>h0_(%CCEbe_4f%~FDPO}hH~Ulm$*j+L&O zqAXvCKm%0uz*VKG_z#{{wm;AwuU@0NPuoHOhU(m2XB&XGi9#&k8wTLtREVZ&<@=W5 zvSNRWv-QJw9xv3!s6R`VBbG{9QRiv2!86pfW@e!yom&n@vT)afv*J9OJLhd^W|q0Y z&~*9aG|6ZMQ#$E26;8B7T%-E@XLIAR^~#=%A_X=w58?{G%bzK|!?&-f9nvp*#C9`e zl-CY5eAqL>o%6h}y36l8``dF7=)7j)UGQiZ0biOmgIV!H(RQrWNrSTbe8!q5#ma~A zP}|f!PpYg(erseKNbYk5{ob_aU*_$G`;jmwkKW`pqI75Mvl{Sknb`SMe&NXCqw#VXIRU~2@zoa?qY|_p6#DYae8%26nk7HI|hsGMsyTT`gCB_p236c_m-I7Ov4x>Ua#@C~5ChD#`dt0r!tmovumW)@FuP$6uFQ>KVgB zQ7HnJuHoR7=Ba52fQDH-0SMCrGZ3@XM0D<4UsB=sUzSD@y9QzUtY*4=?dKEJe2R(a zq|T6Dj1RZOBKGGonJo*maI8)zg3RBBR3-17Yp{D7b4{dxY0Y(K@!Xon{M3wJQh2iD zX|-zlC3~$WRI5YfG4vZVJOl1H+~L@Jt+CQ&Xhm$J>1c22-jdVA2pC%YH}^$9woEIf zBa;OKk6vhCqMI2vbgp#(F_;28 zeQ+WHV9ELD`vdilI!&Wn*2~JkcSUG?gD>XH&?be*ckv1S;peOmJxXd+oLE0e_el?o z4WrPRE2y2tMI)TR9s++JJjCh|I4pJ;jMSQRz)alucHM;WO`CrrgYBEq1VBXvJha+8 zjS0XagN3*Y_V3+XsZ*QOi(Px~AJ&tiHEHEJH?11!+}&Q>(9;7PKXY%xiOmgl|6@=1 N?>yyS+aZMU{|8A0VY&bS diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index bcb163ea0f0356..3cc8efaac10bf6 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -60,6 +60,11 @@ API Enable / disable TCP keep-alive. `delay` is the initial delay in seconds, ignored when `enable` is zero. + After `delay` has been reached, 10 successive probes, each spaced 1 second + from the previous one, will still happen. If the connection is still lost + at the end of this procedure, then the handle is destroyed with a + ``UV_ETIMEDOUT`` error passed to the corresponding callback. + .. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) Enable / disable simultaneous asynchronous accept requests that are diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index 53b1fea4933aae..2ca0736bc6cebc 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -42,6 +42,12 @@ Data types * any traffic, in effect "stealing" the port from the previous listener. */ UV_UDP_REUSEADDR = 4 + /* + * Indicates that the message was received by recvmmsg and that it's not at + * the beginning of the buffer allocated by alloc_cb - so the buffer provided + * must not be freed by the recv_cb callback. + */ + UV_UDP_MMSG_CHUNK = 8 }; .. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status) @@ -62,12 +68,13 @@ Data types * `buf`: :c:type:`uv_buf_t` with the received data. * `addr`: ``struct sockaddr*`` containing the address of the sender. Can be NULL. Valid for the duration of the callback only. - * `flags`: One or more or'ed UV_UDP_* constants. Right now only - ``UV_UDP_PARTIAL`` is used. + * `flags`: One or more or'ed UV_UDP_* constants. The callee is responsible for freeing the buffer, libuv does not reuse it. The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0) - on error. + on error. Don't free the buffer when the UV_UDP_MMSG_CHUNK flag is set. + The final callback receives the whole buffer (containing the first chunk) + with the UV_UDP_MMSG_CHUNK flag cleared. .. note:: The receive callback will be called with `nread` == 0 and `addr` == NULL when there is diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 626cebabd8c9ea..defc0ac44b180c 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -605,7 +605,13 @@ enum uv_udp_flags { * (provided they all set the flag) but only the last one to bind will receive * any traffic, in effect "stealing" the port from the previous listener. */ - UV_UDP_REUSEADDR = 4 + UV_UDP_REUSEADDR = 4, + /* + * Indicates that the message was received by recvmmsg and that it's not at + * the beginning of the buffer allocated by alloc_cb - so the buffer provided + * must not be freed by the recv_cb callback. + */ + UV_UDP_MMSG_CHUNK = 8 }; typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 623ca3ef2cba71..78a2115bb094f9 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 34 -#define UV_VERSION_PATCH 2 +#define UV_VERSION_MINOR 35 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h index 9793eee3e1e166..f5f1d3a3cc2d9b 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -517,7 +517,7 @@ typedef struct { /* eol conversion state */ \ unsigned char previous_eol; \ /* ansi parser state */ \ - unsigned char ansi_parser_state; \ + unsigned short ansi_parser_state; \ unsigned char ansi_csi_argc; \ unsigned short ansi_csi_argv[4]; \ COORD saved_position; \ diff --git a/deps/uv/src/timer.c b/deps/uv/src/timer.c index 8fce7f6472f9fd..9da513fc0c9e40 100644 --- a/deps/uv/src/timer.c +++ b/deps/uv/src/timer.c @@ -87,7 +87,7 @@ int uv_timer_start(uv_timer_t* handle, handle->timer_cb = cb; handle->timeout = clamped_timeout; handle->repeat = repeat; - /* start_id is the second index to be compared in uv__timer_cmp() */ + /* start_id is the second index to be compared in timer_less_than() */ handle->start_id = handle->loop->timer_counter++; heap_insert(timer_heap(handle->loop), diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index a5c47bca05908e..26d337e0a44c0e 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -33,9 +33,12 @@ #include #include +#ifdef __linux__ +#include +#endif + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); -static int uv__async_eventfd(void); int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { @@ -190,36 +193,18 @@ static int uv__async_start(uv_loop_t* loop) { if (loop->async_io_watcher.fd != -1) return 0; - err = uv__async_eventfd(); - if (err >= 0) { - pipefd[0] = err; - pipefd[1] = -1; - } - else if (err == UV_ENOSYS) { - err = uv__make_pipe(pipefd, UV__F_NONBLOCK); -#if defined(__linux__) - /* Save a file descriptor by opening one of the pipe descriptors as - * read/write through the procfs. That file descriptor can then - * function as both ends of the pipe. - */ - if (err == 0) { - char buf[32]; - int fd; - - snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]); - fd = uv__open_cloexec(buf, O_RDWR); - if (fd >= 0) { - uv__close(pipefd[0]); - uv__close(pipefd[1]); - pipefd[0] = fd; - pipefd[1] = fd; - } - } -#endif - } +#ifdef __linux__ + err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (err < 0) + return UV__ERR(errno); + pipefd[0] = err; + pipefd[1] = -1; +#else + err = uv__make_pipe(pipefd, UV__F_NONBLOCK); if (err < 0) return err; +#endif uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); uv__io_start(loop, &loop->async_io_watcher, POLLIN); @@ -253,46 +238,3 @@ void uv__async_stop(uv_loop_t* loop) { uv__close(loop->async_io_watcher.fd); loop->async_io_watcher.fd = -1; } - - -static int uv__async_eventfd(void) { -#if defined(__linux__) - static int no_eventfd2; - static int no_eventfd; - int fd; - - if (no_eventfd2) - goto skip_eventfd2; - - fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK); - if (fd != -1) - return fd; - - if (errno != ENOSYS) - return UV__ERR(errno); - - no_eventfd2 = 1; - -skip_eventfd2: - - if (no_eventfd) - goto skip_eventfd; - - fd = uv__eventfd(0); - if (fd != -1) { - uv__cloexec(fd, 1); - uv__nonblock(fd, 1); - return fd; - } - - if (errno != ENOSYS) - return UV__ERR(errno); - - no_eventfd = 1; - -skip_eventfd: - -#endif - - return UV_ENOSYS; -} diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 04999dce36d193..6d0063513c5020 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -71,20 +71,12 @@ extern char** environ; # include # include # include -# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# if defined(__FreeBSD__) || defined(__linux__) # define uv__accept4 accept4 # endif # if defined(__NetBSD__) # define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) # endif -# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ - defined(__NetBSD__) || defined(__OpenBSD__) -# define UV__SOCK_NONBLOCK SOCK_NONBLOCK -# define UV__SOCK_CLOEXEC SOCK_CLOEXEC -# endif -# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC) -# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC -# endif #endif #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 @@ -179,9 +171,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); - /* Signal handles may not be closed immediately. The signal code will - * itself close uv__make_close_pending whenever appropriate. */ - return; + break; default: assert(0); @@ -246,6 +236,8 @@ int uv__getiovmax(void) { static void uv__finish_close(uv_handle_t* handle) { + uv_signal_t* sh; + /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still * possible for it to be active in the sense that uv__is_active() returns * true. @@ -268,7 +260,20 @@ static void uv__finish_close(uv_handle_t* handle) { case UV_FS_EVENT: case UV_FS_POLL: case UV_POLL: + break; + case UV_SIGNAL: + /* If there are any caught signals "trapped" in the signal pipe, + * we can't call the close callback yet. Reinserting the handle + * into the closing queue makes the event loop spin but that's + * okay because we only need to deliver the pending events. + */ + sh = (uv_signal_t*) handle; + if (sh->caught_signals > sh->dispatched_signals) { + handle->flags ^= UV_HANDLE_CLOSED; + uv__make_close_pending(handle); /* Back into the queue. */ + return; + } break; case UV_NAMED_PIPE: @@ -472,52 +477,32 @@ int uv__accept(int sockfd) { int peerfd; int err; + (void) &err; assert(sockfd >= 0); - while (1) { -#if defined(__linux__) || \ - (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ - defined(__NetBSD__) - static int no_accept4; - - if (no_accept4) - goto skip; - - peerfd = uv__accept4(sockfd, - NULL, - NULL, - UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); - if (peerfd != -1) - return peerfd; - - if (errno == EINTR) - continue; - - if (errno != ENOSYS) - return UV__ERR(errno); - - no_accept4 = 1; -skip: -#endif - + do +#ifdef uv__accept4 + peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); +#else peerfd = accept(sockfd, NULL, NULL); - if (peerfd == -1) { - if (errno == EINTR) - continue; - return UV__ERR(errno); - } +#endif + while (peerfd == -1 && errno == EINTR); - err = uv__cloexec(peerfd, 1); - if (err == 0) - err = uv__nonblock(peerfd, 1); + if (peerfd == -1) + return UV__ERR(errno); - if (err) { - uv__close(peerfd); - return err; - } +#ifndef uv__accept4 + err = uv__cloexec(peerfd, 1); + if (err == 0) + err = uv__nonblock(peerfd, 1); - return peerfd; + if (err != 0) { + uv__close(peerfd); + return err; } +#endif + + return peerfd; } @@ -533,7 +518,7 @@ int uv__close_nocancel(int fd) { #if defined(__APPLE__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" -#if defined(__LP64__) +#if defined(__LP64__) || defined(TARGET_OS_IPHONE) extern int close$NOCANCEL(int); return close$NOCANCEL(fd); #else @@ -1031,54 +1016,30 @@ int uv__open_cloexec(const char* path, int flags) { int uv__dup2_cloexec(int oldfd, int newfd) { +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__) int r; -#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) + r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) return UV__ERR(errno); + return r; -#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) - r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); - if (r != -1) - return r; - if (errno != EINVAL) - return UV__ERR(errno); - /* Fall through. */ -#elif defined(__linux__) - static int no_dup3; - if (!no_dup3) { - do - r = uv__dup3(oldfd, newfd, O_CLOEXEC); - while (r == -1 && errno == EBUSY); - if (r != -1) - return r; - if (errno != ENOSYS) - return UV__ERR(errno); - /* Fall through. */ - no_dup3 = 1; - } -#endif - { - int err; - do - r = dup2(oldfd, newfd); -#if defined(__linux__) - while (r == -1 && errno == EBUSY); #else - while (0); /* Never retry. */ -#endif - - if (r == -1) - return UV__ERR(errno); + int err; + int r; - err = uv__cloexec(newfd, 1); - if (err) { - uv__close(newfd); - return err; - } + r = dup2(oldfd, newfd); /* Never retry. */ + if (r == -1) + return UV__ERR(errno); - return r; + err = uv__cloexec(newfd, 1); + if (err != 0) { + uv__close(newfd); + return err; } + + return r; +#endif } diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index 57bd04e240939b..ef77e127c26c39 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -288,3 +288,28 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv__free(cp_times); return 0; } + + +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags) { +#if __FreeBSD__ >= 11 + return sendmmsg(fd, mmsg, vlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout) { +#if __FreeBSD__ >= 11 + return recvmmsg(fd, mmsg, vlen, flags, timeout); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index 4dd8bb6e3758e3..ff300ea5f8f79f 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -225,22 +225,7 @@ uint64_t uv_get_free_memory(void) { if (get_ibmi_system_status(&rcvr)) return 0; - /* The amount of main storage, in kilobytes, in the system. */ - uint64_t main_storage_size = rcvr.main_storage_size; - - /* The current amount of storage in use for temporary objects. - * in millions (M) of bytes. - */ - uint64_t current_unprotected_storage_used = - rcvr.current_unprotected_storage_used * 1024ULL; - - /* Current unprotected storage includes the storage used for memory - * and disks so it is possible to exceed the amount of main storage. - */ - if (main_storage_size <= current_unprotected_storage_used) - return 0ULL; - - return (main_storage_size - current_unprotected_storage_used) * 1024ULL; + return (uint64_t)rcvr.main_storage_size * 1024ULL; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 47f220000dcd73..598554b607ec42 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -28,9 +28,10 @@ #include /* _POSIX_PATH_MAX, PATH_MAX */ #include /* abort */ #include /* strrchr */ -#include /* O_CLOEXEC, may be */ +#include /* O_CLOEXEC and O_NONBLOCK, if supported. */ #include #include +#include #if defined(__STRICT_ANSI__) # define inline __inline @@ -284,13 +285,12 @@ int uv___stream_fd(const uv_stream_t* handle); #define uv__stream_fd(handle) ((handle)->io_watcher.fd) #endif /* defined(__APPLE__) */ -#ifdef UV__O_NONBLOCK -# define UV__F_NONBLOCK UV__O_NONBLOCK +#ifdef O_NONBLOCK +# define UV__F_NONBLOCK O_NONBLOCK #else # define UV__F_NONBLOCK 1 #endif -int uv__make_socketpair(int fds[2], int flags); int uv__make_pipe(int fds[2], int flags); #if defined(__APPLE__) @@ -328,4 +328,27 @@ int uv__getsockpeername(const uv_handle_t* handle, struct sockaddr* name, int* namelen); +#if defined(__linux__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) +#define HAVE_MMSG 1 +struct uv__mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout); +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags); +#else +#define HAVE_MMSG 0 +#endif + + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index 9b26202fb3366d..42b601adbf898a 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -64,45 +65,17 @@ static void uv__inotify_read(uv_loop_t* loop, static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop); -static int new_inotify_fd(void) { - int err; - int fd; - - fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); - if (fd != -1) - return fd; - - if (errno != ENOSYS) - return UV__ERR(errno); - - fd = uv__inotify_init(); - if (fd == -1) - return UV__ERR(errno); - - err = uv__cloexec(fd, 1); - if (err == 0) - err = uv__nonblock(fd, 1); - - if (err) { - uv__close(fd); - return err; - } - - return fd; -} - - static int init_inotify(uv_loop_t* loop) { - int err; + int fd; if (loop->inotify_fd != -1) return 0; - err = new_inotify_fd(); - if (err < 0) - return err; + fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (fd < 0) + return UV__ERR(errno); - loop->inotify_fd = err; + loop->inotify_fd = fd; uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); @@ -186,7 +159,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { /* No watchers left for this path. Clean up. */ RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); - uv__inotify_rm_watch(loop->inotify_fd, w->wd); + inotify_rm_watch(loop->inotify_fd, w->wd); uv__free(w); } } @@ -194,7 +167,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { static void uv__inotify_read(uv_loop_t* loop, uv__io_t* dummy, unsigned int events) { - const struct uv__inotify_event* e; + const struct inotify_event* e; struct watcher_list* w; uv_fs_event_t* h; QUEUE queue; @@ -219,12 +192,12 @@ static void uv__inotify_read(uv_loop_t* loop, /* Now we have one or more inotify_event structs. */ for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { - e = (const struct uv__inotify_event*)p; + e = (const struct inotify_event*) p; events = 0; - if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY)) + if (e->mask & (IN_ATTRIB|IN_MODIFY)) events |= UV_CHANGE; - if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY)) + if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) events |= UV_RENAME; w = find_watcher(loop, e->wd); @@ -290,16 +263,16 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (err) return err; - events = UV__IN_ATTRIB - | UV__IN_CREATE - | UV__IN_MODIFY - | UV__IN_DELETE - | UV__IN_DELETE_SELF - | UV__IN_MOVE_SELF - | UV__IN_MOVED_FROM - | UV__IN_MOVED_TO; + events = IN_ATTRIB + | IN_CREATE + | IN_MODIFY + | IN_DELETE + | IN_DELETE_SELF + | IN_MOVE_SELF + | IN_MOVED_FROM + | IN_MOVED_TO; - wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); + wd = inotify_add_watch(handle->loop->inotify_fd, path, events); if (wd == -1) return UV__ERR(errno); diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 950387860f04cc..742f26ada8218c 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -26,19 +26,6 @@ #include #include -#if defined(__has_feature) -# if __has_feature(memory_sanitizer) -# define MSAN_ACTIVE 1 -# include -# endif -#endif - -#if defined(__i386__) -# ifndef __NR_socketcall -# define __NR_socketcall 102 -# endif -#endif - #if defined(__arm__) # if defined(__thumb__) || defined(__ARM_EABI__) # define UV_SYSCALL_BASE 0 @@ -47,86 +34,6 @@ # endif #endif /* __arm__ */ -#ifndef __NR_accept4 -# if defined(__x86_64__) -# define __NR_accept4 288 -# elif defined(__i386__) - /* Nothing. Handled through socketcall(). */ -# elif defined(__arm__) -# define __NR_accept4 (UV_SYSCALL_BASE + 366) -# endif -#endif /* __NR_accept4 */ - -#ifndef __NR_eventfd -# if defined(__x86_64__) -# define __NR_eventfd 284 -# elif defined(__i386__) -# define __NR_eventfd 323 -# elif defined(__arm__) -# define __NR_eventfd (UV_SYSCALL_BASE + 351) -# endif -#endif /* __NR_eventfd */ - -#ifndef __NR_eventfd2 -# if defined(__x86_64__) -# define __NR_eventfd2 290 -# elif defined(__i386__) -# define __NR_eventfd2 328 -# elif defined(__arm__) -# define __NR_eventfd2 (UV_SYSCALL_BASE + 356) -# endif -#endif /* __NR_eventfd2 */ - -#ifndef __NR_inotify_init -# if defined(__x86_64__) -# define __NR_inotify_init 253 -# elif defined(__i386__) -# define __NR_inotify_init 291 -# elif defined(__arm__) -# define __NR_inotify_init (UV_SYSCALL_BASE + 316) -# endif -#endif /* __NR_inotify_init */ - -#ifndef __NR_inotify_init1 -# if defined(__x86_64__) -# define __NR_inotify_init1 294 -# elif defined(__i386__) -# define __NR_inotify_init1 332 -# elif defined(__arm__) -# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360) -# endif -#endif /* __NR_inotify_init1 */ - -#ifndef __NR_inotify_add_watch -# if defined(__x86_64__) -# define __NR_inotify_add_watch 254 -# elif defined(__i386__) -# define __NR_inotify_add_watch 292 -# elif defined(__arm__) -# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317) -# endif -#endif /* __NR_inotify_add_watch */ - -#ifndef __NR_inotify_rm_watch -# if defined(__x86_64__) -# define __NR_inotify_rm_watch 255 -# elif defined(__i386__) -# define __NR_inotify_rm_watch 293 -# elif defined(__arm__) -# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318) -# endif -#endif /* __NR_inotify_rm_watch */ - -#ifndef __NR_pipe2 -# if defined(__x86_64__) -# define __NR_pipe2 293 -# elif defined(__i386__) -# define __NR_pipe2 331 -# elif defined(__arm__) -# define __NR_pipe2 (UV_SYSCALL_BASE + 359) -# endif -#endif /* __NR_pipe2 */ - #ifndef __NR_recvmmsg # if defined(__x86_64__) # define __NR_recvmmsg 299 @@ -219,103 +126,7 @@ # endif #endif /* __NR_getrandom */ -int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { -#if defined(__i386__) - unsigned long args[4]; - int r; - - args[0] = (unsigned long) fd; - args[1] = (unsigned long) addr; - args[2] = (unsigned long) addrlen; - args[3] = (unsigned long) flags; - - r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); - - /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does - * a bad flags argument. Try to distinguish between the two cases. - */ - if (r == -1) - if (errno == EINVAL) - if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) - errno = ENOSYS; - - return r; -#elif defined(__NR_accept4) - return syscall(__NR_accept4, fd, addr, addrlen, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__eventfd(unsigned int count) { -#if defined(__NR_eventfd) - return syscall(__NR_eventfd, count); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__eventfd2(unsigned int count, int flags) { -#if defined(__NR_eventfd2) - return syscall(__NR_eventfd2, count, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__inotify_init(void) { -#if defined(__NR_inotify_init) - return syscall(__NR_inotify_init); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__inotify_init1(int flags) { -#if defined(__NR_inotify_init1) - return syscall(__NR_inotify_init1, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) { -#if defined(__NR_inotify_add_watch) - return syscall(__NR_inotify_add_watch, fd, path, mask); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__inotify_rm_watch(int fd, int32_t wd) { -#if defined(__NR_inotify_rm_watch) - return syscall(__NR_inotify_rm_watch, fd, wd); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__pipe2(int pipefd[2], int flags) { -#if defined(__NR_pipe2) - int result; - result = syscall(__NR_pipe2, pipefd, flags); -#if MSAN_ACTIVE - if (!result) - __msan_unpoison(pipefd, sizeof(int[2])); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - +struct uv__mmsghdr; int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index b7729b82aea9ba..2e8fa2a51979c6 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -31,55 +31,6 @@ #include #include -#if defined(__alpha__) -# define UV__O_CLOEXEC 0x200000 -#elif defined(__hppa__) -# define UV__O_CLOEXEC 0x200000 -#elif defined(__sparc__) -# define UV__O_CLOEXEC 0x400000 -#else -# define UV__O_CLOEXEC 0x80000 -#endif - -#if defined(__alpha__) -# define UV__O_NONBLOCK 0x4 -#elif defined(__hppa__) -# define UV__O_NONBLOCK O_NONBLOCK -#elif defined(__mips__) -# define UV__O_NONBLOCK 0x80 -#elif defined(__sparc__) -# define UV__O_NONBLOCK 0x4000 -#else -# define UV__O_NONBLOCK 0x800 -#endif - -#define UV__EFD_CLOEXEC UV__O_CLOEXEC -#define UV__EFD_NONBLOCK UV__O_NONBLOCK - -#define UV__IN_CLOEXEC UV__O_CLOEXEC -#define UV__IN_NONBLOCK UV__O_NONBLOCK - -#define UV__SOCK_CLOEXEC UV__O_CLOEXEC -#if defined(SOCK_NONBLOCK) -# define UV__SOCK_NONBLOCK SOCK_NONBLOCK -#else -# define UV__SOCK_NONBLOCK UV__O_NONBLOCK -#endif - -/* inotify flags */ -#define UV__IN_ACCESS 0x001 -#define UV__IN_MODIFY 0x002 -#define UV__IN_ATTRIB 0x004 -#define UV__IN_CLOSE_WRITE 0x008 -#define UV__IN_CLOSE_NOWRITE 0x010 -#define UV__IN_OPEN 0x020 -#define UV__IN_MOVED_FROM 0x040 -#define UV__IN_MOVED_TO 0x080 -#define UV__IN_CREATE 0x100 -#define UV__IN_DELETE 0x200 -#define UV__IN_DELETE_SELF 0x400 -#define UV__IN_MOVE_SELF 0x800 - struct uv__statx_timestamp { int64_t tv_sec; uint32_t tv_nsec; @@ -110,36 +61,6 @@ struct uv__statx { uint64_t unused1[14]; }; -struct uv__inotify_event { - int32_t wd; - uint32_t mask; - uint32_t cookie; - uint32_t len; - /* char name[0]; */ -}; - -struct uv__mmsghdr { - struct msghdr msg_hdr; - unsigned int msg_len; -}; - -int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); -int uv__eventfd(unsigned int count); -int uv__eventfd2(unsigned int count, int flags); -int uv__inotify_init(void); -int uv__inotify_init1(int flags); -int uv__inotify_add_watch(int fd, const char* path, uint32_t mask); -int uv__inotify_rm_watch(int fd, int32_t wd); -int uv__pipe2(int pipefd[2], int flags); -int uv__recvmmsg(int fd, - struct uv__mmsghdr* mmsg, - unsigned int vlen, - unsigned int flags, - struct timespec* timeout); -int uv__sendmmsg(int fd, - struct uv__mmsghdr* mmsg, - unsigned int vlen, - unsigned int flags); ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 5ba0db022e4a46..713b6c6608a1c8 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -185,7 +185,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { char model[512]; int numcpus = 1; int which[] = {CTL_HW,HW_MODEL}; - int percpu[] = {CTL_HW,HW_CPUSPEED,0}; + int percpu[] = {CTL_KERN,KERN_CPTIME2,0}; size_t size; int i, j; uv_cpu_info_t* cpu_info; @@ -206,17 +206,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { i = 0; *count = numcpus; + which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, ARRAY_SIZE(percpu), &cpuspeed, &size, NULL, 0)) + if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) goto error; size = sizeof(info); - percpu[0] = CTL_KERN; - percpu[1] = KERN_CPTIME2; for (i = 0; i < numcpus; i++) { percpu[2] = i; - size = sizeof(info); - if (sysctl(which, ARRAY_SIZE(percpu), &info, &size, NULL, 0)) + if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0)) goto error; cpu_info = &(*cpu_infos)[i]; diff --git a/deps/uv/src/unix/os390-syscalls.c b/deps/uv/src/unix/os390-syscalls.c index d9abdebaeeda59..4a926c767cc17b 100644 --- a/deps/uv/src/unix/os390-syscalls.c +++ b/deps/uv/src/unix/os390-syscalls.c @@ -43,6 +43,7 @@ int scandir(const char* maindir, struct dirent*** namelist, int (*compar)(const struct dirent**, const struct dirent **)) { struct dirent** nl; + struct dirent** nl_copy; struct dirent* dirent; unsigned count; size_t allocated; @@ -62,19 +63,17 @@ int scandir(const char* maindir, struct dirent*** namelist, 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; - } + if (!copy) + goto error; memcpy(copy, dirent, sizeof(*copy)); - nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); + nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1)); + if (nl_copy == NULL) { + uv__free(copy); + goto error; + } + + nl = nl_copy; nl[count++] = copy; } } @@ -86,6 +85,16 @@ int scandir(const char* maindir, struct dirent*** namelist, *namelist = nl; return count; + +error: + while (count > 0) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index cdf24fa9763cb1..040d57817fa5b1 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -95,8 +95,12 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { if (uv__stream_fd(handle) == -1) return UV_EINVAL; -#if defined(__MVS__) + if (handle->ipc) + return UV_EINVAL; + +#if defined(__MVS__) || defined(__PASE__) /* On zOS, backlog=0 has undefined behaviour */ + /* On IBMi PASE, backlog=0 leads to "Connection refused" error */ if (backlog == 0) backlog = 1; else if (backlog < 0) diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index bb6b76c9fa7005..b021aaeba87d0b 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -112,72 +112,64 @@ static void uv__chld(uv_signal_t* handle, int signum) { } -int uv__make_socketpair(int fds[2], int flags) { -#if defined(__linux__) - static int no_cloexec; - - if (no_cloexec) - goto skip; - - if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0) - return 0; - - /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported. - * Anything else is a genuine error. - */ - if (errno != EINVAL) +static int uv__make_socketpair(int fds[2]) { +#if defined(__FreeBSD__) || defined(__linux__) + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds)) return UV__ERR(errno); - no_cloexec = 1; - -skip: -#endif + return 0; +#else + int err; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) return UV__ERR(errno); - uv__cloexec(fds[0], 1); - uv__cloexec(fds[1], 1); + err = uv__cloexec(fds[0], 1); + if (err == 0) + err = uv__cloexec(fds[1], 1); - if (flags & UV__F_NONBLOCK) { - uv__nonblock(fds[0], 1); - uv__nonblock(fds[1], 1); + if (err != 0) { + uv__close(fds[0]); + uv__close(fds[1]); + return UV__ERR(errno); } return 0; +#endif } int uv__make_pipe(int fds[2], int flags) { -#if defined(__linux__) - static int no_pipe2; - - if (no_pipe2) - goto skip; - - if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0) - return 0; - - if (errno != ENOSYS) +#if defined(__FreeBSD__) || defined(__linux__) + if (pipe2(fds, flags | O_CLOEXEC)) return UV__ERR(errno); - no_pipe2 = 1; - -skip: -#endif - + return 0; +#else if (pipe(fds)) return UV__ERR(errno); - uv__cloexec(fds[0], 1); - uv__cloexec(fds[1], 1); + if (uv__cloexec(fds[0], 1)) + goto fail; + + if (uv__cloexec(fds[1], 1)) + goto fail; if (flags & UV__F_NONBLOCK) { - uv__nonblock(fds[0], 1); - uv__nonblock(fds[1], 1); + if (uv__nonblock(fds[0], 1)) + goto fail; + + if (uv__nonblock(fds[1], 1)) + goto fail; } return 0; + +fail: + uv__close(fds[0]); + uv__close(fds[1]); + return UV__ERR(errno); +#endif } @@ -200,7 +192,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { if (container->data.stream->type != UV_NAMED_PIPE) return UV_EINVAL; else - return uv__make_socketpair(fds, 0); + return uv__make_socketpair(fds); case UV_INHERIT_FD: case UV_INHERIT_STREAM: diff --git a/deps/uv/src/unix/proctitle.c b/deps/uv/src/unix/proctitle.c index 1a8c7a7090e8a6..d124d3c7fcfee0 100644 --- a/deps/uv/src/unix/proctitle.c +++ b/deps/uv/src/unix/proctitle.c @@ -24,17 +24,19 @@ #include #include +struct uv__process_title { + char* str; + size_t len; /* Length of the current process title. */ + size_t cap; /* Maximum capacity. Computed once in uv_setup_args(). */ +}; + extern void uv__set_process_title(const char* title); static uv_mutex_t process_title_mutex; static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static struct uv__process_title process_title; static void* args_mem; -static struct { - char* str; - size_t len; -} process_title; - static void init_process_title_mutex_once(void) { uv_mutex_init(&process_title_mutex); @@ -42,6 +44,7 @@ static void init_process_title_mutex_once(void) { char** uv_setup_args(int argc, char** argv) { + struct uv__process_title pt; char** new_argv; size_t size; char* s; @@ -50,53 +53,69 @@ char** uv_setup_args(int argc, char** argv) { if (argc <= 0) return argv; + pt.str = argv[0]; + pt.len = strlen(argv[0]); + pt.cap = pt.len + 1; + /* Calculate how much memory we need for the argv strings. */ - size = 0; - for (i = 0; i < argc; i++) + size = pt.cap; + for (i = 1; 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*); 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. */ + i = 0; s = (char*) &new_argv[argc + 1]; - for (i = 0; i < argc; i++) { + size = pt.cap; + goto loop; + + for (/* empty */; i < argc; i++) { size = strlen(argv[i]) + 1; + loop: memcpy(s, argv[i], size); new_argv[i] = s; s += size; } new_argv[i] = NULL; + /* argv is not adjacent on z/os, we use just argv[0] on that platform. */ +#ifndef __MVS__ + pt.cap = argv[i - 1] + size - argv[0]; +#endif + + args_mem = new_argv; + process_title = pt; + return new_argv; } int uv_set_process_title(const char* title) { + struct uv__process_title* pt; + size_t len; + + pt = &process_title; + len = strlen(title); + uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); - if (process_title.len != 0) { - /* No need to terminate, byte after is always '\0'. */ - strncpy(process_title.str, title, process_title.len); - uv__set_process_title(title); + if (len >= pt->cap) { + len = 0; + if (pt->cap > 0) + len = pt->cap - 1; } + memcpy(pt->str, title, len); + memset(pt->str + len, '\0', pt->cap - len); + pt->len = len; + uv_mutex_unlock(&process_title_mutex); return 0; diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index ba8fcc204f80a1..1e7e8ac574dfa4 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -331,16 +331,7 @@ int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { void uv__signal_close(uv_signal_t* handle) { - uv__signal_stop(handle); - - /* If there are any caught signals "trapped" in the signal pipe, we can't - * call the close callback yet. Otherwise, add the handle to the finish_close - * queue. - */ - if (handle->caught_signals == handle->dispatched_signals) { - uv__make_close_pending((uv_handle_t*) handle); - } } @@ -472,17 +463,6 @@ static void uv__signal_event(uv_loop_t* loop, if (handle->flags & UV_SIGNAL_ONE_SHOT) uv__signal_stop(handle); - - /* If uv_close was called while there were caught signals that were not - * yet dispatched, the uv__finish_close was deferred. Make close pending - * now if this has happened. - */ - if (handle->caught_signals == handle->dispatched_signals) { - if (handle->signum == 0) - uv__handle_stop(handle); - if (handle->flags & UV_HANDLE_CLOSING) - uv__make_close_pending((uv_handle_t*) handle); - } } bytes -= end; @@ -572,6 +552,5 @@ static void uv__signal_stop(uv_signal_t* handle) { uv__signal_unlock_and_unblock(&saved_sigmask); handle->signum = 0; - if (handle->caught_signals == handle->dispatched_signals) - uv__handle_stop(handle); + uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index fa660f1381315e..d47e9433dbbd83 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -379,8 +379,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { return UV__ERR(errno); #ifdef TCP_KEEPIDLE - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return UV__ERR(errno); + if (on) { + int intvl = 1; /* 1 second; same as default on Win32 */ + int cnt = 10; /* 10 retries; same as hardcoded on Win32 */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return UV__ERR(errno); + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) + return UV__ERR(errno); + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) + return UV__ERR(errno); + } #endif /* Solaris/SmartOS, if you don't support keep-alive, diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 98215f7e1d212b..eb4b8f4ce7f13f 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -32,6 +32,8 @@ #endif #include +#define UV__UDP_DGRAM_MAXSIZE (64 * 1024) + #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #endif @@ -49,6 +51,36 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags); +#if HAVE_MMSG + +#define UV__MMSG_MAXWIDTH 20 + +static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf); +static void uv__udp_sendmmsg(uv_udp_t* handle); + +static int uv__recvmmsg_avail; +static int uv__sendmmsg_avail; +static uv_once_t once = UV_ONCE_INIT; + +static void uv__udp_mmsg_init(void) { + int ret; + int s; + s = uv__socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return; + ret = uv__sendmmsg(s, NULL, 0, 0); + if (ret == 0 || errno != ENOSYS) { + uv__sendmmsg_avail = 1; + uv__recvmmsg_avail = 1; + } else { + ret = uv__recvmmsg(s, NULL, 0, 0, NULL); + if (ret == 0 || errno != ENOSYS) + uv__recvmmsg_avail = 1; + } + uv__close(s); +} + +#endif void uv__udp_close(uv_udp_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); @@ -148,6 +180,60 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } } +#if HAVE_MMSG +static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { + struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH]; + struct iovec iov[UV__MMSG_MAXWIDTH]; + struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH]; + ssize_t nread; + uv_buf_t chunk_buf; + size_t chunks; + int flags; + size_t k; + + /* prepare structures for recvmmsg */ + chunks = buf->len / UV__UDP_DGRAM_MAXSIZE; + if (chunks > ARRAY_SIZE(iov)) + chunks = ARRAY_SIZE(iov); + for (k = 0; k < chunks; ++k) { + iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE; + iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE; + msgs[k].msg_hdr.msg_iov = iov + k; + msgs[k].msg_hdr.msg_iovlen = 1; + msgs[k].msg_hdr.msg_name = peers + k; + msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]); + } + + do + nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); + while (nread == -1 && errno == EINTR); + + if (nread < 1) { + if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK) + handle->recv_cb(handle, 0, buf, NULL, 0); + else + handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0); + } else { + /* count to zero, so the buffer base comes last */ + for (k = nread; k > 0 && handle->recv_cb != NULL;) { + k--; + flags = 0; + if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC) + flags |= UV_UDP_PARTIAL; + if (k != 0) + flags |= UV_UDP_MMSG_CHUNK; + + chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len); + handle->recv_cb(handle, + msgs[k].msg_len, + &chunk_buf, + msgs[k].msg_hdr.msg_name, + flags); + } + } + return nread; +} +#endif static void uv__udp_recvmsg(uv_udp_t* handle) { struct sockaddr_storage peer; @@ -167,13 +253,27 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { do { buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf); if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); return; } assert(buf.base != NULL); +#if HAVE_MMSG + uv_once(&once, uv__udp_mmsg_init); + if (uv__recvmmsg_avail) { + /* Returned space for more than 1 datagram, use it to receive + * multiple datagrams. */ + if (buf.len >= 2 * UV__UDP_DGRAM_MAXSIZE) { + nread = uv__udp_recvmmsg(handle, &buf); + if (nread > 0) + count -= nread; + continue; + } + } +#endif + memset(&h, 0, sizeof(h)); memset(&peer, 0, sizeof(peer)); h.msg_name = &peer; @@ -199,21 +299,120 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags); } + count--; } /* recv_cb callback may decide to pause or close the handle */ while (nread != -1 - && count-- > 0 + && count > 0 && handle->io_watcher.fd != -1 && handle->recv_cb != NULL); } +#if HAVE_MMSG +static void uv__udp_sendmmsg(uv_udp_t* handle) { + uv_udp_send_t* req; + struct uv__mmsghdr h[UV__MMSG_MAXWIDTH]; + struct uv__mmsghdr *p; + QUEUE* q; + ssize_t npkts; + size_t pkts; + size_t i; + + if (QUEUE_EMPTY(&handle->write_queue)) + return; + +write_queue_drain: + for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue); + pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue; + ++pkts, q = QUEUE_HEAD(q)) { + assert(q != NULL); + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + p = &h[pkts]; + memset(p, 0, sizeof(*p)); + if (req->addr.ss_family == AF_UNSPEC) { + p->msg_hdr.msg_name = NULL; + p->msg_hdr.msg_namelen = 0; + } else { + p->msg_hdr.msg_name = &req->addr; + if (req->addr.ss_family == AF_INET6) + p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); + else if (req->addr.ss_family == AF_INET) + p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in); + else if (req->addr.ss_family == AF_UNIX) + p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un); + else { + assert(0 && "unsupported address family"); + abort(); + } + } + h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs; + h[pkts].msg_hdr.msg_iovlen = req->nbufs; + } + + do + npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0); + while (npkts == -1 && errno == EINTR); + + if (npkts < 1) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + return; + for (i = 0, q = QUEUE_HEAD(&handle->write_queue); + i < pkts && q != &handle->write_queue; + ++i, q = QUEUE_HEAD(q)) { + assert(q != NULL); + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + req->status = UV__ERR(errno); + QUEUE_REMOVE(&req->queue); + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } + uv__io_feed(handle->loop, &handle->io_watcher); + return; + } + + for (i = 0, q = QUEUE_HEAD(&handle->write_queue); + i < pkts && q != &handle->write_queue; + ++i, q = QUEUE_HEAD(&handle->write_queue)) { + assert(q != NULL); + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + req->status = req->bufs[0].len; + + /* Sending a datagram is an atomic operation: either all data + * is written or nothing is (and EMSGSIZE is raised). That is + * why we don't handle partial writes. Just pop the request + * off the write queue and onto the completed queue, done. + */ + QUEUE_REMOVE(&req->queue); + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } + + /* couldn't batch everything, continue sending (jump to avoid stack growth) */ + if (!QUEUE_EMPTY(&handle->write_queue)) + goto write_queue_drain; + uv__io_feed(handle->loop, &handle->io_watcher); + return; +} +#endif static void uv__udp_sendmsg(uv_udp_t* handle) { uv_udp_send_t* req; - QUEUE* q; struct msghdr h; + QUEUE* q; ssize_t size; +#if HAVE_MMSG + uv_once(&once, uv__udp_mmsg_init); + if (uv__sendmmsg_avail) { + uv__udp_sendmmsg(handle); + return; + } +#endif + while (!QUEUE_EMPTY(&handle->write_queue)) { q = QUEUE_HEAD(&handle->write_queue); assert(q != NULL); @@ -263,7 +462,6 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { } } - /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. * @@ -653,7 +851,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, } -#if !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__) static int uv__udp_set_source_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, const char* interface_addr, @@ -842,7 +1040,7 @@ int uv_udp_set_source_membership(uv_udp_t* handle, const char* interface_addr, const char* source_addr, uv_membership membership) { -#if !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__) int err; struct sockaddr_storage mcast_addr; struct sockaddr_in* mcast_addr4; @@ -870,7 +1068,7 @@ int uv_udp_set_source_membership(uv_udp_t* handle, src_addr6, membership); } - + err = uv_ip4_addr(source_addr, 0, src_addr4); if (err) return err; @@ -889,7 +1087,7 @@ static int uv__setsockopt(uv_udp_t* handle, int option4, int option6, const void* val, - size_t size) { + socklen_t size) { int r; if (handle->flags & UV_HANDLE_IPV6) @@ -1012,7 +1210,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * and use the general uv__setsockopt_maybe_char call otherwise. */ #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ - defined(__MVS__) + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 277f6497a25234..fc0112a33cf62f 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -264,8 +264,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop, DWORD current_mode = 0; DWORD err = 0; - if (!(handle->flags & UV_HANDLE_PIPESERVER) && - handle->handle != INVALID_HANDLE_VALUE) + if (handle->flags & UV_HANDLE_PIPESERVER) + return UV_EINVAL; + if (handle->handle != INVALID_HANDLE_VALUE) return UV_EBUSY; if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { @@ -312,7 +313,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop, /* Overlapped pipe. Try to associate with IOCP. */ if (CreateIoCompletionPort(pipeHandle, loop->iocp, - (ULONG_PTR)handle, + (ULONG_PTR) handle, 0) == NULL) { handle->flags |= UV_HANDLE_EMULATE_IOCP; } @@ -326,6 +327,38 @@ static int uv_set_pipe_handle(uv_loop_t* loop, } +static int pipe_alloc_accept(uv_loop_t* loop, uv_pipe_t* handle, + uv_pipe_accept_t* req, BOOL firstInstance) { + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + + req->pipeHandle = + CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC | + (firstInstance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0), + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (req->pipeHandle == INVALID_HANDLE_VALUE) { + return 0; + } + + /* Associate it with IOCP so we can get events. */ + if (CreateIoCompletionPort(req->pipeHandle, + loop->iocp, + (ULONG_PTR) handle, + 0) == NULL) { + uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); + } + + /* Stash a handle in the server object for use from places such as + * getsockname and chmod. As we transfer ownership of these to client + * objects, we'll allocate new ones here. */ + handle->handle = req->pipeHandle; + + return 1; +} + + static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { uv_loop_t* loop; uv_pipe_t* handle; @@ -458,7 +491,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { UnregisterWait(handle->read_req.wait_handle); handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } - if (handle->read_req.event_handle) { + if (handle->read_req.event_handle != NULL) { CloseHandle(handle->read_req.event_handle); handle->read_req.event_handle = NULL; } @@ -540,13 +573,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. * If this fails then there's already a pipe server for the given pipe name. */ - handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); - - if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) { + if (!pipe_alloc_accept(loop, + handle, + &handle->pipe.serv.accept_reqs[0], + TRUE)) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) { err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ @@ -556,15 +586,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { goto error; } - if (uv_set_pipe_handle(loop, - handle, - handle->pipe.serv.accept_reqs[0].pipeHandle, - -1, - 0)) { - err = GetLastError(); - goto error; - } - handle->pipe.serv.pending_accepts = NULL; handle->flags |= UV_HANDLE_PIPESERVER; handle->flags |= UV_HANDLE_BOUND; @@ -577,11 +598,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { handle->name = NULL; } - if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) { - CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle); - handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE; - } - return uv_translate_sys_error(err); } @@ -827,29 +843,11 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); - if (!firstInstance) { - assert(req->pipeHandle == INVALID_HANDLE_VALUE); - - req->pipeHandle = CreateNamedPipeW(handle->name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); - - if (req->pipeHandle == INVALID_HANDLE_VALUE) { - SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*) req); - handle->reqs_pending++; - return; - } - - if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) { - CloseHandle(req->pipeHandle); - req->pipeHandle = INVALID_HANDLE_VALUE; - SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*) req); - handle->reqs_pending++; - return; - } + if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; } assert(req->pipeHandle != INVALID_HANDLE_VALUE); @@ -904,7 +902,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { uv__free(item); } else { - pipe_client = (uv_pipe_t*)client; + pipe_client = (uv_pipe_t*) client; /* Find a connection instance that has been connected, but not yet * accepted. */ @@ -925,6 +923,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { req->next_pending = NULL; req->pipeHandle = INVALID_HANDLE_VALUE; + server->handle = INVALID_HANDLE_VALUE; if (!(server->flags & UV_HANDLE_CLOSING)) { uv_pipe_queue_accept(loop, server, req, FALSE); } @@ -955,6 +954,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { return ERROR_NOT_SUPPORTED; } + if (handle->ipc) { + return WSAEINVAL; + } + handle->flags |= UV_HANDLE_LISTENING; INCREASE_ACTIVE_COUNT(loop, handle); handle->stream.serv.connection_cb = cb; @@ -1131,6 +1134,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { } else { memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + assert(req->event_handle != NULL); req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); } @@ -1148,15 +1152,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (!req->event_handle) { - req->event_handle = CreateEvent(NULL, 0, 0, NULL); - if (!req->event_handle) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - } if (req->wait_handle == INVALID_HANDLE_VALUE) { if (!RegisterWaitForSingleObject(&req->wait_handle, - req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req, + req->event_handle, post_completion_read_wait, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); goto error; @@ -1190,8 +1188,16 @@ int uv_pipe_read_start(uv_pipe_t* handle, /* If reading was stopped and then started again, there could still be a read * request pending. */ - if (!(handle->flags & UV_HANDLE_READ_PENDING)) + if (!(handle->flags & UV_HANDLE_READ_PENDING)) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + handle->read_req.event_handle == NULL) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (handle->read_req.event_handle == NULL) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } uv_pipe_queue_read(loop, handle); + } return 0; } @@ -1326,7 +1332,16 @@ static int uv__pipe_write_data(uv_loop_t* loop, req->coalesced = 0; req->event_handle = NULL; req->wait_handle = INVALID_HANDLE_VALUE; + + /* Prepare the overlapped structure. */ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + if (handle->flags & (UV_HANDLE_EMULATE_IOCP | UV_HANDLE_BLOCKING_WRITES)) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (req->event_handle == NULL) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + } req->write_buffer = uv_null_buf_; if (nbufs == 0) { @@ -1375,11 +1390,6 @@ static int uv__pipe_write_data(uv_loop_t* loop, handle->write_queue_size += req->u.io.queued_bytes; } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { /* Using overlapped IO, but wait for completion before returning */ - req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); - if (!req->u.io.overlapped.hEvent) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - result = WriteFile(handle->handle, write_buf.base, write_buf.len, @@ -1388,7 +1398,8 @@ static int uv__pipe_write_data(uv_loop_t* loop, if (!result && GetLastError() != ERROR_IO_PENDING) { err = GetLastError(); - CloseHandle(req->u.io.overlapped.hEvent); + CloseHandle(req->event_handle); + req->event_handle = NULL; return err; } @@ -1399,14 +1410,16 @@ static int uv__pipe_write_data(uv_loop_t* loop, /* Request queued by the kernel. */ req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; - if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) != + if (WaitForSingleObject(req->event_handle, INFINITE) != WAIT_OBJECT_0) { err = GetLastError(); - CloseHandle(req->u.io.overlapped.hEvent); + CloseHandle(req->event_handle); + req->event_handle = NULL; return err; } } - CloseHandle(req->u.io.overlapped.hEvent); + CloseHandle(req->event_handle); + req->event_handle = NULL; REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; @@ -1433,12 +1446,8 @@ static int uv__pipe_write_data(uv_loop_t* loop, } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - req->event_handle = CreateEvent(NULL, 0, 0, NULL); - if (!req->event_handle) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } if (!RegisterWaitForSingleObject(&req->wait_handle, - req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req, + req->event_handle, post_completion_write_wait, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { return GetLastError(); } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index fd34c623d8c543..941c8010d3f699 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -251,7 +251,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { UnregisterWait(req->wait_handle); req->wait_handle = INVALID_HANDLE_VALUE; } - if (req->event_handle) { + if (req->event_handle != NULL) { CloseHandle(req->event_handle); req->event_handle = NULL; } @@ -268,7 +268,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { UnregisterWait(handle->read_req.wait_handle); handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } - if (handle->read_req.event_handle) { + if (handle->read_req.event_handle != NULL) { CloseHandle(handle->read_req.event_handle); handle->read_req.event_handle = NULL; } @@ -428,6 +428,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { /* Prepare the overlapped structure. */ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + assert(req->event_handle != NULL); req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); } @@ -466,7 +467,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { closesocket(accept_socket); /* Destroy the event handle */ if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - CloseHandle(req->u.io.overlapped.hEvent); + CloseHandle(req->event_handle); req->event_handle = NULL; } } @@ -509,7 +510,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { /* Prepare the overlapped structure. */ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - assert(req->event_handle); + assert(req->event_handle != NULL); req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); } @@ -612,8 +613,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 : uv_simultaneous_server_accepts; - if(!handle->tcp.serv.accept_reqs) { - handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*) + if (handle->tcp.serv.accept_reqs == NULL) { + handle->tcp.serv.accept_reqs = uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); if (!handle->tcp.serv.accept_reqs) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); @@ -628,7 +629,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { req->wait_handle = INVALID_HANDLE_VALUE; if (handle->flags & UV_HANDLE_EMULATE_IOCP) { req->event_handle = CreateEvent(NULL, 0, 0, NULL); - if (!req->event_handle) { + if (req->event_handle == NULL) { uv_fatal_error(GetLastError(), "CreateEvent"); } } else { @@ -737,9 +738,9 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && - !handle->read_req.event_handle) { + handle->read_req.event_handle == NULL) { handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); - if (!handle->read_req.event_handle) { + if (handle->read_req.event_handle == NULL) { uv_fatal_error(GetLastError(), "CreateEvent"); } } @@ -862,7 +863,7 @@ int uv_tcp_write(uv_loop_t* loop, memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { req->event_handle = CreateEvent(NULL, 0, 0, NULL); - if (!req->event_handle) { + if (req->event_handle == NULL) { uv_fatal_error(GetLastError(), "CreateEvent"); } req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); @@ -1080,7 +1081,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, UnregisterWait(req->wait_handle); req->wait_handle = INVALID_HANDLE_VALUE; } - if (req->event_handle) { + if (req->event_handle != NULL) { CloseHandle(req->event_handle); req->event_handle = NULL; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 517aa4af79f6e9..488d9b2a14371e 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -46,14 +46,16 @@ #define UNICODE_REPLACEMENT_CHARACTER (0xfffd) -#define ANSI_NORMAL 0x00 -#define ANSI_ESCAPE_SEEN 0x02 -#define ANSI_CSI 0x04 -#define ANSI_ST_CONTROL 0x08 -#define ANSI_IGNORE 0x10 -#define ANSI_IN_ARG 0x20 -#define ANSI_IN_STRING 0x40 -#define ANSI_BACKSLASH_SEEN 0x80 +#define ANSI_NORMAL 0x0000 +#define ANSI_ESCAPE_SEEN 0x0002 +#define ANSI_CSI 0x0004 +#define ANSI_ST_CONTROL 0x0008 +#define ANSI_IGNORE 0x0010 +#define ANSI_IN_ARG 0x0020 +#define ANSI_IN_STRING 0x0040 +#define ANSI_BACKSLASH_SEEN 0x0080 +#define ANSI_EXTENSION 0x0100 +#define ANSI_DECSCUSR 0x0200 #define MAX_INPUT_BUFFER_LENGTH 8192 #define MAX_CONSOLE_CHAR 8192 @@ -62,7 +64,12 @@ #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif -static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); +#define CURSOR_SIZE_SMALL 25 +#define CURSOR_SIZE_LARGE 100 + +static void uv_tty_capture_initial_style( + CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, + CONSOLE_CURSOR_INFO* cursor_info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); static int uv__cancel_read_console(uv_tty_t* handle); @@ -149,6 +156,8 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; +static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info; + /* Determine whether or not ANSI support is enabled. */ static BOOL uv__need_check_vterm_state = TRUE; static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; @@ -183,6 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { DWORD NumberOfEvents; HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + CONSOLE_CURSOR_INFO cursor_info; (void)unused; uv__once_init(); @@ -215,6 +225,11 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { return uv_translate_sys_error(GetLastError()); } + /* Obtain the cursor info with the output handle. */ + if (!GetConsoleCursorInfo(handle, &cursor_info)) { + return uv_translate_sys_error(GetLastError()); + } + /* Obtain the tty_output_lock because the virtual window state is shared * between all uv_tty_t handles. */ uv_sem_wait(&uv_tty_output_lock); @@ -222,8 +237,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { if (uv__need_check_vterm_state) uv__determine_vterm_state(handle); - /* Remember the original console text attributes. */ - uv_tty_capture_initial_style(&screen_buffer_info); + /* Remember the original console text attributes and cursor info. */ + uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info); uv_tty_update_virtual_window(&screen_buffer_info); @@ -274,7 +289,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Set the default console text attributes based on how the console was * configured when libuv started. */ -static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { +static void uv_tty_capture_initial_style( + CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, + CONSOLE_CURSOR_INFO* cursor_info) { static int style_captured = 0; /* Only do this once. @@ -283,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { return; /* Save raw win32 attributes. */ - uv_tty_default_text_attributes = info->wAttributes; + uv_tty_default_text_attributes = screen_buffer_info->wAttributes; /* Convert black text on black background to use white text. */ if (uv_tty_default_text_attributes == 0) @@ -323,6 +340,9 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO) uv_tty_default_inverse = 1; + /* Save the cursor size and the cursor state. */ + uv_tty_default_cursor_info = *cursor_info; + style_captured = 1; } @@ -1230,7 +1250,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { const COORD origin = {0, 0}; const WORD char_attrs = uv_tty_default_text_attributes; - CONSOLE_SCREEN_BUFFER_INFO info; + CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; DWORD count, written; if (*error != ERROR_SUCCESS) { @@ -1251,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { /* Clear the screen buffer. */ retry: - if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { - *error = GetLastError(); - return -1; + if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) { + *error = GetLastError(); + return -1; } - count = info.dwSize.X * info.dwSize.Y; + count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y; if (!(FillConsoleOutputCharacterW(handle->handle, L'\x20', @@ -1279,7 +1299,13 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { /* Move the virtual window up to the top. */ uv_tty_virtual_offset = 0; - uv_tty_update_virtual_window(&info); + uv_tty_update_virtual_window(&screen_buffer_info); + + /* Reset the cursor size and the cursor state. */ + if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) { + *error = GetLastError(); + return -1; + } return 0; } @@ -1618,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle, return 0; } +static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { + CONSOLE_CURSOR_INFO cursor_info; + + if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + if (style == 0) { + cursor_info.dwSize = uv_tty_default_cursor_info.dwSize; + } else if (style <= 2) { + cursor_info.dwSize = CURSOR_SIZE_LARGE; + } else { + cursor_info.dwSize = CURSOR_SIZE_SMALL; + } + + if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + static int uv_tty_write_bufs(uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs, @@ -1645,7 +1696,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left; unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint; unsigned char previous_eol = handle->tty.wr.previous_eol; - unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state; + unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state; /* Store the error here. If we encounter an error, stop trying to do i/o but * keep parsing the buffer so we leave the parser in a consistent state. */ @@ -1761,7 +1812,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, ansi_parser_state = ANSI_NORMAL; continue; - case '8': + case '8': /* Restore the cursor position and text attributes */ FLUSH_TEXT(); uv_tty_restore_state(handle, 1, error); @@ -1779,121 +1830,193 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } } + } else if (ansi_parser_state == ANSI_IGNORE) { + /* We're ignoring this command. Stop only on command character. */ + if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + ansi_parser_state = ANSI_NORMAL; + } + continue; + + } else if (ansi_parser_state == ANSI_DECSCUSR) { + /* So far we've the sequence `ESC [ arg space`, and we're waiting for + * the final command byte. */ + if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + /* Command byte */ + if (utf8_codepoint == 'q') { + /* Change the cursor shape */ + int style = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1; + if (style >= 0 && style <= 6) { + FLUSH_TEXT(); + uv_tty_set_cursor_shape(handle, style, error); + } + } + + /* Sequence ended - go back to normal state. */ + ansi_parser_state = ANSI_NORMAL; + continue; + } + /* Unexpected character, but sequence hasn't ended yet. Ignore the rest + * of the sequence. */ + ansi_parser_state = ANSI_IGNORE; + } else if (ansi_parser_state & ANSI_CSI) { - if (!(ansi_parser_state & ANSI_IGNORE)) { - if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { - /* Parsing a numerical argument */ - - if (!(ansi_parser_state & ANSI_IN_ARG)) { - /* We were not currently parsing a number */ - - /* Check for too many arguments */ - if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { - ansi_parser_state |= ANSI_IGNORE; - continue; - } - - ansi_parser_state |= ANSI_IN_ARG; - handle->tty.wr.ansi_csi_argc++; - handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = - (unsigned short) utf8_codepoint - '0'; + /* So far we've seen `ESC [`, and we may or may not have already parsed + * some of the arguments that follow. */ + + if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { + /* Parse a numerical argument. */ + if (!(ansi_parser_state & ANSI_IN_ARG)) { + /* We were not currently parsing a number, add a new one. */ + /* Check for that there are too many arguments. */ + if (handle->tty.wr.ansi_csi_argc >= + ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state = ANSI_IGNORE; continue; - } else { - /* We were already parsing a number. Parse next digit. */ - uint32_t value = 10 * - handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1]; - - /* Check for overflow. */ - if (value > UINT16_MAX) { - ansi_parser_state |= ANSI_IGNORE; - continue; - } - - handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = - (unsigned short) value + (utf8_codepoint - '0'); - continue; } + ansi_parser_state |= ANSI_IN_ARG; + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) utf8_codepoint - '0'; + continue; + + } else { + /* We were already parsing a number. Parse next digit. */ + uint32_t value = 10 * + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1]; - } else if (utf8_codepoint == ';') { - /* Denotes the end of an argument. */ - if (ansi_parser_state & ANSI_IN_ARG) { - ansi_parser_state &= ~ANSI_IN_ARG; + /* Check for overflow. */ + if (value > UINT16_MAX) { + ansi_parser_state = ANSI_IGNORE; continue; + } - } else { - /* If ANSI_IN_ARG is not set, add another argument and default it - * to 0. */ + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) value + (utf8_codepoint - '0'); + continue; + } - /* Check for too many arguments */ - if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { - ansi_parser_state |= ANSI_IGNORE; - continue; - } + } else if (utf8_codepoint == ';') { + /* Denotes the end of an argument. */ + if (ansi_parser_state & ANSI_IN_ARG) { + ansi_parser_state &= ~ANSI_IN_ARG; + continue; + + } else { + /* If ANSI_IN_ARG is not set, add another argument and default + * it to 0. */ - handle->tty.wr.ansi_csi_argc++; - handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0; + /* Check for too many arguments */ + if (handle->tty.wr.ansi_csi_argc >= + + ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state = ANSI_IGNORE; continue; } - } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) && - handle->tty.wr.ansi_csi_argc == 0) { - /* Ignores '?' if it is the first character after CSI[. This is an - * extension character from the VT100 codeset that is supported and - * used by most ANSI terminals today. */ + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0; continue; + } - } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && - (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) { - int x, y, d; + } else if (utf8_codepoint == '?' && + !(ansi_parser_state & ANSI_IN_ARG) && + !(ansi_parser_state & ANSI_EXTENSION) && + handle->tty.wr.ansi_csi_argc == 0) { + /* Pass through '?' if it is the first character after CSI */ + /* This is an extension character from the VT100 codeset */ + /* that is supported and used by most ANSI terminals today. */ + ansi_parser_state |= ANSI_EXTENSION; + continue; + + } else if (utf8_codepoint == ' ' && + !(ansi_parser_state & ANSI_EXTENSION)) { + /* We expect a command byte to follow after this space. The only + * command that we current support is 'set cursor style'. */ + ansi_parser_state = ANSI_DECSCUSR; + continue; + + } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + /* Command byte */ + if (ansi_parser_state & ANSI_EXTENSION) { + /* Sequence is `ESC [ ? args command`. */ + switch (utf8_codepoint) { + case 'l': + /* Hide the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 0, error); + } + break; + + case 'h': + /* Show the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 1, error); + } + break; + } - /* Command byte */ + } else { + /* Sequence is `ESC [ args command`. */ + int x, y, d; switch (utf8_codepoint) { case 'A': /* cursor up */ FLUSH_TEXT(); - y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + y = -(handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1); uv_tty_move_caret(handle, 0, 1, y, 1, error); break; case 'B': /* cursor down */ FLUSH_TEXT(); - y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + y = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1; uv_tty_move_caret(handle, 0, 1, y, 1, error); break; case 'C': /* cursor forward */ FLUSH_TEXT(); - x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + x = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1; uv_tty_move_caret(handle, x, 1, 0, 1, error); break; case 'D': /* cursor back */ FLUSH_TEXT(); - x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + x = -(handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1); uv_tty_move_caret(handle, x, 1, 0, 1, error); break; case 'E': /* cursor next line */ FLUSH_TEXT(); - y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + y = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1; uv_tty_move_caret(handle, 0, 0, y, 1, error); break; case 'F': /* cursor previous line */ FLUSH_TEXT(); - y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + y = -(handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 1); uv_tty_move_caret(handle, 0, 0, y, 1, error); break; case 'G': /* cursor horizontal move absolute */ FLUSH_TEXT(); - x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + x = (handle->tty.wr.ansi_csi_argc >= 1 && + handle->tty.wr.ansi_csi_argv[0]) ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; uv_tty_move_caret(handle, x, 0, 0, 1, error); break; @@ -1902,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case 'f': /* cursor move absolute */ FLUSH_TEXT(); - y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + y = (handle->tty.wr.ansi_csi_argc >= 1 && + handle->tty.wr.ansi_csi_argv[0]) ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; - x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1]) + x = (handle->tty.wr.ansi_csi_argc >= 2 && + handle->tty.wr.ansi_csi_argv[1]) ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; uv_tty_move_caret(handle, x, 0, y, 0, error); break; @@ -1912,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case 'J': /* Erase screen */ FLUSH_TEXT(); - d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + d = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 0; if (d >= 0 && d <= 2) { uv_tty_clear(handle, d, 1, error); } @@ -1921,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case 'K': /* Erase line */ FLUSH_TEXT(); - d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + d = handle->tty.wr.ansi_csi_argc + ? handle->tty.wr.ansi_csi_argv[0] : 0; if (d >= 0 && d <= 2) { uv_tty_clear(handle, d, 0, error); } @@ -1944,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); uv_tty_restore_state(handle, 0, error); break; - - case 'l': - /* Hide the cursor */ - if (handle->tty.wr.ansi_csi_argc == 1 && - handle->tty.wr.ansi_csi_argv[0] == 25) { - FLUSH_TEXT(); - uv_tty_set_cursor_visibility(handle, 0, error); - } - break; - - case 'h': - /* Show the cursor */ - if (handle->tty.wr.ansi_csi_argc == 1 && - handle->tty.wr.ansi_csi_argv[0] == 25) { - FLUSH_TEXT(); - uv_tty_set_cursor_visibility(handle, 1, error); - } - break; } + } - /* Sequence ended - go back to normal state. */ - ansi_parser_state = ANSI_NORMAL; - continue; + /* Sequence ended - go back to normal state. */ + ansi_parser_state = ANSI_NORMAL; + continue; - } else { - /* We don't support commands that use private mode characters or - * intermediaries. Ignore the rest of the sequence. */ - ansi_parser_state |= ANSI_IGNORE; - continue; - } } else { - /* We're ignoring this command. Stop only on command character. */ - if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { - ansi_parser_state = ANSI_NORMAL; - } + /* We don't support commands that use private mode characters or + * intermediaries. Ignore the rest of the sequence. */ + ansi_parser_state = ANSI_IGNORE; continue; } diff --git a/deps/uv/test/benchmark-list.h b/deps/uv/test/benchmark-list.h index 1e843071c01c3c..29e44c30f025b3 100644 --- a/deps/uv/test/benchmark-list.h +++ b/deps/uv/test/benchmark-list.h @@ -23,6 +23,7 @@ BENCHMARK_DECLARE (sizes) BENCHMARK_DECLARE (loop_count) BENCHMARK_DECLARE (loop_count_timed) BENCHMARK_DECLARE (ping_pongs) +BENCHMARK_DECLARE (ping_udp) BENCHMARK_DECLARE (tcp_write_batch) BENCHMARK_DECLARE (tcp4_pound_100) BENCHMARK_DECLARE (tcp4_pound_1000) diff --git a/deps/uv/test/benchmark-multi-accept.c b/deps/uv/test/benchmark-multi-accept.c index 2f32c0caf4a202..5a186233f580d9 100644 --- a/deps/uv/test/benchmark-multi-accept.c +++ b/deps/uv/test/benchmark-multi-accept.c @@ -218,8 +218,12 @@ static void send_listen_handles(uv_handle_type type, } else ASSERT(0); - - ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1)); + /* We need to initialize this pipe with ipc=0 - this is not a uv_pipe we'll + * be sending handles over, it's just for listening for new connections. + * If we accept a connection then the connected pipe must be initialized + * with ipc=1. + */ + ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 0)); ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME)); ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb)); diff --git a/deps/uv/test/benchmark-ping-udp.c b/deps/uv/test/benchmark-ping-udp.c new file mode 100644 index 00000000000000..a29502a786fd7f --- /dev/null +++ b/deps/uv/test/benchmark-ping-udp.c @@ -0,0 +1,163 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +/* Run the benchmark for this many ms */ +#define TIME 5000 + +typedef struct { + int pongs; + int state; + uv_udp_t udp; + struct sockaddr_in server_addr; +} pinger_t; + +typedef struct buf_s { + uv_buf_t uv_buf_t; + struct buf_s* next; +} buf_t; + +static char PING[] = "PING\n"; + +static uv_loop_t* loop; + +static int completed_pingers; +static unsigned long completed_pings; +static int64_t start_time; + + +static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) { + static char slab[64 * 1024]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void buf_free(const uv_buf_t* buf) { +} + + +static void pinger_close_cb(uv_handle_t* handle) { + pinger_t* pinger; + + pinger = (pinger_t*)handle->data; +#if DEBUG + fprintf(stderr, "ping_pongs: %d roundtrips/s\n", + pinger->pongs / (TIME / 1000)); +#endif + + completed_pings += pinger->pongs; + completed_pingers++; + free(pinger); +} + +static void pinger_write_ping(pinger_t* pinger) { + uv_buf_t buf; + int r; + + buf = uv_buf_init(PING, sizeof(PING) - 1); + r = uv_udp_try_send(&pinger->udp, &buf, 1, + (const struct sockaddr*) &pinger->server_addr); + if (r < 0) + FATAL("uv_udp_send failed"); +} + +static void pinger_read_cb(uv_udp_t* udp, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + ssize_t i; + pinger_t* pinger; + pinger = (pinger_t*)udp->data; + + /* Now we count the pings */ + for (i = 0; i < nread; i++) { + ASSERT(buf->base[i] == PING[pinger->state]); + pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); + if (pinger->state == 0) { + pinger->pongs++; + if (uv_now(loop) - start_time > TIME) { + uv_close((uv_handle_t*)udp, pinger_close_cb); + break; + } + pinger_write_ping(pinger); + } + } + + buf_free(buf); +} + +static void udp_pinger_new(void) { + pinger_t* pinger = malloc(sizeof(*pinger)); + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &pinger->server_addr)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to do NUM_PINGS ping-pongs (connection-less). */ + r = uv_udp_init(loop, &pinger->udp); + ASSERT(r == 0); + + pinger->udp.data = pinger; + + /* Start pinging */ + if (0 != uv_udp_recv_start(&pinger->udp, buf_alloc, pinger_read_cb)) { + FATAL("uv_udp_read_start failed"); + } + pinger_write_ping(pinger); +} + +static int ping_udp(unsigned pingers) { + unsigned i; + + loop = uv_default_loop(); + start_time = uv_now(loop); + + for (i = 0; i < pingers; ++i) { + udp_pinger_new(); + } + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(completed_pingers >= 1); + + fprintf(stderr, "ping_pongs: %d pingers, ~ %lu roundtrips/s\n", + completed_pingers, completed_pings / (TIME/1000)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#define X(PINGERS) \ +BENCHMARK_IMPL(ping_udp##PINGERS) {\ + return ping_udp(PINGERS); \ +} + +X(1) +X(10) +X(100) + +#undef X diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c index a38e975d4841d6..c65142ff901794 100644 --- a/deps/uv/test/echo-server.c +++ b/deps/uv/test/echo-server.c @@ -37,6 +37,7 @@ static uv_tcp_t tcpServer; static uv_udp_t udpServer; static uv_pipe_t pipeServer; static uv_handle_t* server; +static uv_udp_send_t* send_freelist; static void after_write(uv_write_t* req, int status); static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf); @@ -133,6 +134,14 @@ static void echo_alloc(uv_handle_t* handle, buf->len = suggested_size; } +static void slab_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* up to 16 datagrams at once */ + static char slab[16 * 64 * 1024]; + buf->base = slab; + buf->len = sizeof(slab); +} static void on_connection(uv_stream_t* server, int status) { uv_stream_t* stream; @@ -178,35 +187,43 @@ static void on_server_close(uv_handle_t* handle) { ASSERT(handle == server); } +static uv_udp_send_t* send_alloc(void) { + uv_udp_send_t* req = send_freelist; + if (req != NULL) + send_freelist = req->data; + else + req = malloc(sizeof(*req)); + return req; +} -static void on_send(uv_udp_send_t* req, int status); - +static void on_send(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + req->data = send_freelist; + send_freelist = req; +} static void on_recv(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; + if (nread == 0) { + /* Everything OK, but nothing read. */ + return; + } + ASSERT(nread > 0); ASSERT(addr->sa_family == AF_INET); - req = malloc(sizeof(*req)); + uv_udp_send_t* req = send_alloc(); ASSERT(req != NULL); - - sndbuf = *rcvbuf; - ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); -} - - -static void on_send(uv_udp_send_t* req, int status) { - ASSERT(status == 0); - free(req); + sndbuf = uv_buf_init(rcvbuf->base, nread); + ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); } - static int tcp4_echo_start(int port) { struct sockaddr_in addr; int r; @@ -277,8 +294,10 @@ static int tcp6_echo_start(int port) { static int udp4_echo_start(int port) { + struct sockaddr_in addr; int r; + ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr)); server = (uv_handle_t*)&udpServer; serverType = UDP; @@ -288,7 +307,13 @@ static int udp4_echo_start(int port) { return 1; } - r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv); + r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0); + if (r) { + fprintf(stderr, "uv_udp_bind: %s\n", uv_strerror(r)); + return 1; + } + + r = uv_udp_recv_start(&udpServer, slab_alloc, on_recv); if (r) { fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r)); return 1; diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index 2aad6a522ff5e3..3a6452ffdfd067 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -45,6 +45,7 @@ int ipc_helper_bind_twice(void); int ipc_helper_send_zero(void); int stdio_over_pipes_helper(void); void spawn_stdin_stdout(void); +void process_title_big_argv(void); int spawn_tcp_server_helper(void); static int maybe_run_test(int argc, char **argv); @@ -210,7 +211,11 @@ static int maybe_run_test(int argc, char **argv) { notify_parent_process(); ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd))); ASSERT(fd > 2); +# if defined(__PASE__) /* On IBMi PASE, write() returns 1 */ + ASSERT(1 == write(fd, "x", 1)); +# else ASSERT(-1 == write(fd, "x", 1)); +# endif /* !__PASE__ */ return 1; } @@ -235,5 +240,11 @@ static int maybe_run_test(int argc, char **argv) { } #endif /* !_WIN32 */ + if (strcmp(argv[1], "process_title_big_argv_helper") == 0) { + notify_parent_process(); + process_title_big_argv(); + return 0; + } + return run_test(argv[1], 0, 1); } diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index a0f5df8947bac8..bb50b43b304ab6 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -20,6 +20,7 @@ */ #include +#include #include #include "runner.h" @@ -167,6 +168,7 @@ int run_test(const char* test, process_info_t processes[1024]; process_info_t *main_proc; task_entry_t* task; + int timeout_multiplier; int process_count; int result; int status; @@ -249,7 +251,22 @@ int run_test(const char* test, goto out; } - result = process_wait(main_proc, 1, task->timeout); + timeout_multiplier = 1; +#ifndef _WIN32 + do { + const char* var; + + var = getenv("UV_TEST_TIMEOUT_MULTIPLIER"); + if (var == NULL) + break; + + timeout_multiplier = atoi(var); + if (timeout_multiplier <= 0) + timeout_multiplier = 1; + } while (0); +#endif + + result = process_wait(main_proc, 1, task->timeout * timeout_multiplier); if (result == -1) { FATAL("process_wait failed"); } else if (result == -2) { diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c index c3e698e5852cba..3335c881064ffd 100644 --- a/deps/uv/test/test-fs-copyfile.c +++ b/deps/uv/test/test-fs-copyfile.c @@ -199,8 +199,11 @@ TEST_IMPL(fs_copyfile) { touch_file(dst, 0); chmod(dst, S_IRUSR|S_IRGRP|S_IROTH); /* Sets file mode to 444 (read-only). */ r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + /* On IBMi PASE, qsecofr users can overwrite read-only files */ +# ifndef __PASE__ ASSERT(req.result == UV_EACCES); ASSERT(r == UV_EACCES); +# endif uv_fs_req_cleanup(&req); #endif diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index e694d258ea9306..28a6a1ebb3f096 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -285,6 +285,12 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, if (filename && strcmp(filename, file_prefix_in_subdir) == 0) return; #endif + /* It may happen that the "subdir" creation event is captured even though + * we started watching after its actual creation. + */ + if (strcmp(filename, "subdir") == 0) + return; + fs_multievent_cb_called++; ASSERT(handle == &fs_event); ASSERT(status == 0); @@ -300,11 +306,13 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, sizeof(file_prefix_in_subdir) - 1) == 0); #endif - if (fs_event_created + fs_event_removed == fs_event_file_count) { + if (fs_event_created == fs_event_file_count && + fs_multievent_cb_called == fs_event_created) { /* Once we've processed all create events, delete all files */ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0)); } else if (fs_multievent_cb_called == 2 * fs_event_file_count) { /* Once we've processed all create and delete events, stop watching */ + ASSERT(fs_event_removed == fs_event_file_count); uv_close((uv_handle_t*) &timer, close_cb); uv_close((uv_handle_t*) handle, close_cb); } diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 75cefe32d87edf..b6b2b19981bdd4 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -309,6 +309,12 @@ static void chown_root_cb(uv_fs_t* req) { # if defined(__CYGWIN__) /* On Cygwin, uid 0 is invalid (no root). */ ASSERT(req->result == UV_EINVAL); +# elif defined(__PASE__) + /* On IBMi PASE, there is no root user. uid 0 is user qsecofr. + * User may grant qsecofr's privileges, including changing + * the file's ownership to uid 0. + */ + ASSERT(req->result == 0); # else ASSERT(req->result == UV_EPERM); # endif @@ -2223,7 +2229,12 @@ int test_symlink_dir_impl(int type) { #ifdef _WIN32 ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4)); #else +# ifdef __PASE__ + /* On IBMi PASE, st_size returns the length of the symlink itself. */ + ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen("test_dir_symlink")); +# else ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir)); +# endif #endif uv_fs_req_cleanup(&req); diff --git a/deps/uv/test/test-get-memory.c b/deps/uv/test/test-get-memory.c index 6a9a46dc81dcef..4555ba08895e7d 100644 --- a/deps/uv/test/test-get-memory.c +++ b/deps/uv/test/test-get-memory.c @@ -32,14 +32,13 @@ TEST_IMPL(get_memory) { (unsigned long long) total_mem, (unsigned long long) constrained_mem); - /* On IBMi PASE, the amount of memory in use includes storage used for - * memory and disks so it is possible to exceed the amount of main storage. - */ -#ifndef __PASE__ ASSERT(free_mem > 0); -#endif ASSERT(total_mem > 0); + /* On IBMi PASE, the amount of memory in use is always zero. */ +#ifdef __PASE__ + ASSERT(total_mem == free_mem); +#else ASSERT(total_mem > free_mem); - +#endif return 0; } diff --git a/deps/uv/test/test-get-passwd.c b/deps/uv/test/test-get-passwd.c index 8e16fb83c8f1b6..9b5273b315db6f 100644 --- a/deps/uv/test/test-get-passwd.c +++ b/deps/uv/test/test-get-passwd.c @@ -38,7 +38,9 @@ TEST_IMPL(get_passwd) { ASSERT(pwd.shell == NULL); #else len = strlen(pwd.shell); +# ifndef __PASE__ ASSERT(len > 0); +# endif #endif len = strlen(pwd.homedir); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index a6cfc6bb9284bd..003b8d26517570 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -56,10 +56,27 @@ TEST_DECLARE (tty_raw_cancel) TEST_DECLARE (tty_duplicate_vt100_fn_key) TEST_DECLARE (tty_duplicate_alt_modifier_key) TEST_DECLARE (tty_composing_character) +TEST_DECLARE (tty_cursor_up) +TEST_DECLARE (tty_cursor_down) +TEST_DECLARE (tty_cursor_forward) +TEST_DECLARE (tty_cursor_back) +TEST_DECLARE (tty_cursor_next_line) +TEST_DECLARE (tty_cursor_previous_line) +TEST_DECLARE (tty_cursor_horizontal_move_absolute) +TEST_DECLARE (tty_cursor_move_absolute) +TEST_DECLARE (tty_hide_show_cursor) +TEST_DECLARE (tty_set_cursor_shape) +TEST_DECLARE (tty_erase) +TEST_DECLARE (tty_erase_line) +TEST_DECLARE (tty_set_style) +TEST_DECLARE (tty_save_restore_cursor_position) +TEST_DECLARE (tty_full_reset) +TEST_DECLARE (tty_escape_sequence_processing) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) +TEST_DECLARE (stdio_emulate_iocp) TEST_DECLARE (ip6_pton) TEST_DECLARE (connect_unspecified) TEST_DECLARE (ipc_heavy_traffic_deadlock_bug) @@ -242,6 +259,7 @@ TEST_DECLARE (async_null_cb) TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) +TEST_DECLARE (process_title_big_argv) TEST_DECLARE (process_title_threadsafe) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) @@ -453,6 +471,7 @@ TEST_DECLARE (we_get_signal_one_shot) TEST_DECLARE (we_get_signals_mixed) TEST_DECLARE (signal_multiple_loops) TEST_DECLARE (signal_pending_on_close) +TEST_DECLARE (signal_close_loop_alive) TEST_DECLARE (closed_fd_events) #endif #ifdef __APPLE__ @@ -545,10 +564,27 @@ TASK_LIST_START TEST_ENTRY (tty_duplicate_vt100_fn_key) TEST_ENTRY (tty_duplicate_alt_modifier_key) TEST_ENTRY (tty_composing_character) + TEST_ENTRY (tty_cursor_up) + TEST_ENTRY (tty_cursor_down) + TEST_ENTRY (tty_cursor_forward) + TEST_ENTRY (tty_cursor_back) + TEST_ENTRY (tty_cursor_next_line) + TEST_ENTRY (tty_cursor_previous_line) + TEST_ENTRY (tty_cursor_horizontal_move_absolute) + TEST_ENTRY (tty_cursor_move_absolute) + TEST_ENTRY (tty_hide_show_cursor) + TEST_ENTRY (tty_set_cursor_shape) + TEST_ENTRY (tty_erase) + TEST_ENTRY (tty_erase_line) + TEST_ENTRY (tty_set_style) + TEST_ENTRY (tty_save_restore_cursor_position) + TEST_ENTRY (tty_full_reset) + TEST_ENTRY (tty_escape_sequence_processing) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) + TEST_ENTRY (stdio_emulate_iocp) TEST_ENTRY (ip6_pton) TEST_ENTRY (connect_unspecified) TEST_ENTRY (ipc_heavy_traffic_deadlock_bug) @@ -684,11 +720,9 @@ TASK_LIST_START TEST_ENTRY (udp_try_send) TEST_ENTRY (udp_open) - TEST_HELPER (udp_open, udp4_echo_server) TEST_ENTRY (udp_open_twice) TEST_ENTRY (udp_open_bound) TEST_ENTRY (udp_open_connect) - TEST_HELPER (udp_open_connect, udp4_echo_server) #ifndef _WIN32 TEST_ENTRY (udp_send_unix) #endif @@ -788,6 +822,7 @@ TASK_LIST_START TEST_ENTRY (get_currentexe) TEST_ENTRY (process_title) + TEST_ENTRY (process_title_big_argv) TEST_ENTRY (process_title_threadsafe) TEST_ENTRY (cwd_and_chdir) @@ -903,6 +938,7 @@ TASK_LIST_START TEST_ENTRY (we_get_signals_mixed) TEST_ENTRY (signal_multiple_loops) TEST_ENTRY (signal_pending_on_close) + TEST_ENTRY (signal_close_loop_alive) TEST_ENTRY (closed_fd_events) #endif diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index cc2b5fbe59de8c..b3308446f1d81f 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -222,7 +222,10 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { case 1: { /* Read a couple of bytes. */ static char buffer[74]; - r = recv(context->sock, buffer, sizeof buffer, 0); + + do + r = recv(context->sock, buffer, sizeof buffer, 0); + while (r == -1 && errno == EINTR); ASSERT(r >= 0); if (r > 0) { @@ -240,12 +243,16 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { case 3: { /* Read until EAGAIN. */ static char buffer[931]; - r = recv(context->sock, buffer, sizeof buffer, 0); - ASSERT(r >= 0); - while (r > 0) { + for (;;) { + do + r = recv(context->sock, buffer, sizeof buffer, 0); + while (r == -1 && errno == EINTR); + + if (r <= 0) + break; + context->read += r; - r = recv(context->sock, buffer, sizeof buffer, 0); } if (r == 0) { @@ -301,7 +308,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); ASSERT(send_bytes > 0); - r = send(context->sock, buffer, send_bytes, 0); + do + r = send(context->sock, buffer, send_bytes, 0); + while (r == -1 && errno == EINTR); if (r < 0) { ASSERT(got_eagain()); @@ -323,7 +332,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); ASSERT(send_bytes > 0); - r = send(context->sock, buffer, send_bytes, 0); + do + r = send(context->sock, buffer, send_bytes, 0); + while (r == -1 && errno == EINTR); if (r < 0) { ASSERT(got_eagain()); @@ -339,12 +350,18 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); ASSERT(send_bytes > 0); - r = send(context->sock, buffer, send_bytes, 0); + do + r = send(context->sock, buffer, send_bytes, 0); + while (r == -1 && errno == EINTR); + ASSERT(r != 0); + + if (r < 0) { + ASSERT(got_eagain()); + break; + } - if (r <= 0) break; context->sent += r; } - ASSERT(r > 0 || got_eagain()); break; } diff --git a/deps/uv/test/test-process-title.c b/deps/uv/test/test-process-title.c index b49f3bc4264410..35a14809fb3ccd 100644 --- a/deps/uv/test/test-process-title.c +++ b/deps/uv/test/test-process-title.c @@ -74,3 +74,62 @@ TEST_IMPL(process_title) { return 0; } + + +static void exit_cb(uv_process_t* process, int64_t status, int signo) { + ASSERT(status == 0); + ASSERT(signo == 0); + uv_close((uv_handle_t*) process, NULL); +} + + +TEST_IMPL(process_title_big_argv) { + uv_process_options_t options; + uv_process_t process; + size_t exepath_size; + char exepath[1024]; + char jumbo[512]; + char* args[5]; + +#ifdef _WIN32 + /* Remove once https://github.com/libuv/libuv/issues/2667 is fixed. */ + uv_set_process_title("run-tests"); +#endif + + exepath_size = sizeof(exepath) - 1; + ASSERT(0 == uv_exepath(exepath, &exepath_size)); + exepath[exepath_size] = '\0'; + + memset(jumbo, 'x', sizeof(jumbo) - 1); + jumbo[sizeof(jumbo) - 1] = '\0'; + + /* Note: need to pass three arguments, not two, otherwise + * run-tests.c thinks it's the name of a test to run. + */ + args[0] = exepath; + args[1] = "process_title_big_argv_helper"; + args[2] = jumbo; + args[3] = jumbo; + args[4] = NULL; + + memset(&options, 0, sizeof(options)); + options.file = exepath; + options.args = args; + options.exit_cb = exit_cb; + + ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +/* Called by process_title_big_argv_helper. */ +void process_title_big_argv(void) { + char buf[256] = "fail"; + + /* Return value deliberately ignored. */ + uv_get_process_title(buf, sizeof(buf)); + ASSERT(0 != strcmp(buf, "fail")); +} diff --git a/deps/uv/test/test-signal-pending-on-close.c b/deps/uv/test/test-signal-pending-on-close.c index bf8d2793d51f01..23b9ec8d16f1d4 100644 --- a/deps/uv/test/test-signal-pending-on-close.c +++ b/deps/uv/test/test-signal-pending-on-close.c @@ -34,6 +34,11 @@ static char* buf; static int close_cb_called; +static void stop_loop_cb(uv_signal_t* signal, int signum) { + ASSERT(signum == SIGPIPE); + uv_stop(signal->loop); +} + static void signal_cb(uv_signal_t* signal, int signum) { ASSERT(0); } @@ -91,4 +96,24 @@ TEST_IMPL(signal_pending_on_close) { return 0; } -#endif \ No newline at end of file + +TEST_IMPL(signal_close_loop_alive) { + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_signal_init(&loop, &signal_hdl)); + ASSERT(0 == uv_signal_start(&signal_hdl, stop_loop_cb, SIGPIPE)); + uv_unref((uv_handle_t*) &signal_hdl); + + ASSERT(0 == uv_kill(uv_os_getpid(), SIGPIPE)); + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + uv_close((uv_handle_t*) &signal_hdl, close_cb); + ASSERT(1 == uv_loop_alive(&loop)); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_loop_close(&loop)); + ASSERT(1 == close_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index be9e2539aa6562..2b7f5d56d24fd2 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1420,6 +1420,8 @@ TEST_IMPL(spawn_setuid_fails) { int r; /* if root, become nobody. */ + /* On IBMi PASE, there is no nobody user. */ +#ifndef __PASE__ uv_uid_t uid = getuid(); if (uid == 0) { struct passwd* pw; @@ -1428,11 +1430,19 @@ TEST_IMPL(spawn_setuid_fails) { ASSERT(0 == setgid(pw->pw_gid)); ASSERT(0 == setuid(pw->pw_uid)); } +#endif /* !__PASE__ */ init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETUID; + /* On IBMi PASE, there is no root user. User may grant + * root-like privileges, including setting uid to 0. + */ +#if defined(__PASE__) + options.uid = -1; +#else options.uid = 0; +#endif /* These flags should be ignored on Unices. */ options.flags |= UV_PROCESS_WINDOWS_HIDE; @@ -1441,7 +1451,7 @@ TEST_IMPL(spawn_setuid_fails) { options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; r = uv_spawn(uv_default_loop(), &process, &options); -#if defined(__CYGWIN__) +#if defined(__CYGWIN__) || defined(__PASE__) ASSERT(r == UV_EINVAL); #else ASSERT(r == UV_EPERM); @@ -1461,6 +1471,8 @@ TEST_IMPL(spawn_setgid_fails) { int r; /* if root, become nobody. */ + /* On IBMi PASE, there is no nobody user. */ +#ifndef __PASE__ uv_uid_t uid = getuid(); if (uid == 0) { struct passwd* pw; @@ -1469,18 +1481,22 @@ TEST_IMPL(spawn_setgid_fails) { ASSERT(0 == setgid(pw->pw_gid)); ASSERT(0 == setuid(pw->pw_uid)); } +#endif /* !__PASE__ */ init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETGID; -#if defined(__MVS__) + /* On IBMi PASE, there is no root user. User may grant + * root-like privileges, including setting gid to 0. + */ +#if defined(__MVS__) || defined(__PASE__) options.gid = -1; #else options.gid = 0; #endif r = uv_spawn(uv_default_loop(), &process, &options); -#if defined(__CYGWIN__) || defined(__MVS__) +#if defined(__CYGWIN__) || defined(__MVS__) || defined(__PASE__) ASSERT(r == UV_EINVAL); #else ASSERT(r == UV_EPERM); diff --git a/deps/uv/test/test-stdio-over-pipes.c b/deps/uv/test/test-stdio-over-pipes.c index a130ff6a9bc0c1..1aed47122772ab 100644 --- a/deps/uv/test/test-stdio-over-pipes.c +++ b/deps/uv/test/test-stdio-over-pipes.c @@ -94,7 +94,7 @@ static void after_write(uv_write_t* req, int status) { } -static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { +static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) { uv_write_t* req; uv_buf_t wrbuf; int r; @@ -103,11 +103,11 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { if (nread > 0) { output_used += nread; - if (output_used == 12) { + if (output_used % 12 == 0) { ASSERT(memcmp("hello world\n", output, 12) == 0); - wrbuf = uv_buf_init(output, output_used); + wrbuf = uv_buf_init(output, 12); req = malloc(sizeof(*req)); - r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write); + r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write); ASSERT(r == 0); } } @@ -116,10 +116,10 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { } -TEST_IMPL(stdio_over_pipes) { +static void test_stdio_over_pipes(int overlapped) { int r; uv_process_t process; - uv_stdio_container_t stdio[2]; + uv_stdio_container_t stdio[3]; loop = uv_default_loop(); @@ -129,11 +129,15 @@ TEST_IMPL(stdio_over_pipes) { uv_pipe_init(loop, &in, 0); options.stdio = stdio; - options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - options.stdio[0].data.stream = (uv_stream_t*)∈ - options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[1].data.stream = (uv_stream_t*)&out; - options.stdio_count = 2; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | + (overlapped ? UV_OVERLAPPED_PIPE : 0); + options.stdio[0].data.stream = (uv_stream_t*) ∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE | + (overlapped ? UV_OVERLAPPED_PIPE : 0); + options.stdio[1].data.stream = (uv_stream_t*) &out; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = 2; + options.stdio_count = 3; r = uv_spawn(loop, &process, &options); ASSERT(r == 0); @@ -145,13 +149,22 @@ TEST_IMPL(stdio_over_pipes) { ASSERT(r == 0); ASSERT(on_read_cb_called > 1); - ASSERT(after_write_cb_called == 1); + ASSERT(after_write_cb_called == 2); ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 3); - ASSERT(memcmp("hello world\n", output, 12) == 0); - ASSERT(output_used == 12); + ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0); + ASSERT(output_used == 24); MAKE_VALGRIND_HAPPY(); +} + +TEST_IMPL(stdio_over_pipes) { + test_stdio_over_pipes(0); + return 0; +} + +TEST_IMPL(stdio_emulate_iocp) { + test_stdio_over_pipes(1); return 0; } @@ -160,18 +173,19 @@ TEST_IMPL(stdio_over_pipes) { static int on_pipe_read_called; static int after_write_called; -static uv_pipe_t stdin_pipe; -static uv_pipe_t stdout_pipe; +static uv_pipe_t stdin_pipe1; +static uv_pipe_t stdout_pipe1; +static uv_pipe_t stdin_pipe2; +static uv_pipe_t stdout_pipe2; -static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { +static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { ASSERT(nread > 0); ASSERT(memcmp("hello world\n", buf->base, nread) == 0); on_pipe_read_called++; free(buf->base); - uv_close((uv_handle_t*)&stdin_pipe, close_cb); - uv_close((uv_handle_t*)&stdout_pipe, close_cb); + uv_read_stop(pipe); } @@ -204,52 +218,81 @@ int stdio_over_pipes_helper(void) { uv_write_t write_req[ARRAY_SIZE(buffers)]; uv_buf_t buf[ARRAY_SIZE(buffers)]; unsigned int i; + int j; int r; uv_loop_t* loop = uv_default_loop(); ASSERT(UV_NAMED_PIPE == uv_guess_handle(0)); ASSERT(UV_NAMED_PIPE == uv_guess_handle(1)); - r = uv_pipe_init(loop, &stdin_pipe, 0); + r = uv_pipe_init(loop, &stdin_pipe1, 0); + ASSERT(r == 0); + r = uv_pipe_init(loop, &stdout_pipe1, 0); + ASSERT(r == 0); + r = uv_pipe_init(loop, &stdin_pipe2, 0); ASSERT(r == 0); - r = uv_pipe_init(loop, &stdout_pipe, 0); + r = uv_pipe_init(loop, &stdout_pipe2, 0); ASSERT(r == 0); - uv_pipe_open(&stdin_pipe, 0); - uv_pipe_open(&stdout_pipe, 1); + uv_pipe_open(&stdin_pipe1, 0); + uv_pipe_open(&stdout_pipe1, 1); + uv_pipe_open(&stdin_pipe2, 0); + uv_pipe_open(&stdout_pipe2, 1); - /* Unref both stdio handles to make sure that all writes complete. */ - uv_unref((uv_handle_t*)&stdin_pipe); - uv_unref((uv_handle_t*)&stdout_pipe); + for (j = 0; j < 2; j++) { + /* Unref both stdio handles to make sure that all writes complete. */ + uv_unref((uv_handle_t*) &stdin_pipe1); + uv_unref((uv_handle_t*) &stdout_pipe1); + uv_unref((uv_handle_t*) &stdin_pipe2); + uv_unref((uv_handle_t*) &stdout_pipe2); - for (i = 0; i < ARRAY_SIZE(buffers); i++) { - buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); - } + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + buf[i] = uv_buf_init((char*) buffers[i], strlen(buffers[i])); + } - for (i = 0; i < ARRAY_SIZE(buffers); i++) { - r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1, - after_pipe_write); - ASSERT(r == 0); - } + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + r = uv_write(&write_req[i], + (uv_stream_t*) (j == 0 ? &stdout_pipe1 : &stdout_pipe2), + &buf[i], + 1, + after_pipe_write); + ASSERT(r == 0); + } - notify_parent_process(); - uv_run(loop, UV_RUN_DEFAULT); + notify_parent_process(); + uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 7); - ASSERT(on_pipe_read_called == 0); - ASSERT(close_cb_called == 0); + ASSERT(after_write_called == 7 * (j + 1)); + ASSERT(on_pipe_read_called == j); + ASSERT(close_cb_called == 0); - uv_ref((uv_handle_t*)&stdout_pipe); - uv_ref((uv_handle_t*)&stdin_pipe); + uv_ref((uv_handle_t*) &stdout_pipe1); + uv_ref((uv_handle_t*) &stdin_pipe1); + uv_ref((uv_handle_t*) &stdout_pipe2); + uv_ref((uv_handle_t*) &stdin_pipe2); - r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); - ASSERT(r == 0); + r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2), + on_read_alloc, + on_pipe_read); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(after_write_called == 7 * (j + 1)); + ASSERT(on_pipe_read_called == j + 1); + ASSERT(close_cb_called == 0); + } + + uv_close((uv_handle_t*)&stdin_pipe1, close_cb); + uv_close((uv_handle_t*)&stdout_pipe1, close_cb); + uv_close((uv_handle_t*)&stdin_pipe2, close_cb); + uv_close((uv_handle_t*)&stdout_pipe2, close_cb); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 7); - ASSERT(on_pipe_read_called == 1); - ASSERT(close_cb_called == 2); + ASSERT(after_write_called == 14); + ASSERT(on_pipe_read_called == 2); + ASSERT(close_cb_called == 4); MAKE_VALGRIND_HAPPY(); return 0; diff --git a/deps/uv/test/test-tty-escape-sequence-processing.c b/deps/uv/test/test-tty-escape-sequence-processing.c new file mode 100644 index 00000000000000..c4461e91e06cf9 --- /dev/null +++ b/deps/uv/test/test-tty-escape-sequence-processing.c @@ -0,0 +1,1621 @@ +/* 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. + */ + +#ifdef _WIN32 + +#include "task.h" +#include "uv.h" + +#include +#include + +#include +#include + +#define ESC "\033" +#define CSI ESC "[" +#define ST ESC "\\" +#define BEL "\x07" +#define HELLO "Hello" + +#define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define FOREGROUND_BLACK 0 +#define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN) +#define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE) +#define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE) +#define BACKGROUND_WHITE (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) +#define BACKGROUND_BLACK 0 +#define BACKGROUND_YELLOW (BACKGROUND_RED | BACKGROUND_GREEN) +#define BACKGROUND_CYAN (BACKGROUND_GREEN | BACKGROUND_BLUE) +#define BACKGROUND_MAGENTA (BACKGROUND_RED | BACKGROUND_BLUE) + +#define F_INTENSITY 1 +#define FB_INTENSITY 2 +#define B_INTENSITY 5 +#define INVERSE 7 +#define F_INTENSITY_OFF1 21 +#define F_INTENSITY_OFF2 22 +#define B_INTENSITY_OFF 25 +#define INVERSE_OFF 27 +#define F_BLACK 30 +#define F_RED 31 +#define F_GREEN 32 +#define F_YELLOW 33 +#define F_BLUE 34 +#define F_MAGENTA 35 +#define F_CYAN 36 +#define F_WHITE 37 +#define F_DEFAULT 39 +#define B_BLACK 40 +#define B_RED 41 +#define B_GREEN 42 +#define B_YELLOW 43 +#define B_BLUE 44 +#define B_MAGENTA 45 +#define B_CYAN 46 +#define B_WHITE 47 +#define B_DEFAULT 49 + +#define CURSOR_SIZE_SMALL 25 +#define CURSOR_SIZE_MIDDLE 50 +#define CURSOR_SIZE_LARGE 100 + +struct screen_info { + CONSOLE_SCREEN_BUFFER_INFO csbi; + int top; + int width; + int height; + int length; + WORD default_attr; +}; + +struct captured_screen { + char* text; + WORD* attributes; + struct screen_info si; +}; + +static void get_screen_info(uv_tty_t* tty_out, struct screen_info* si) { + ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &(si->csbi))); + si->width = si->csbi.dwSize.X; + si->height = si->csbi.srWindow.Bottom - si->csbi.srWindow.Top + 1; + si->length = si->width * si->height; + si->default_attr = si->csbi.wAttributes; + si->top = si->csbi.srWindow.Top; +} + +static void set_cursor_position(uv_tty_t* tty_out, COORD pos) { + HANDLE handle = tty_out->handle; + CONSOLE_SCREEN_BUFFER_INFO info; + ASSERT(GetConsoleScreenBufferInfo(handle, &info)); + pos.X -= 1; + pos.Y += info.srWindow.Top - 1; + ASSERT(SetConsoleCursorPosition(handle, pos)); +} + +static void get_cursor_position(uv_tty_t* tty_out, COORD* cursor_position) { + HANDLE handle = tty_out->handle; + CONSOLE_SCREEN_BUFFER_INFO info; + ASSERT(GetConsoleScreenBufferInfo(handle, &info)); + cursor_position->X = info.dwCursorPosition.X + 1; + cursor_position->Y = info.dwCursorPosition.Y - info.srWindow.Top + 1; +} + +static void set_cursor_to_home(uv_tty_t* tty_out) { + COORD origin = {1, 1}; + set_cursor_position(tty_out, origin); +} + +static CONSOLE_CURSOR_INFO get_cursor_info(uv_tty_t* tty_out) { + HANDLE handle = tty_out->handle; + CONSOLE_CURSOR_INFO info; + ASSERT(GetConsoleCursorInfo(handle, &info)); + return info; +} + +static void set_cursor_size(uv_tty_t* tty_out, DWORD size) { + CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); + info.dwSize = size; + ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); +} + +static DWORD get_cursor_size(uv_tty_t* tty_out) { + return get_cursor_info(tty_out).dwSize; +} + +static void set_cursor_visibility(uv_tty_t* tty_out, BOOL visible) { + CONSOLE_CURSOR_INFO info = get_cursor_info(tty_out); + info.bVisible = visible; + ASSERT(SetConsoleCursorInfo(tty_out->handle, &info)); +} + +static BOOL get_cursor_visibility(uv_tty_t* tty_out) { + return get_cursor_info(tty_out).bVisible; +} + +static BOOL is_scrolling(uv_tty_t* tty_out, struct screen_info si) { + CONSOLE_SCREEN_BUFFER_INFO info; + ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); + return info.srWindow.Top != si.top; +} + +static void write_console(uv_tty_t* tty_out, char* src) { + int r; + uv_buf_t buf; + + buf.base = src; + buf.len = strlen(buf.base); + + r = uv_try_write((uv_stream_t*) tty_out, &buf, 1); + ASSERT(r >= 0); + ASSERT((unsigned int) r == buf.len); +} + +static void setup_screen(uv_tty_t* tty_out) { + DWORD length, number_of_written; + COORD origin; + CONSOLE_SCREEN_BUFFER_INFO info; + ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); + length = info.dwSize.X * (info.srWindow.Bottom - info.srWindow.Top + 1); + origin.X = 0; + origin.Y = info.srWindow.Top; + ASSERT(FillConsoleOutputCharacter( + tty_out->handle, '.', length, origin, &number_of_written)); + ASSERT(length == number_of_written); +} + +static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) { + DWORD length, number_of_written; + COORD origin; + CONSOLE_SCREEN_BUFFER_INFO info; + ASSERT(GetConsoleScreenBufferInfo(tty_out->handle, &info)); + length = (info.srWindow.Bottom - info.srWindow.Top + 1) * info.dwSize.X - 1; + origin.X = 0; + origin.Y = info.srWindow.Top; + FillConsoleOutputCharacterA( + tty_out->handle, ' ', length, origin, &number_of_written); + ASSERT(length == number_of_written); + FillConsoleOutputAttribute( + tty_out->handle, si->default_attr, length, origin, &number_of_written); + ASSERT(length == number_of_written); +} + +static void free_screen(struct captured_screen* cs) { + free(cs->text); + cs->text = NULL; + free(cs->attributes); + cs->attributes = NULL; +} + +static void capture_screen(uv_tty_t* tty_out, struct captured_screen* cs) { + DWORD length; + COORD origin; + get_screen_info(tty_out, &(cs->si)); + origin.X = 0; + origin.Y = cs->si.csbi.srWindow.Top; + cs->text = malloc(cs->si.length * sizeof(*cs->text)); + ASSERT(cs->text != NULL); + cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes)); + ASSERT(cs->attributes != NULL); + ASSERT(ReadConsoleOutputCharacter( + tty_out->handle, cs->text, cs->si.length, origin, &length)); + ASSERT((unsigned int) cs->si.length == length); + ASSERT(ReadConsoleOutputAttribute( + tty_out->handle, cs->attributes, cs->si.length, origin, &length)); + ASSERT((unsigned int) cs->si.length == length); +} + +static void make_expect_screen_erase(struct captured_screen* cs, + COORD cursor_position, + int dir, + BOOL entire_screen) { + /* beginning of line */ + char* start; + char* end; + start = cs->text + cs->si.width * (cursor_position.Y - 1); + if (dir == 0) { + if (entire_screen) { + /* erase to end of screen */ + end = cs->text + cs->si.length; + } else { + /* erase to end of line */ + end = start + cs->si.width; + } + /* erase from postition of cursor */ + start += cursor_position.X - 1; + } else if (dir == 1) { + /* erase to position of cursor */ + end = start + cursor_position.X; + if (entire_screen) { + /* erase form beginning of screen */ + start = cs->text; + } + } else if (dir == 2) { + if (entire_screen) { + /* erase form beginning of screen */ + start = cs->text; + /* erase to end of screen */ + end = cs->text + cs->si.length; + } else { + /* erase to end of line */ + end = start + cs->si.width; + } + } else { + ASSERT(FALSE); + } + ASSERT(start < end); + ASSERT(end - cs->text <= cs->si.length); + for (; start < end; start++) { + *start = ' '; + } +} + +static void make_expect_screen_write(struct captured_screen* cs, + COORD cursor_position, + const char* text) { + /* postion of cursor */ + char* start; + start = cs->text + cs->si.width * (cursor_position.Y - 1) + + cursor_position.X - 1; + size_t length = strlen(text); + size_t remain_length = cs->si.length - (cs->text - start); + length = length > remain_length ? remain_length : length; + memcpy(start, text, length); +} + +static void make_expect_screen_set_attr(struct captured_screen* cs, + COORD cursor_position, + size_t length, + WORD attr) { + WORD* start; + start = cs->attributes + cs->si.width * (cursor_position.Y - 1) + + cursor_position.X - 1; + size_t remain_length = cs->si.length - (cs->attributes - start); + length = length > remain_length ? remain_length : length; + while (length) { + *start = attr; + start++; + length--; + } +} + +static BOOL compare_screen(uv_tty_t* tty_out, + struct captured_screen* actual, + struct captured_screen* expect) { + int line, col; + BOOL result = TRUE; + int current = 0; + ASSERT(actual->text); + ASSERT(actual->attributes); + ASSERT(expect->text); + ASSERT(expect->attributes); + if (actual->si.length != expect->si.length) { + return FALSE; + } + if (actual->si.width != expect->si.width) { + return FALSE; + } + if (actual->si.height != expect->si.height) { + return FALSE; + } + while (current < actual->si.length) { + if (*(actual->text + current) != *(expect->text + current)) { + line = current / actual->si.width + 1; + col = current - actual->si.width * (line - 1) + 1; + fprintf(stderr, + "line:%d col:%d expected character '%c' but found '%c'\n", + line, + col, + *(expect->text + current), + *(actual->text + current)); + result = FALSE; + } + if (*(actual->attributes + current) != *(expect->attributes + current)) { + line = current / actual->si.width + 1; + col = current - actual->si.width * (line - 1) + 1; + fprintf(stderr, + "line:%d col:%d expected attributes '%u' but found '%u'\n", + line, + col, + *(expect->attributes + current), + *(actual->attributes + current)); + result = FALSE; + } + current++; + } + clear_screen(tty_out, &expect->si); + free_screen(expect); + free_screen(actual); + return result; +} + +static void initialize_tty(uv_tty_t* tty_out) { + int r; + int ttyout_fd; + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED); + + handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CONSOLE_TEXTMODE_BUFFER, + 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); +} + +static void terminate_tty(uv_tty_t* tty_out) { + set_cursor_to_home(tty_out); + uv_close((uv_handle_t*) tty_out, NULL); +} + +TEST_IMPL(tty_cursor_up) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor up one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sA", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor up nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dA", CSI, si.height / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor up from Window top does nothing */ + cursor_pos_old.X = 1; + cursor_pos_old.Y = 1; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sA", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_down) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor down one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sB", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor down nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dB", CSI, si.height / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor down from bottom line does nothing */ + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sB", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_forward) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor forward one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sC", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X + 1 == cursor_pos.X); + + /* cursor forward nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dC", CSI, si.width / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X + si.width / 4 == cursor_pos.X); + + /* cursor forward from end of line does nothing*/ + cursor_pos_old.X = si.width; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sC", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor forward from end of screen does nothing */ + cursor_pos_old.X = si.width; + cursor_pos_old.Y = si.height; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sC", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_back) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor back one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sD", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X - 1 == cursor_pos.X); + + /* cursor back nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dD", CSI, si.width / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X - si.width / 4 == cursor_pos.X); + + /* cursor back from beginning of line does nothing */ + cursor_pos_old.X = 1; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sD", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(cursor_pos_old.X == cursor_pos.X); + + /* cursor back from top of screen does nothing */ + cursor_pos_old.X = 1; + cursor_pos_old.Y = 1; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sD", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(1 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_next_line) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor next line one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sE", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + + /* cursor next line nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dE", CSI, si.height / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + + /* cursor next line from buttom row moves beginning of line */ + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sE", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_previous_line) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* cursor previous line one times if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sF", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + + /* cursor previous line nth times */ + cursor_pos_old = cursor_pos; + snprintf(buffer, sizeof(buffer), "%s%dF", CSI, si.height / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + + /* cursor previous line from top of screen does nothing */ + cursor_pos_old.X = 1; + cursor_pos_old.Y = 1; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, sizeof(buffer), "%sD", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(1 == cursor_pos.Y); + ASSERT(1 == cursor_pos.X); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_horizontal_move_absolute) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* Move to beginning of line if omitted argument */ + snprintf(buffer, sizeof(buffer), "%sG", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(1 == cursor_pos.X); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + + /* Move cursor to nth character */ + snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(si.width / 4 == cursor_pos.X); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + + /* Moving out of screen will fit within screen */ + snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width + 1); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(si.width == cursor_pos.X); + ASSERT(cursor_pos_old.Y == cursor_pos.Y); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_cursor_move_absolute) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos.X = si.width / 2; + cursor_pos.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos); + + /* Move the cursor to home if omitted arguments */ + snprintf(buffer, sizeof(buffer), "%sH", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(1 == cursor_pos.X); + ASSERT(1 == cursor_pos.Y); + + /* Move the cursor to the middle of the screen */ + snprintf( + buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width / 2); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(si.width / 2 == cursor_pos.X); + ASSERT(si.height / 2 == cursor_pos.Y); + + /* Moving out of screen will fit within screen */ + snprintf( + buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width + 1); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(si.width == cursor_pos.X); + ASSERT(si.height / 2 == cursor_pos.Y); + + snprintf( + buffer, sizeof(buffer), "%s%d;%df", CSI, si.height + 1, si.width / 2); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(si.width / 2 == cursor_pos.X); + ASSERT(si.height == cursor_pos.Y); + ASSERT(!is_scrolling(&tty_out, si)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_hide_show_cursor) { + uv_tty_t tty_out; + uv_loop_t* loop; + char buffer[1024]; + BOOL saved_cursor_visibility; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + saved_cursor_visibility = get_cursor_visibility(&tty_out); + + /* Hide the cursor */ + set_cursor_visibility(&tty_out, TRUE); + snprintf(buffer, sizeof(buffer), "%s?25l", CSI); + write_console(&tty_out, buffer); + ASSERT(!get_cursor_visibility(&tty_out)); + + /* Show the cursor */ + set_cursor_visibility(&tty_out, FALSE); + snprintf(buffer, sizeof(buffer), "%s?25h", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_visibility(&tty_out)); + + set_cursor_visibility(&tty_out, saved_cursor_visibility); + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_erase) { + int dir; + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos; + char buffer[1024]; + struct captured_screen actual = {0}, expect = {0}; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + /* Erase to below if omitted argument */ + dir = 0; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%sJ", CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase to below(dir = 0) */ + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase to above */ + dir = 1; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase All */ + dir = 2; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, TRUE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dJ", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_erase_line) { + int dir; + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos; + char buffer[1024]; + struct captured_screen actual = {0}, expect = {0}; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + /* Erase to right if omitted arguments */ + dir = 0; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%sK", CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase to right(dir = 0) */ + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase to Left */ + dir = 1; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Erase All */ + dir = 2; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + make_expect_screen_erase(&expect, cursor_pos, dir, FALSE); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%dK", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_set_cursor_shape) { + uv_tty_t tty_out; + uv_loop_t* loop; + DWORD saved_cursor_size; + char buffer[1024]; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + saved_cursor_size = get_cursor_size(&tty_out); + + /* cursor size large if omitted arguments */ + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + + /* cursor size large */ + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s1 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s2 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + + /* cursor size small */ + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s3 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s6 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); + + /* Nothing occurs with arguments outside valid range */ + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s7 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + + /* restore cursor size if arguments is zero */ + snprintf(buffer, sizeof(buffer), "%s0 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_set_style) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos; + char buffer[1024]; + struct captured_screen actual = {0}, expect = {0}; + WORD fg, bg; + WORD fg_attrs[9][2] = {{F_BLACK, FOREGROUND_BLACK}, + {F_RED, FOREGROUND_RED}, + {F_GREEN, FOREGROUND_GREEN}, + {F_YELLOW, FOREGROUND_YELLOW}, + {F_BLUE, FOREGROUND_BLUE}, + {F_MAGENTA, FOREGROUND_MAGENTA}, + {F_CYAN, FOREGROUND_CYAN}, + {F_WHITE, FOREGROUND_WHITE}, + {F_DEFAULT, 0}}; + WORD bg_attrs[9][2] = {{B_DEFAULT, 0}, + {B_BLACK, BACKGROUND_BLACK}, + {B_RED, BACKGROUND_RED}, + {B_GREEN, BACKGROUND_GREEN}, + {B_YELLOW, BACKGROUND_YELLOW}, + {B_BLUE, BACKGROUND_BLUE}, + {B_MAGENTA, BACKGROUND_MAGENTA}, + {B_CYAN, BACKGROUND_CYAN}, + {B_WHITE, BACKGROUND_WHITE}}; + WORD attr; + int i, length; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + capture_screen(&tty_out, &expect); + fg_attrs[8][1] = expect.si.default_attr & FOREGROUND_WHITE; + bg_attrs[0][1] = expect.si.default_attr & BACKGROUND_WHITE; + + /* Set foreground color */ + length = ARRAY_SIZE(fg_attrs); + for (i = 0; i < length; i++) { + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + attr = (expect.si.default_attr & ~FOREGROUND_WHITE) | fg_attrs[i][1]; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + + set_cursor_position(&tty_out, cursor_pos); + snprintf( + buffer, sizeof(buffer), "%s%dm%s%sm", CSI, fg_attrs[i][0], HELLO, CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + } + + /* Set background color */ + length = ARRAY_SIZE(bg_attrs); + for (i = 0; i < length; i++) { + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + attr = (expect.si.default_attr & ~BACKGROUND_WHITE) | bg_attrs[i][1]; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + + set_cursor_position(&tty_out, cursor_pos); + snprintf( + buffer, sizeof(buffer), "%s%dm%s%sm", CSI, bg_attrs[i][0], HELLO, CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + } + + /* Set foregroud and background color */ + ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs)); + length = ARRAY_SIZE(bg_attrs); + for (i = 0; i < length; i++) { + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + attr = expect.si.default_attr & ~FOREGROUND_WHITE & ~BACKGROUND_WHITE; + attr |= fg_attrs[i][1] | bg_attrs[i][1]; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, + sizeof(buffer), + "%s%d;%dm%s%sm", + CSI, + bg_attrs[i][0], + fg_attrs[i][0], + HELLO, + CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + } + + /* Set foreground bright on */ + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + set_cursor_position(&tty_out, cursor_pos); + attr = expect.si.default_attr; + attr |= FOREGROUND_INTENSITY; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + + snprintf(buffer, + sizeof(buffer), + "%s%dm%s%s%dm%s%dm%s%s%dm", + CSI, + F_INTENSITY, + HELLO, + CSI, + F_INTENSITY_OFF1, + CSI, + F_INTENSITY, + HELLO, + CSI, + F_INTENSITY_OFF2); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Set background bright on */ + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + set_cursor_position(&tty_out, cursor_pos); + attr = expect.si.default_attr; + attr |= BACKGROUND_INTENSITY; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + + snprintf(buffer, + sizeof(buffer), + "%s%dm%s%s%dm", + CSI, + B_INTENSITY, + HELLO, + CSI, + B_INTENSITY_OFF); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Inverse */ + capture_screen(&tty_out, &expect); + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + set_cursor_position(&tty_out, cursor_pos); + attr = expect.si.default_attr; + fg = attr & FOREGROUND_WHITE; + bg = attr & BACKGROUND_WHITE; + attr &= (~FOREGROUND_WHITE & ~BACKGROUND_WHITE); + attr |= COMMON_LVB_REVERSE_VIDEO; + attr |= fg << 4; + attr |= bg >> 4; + make_expect_screen_write(&expect, cursor_pos, HELLO); + make_expect_screen_set_attr(&expect, cursor_pos, strlen(HELLO), attr); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + + snprintf(buffer, + sizeof(buffer), + "%s%dm%s%s%dm%s", + CSI, + INVERSE, + HELLO, + CSI, + INVERSE_OFF, + HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_save_restore_cursor_position) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + char buffer[1024]; + struct screen_info si; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + get_screen_info(&tty_out, &si); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* save the cursor position */ + snprintf(buffer, sizeof(buffer), "%ss", CSI); + write_console(&tty_out, buffer); + + cursor_pos.X = si.width / 4; + cursor_pos.Y = si.height / 4; + set_cursor_position(&tty_out, cursor_pos); + + /* restore the cursor postion */ + snprintf(buffer, sizeof(buffer), "%su", CSI); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos.X == cursor_pos_old.X); + ASSERT(cursor_pos.Y == cursor_pos_old.Y); + + cursor_pos_old.X = si.width / 2; + cursor_pos_old.Y = si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + + /* save the cursor position */ + snprintf(buffer, sizeof(buffer), "%s7", ESC); + write_console(&tty_out, buffer); + + cursor_pos.X = si.width / 4; + cursor_pos.Y = si.height / 4; + set_cursor_position(&tty_out, cursor_pos); + + /* restore the cursor postion */ + snprintf(buffer, sizeof(buffer), "%s8", ESC); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos.X == cursor_pos_old.X); + ASSERT(cursor_pos.Y == cursor_pos_old.Y); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_full_reset) { + uv_tty_t tty_out; + uv_loop_t* loop; + char buffer[1024]; + struct captured_screen actual = {0}, expect = {0}; + COORD cursor_pos; + DWORD saved_cursor_size; + BOOL saved_cursor_visibility; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + capture_screen(&tty_out, &expect); + setup_screen(&tty_out); + cursor_pos.X = expect.si.width; + cursor_pos.Y = expect.si.height; + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s%d;%dm%s", CSI, F_CYAN, B_YELLOW, HELLO); + saved_cursor_size = get_cursor_size(&tty_out); + set_cursor_size(&tty_out, + saved_cursor_size == CURSOR_SIZE_LARGE ? CURSOR_SIZE_SMALL + : CURSOR_SIZE_LARGE); + saved_cursor_visibility = get_cursor_visibility(&tty_out); + set_cursor_visibility(&tty_out, saved_cursor_visibility ? FALSE : TRUE); + write_console(&tty_out, buffer); + snprintf(buffer, sizeof(buffer), "%sc", ESC); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); + ASSERT(get_cursor_visibility(&tty_out) == saved_cursor_visibility); + ASSERT(actual.si.csbi.srWindow.Top == 0); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tty_escape_sequence_processing) { + uv_tty_t tty_out; + uv_loop_t* loop; + COORD cursor_pos, cursor_pos_old; + DWORD saved_cursor_size; + char buffer[1024]; + struct captured_screen actual = {0}, expect = {0}; + int dir; + + loop = uv_default_loop(); + + initialize_tty(&tty_out); + + /* CSI + finaly byte does not output anything */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%s@%s%s~%s", CSI, HELLO, CSI, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* CSI(C1) + finaly byte does not output anything */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "\xC2\x9B@%s\xC2\x9B~%s", HELLO, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* CSI + intermediate byte + finaly byte does not output anything */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* CSI + parameter byte + finaly byte does not output anything */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + snprintf(buffer, + sizeof(buffer), + "%s0@%s%s>~%s%s?~%s", + CSI, + HELLO, + CSI, + HELLO, + CSI, + HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* ESC Single-char control does not output anyghing */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%s @%s%s/~%s", CSI, HELLO, CSI, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Nothing is output from ESC + ^, _, P, ] to BEL or ESC \ */ + /* Operaging System Command */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%s]0;%s%s%s", ESC, HELLO, BEL, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + /* Device Control Sequence */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%sP$m%s%s", ESC, ST, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + /* Privacy Message */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, + sizeof(buffer), + "%s^\"%s\\\"%s\"%s%s", + ESC, + HELLO, + HELLO, + ST, + HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + /* Application Program Command */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, + sizeof(buffer), + "%s_\"%s%s%s\"%s%s", + ESC, + HELLO, + ST, + HELLO, + BEL, + HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Ignore double escape */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + cursor_pos.X += strlen(HELLO); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, + sizeof(buffer), + "%s%s@%s%s%s~%s", + ESC, + CSI, + HELLO, + ESC, + CSI, + HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Ignored if argument overflow */ + set_cursor_to_home(&tty_out); + snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos.X == 1); + ASSERT(cursor_pos.Y == 1); + + /* Too many argument are ignored */ + cursor_pos.X = 1; + cursor_pos.Y = 1; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, + sizeof(buffer), + "%s%d;%d;%d;%d;%dm%s%sm", + CSI, + F_RED, + F_INTENSITY, + INVERSE, + B_CYAN, + B_INTENSITY_OFF, + HELLO, + CSI); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* In the case of DECSCUSR, the others are ignored */ + set_cursor_to_home(&tty_out); + snprintf(buffer, + sizeof(buffer), + "%s%d;%d H", + CSI, + expect.si.height / 2, + expect.si.width / 2); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos.X == 1); + ASSERT(cursor_pos.Y == 1); + + /* Invalid sequence are ignored */ + saved_cursor_size = get_cursor_size(&tty_out); + set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s 1q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + snprintf(buffer, sizeof(buffer), "%s 1 q", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + set_cursor_size(&tty_out, saved_cursor_size); + + /* #1874 2. */ + snprintf(buffer, sizeof(buffer), "%s??25l", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_visibility(&tty_out)); + snprintf(buffer, sizeof(buffer), "%s25?l", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_visibility(&tty_out)); + cursor_pos_old.X = expect.si.width / 2; + cursor_pos_old.Y = expect.si.height / 2; + set_cursor_position(&tty_out, cursor_pos_old); + snprintf(buffer, + sizeof(buffer), + "%s??%d;%df", + CSI, + expect.si.height / 4, + expect.si.width / 4); + write_console(&tty_out, buffer); + get_cursor_position(&tty_out, &cursor_pos); + ASSERT(cursor_pos.X = cursor_pos_old.X); + ASSERT(cursor_pos.Y = cursor_pos_old.Y); + set_cursor_to_home(&tty_out); + + /* CSI 25 l does nothing (#1874 4.) */ + snprintf(buffer, sizeof(buffer), "%s25l", CSI); + write_console(&tty_out, buffer); + ASSERT(get_cursor_visibility(&tty_out)); + + /* Unsupported sequences are ignored(#1874 5.) */ + dir = 2; + setup_screen(&tty_out); + capture_screen(&tty_out, &expect); + set_cursor_position(&tty_out, cursor_pos); + snprintf(buffer, sizeof(buffer), "%s?%dJ", CSI, dir); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + /* Finaly byte immedately after CSI [ are also output(#1874 1.) */ + cursor_pos.X = expect.si.width / 2; + cursor_pos.Y = expect.si.height / 2; + set_cursor_position(&tty_out, cursor_pos); + capture_screen(&tty_out, &expect); + make_expect_screen_write(&expect, cursor_pos, HELLO); + snprintf(buffer, sizeof(buffer), "%s[%s", CSI, HELLO); + write_console(&tty_out, buffer); + capture_screen(&tty_out, &actual); + ASSERT(compare_screen(&tty_out, &actual, &expect)); + + terminate_tty(&tty_out); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#else + +typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ + +#endif /* ifdef _WIN32 */ diff --git a/deps/uv/test/test-udp-connect.c b/deps/uv/test/test-udp-connect.c index f44634248f7e31..58cf9475a40b57 100644 --- a/deps/uv/test/test-udp-connect.c +++ b/deps/uv/test/test-udp-connect.c @@ -98,6 +98,10 @@ static void sv_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_connect) { +#if defined(__PASE__) + RETURN_SKIP( + "IBMi PASE's UDP connection can not be disconnected with AF_UNSPEC."); +#endif uv_udp_send_t req; struct sockaddr_in ext_addr; struct sockaddr_in tmp_addr; diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 9d4db2bc4fedf0..7099953097cdd8 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -41,11 +41,13 @@ static uv_udp_t client; static uv_udp_t server; static uv_udp_send_t req_; +static char data[10]; static uv_timer_t timeout; static int send_cb_called; static int recv_cb_called; static int close_cb_called; +static uint16_t client_port; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) static int can_ipv6_ipv4_dual(void) { @@ -83,12 +85,35 @@ static void send_cb(uv_udp_send_t* req, int status) { send_cb_called++; } +static int is_from_client(const struct sockaddr* addr) { + const struct sockaddr_in6* addr6; + char dst[256]; + int r; + + /* Debugging output, and filter out unwanted network traffic */ + if (addr != NULL) { + ASSERT(addr->sa_family == AF_INET6); + addr6 = (struct sockaddr_in6*) addr; + r = uv_inet_ntop(addr->sa_family, &addr6->sin6_addr, dst, sizeof(dst)); + if (r == 0) + printf("from [%.*s]:%d\n", (int) sizeof(dst), dst, addr6->sin6_port); + if (addr6->sin6_port != client_port) + return 0; + if (r != 0 || strcmp(dst, "::ffff:127.0.0.1")) + return 0; + } + return 1; +} + static void ipv6_recv_fail(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { + printf("got %d %.*s\n", (int) nread, nread > 0 ? (int) nread : 0, buf->base); + if (!is_from_client(addr) || (nread == 0 && addr == NULL)) + return; ASSERT(0 && "this function should not have been called"); } @@ -99,10 +124,14 @@ static void ipv6_recv_ok(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { CHECK_HANDLE(handle); - ASSERT(nread >= 0); - if (nread) - recv_cb_called++; + printf("got %d %.*s\n", (int) nread, nread > 0 ? (int) nread : 0, buf->base); + if (!is_from_client(addr) || (nread == 0 && addr == NULL)) + return; + + ASSERT(nread == 9); + ASSERT(!memcmp(buf->base, data, 9)); + recv_cb_called++; } @@ -116,7 +145,10 @@ static void timeout_cb(uv_timer_t* timer) { static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { struct sockaddr_in6 addr6; struct sockaddr_in addr; + int addr6_len; + int addr_len; uv_buf_t buf; + char dst[256]; int r; ASSERT(0 == uv_ip6_addr("::0", TEST_PORT, &addr6)); @@ -127,14 +159,25 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags); ASSERT(r == 0); + addr6_len = sizeof(addr6); + ASSERT(uv_udp_getsockname(&server, (struct sockaddr*) &addr6, &addr6_len) == 0); + ASSERT(uv_inet_ntop(addr6.sin6_family, &addr6.sin6_addr, dst, sizeof(dst)) == 0); + printf("on [%.*s]:%d\n", (int) sizeof(dst), dst, addr6.sin6_port); + r = uv_udp_recv_start(&server, alloc_cb, recv_cb); ASSERT(r == 0); r = uv_udp_init(uv_default_loop(), &client); ASSERT(r == 0); - buf = uv_buf_init("PING", 4); ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst)) == 0); + printf("to [%.*s]:%d\n", (int) sizeof(dst), dst, addr.sin_port); + + /* Create some unique data to send */ + ASSERT(9 == snprintf(data, sizeof(data), "PING%5u", uv_os_getpid() & 0xFFFF)); + buf = uv_buf_init(data, 9); + printf("sending %s\n", data); r = uv_udp_send(&req_, &client, @@ -144,6 +187,12 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { send_cb); ASSERT(r == 0); + addr_len = sizeof(addr); + ASSERT(uv_udp_getsockname(&client, (struct sockaddr*) &addr, &addr_len) == 0); + ASSERT(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst)) == 0); + printf("from [%.*s]:%d\n", (int) sizeof(dst), dst, addr.sin_port); + client_port = addr.sin_port; + r = uv_timer_init(uv_default_loop(), &timeout); ASSERT(r == 0); @@ -180,6 +229,8 @@ TEST_IMPL(udp_dual_stack) { do_test(ipv6_recv_ok, 0); + printf("recv_cb_called %d\n", recv_cb_called); + printf("send_cb_called %d\n", send_cb_called); ASSERT(recv_cb_called == 1); ASSERT(send_cb_called == 1); diff --git a/deps/uv/test/test-watcher-cross-stop.c b/deps/uv/test/test-watcher-cross-stop.c index 29a82a5c374029..b26deb8d88c50f 100644 --- a/deps/uv/test/test-watcher-cross-stop.c +++ b/deps/uv/test/test-watcher-cross-stop.c @@ -26,8 +26,9 @@ #include /* NOTE: Number should be big enough to trigger this problem */ -#if defined(__CYGWIN__) || defined(__MSYS__) +#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__PASE__) /* Cygwin crashes or hangs in socket() with too many AF_INET sockets. */ +/* IBMi PASE timeout with too many AF_INET sockets. */ static uv_udp_t sockets[1250]; #else static uv_udp_t sockets[2500]; diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 73ff42c56e431c..48fc5eaf8e3f8d 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -143,6 +143,7 @@ 'test-timer-from-check.c', 'test-timer.c', 'test-tty-duplicate-key.c', + 'test-tty-escape-sequence-processing.c', 'test-tty.c', 'test-udp-alloc-cb-fail.c', 'test-udp-bind.c', @@ -240,6 +241,7 @@ 'benchmark-million-timers.c', 'benchmark-multi-accept.c', 'benchmark-ping-pongs.c', + 'benchmark-ping-udp.c', 'benchmark-pound.c', 'benchmark-pump.c', 'benchmark-sizes.c', diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index fa0a001527d790..116b7537195618 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -261,7 +261,6 @@ 'src/unix/android-ifaddrs.c', 'src/unix/procfs-exepath.c', 'src/unix/random-getrandom.c', - 'src/unix/random-getentropy.c', 'src/unix/random-sysctl-linux.c', 'src/unix/sysinfo-loadavg.c', ],