diff -Nru libuv1-1.34.2/android-configure-arm libuv1-1.40.0/android-configure-arm --- libuv1-1.34.2/android-configure-arm 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/android-configure-arm 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain-arm -mkdir -p $TOOLCHAIN -API=${3:-24} -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.9 \ - --arch=arm \ - --install-dir=$TOOLCHAIN \ - --platform=android-$API \ - --force -export PATH=$TOOLCHAIN/bin:$PATH -export AR=arm-linux-androideabi-ar -export CC=arm-linux-androideabi-gcc -export CXX=arm-linux-androideabi-g++ -export LINK=arm-linux-androideabi-g++ -export PLATFORM=android -export CFLAGS="-D__ANDROID_API__=$API" - -if [[ $2 == 'gyp' ]] - then - ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android -fi diff -Nru libuv1-1.34.2/android-configure-arm64 libuv1-1.40.0/android-configure-arm64 --- libuv1-1.34.2/android-configure-arm64 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/android-configure-arm64 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain-arm64 -mkdir -p $TOOLCHAIN -API=${3:-24} -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=aarch64-linux-android-4.9 \ - --arch=arm64 \ - --install-dir=$TOOLCHAIN \ - --platform=android-$API \ - --force -export PATH=$TOOLCHAIN/bin:$PATH -export AR=aarch64-linux-android-ar -export CC=aarch64-linux-android-gcc -export CXX=aarch64-linux-android-g++ -export LINK=aarch64-linux-android-g++ -export PLATFORM=android -export CFLAGS="-D__ANDROID_API__=$API" - -if [[ $2 == 'gyp' ]] - then - ./gyp_uv.py -Dtarget_arch=arm64 -DOS=android -f make-android -fi diff -Nru libuv1-1.34.2/android-configure-x86 libuv1-1.40.0/android-configure-x86 --- libuv1-1.34.2/android-configure-x86 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/android-configure-x86 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain-x86 -mkdir -p $TOOLCHAIN -API=${3:-24} -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=x86-4.9 \ - --arch=x86 \ - --install-dir=$TOOLCHAIN \ - --platform=android-$API \ - --force -export PATH=$TOOLCHAIN/bin:$PATH -export AR=i686-linux-android-ar -export CC=i686-linux-android-gcc -export CXX=i686-linux-android-g++ -export LINK=i686-linux-android-g++ -export PLATFORM=android -export CFLAGS="-D__ANDROID_API__=$API" - -if [[ $2 == 'gyp' ]] - then - ./gyp_uv.py -Dtarget_arch=x86 -DOS=android -f make-android -fi diff -Nru libuv1-1.34.2/android-configure-x86_64 libuv1-1.40.0/android-configure-x86_64 --- libuv1-1.34.2/android-configure-x86_64 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/android-configure-x86_64 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain-x86_64 -mkdir -p $TOOLCHAIN -API=${3:-24} -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=x86_64-4.9 \ - --arch=x86_64 \ - --install-dir=$TOOLCHAIN \ - --platform=android-$API \ - --force -export PATH=$TOOLCHAIN/bin:$PATH -export AR=x86_64-linux-android-ar -export CC=x86_64-linux-android-gcc -export CXX=x86_64-linux-android-g++ -export LINK=x86_64-linux-android-g++ -export PLATFORM=android -export CFLAGS="-D__ANDROID_API__=$API -fPIC" -export CXXFLAGS="-D__ANDROID_API__=$API -fPIC" -export LDFLAGS="-fPIC" - -if [[ $2 == 'gyp' ]] - then - ./gyp_uv.py -Dtarget_arch=x86_64 -DOS=android -f make-android -fi diff -Nru libuv1-1.34.2/appveyor.yml libuv1-1.40.0/appveyor.yml --- libuv1-1.34.2/appveyor.yml 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/appveyor.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -version: v1.18.0.build{build} - -init: - - git config --global core.autocrlf true - -install: - - cinst -y nsis - -matrix: - fast_finish: true - allow_failures: - - platform: x86 - configuration: Release - - platform: x64 - configuration: Release - -platform: - - x86 - - x64 - -configuration: - - Release - -build_script: - # Fixed tag version number if using a tag. - - cmd: if "%APPVEYOR_REPO_TAG%" == "true" set APPVEYOR_BUILD_VERSION=%APPVEYOR_REPO_TAG_NAME% - # vcbuild overwrites the platform variable. - - cmd: set ARCH=%platform% - - cmd: vcbuild.bat release %ARCH% shared - -cache: - - C:\projects\libuv\build\gyp diff -Nru libuv1-1.34.2/AUTHORS libuv1-1.40.0/AUTHORS --- libuv1-1.34.2/AUTHORS 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/AUTHORS 2020-09-25 00:34:43.000000000 +0000 @@ -413,3 +413,38 @@ Stefan Bender nia virtualyw +Witold Kręcicki +Dominique Dumont +Manuel BACHMANN +Marek Vavrusa +TK-one +Irek Fakhrutdinov +Lin Zhang +毛毛 +Sk Sajidul Kadir +twosee +Rikard Falkeborn +Yash Ladha +James Ross +Colin Finck +Shohei YOSHIDA +Philip Chimento +Michal Artazov +Jeroen Roovers +MasterDuke17 +Alexander Tokmakov +Arenoros +lander0s +Turbinya +OleksandrKvl +Carter Li +Juan Sebastian velez Posada +escherstair +Evan Lucas +tjarlama <59913901+tjarlama@users.noreply.github.com> +司徒玟琅 +YuMeiJie +Aleksej Lebedev +Nikolay Mitev +Ulrik Strid +Elad Lahav diff -Nru libuv1-1.34.2/ChangeLog libuv1-1.40.0/ChangeLog --- libuv1-1.34.2/ChangeLog 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/ChangeLog 2020-09-25 00:34:43.000000000 +0000 @@ -1,4 +1,408 @@ -2020.01.24, Version 1.34.2 (Stable) +2020.09.26, Version 1.40.0 (Stable) + +Changes since version 1.39.0: + +* udp: add UV_UDP_MMSG_FREE recv_cb flag (Ryan Liptak) + +* include: re-map UV__EPROTO from 4046 to -4046 (YuMeiJie) + +* doc: correct UV_UDP_MMSG_FREE version added (cjihrig) + +* doc: add uv_metrics_idle_time() version metadata (Ryan Liptak) + +* win,tty: pass through utf-16 surrogate pairs (Mustafa M) + +* unix: fix DragonFly BSD build (Aleksej Lebedev) + +* win,udp: fix error code returned by connect() (Santiago Gimeno) + +* src: suppress user_timeout maybe-uninitialized (Daniel Bevenius) + +* test: fix compiler warning (Vladimír Čunát) + +* build: fix the Haiku cmake build (David Carlier) + +* linux: fix i386 sendmmsg/recvmmsg support (Ben Noordhuis) + +* build: add libuv-static pkg-config file (Nikolay Mitev) + +* unix,win: add uv_timer_get_due_in() (Ulrik Strid) + +* build,unix: add QNX support (Elad Lahav) + +* include: remove incorrect UV__ERR() for EPROTO (cjihrig) + + +2020.08.26, Version 1.39.0 (Stable), 25f4b8b8a3c0f934158cd37a37b0525d75ca488e + +Changes since version 1.38.1: + +* unix: use relaxed loads/stores for clock id (Ben Noordhuis) + +* build,win: link to user32.lib and advapi32.lib (George Zhao) + +* unix: squelch harmless valgrind warning (ssrlive) + +* include: fx c++ style comments warnings (Turbinya) + +* build,cmake: Change installation location on MinGW (erw7) + +* linux: use copy_file_range for uv_fs_copyfile when possible (Carter Li) + +* win,tcp: avoid reinserting a pending request ( + +* docs: improve the descriptions for get memory info (Juan Sebastian velez + Posada) + +* test: add udp-mmsg test (Ryan Liptak) + +* udp: add uv_udp_using_recvmmsg query (Ryan Liptak) + +* doc: add more error constants (TK-one) + +* zos: fix potential event loop stall (Trevor Norris) + +* include: add internal fields struct to uv_loop_t (Trevor Norris) + +* core: add API to measure event loop idle time (Trevor Norris) + +* win,fs: use CreateDirectoryW instead of _wmkdir (Mustafa M) + +* win,nfc: fix integer comparison signedness (escherstair) + +* win,nfc: use + +* win,nfc: removed some unused variables (escherstair) + +* win,nfc: add missing return statement (escherstair) + +* win,nfc: disable clang-format for + +* darwin: use IOKit for uv_cpu_info (Evan Lucas) + +* test: fix thread race in process_title_threadsafe (Ben Noordhuis) + +* win,fs: avoid implicit access to _doserrno (Jameson Nash) + +* test: give hrtime test a custom 20s timeout (Jameson Nash) + +* build: add more failed test, for qemu version bump (gengjiawen) + +* unix: handle src, dest same in uv_fs_copyfile() (cjihrig) + +* unix: error when uv_setup_args() is not called (Ryan Liptak) + +* aix: protect uv_exepath() from uv_set_process_title() (Richard Lau) + +* fs: clobber req->path on uv_fs_mkstemp() error (tjarlama) + +* cmake: fix compile error C2001 on Chinese Windows (司徒玟琅) + +* test: avoid double evaluation in ASSERT_BASE macro (tjarlama) + +* tcp: fail instantly if local port is unbound (Bartosz Sosnowski) + +* doc: fix most sphinx warnings (Jameson Nash) + +* nfci: address some style nits (Jameson Nash) + +* unix: don't use _POSIX_PATH_MAX (Ben Noordhuis) + + +2020.07.04, Version 1.38.1 (Stable), e8b989ea1f7f9d4083511a2caec7791e9abd1871 + +Changes since version 1.38.0: + +* test: use last matching qemu version (cjihrig) + +* win, util: rearrange uv_hrtime (Bartosz Sosnowski) + +* test: skip signal_multiple_loops test on QEMU (gengjiawen) + +* build: add android build to CI (gengjiawen) + +* test: extend fs_event_error_reporting timeout (cjihrig) + +* build: link libkvm on netbsd only (Alexander Tokmakov) + +* linux: refactor /proc file reader logic (Ben Noordhuis) + +* linux: read load average from /proc/loadavg (Ben Noordhuis) + +* android: remove patch code for below 21 (gengjiawen) + +* win: fix visual studio 2008 build (Arenoros) + +* win,tty: fix deadlock caused by inconsistent state (lander0s) + +* unix: use relaxed loads/stores for feature checks (Ben Noordhuis) + +* build: don't .gitignore m4/ax_pthread.m4 (Ben Noordhuis) + +* unix: fix gcc atomics feature check (Ben Noordhuis) + +* darwin: work around clock jumping back in time (Ben Noordhuis) + +* udp: fix write_queue cleanup on sendmmsg error (Santiago Gimeno) + +* src: build fix for Android (David Carlier) + + +2020.05.18, Version 1.38.0 (Stable), 1ab9ea3790378f9f25c4e78e9e2b511c75f9c9ed + +Changes since version 1.37.0: + +* test: skip poll_duplex and poll_unidirectional on PASE (Xu Meng) + +* linux: make cpu_times consistently be milliseconds (James Ross) + +* win: DRY uv_poll_start() and uv_poll_stop() (Ben Noordhuis) + +* win: DRY uv_poll_close() (Ben Noordhuis) + +* unix,win: add uv_library_shutdown() (Ben Noordhuis) + +* unix: yield cpu when spinlocking on async handle (Ben Noordhuis) + +* win: remove dep on GetQueuedCompletionStatusEx (Colin Finck) + +* doc: correct source lines (Shohei YOSHIDA) + +* build,android: fix typo (twosee) + +* doc: uv_cancel() handles uv_random_t requests (Philip Chimento) + +* doc: fix unescaped character (Philip Chimento) + +* build,cmake: fix compilation on old MinGW (erw7) + +* build: remove unnessesary MSVC warnings (Bartosz Sosnowski) + +* win: make uv_udp_init_ex() accept UV_UDP_RECVMMSG (Ben Noordhuis) + +* unix: simplify uv__udp_init_ex() (Ben Noordhuis) + +* win: remove MAX_PATH limitations (Bartosz Sosnowski) + +* build, win: add long path aware manifest (Bartosz Sosnowski) + +* doc: check/idle/prepare functions always succeed (Ben Noordhuis) + +* darwin: fix build with non-apple compilers (Ben Noordhuis) + +* win: support environment variables > 32767 chars (Ben Noordhuis) + +* unix: fully initialize struct msghdr (Ben Noordhuis) + +* doc: add uv_replace_allocator thread safety warning (twosee) + +* unix: fix int overflow when copying large files (Michal Artazov) + +* fs: report original error (Bartosz Sosnowski) + +* win, fs: add IO_REPARSE_TAG_APPEXECLINK support (Bartosz Sosnowski) + +* doc: fix formatting (Ben Noordhuis) + +* unix: fix memory leak when uv_loop_init() fails (Anna Henningsen) + +* unix: shrink uv_udp_set_source_membership() stack (Ben Noordhuis) + +* unix,win: fix wrong sizeof argument to memcpy() (Ben Noordhuis) + +* build: check for libraries not provided by libc (Jeroen Roovers) + +* doc: fix the order of arguments to calloc() (MasterDuke17) + +* unix: don't abort when getrlimit() fails (Ben Noordhuis) + +* test: support common user profile on IBMi (Xu Meng) + +* build: test on more platforms via QEMU in CI (gengjiawen) + + +2020.04.20, Version 1.37.0 (Stable), 02a9e1be252b623ee032a3137c0b0c94afbe6809 + +Changes since version 1.36.0: + +* timer: remove redundant check in heap compare (Yash Ladha) + +* udp: add flag to enable recvmmsg(2) explicitly (Saúl Ibarra Corretgé) + + +2020.04.16, Version 1.36.0 (Stable), 533b738838ad8407032e14b6772b29ef9af63cfa + +Changes since version 1.35.0: + +* build: add aix-common.c for AIX cmake build (Jesse Gorzinski) + +* zos: explicitly mark message queue events (Irek Fakhrutdinov) + +* zos: move mq check out of loop to save cpu cycles (Irek Fakhrutdinov) + +* zos: add checks to ensure behavior of epoll_wait (Irek Fakhrutdinov) + +* src: add uv__reallocf() (Ben Noordhuis) + +* build: ibmi support for cmake (Jesse Gorzinski) + +* build: fix gyp build for Android API >= 28 (Lin Zhang) + +* udp: return recvmmsg-ed datagrams in order (Saúl Ibarra Corretgé) + +* zos,test: fix spawn_empty_env for shared library build (Richard Lau) + +* zos: fix non-Release builds (Richard Lau) + +* zos: fix return value on expired nanosleep() call (Richard Lau) + +* build: fix z/OS cmake build (Richard Lau) + +* test: add a bunch of ASSERT macros (Santiago Gimeno) + +* test: remove unused extern declaration (Ben Noordhuis) + +* test: canonicalize argv[0] in exepath test (Ben Noordhuis) + +* test: simplify platform_init() (Ben Noordhuis) + +* ibmi: Fix isatty EBADF handling and refactor (Kevin Adler) + +* test: Test EBADF tty handling (Kevin Adler) + +* build: make cmake build benchmarks (Ben Noordhuis) + +* win: use RtlGenRandom from advapi32.dll directly (Ben Noordhuis) + +* android: fix OOB write in uv_interface_addresses() (Lin Zhang) + +* test: pass test when hostname is single character (毛毛) + +* ibmi: set the highest process priority to -10 (Xu Meng) + +* build: remove support for gyp (Ben Noordhuis) + +* doc: add note to README on cross-compiling (Ben Noordhuis) + +* fs: add uv_fs_lutime() (Sk Sajidul Kadir) + +* unix: implement cpu_relax() for arm (David Carlier) + +* linux: fix uv__accept4() (twosee) + +* win: handle file paths in uv_fs_statfs() (erw7) + +* unix: fix uv_os_environ() null pointer check (Rikard Falkeborn) + +* win: fix uv_os_environ() null pointer check (Rikard Falkeborn) + +* unix: fix compilation on macOS 32-bit architectures (Brad King) + +* win: replace alloca() with stack-based array (Ben Noordhuis) + + +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 -Nru libuv1-1.34.2/CMakeLists.txt libuv1-1.40.0/CMakeLists.txt --- libuv1-1.34.2/CMakeLists.txt 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/CMakeLists.txt 2020-09-25 00:34:43.000000000 +0000 @@ -1,23 +1,99 @@ -# TODO: determine CMAKE_SYSTEM_NAME on OS/390. Currently assumes "OS/390". 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) - -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() +cmake_dependent_option(LIBUV_BUILD_BENCH + "Build the benchmarks when building unit tests and we are the root project" ON + "LIBUV_BUILD_TESTS" OFF) + +# Qemu Build +option(QEMU "build for qemu" OFF) +if(QEMU) + add_definitions(-D__QEMU__=1) +endif() + +# Compiler check +string(CONCAT is-msvc $, + $ +>) + +check_c_compiler_flag(/W4 UV_LINT_W4) +check_c_compiler_flag(/wd4100 UV_LINT_NO_UNUSED_PARAMETER_MSVC) +check_c_compiler_flag(/wd4127 UV_LINT_NO_CONDITIONAL_CONSTANT_MSVC) +check_c_compiler_flag(/wd4201 UV_LINT_NO_NONSTANDARD_MSVC) +check_c_compiler_flag(/wd4206 UV_LINT_NO_NONSTANDARD_EMPTY_TU_MSVC) +check_c_compiler_flag(/wd4210 UV_LINT_NO_NONSTANDARD_FILE_SCOPE_MSVC) +check_c_compiler_flag(/wd4232 UV_LINT_NO_NONSTANDARD_NONSTATIC_DLIMPORT_MSVC) +check_c_compiler_flag(/wd4456 UV_LINT_NO_HIDES_LOCAL) +check_c_compiler_flag(/wd4457 UV_LINT_NO_HIDES_PARAM) +check_c_compiler_flag(/wd4459 UV_LINT_NO_HIDES_GLOBAL) +check_c_compiler_flag(/wd4706 UV_LINT_NO_CONDITIONAL_ASSIGNMENT_MSVC) +check_c_compiler_flag(/wd4996 UV_LINT_NO_UNSAFE_MSVC) + +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) + +check_c_compiler_flag(/utf-8 UV_LINT_UTF8_MSVC) + +set(lint-no-unused-parameter $<$:-Wno-unused-parameter>) +set(lint-strict-prototypes $<$:-Wstrict-prototypes>) +set(lint-extra $<$:-Wextra>) +set(lint-w4 $<$:/W4>) +set(lint-no-unused-parameter-msvc $<$:/wd4100>) +set(lint-no-conditional-constant-msvc $<$:/wd4127>) +set(lint-no-nonstandard-msvc $<$:/wd4201>) +set(lint-no-nonstandard-empty-tu-msvc $<$:/wd4206>) +set(lint-no-nonstandard-file-scope-msvc $<$:/wd4210>) +set(lint-no-nonstandard-nonstatic-dlimport-msvc $<$:/wd4232>) +set(lint-no-hides-local-msvc $<$:/wd4456>) +set(lint-no-hides-param-msvc $<$:/wd4457>) +set(lint-no-hides-global-msvc $<$:/wd4459>) +set(lint-no-conditional-assignment-msvc $<$:/wd4706>) +set(lint-no-unsafe-msvc $<$:/wd4996>) +# Unfortunately, this one is complicated because MSVC and clang-cl support -Wall +# but using it is like calling -Weverything +string(CONCAT lint-default $< + $,$>:-Wall +>) +set(lint-utf8-msvc $<$:/utf-8>) + +list(APPEND uv_cflags ${lint-strict-prototypes} ${lint-extra} ${lint-default} ${lint-w4}) +list(APPEND uv_cflags ${lint-no-unused-parameter}) +list(APPEND uv_cflags ${lint-no-unused-parameter-msvc}) +list(APPEND uv_cflags ${lint-no-conditional-constant-msvc}) +list(APPEND uv_cflags ${lint-no-nonstandard-msvc}) +list(APPEND uv_cflags ${lint-no-nonstandard-empty-tu-msvc}) +list(APPEND uv_cflags ${lint-no-nonstandard-file-scope-msvc}) +list(APPEND uv_cflags ${lint-no-nonstandard-nonstatic-dlimport-msvc}) +list(APPEND uv_cflags ${lint-no-hides-local-msvc}) +list(APPEND uv_cflags ${lint-no-hides-param-msvc}) +list(APPEND uv_cflags ${lint-no-hides-global-msvc}) +list(APPEND uv_cflags ${lint-no-conditional-assignment-msvc}) +list(APPEND uv_cflags ${lint-no-unsafe-msvc}) +list(APPEND uv_cflags ${lint-utf8-msvc} ) set(uv_sources src/fs-poll.c @@ -31,172 +107,13 @@ 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) list(APPEND uv_libraries - advapi32 - iphlpapi psapi - shell32 user32 + advapi32 + iphlpapi userenv ws2_32) list(APPEND uv_sources @@ -229,7 +146,8 @@ list(APPEND uv_test_sources src/win/snprintf.c test/runner-win.c) else() list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + if(NOT CMAKE_SYSTEM_NAME MATCHES "Android|OS390|QNX") + # 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) @@ -261,13 +179,17 @@ _ALL_SOURCE _LINUX_SOURCE_COMPAT _THREAD_SAFE - _XOPEN_SOURCE=500) + _XOPEN_SOURCE=500 + HAVE_SYS_AHAFS_EVPRODS_H) list(APPEND uv_libraries perfstat) - list(APPEND uv_sources src/unix/aix.c) + list(APPEND uv_sources + src/unix/aix.c + src/unix/aix-common.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Android") - list(APPEND uv_libs dl) + list(APPEND uv_defines _GNU_SOURCE) + list(APPEND uv_libraries dl) list(APPEND uv_sources src/unix/android-ifaddrs.c src/unix/linux-core.c @@ -275,12 +197,12 @@ 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) + src/unix/random-sysctl-linux.c) endif() -if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux|OS/390") +if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux|OS390") list(APPEND uv_sources src/unix/proctitle.c) endif() @@ -290,7 +212,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD") list(APPEND uv_sources src/unix/posix-hrtime.c src/unix/bsd-proctitle.c) - list(APPEND uv_libraries kvm) endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD") @@ -322,22 +243,23 @@ src/unix/linux-syscalls.c src/unix/procfs-exepath.c src/unix/random-getrandom.c - src/unix/random-sysctl-linux.c - src/unix/sysinfo-loadavg.c) + src/unix/random-sysctl-linux.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") list(APPEND uv_sources src/unix/netbsd.c) + list(APPEND uv_libraries kvm) endif() if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") list(APPEND uv_sources src/unix/openbsd.c) endif() -if(CMAKE_SYSTEM_NAME STREQUAL "OS/390") +if(CMAKE_SYSTEM_NAME STREQUAL "OS390") list(APPEND uv_defines PATH_MAX=255) list(APPEND uv_defines _AE_BIMODAL) list(APPEND uv_defines _ALL_SOURCE) + list(APPEND uv_defines _ISOC99_SOURCE) list(APPEND uv_defines _LARGE_TIME_API) list(APPEND uv_defines _OPEN_MSGQ_EXT) list(APPEND uv_defines _OPEN_SYS_FILE_EXT) @@ -350,9 +272,24 @@ list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED) list(APPEND uv_sources src/unix/pthread-fixes.c - src/unix/pthread-barrier.c src/unix/os390.c src/unix/os390-syscalls.c) + list(APPEND uv_cflags -Wc,DLL -Wc,exportall -Wc,xplink) + list(APPEND uv_libraries -Wl,xplink) + list(APPEND uv_test_libraries -Wl,xplink) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OS400") + list(APPEND uv_defines + _ALL_SOURCE + _LINUX_SOURCE_COMPAT + _THREAD_SAFE + _XOPEN_SOURCE=500) + list(APPEND uv_sources + src/unix/aix-common.c + src/unix/ibmi.c + src/unix/no-fsevents.c + src/unix/posix-poll.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") @@ -361,26 +298,258 @@ list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "Haiku") + list(APPEND uv_defines _BSD_SOURCE) + list(APPEND uv_libraries bsd network) + list(APPEND uv_sources + src/unix/haiku.c + src/unix/bsd-ifaddrs.c + src/unix/no-fsevents.c + src/unix/no-proctitle.c + src/unix/posix-hrtime.c + src/unix/posix-poll.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "QNX") + list(APPEND uv_sources + src/unix/posix-hrtime.c + src/unix/posix-poll.c + src/unix/qnx.c + src/unix/bsd-ifaddrs.c + src/unix/no-proctitle.c + src/unix/no-fsevents.c) + list(APPEND uv_cflags -fno-strict-aliasing) + list(APPEND uv_libraries socket) +endif() + if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) 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) - add_executable(uv_run_tests ${uv_test_sources}) + # Small hack: use ${uv_test_sources} now to get the runner skeleton, + # before the actual tests are added. + add_executable( + uv_run_benchmarks_a + ${uv_test_sources} + test/benchmark-async-pummel.c + test/benchmark-async.c + test/benchmark-fs-stat.c + test/benchmark-getaddrinfo.c + test/benchmark-loop-count.c + test/benchmark-million-async.c + test/benchmark-million-timers.c + test/benchmark-multi-accept.c + test/benchmark-ping-pongs.c + test/benchmark-ping-udp.c + test/benchmark-pound.c + test/benchmark-pump.c + test/benchmark-sizes.c + test/benchmark-spawn.c + test/benchmark-tcp-write-batch.c + test/benchmark-thread.c + test/benchmark-udp-pummel.c + test/blackhole-server.c + test/dns-server.c + test/echo-server.c + test/run-benchmarks.c + test/runner.c) + target_compile_definitions(uv_run_benchmarks_a PRIVATE ${uv_defines}) + target_compile_options(uv_run_benchmarks_a PRIVATE ${uv_cflags}) + target_link_libraries(uv_run_benchmarks_a uv_a ${uv_test_libraries}) + + 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-metrics.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-read-stop-start.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-test-macros.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-mmsg.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-sendmmsg-error.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} uv_win_longpath.manifest) target_compile_definitions(uv_run_tests PRIVATE ${uv_defines} USING_UV_SHARED=1) target_compile_options(uv_run_tests PRIVATE ${uv_cflags}) @@ -388,43 +557,63 @@ add_test(NAME uv_test COMMAND uv_run_tests WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - add_executable(uv_run_tests_a ${uv_test_sources}) + if(CMAKE_SYSTEM_NAME STREQUAL "OS390") + set_tests_properties(uv_test PROPERTIES ENVIRONMENT + "LIBPATH=${CMAKE_BINARY_DIR}:$ENV{LIBPATH}") + endif() + add_executable(uv_run_tests_a ${uv_test_sources} uv_win_longpath.manifest) target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines}) target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags}) - target_link_libraries(uv_run_tests_a uv_a ${uv_test_libraries}) + if(QEMU) + target_link_libraries(uv_run_tests_a uv_a ${uv_test_libraries} -static) + else() + target_link_libraries(uv_run_tests_a uv_a ${uv_test_libraries}) + endif() add_test(NAME uv_test_a COMMAND uv_run_tests_a WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() -if(UNIX) +if(UNIX OR MINGW) # 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) + configure_file(libuv-static.pc.in libuv-static.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 ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() -if(WIN32) +if(MSVC) install(DIRECTORY include/ DESTINATION include) install(FILES LICENSE DESTINATION .) install(TARGETS uv uv_a RUNTIME DESTINATION lib/$ ARCHIVE DESTINATION lib/$) endif() + +message(STATUS "summary of build options: + Install prefix: ${CMAKE_INSTALL_PREFIX} + Target system: ${CMAKE_SYSTEM_NAME} + Compiler: + C compiler: ${CMAKE_C_COMPILER} + CFLAGS: ${CMAKE_C_FLAGS_${_build_type}} ${CMAKE_C_FLAGS} +") diff -Nru libuv1-1.34.2/common.gypi libuv1-1.40.0/common.gypi --- libuv1-1.34.2/common.gypi 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/common.gypi 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -{ - 'variables': { - 'target_arch%': 'ia32', # set v8's target architecture - 'host_arch%': 'ia32', # set v8's host architecture - 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds - 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way - }, - - 'target_defaults': { - 'default_configuration': 'Debug', - 'configurations': { - 'Debug': { - 'defines': [ 'DEBUG', '_DEBUG' ], - 'cflags': [ '-g' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['uv_library=="static_library"', { - 'RuntimeLibrary': 1, # /MTd static debug - }, { - 'RuntimeLibrary': 3, # /MDd DLL debug - }], - ], - 'Optimization': 0, # /Od, no optimization - 'MinimalRebuild': 'false', - 'OmitFramePointers': 'false', - 'BasicRuntimeChecks': 3, # /RTC1 - }, - 'VCLinkerTool': { - 'LinkIncremental': 2, # enable incremental linking - }, - }, - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '0', - }, - 'conditions': [ - ['OS != "zos"', { - 'cflags': [ '-O0', '-fno-common', '-fwrapv' ] - }], - ['OS == "android"', { - 'cflags': [ '-fPIE' ], - 'ldflags': [ '-fPIE', '-pie' ] - }] - ] - }, - 'Release': { - 'defines': [ 'NDEBUG' ], - 'cflags': [ - '-O3', - ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['uv_library=="static_library"', { - 'RuntimeLibrary': 0, # /MT static release - }, { - 'RuntimeLibrary': 2, # /MD DLL release - }], - ], - 'Optimization': 3, # /Ox, full optimization - 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size - 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible - 'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG - 'OmitFramePointers': 'true', - 'EnableFunctionLevelLinking': 'true', - 'EnableIntrinsicFunctions': 'true', - }, - 'VCLibrarianTool': { - 'AdditionalOptions': [ - '/LTCG', # link time code generation - ], - }, - 'VCLinkerTool': { - 'LinkTimeCodeGeneration': 1, # link-time code generation - 'OptimizeReferences': 2, # /OPT:REF - 'EnableCOMDATFolding': 2, # /OPT:ICF - 'LinkIncremental': 1, # disable incremental linking - }, - }, - 'conditions': [ - ['OS != "zos"', { - 'cflags': [ - '-fdata-sections', - '-ffunction-sections', - '-fno-common', - '-fomit-frame-pointer', - ], - }], - ] - } - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'StringPooling': 'true', # pool string literals - 'DebugInformationFormat': 3, # Generate a PDB - 'WarningLevel': 3, - 'BufferSecurityCheck': 'true', - 'ExceptionHandling': 1, # /EHsc - 'SuppressStartupBanner': 'true', - 'WarnAsError': 'false', - 'AdditionalOptions': [ - '/MP', # compile across multiple CPUs - ], - }, - 'VCLibrarianTool': { - }, - 'VCLinkerTool': { - 'GenerateDebugInformation': 'true', - 'RandomizedBaseAddress': 2, # enable ASLR - 'DataExecutionPrevention': 2, # enable DEP - 'AllowIsolation': 'true', - 'SuppressStartupBanner': 'true', - 'target_conditions': [ - ['_type=="executable"', { - 'SubSystem': 1, # console executable - }], - ], - }, - }, - 'conditions': [ - ['OS == "win"', { - 'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin - 'defines': [ - 'WIN32', - # we don't really want VC++ warning us about - # how dangerous C functions are... - '_CRT_SECURE_NO_DEPRECATE', - # ... or that C implementations shouldn't use - # POSIX names - '_CRT_NONSTDC_NO_DEPRECATE', - ], - 'target_conditions': [ - ['target_arch=="x64"', { - 'msvs_configuration_platform': 'x64' - }] - ] - }], - ['OS in "freebsd dragonflybsd linux openbsd solaris android aix"', { - 'cflags': [ '-Wall' ], - 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], - 'target_conditions': [ - ['_type=="static_library"', { - 'standalone_static_library': 1, # disable thin archive which needs binutils >= 2.19 - }], - ], - 'conditions': [ - [ 'host_arch != target_arch and target_arch=="ia32"', { - 'cflags': [ '-m32' ], - 'ldflags': [ '-m32' ], - }], - [ 'target_arch=="x32"', { - 'cflags': [ '-mx32' ], - 'ldflags': [ '-mx32' ], - }], - [ 'OS=="linux"', { - 'cflags': [ '-ansi' ], - }], - [ 'OS=="solaris"', { - 'cflags': [ '-pthreads' ], - 'ldflags': [ '-pthreads' ], - }], - [ 'OS not in "solaris android zos"', { - 'cflags': [ '-pthread' ], - 'ldflags': [ '-pthread' ], - }], - [ 'OS=="aix" and target_arch=="ppc64"', { - 'cflags': [ '-maix64' ], - 'ldflags': [ '-maix64' ], - }], - ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'ALWAYS_SEARCH_USER_PATHS': 'NO', - 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks - 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic - # (Equivalent to -fPIC) - 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions - 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti - 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics - 'PREBINDING': 'NO', # No -Wl,-prebind - 'USE_HEADERMAP': 'NO', - 'WARNING_CFLAGS': [ - '-Wall', - '-Wendif-labels', - '-W', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - }, - 'conditions': [ - ['target_arch=="ia32"', { - 'xcode_settings': {'ARCHS': ['i386']}, - }], - ['target_arch=="x64"', { - 'xcode_settings': {'ARCHS': ['x86_64']}, - }], - ], - 'target_conditions': [ - ['_type!="static_library"', { - 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, - }], - ], - }], - ['OS=="solaris"', { - 'cflags': [ '-fno-omit-frame-pointer' ], - # pull in V8's postmortem metadata - 'ldflags': [ '-Wl,-z,allextract' ] - }], - ], - }, -} diff -Nru libuv1-1.34.2/configure.ac libuv1-1.40.0/configure.ac --- libuv1-1.34.2/configure.ac 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/configure.ac 2020-09-25 00:34:43.000000000 +0000 @@ -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.40.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]) @@ -38,15 +38,17 @@ AC_PROG_LIBTOOL m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) LT_INIT -# TODO(bnoordhuis) Check for -pthread vs. -pthreads +AX_PTHREAD([ + LIBS="$LIBS $PTHREAD_LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +]) AC_CHECK_LIB([dl], [dlopen]) -AC_CHECK_LIB([kstat], [kstat_lookup]) -AC_CHECK_LIB([nsl], [gethostbyname]) -AC_CHECK_LIB([perfstat], [perfstat_cpu]) -AC_CHECK_LIB([pthread], [pthread_mutex_init]) -AC_CHECK_LIB([rt], [clock_gettime]) -AC_CHECK_LIB([sendfile], [sendfile]) -AC_CHECK_LIB([socket], [socket]) +AC_SEARCH_LIBS([kstat_lookup], [kstat]) +AC_SEARCH_LIBS([gethostbyname], [nsl]) +AC_SEARCH_LIBS([perfstat_cpu], [perfstat]) +AC_SEARCH_LIBS([clock_gettime], [rt]) +AC_SEARCH_LIBS([sendfile], [sendfile]) +AC_SEARCH_LIBS([socket], [socket]) AC_SYS_LARGEFILE AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])]) AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])]) diff -Nru libuv1-1.34.2/CONTRIBUTING.md libuv1-1.40.0/CONTRIBUTING.md --- libuv1-1.34.2/CONTRIBUTING.md 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/CONTRIBUTING.md 2020-09-25 00:34:43.000000000 +0000 @@ -48,11 +48,11 @@ 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. @@ -142,7 +142,6 @@ If you add a new test file, it needs to be registered in three places: - `CMakeLists.txt`: add the file's name to the `uv_test_sources` list. - `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. -- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. Look at other tests to see how they should be structured (license boilerplate, the way entry points are declared, etc.). diff -Nru libuv1-1.34.2/debian/changelog libuv1-1.40.0/debian/changelog --- libuv1-1.34.2/debian/changelog 2020-02-13 20:38:11.000000000 +0000 +++ libuv1-1.40.0/debian/changelog 2021-02-14 12:39:00.000000000 +0000 @@ -1,9 +1,91 @@ -libuv1 (1.34.2-1ubuntu1) focal; urgency=low +libuv1 (1.40.0-1.1~ubuntu20.04.1~ppa1) focal; urgency=medium - * Merge from Debian unstable. Remaining changes: - - Use python2 in the autopkg test. + * Set d/compat back to 9. + * No-change backport to focal - -- Steve Langasek Thu, 13 Feb 2020 12:38:11 -0800 + -- Andy Li Sun, 14 Feb 2021 20:39:00 +0800 + +libuv1 (1.40.0-1) unstable; urgency=medium + + * new upstream version + * update copyright with cme + * refreshed patch + * update symbol file + + -- Dominique Dumont Sat, 31 Oct 2020 18:43:46 +0100 + +libuv1 (1.39.0-1) unstable; urgency=medium + + * new upstream version + * update copyright with cme + * refreshed patch + * update symbol file + + -- Dominique Dumont Sun, 13 Sep 2020 17:27:18 +0200 + +libuv1 (1.38.0-3) unstable; urgency=medium + + * rules: increase timeout of time sensitive tests for all arch + + -- Dominique Dumont Sun, 28 Jun 2020 15:27:10 +0200 + +libuv1 (1.38.0-2) unstable; urgency=medium + + * use cmake instead of autotools to build libuv. + As a consequence: + * control: add cmake build dep + * archive lib is now libuv_a.a + * remove all internal symbols from symbol file + * rules is updated to not run tests in parallel + * remove autopkgtest (Closes: 961878) + + -- Dominique Dumont Wed, 10 Jun 2020 19:18:03 +0200 + +libuv1 (1.38.0-1) unstable; urgency=medium + + * new upstream version + * fill.copyright.blanks: add override for files under m4/ + * refreshed copyright with cme + * refreshed patches + * update symbols + * rules: increase test timeout for sparc64 + + -- Dominique Dumont Fri, 22 May 2020 18:55:41 +0200 + +libuv1 (1.35.0-2) unstable; urgency=medium + + * rules: fix increased timeout of time sensitive tests + + -- Dominique Dumont Thu, 16 Apr 2020 10:49:47 +0200 + +libuv1 (1.35.0-1) unstable; urgency=medium + + * new upstream version + * copyright: update with cme + * remove slow-down-some-tests patch + * README.source: fix instructions for symbol patch generation + * update symbols file + + -- Dominique Dumont Wed, 15 Apr 2020 16:29:44 +0200 + +libuv1 (1.34.2-4) experimental; urgency=medium + + * fix gnumake syntax + + -- Dominique Dumont Fri, 14 Feb 2020 10:01:00 +0100 + +libuv1 (1.34.2-3) experimental; urgency=medium + + * rules: slow down tests for hppa and riscv64 + + -- Dominique Dumont Thu, 13 Feb 2020 14:43:56 +0100 + +libuv1 (1.34.2-2) experimental; urgency=medium + + * add patch to slow test down for slow arches + * rules: relax timeout on heavy tests + + -- Dominique Dumont Wed, 12 Feb 2020 18:09:31 +0100 libuv1 (1.34.2-1) unstable; urgency=medium @@ -16,15 +98,6 @@ -- Dominique Dumont Fri, 07 Feb 2020 14:55:42 +0100 -libuv1 (1.33.1-3ubuntu1) focal; urgency=low - - * Merge from Debian unstable. Remaining changes: - - Use python2 in the autopkg test. - * Dropped changes, included in Debian: - - Make autopkgtests cross-build-friendly. - - -- Steve Langasek Sat, 01 Feb 2020 21:20:24 -0800 - libuv1 (1.33.1-3) unstable; urgency=medium * make autopkgtests cross-test-friendly. @@ -33,18 +106,6 @@ -- Dominique Dumont Fri, 31 Jan 2020 15:46:39 +0100 -libuv1 (1.33.1-2ubuntu2) focal; urgency=medium - - * Make autopkgtests cross-build-friendly. - - -- Steve Langasek Thu, 30 Jan 2020 16:53:07 -0800 - -libuv1 (1.33.1-2ubuntu1) focal; urgency=medium - - * Use python2 in the autopkg test. - - -- Matthias Klose Wed, 22 Jan 2020 08:36:19 +0100 - libuv1 (1.33.1-2) unstable; urgency=medium * add patch to disable multicast testsuite which break @@ -590,4 +651,3 @@ * Initial upload (Closes: #709480) -- Luca Bruno Sat, 25 May 2013 21:11:26 +0200 - diff -Nru libuv1-1.34.2/debian/compat libuv1-1.40.0/debian/compat --- libuv1-1.34.2/debian/compat 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/debian/compat 2021-02-14 11:39:07.000000000 +0000 @@ -0,0 +1 @@ +9 \ No newline at end of file diff -Nru libuv1-1.34.2/debian/control libuv1-1.40.0/debian/control --- libuv1-1.34.2/debian/control 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/control 2021-02-14 11:39:00.000000000 +0000 @@ -1,10 +1,10 @@ Source: libuv1 -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Dominique Dumont +Maintainer: Dominique Dumont Uploaders: Luca Bruno Section: libs Priority: optional -Build-Depends: debhelper-compat (= 12), +Build-Depends: cmake, + debhelper (>= 9), dh-exec, freebsd-glue [kfreebsd-any], libkvm-dev [kfreebsd-any], diff -Nru libuv1-1.34.2/debian/copyright libuv1-1.40.0/debian/copyright --- libuv1-1.34.2/debian/copyright 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/copyright 2021-02-14 11:38:29.000000000 +0000 @@ -17,7 +17,6 @@ ChangeLog MAINTAINERS.md SUPPORTED_PLATFORMS.md - gyp_uv.py libuv.pc.in Copyright: 2011-2015, Joyent, Inc. and other Node contributors. License: Expat @@ -64,14 +63,24 @@ Copyright: 2002, Niels Provos License: BSD-2-clause +Files: libuv-static.pc.in +Copyright: 2015-2020, libuv project contributors. + 2011-2015, Joyent, Inc. and other Node contributors. +License: Expat + Files: m4/* Copyright: 2011-2015, Joyent, Inc. and other Node contributors. License: Expat +Files: m4/ax_pthread.m4 +Copyright: 2011, Daniel Richard G. + 2008, Steven G. Johnson +License: GPL3+ with autoconf exception + Files: m4/libuv-check-flags.m4 Copyright: 2006-2008, xine project 2006-2008, Diego Pettenò -License: GPL-3+ +License: GPL3+ with autoconf exception Files: src/* Copyright: Joyent, Inc. and other Node contributors. @@ -93,10 +102,17 @@ Copyright: libuv contributors. License: Expat +Files: src/strscpy.c + src/strscpy.h + src/uv-data-getter-setters.c +Copyright: libuv project contributors. +License: Expat + Files: src/unix/aix-common.c src/unix/bsd-ifaddrs.c src/unix/bsd-proctitle.c src/unix/cygwin.c + src/unix/darwin-stub.h src/unix/haiku.c src/unix/ibmi.c src/unix/no-fsevents.c @@ -127,19 +143,17 @@ 2012, Google Inc. License: BSD-3-clause -Files: src/unix/random-devurandom.c +Files: src/unix/qnx.c + src/unix/random-devurandom.c src/unix/random-getentropy.c src/unix/random-getrandom.c src/unix/random-sysctl-linux.c Copyright: libuv contributors. License: Expat -Files: src/uv-data-getter-setters.c -Copyright: 2011-2015, Joyent, Inc. and other Node contributors. -License: Expat - Files: src/win/detect-wakeup.c -Copyright: 2011-2015, Joyent, Inc. and other Node contributors. + src/win/fs-fd-hash-inl.h +Copyright: libuv project contributors. License: Expat Files: src/win/snprintf.c @@ -150,24 +164,29 @@ Copyright: Joyent, Inc. and other Node contributors. License: Expat -Files: test/test-connect-unspecified.c +Files: test/benchmark-ping-udp.c + test/test-connect-unspecified.c test/test-eintr-handling.c test/test-fork.c test/test-fs-copyfile.c test/test-fs-fd-hash.c test/test-fs-open-flags.c test/test-fs-readdir.c + test/test-getters-setters.c test/test-gettimeofday.c test/test-homedir.c test/test-ipc-heavy-traffic-deadlock-bug.c + test/test-metrics.c test/test-pipe-set-fchmod.c test/test-poll-oob.c test/test-process-title-threadsafe.c test/test-signal-pending-on-close.c test/test-strscpy.c test/test-tcp-close-reset.c + test/test-tcp-read-stop-start.c test/test-tmpdir.c test/test-tty-duplicate-key.c + test/test-tty-escape-sequence-processing.c test/test-uname.c Copyright: libuv project contributors. License: Expat @@ -178,13 +197,11 @@ test/test-process-priority.c test/test-random.c test/test-tcp-try-write-error.c + test/test-test-macros.c + test/test-udp-mmsg.c Copyright: libuv contributors. License: Expat -Files: test/test-getters-setters.c -Copyright: 2011-2015, Joyent, Inc. and other Node contributors. -License: Expat - Files: test/test-idna.c test/test-queue-foreach-delete.c test/test-udp-send-hang-loop.c @@ -210,6 +227,7 @@ Files: test/test-tcp-alloc-cb-fail.c test/test-udp-connect.c + test/test-udp-sendmmsg-error.c Copyright: libuv project and contributors. License: Expat @@ -713,14 +731,32 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -License: GPL-3+ - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 3 dated June, 2007, or (at - your option) any later version. - . - On Debian systems, the complete text of version 3 of the GNU General - Public License can be found in '/usr/share/common-licenses/GPL-3'. +License: GPL3+ with autoconf exception + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + . + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + . + You should have received a copy of the GNU General Public License along + with this program. If not, see . + . + As a special exception, the respective Autoconf Macro's copyright owner + gives unlimited permission to copy, distribute and modify the configure + scripts that are the output of Autoconf when processing the Macro. You + need not follow the terms of the GNU General Public License when using + or distributing such scripts, even though portions of the text of the + Macro appear in them. The GNU General Public License (GPL) does govern + all other use of the material that constitutes the Autoconf Macro. + . + This special exception to the GPL applies to versions of the Autoconf + Macro released by the Autoconf Archive. When you make and distribute a + modified version of the Autoconf Macro, you may extend this special + exception to the GPL to apply to your modified version as well. License: ISC Permission to use, copy, modify, and distribute this software for any diff -Nru libuv1-1.34.2/debian/fill.copyright.blanks.yml libuv1-1.40.0/debian/fill.copyright.blanks.yml --- libuv1-1.34.2/debian/fill.copyright.blanks.yml 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/fill.copyright.blanks.yml 2021-02-14 11:38:29.000000000 +0000 @@ -11,3 +11,9 @@ include/uv/stdint-msvc2008.h: override-license: BSD-3-clause skip: false +m4/ax_pthread.m4: + override-license: GPL3+ with autoconf exception + skip: false +m4/libuv-check-flags.m4: + override-license: GPL3+ with autoconf exception + skip: false diff -Nru libuv1-1.34.2/debian/libuv1-dev.install libuv1-1.40.0/debian/libuv1-dev.install --- libuv1-1.34.2/debian/libuv1-dev.install 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/libuv1-dev.install 2021-02-14 11:38:29.000000000 +0000 @@ -1,5 +1,5 @@ #!/usr/bin/dh-exec usr/include usr/ -usr/lib/*/libuv.a usr/lib/${DEB_HOST_MULTIARCH}/ +usr/lib/*/libuv_a.a usr/lib/${DEB_HOST_MULTIARCH}/ usr/lib/*/pkgconfig usr/lib/${DEB_HOST_MULTIARCH}/ usr/lib/*/libuv.so usr/lib/${DEB_HOST_MULTIARCH}/ diff -Nru libuv1-1.34.2/debian/libuv1.symbols libuv1-1.40.0/debian/libuv1.symbols --- libuv1-1.34.2/debian/libuv1.symbols 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/libuv1.symbols 2021-02-14 11:38:29.000000000 +0000 @@ -1,109 +1,109 @@ libuv.so.1 libuv1 #MINVER# * Build-Depends-Package: libuv1-dev - (regex|optional)"^uv__" 1.0 +#MISSING: 1.40.0-1# (regex|optional)"^uv__" 1.0 (arch=hurd-any)pthread_atfork@Base 1.22.0-1 - (arch=linux-any|optional)uv__accept4@Base 1.11.0 - (optional)uv__accept@Base 1.11.0 - (optional)uv__async_close@Base 1.11.0 - (optional)uv__async_fork@Base 1.18.0 - (optional)uv__async_stop@Base 1.11.0 - (optional)uv__calloc@Base 1.11.0 - (optional)uv__check_close@Base 1.11.0 - (optional)uv__cloexec_fcntl@Base 1.11.0 - (optional)uv__cloexec_ioctl@Base 1.11.0 - (optional)uv__close@Base 1.11.0 - (optional)uv__close_nocheckstdio@Base 1.11.0 - (optional)uv__count_bufs@Base 1.11.0 - (optional)uv__dup2_cloexec@Base 1.11.0 - (arch=linux-any|optional)uv__dup3@Base 1.11.0 -#MISSING: 1.34.2-1# (optional)uv__dup@Base 1.11.0 - (arch=linux-any|optional)uv__eventfd2@Base 1.11.0 - (arch=linux-any|optional)uv__eventfd@Base 1.11.0 - (optional)uv__fd_exists@Base 1.21.0 - (optional)uv__free@Base 1.11.0 - (optional)uv__fs_event_close@Base 1.11.0 - (optional)uv__fs_poll_close@Base 1.11.0 - (optional)uv__fs_scandir_cleanup@Base 1.11.0 - (optional)uv__getaddrinfo_translate_error@Base 1.11.0 - (optional)uv__getiovmax@Base 1.11.0 - (optional)uv__getpwuid_r@Base 1.11.0 - (optional)uv__handle_type@Base 1.11.0 - (optional)uv__hrtime@Base 1.11.0 - (optional)uv__idle_close@Base 1.11.0 - (arch=linux-any|optional)uv__inotify_add_watch@Base 1.11.0 - (arch=linux-any|optional)uv__inotify_fork@Base 1.18.0 - (arch=linux-any|optional)uv__inotify_init1@Base 1.11.0 - (arch=linux-any|optional)uv__inotify_init@Base 1.11.0 - (arch=linux-any|optional)uv__inotify_rm_watch@Base 1.11.0 - (optional)uv__io_active@Base 1.11.0 - (optional)uv__io_check_fd@Base 1.11.0 - (optional)uv__io_close@Base 1.11.0 - (optional)uv__io_feed@Base 1.11.0 - (optional)uv__io_fork@Base 1.18.0 - (optional)uv__io_init@Base 1.11.0 - (optional)uv__io_poll@Base 1.11.0 - (optional)uv__io_start@Base 1.11.0 - (optional)uv__io_stop@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__accept4@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__accept@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__async_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__async_fork@Base 1.18.0 +#MISSING: 1.40.0-1# (optional)uv__async_stop@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__calloc@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__check_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__cloexec_fcntl@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__cloexec_ioctl@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__close_nocheckstdio@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__count_bufs@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__dup2_cloexec@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__dup3@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__dup@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__eventfd2@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__eventfd@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__fd_exists@Base 1.21.0 +#MISSING: 1.40.0-1# (optional)uv__free@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__fs_event_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__fs_poll_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__fs_scandir_cleanup@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__getaddrinfo_translate_error@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__getiovmax@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__getpwuid_r@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__handle_type@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__hrtime@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__idle_close@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__inotify_add_watch@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__inotify_fork@Base 1.18.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__inotify_init1@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__inotify_init@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__inotify_rm_watch@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_active@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_check_fd@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_feed@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_fork@Base 1.18.0 +#MISSING: 1.40.0-1# (optional)uv__io_init@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_poll@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_start@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__io_stop@Base 1.11.0 (arch=kfreebsd-any|optional)uv__kqueue_init@Base 1.22.0-1 - (optional)uv__loop_close@Base 1.11.0 - (optional)uv__loop_configure@Base 1.11.0 - (optional)uv__make_close_pending@Base 1.11.0 - (optional)uv__make_pipe@Base 1.11.0 - (optional)uv__make_socketpair@Base 1.11.0 - (optional)uv__malloc@Base 1.11.0 - (optional)uv__next_timeout@Base 1.11.0 - (optional)uv__nonblock_fcntl@Base 1.11.0 - (optional)uv__nonblock_ioctl@Base 1.11.0 - (optional)uv__open_cloexec@Base 1.11.0 - (optional)uv__open_file@Base 1.11.0 - (arch=linux-any|optional)uv__pipe2@Base 1.11.0 - (optional)uv__pipe_close@Base 1.11.0 - (optional)uv__platform_invalidate_fd@Base 1.11.0 - (optional)uv__platform_loop_delete@Base 1.11.0 - (optional)uv__platform_loop_init@Base 1.11.0 - (optional)uv__poll_close@Base 1.11.0 - (arch=linux-any|optional)uv__preadv@Base 1.11.0 - (optional)uv__prepare_close@Base 1.11.0 - (optional)uv__process_close@Base 1.11.0 - (arch=linux-any|optional)uv__pwritev@Base 1.11.0 - (optional)uv__realloc@Base 1.11.0 - (arch=linux-any|optional)uv__recvmmsg@Base 1.11.0 - (optional)uv__recvmsg@Base 1.11.0 - (optional)uv__run_check@Base 1.11.0 - (optional)uv__run_idle@Base 1.11.0 - (optional)uv__run_prepare@Base 1.11.0 - (optional)uv__run_timers@Base 1.11.0 - (arch=linux-any|optional)uv__sendmmsg@Base 1.11.0 - (optional)uv__server_io@Base 1.11.0 - (arch=!hurd-any !kfreebsd-any|optional)uv__set_process_title@Base 1.11.0 - (optional)uv__signal_close@Base 1.11.0 - (optional)uv__signal_global_once_init@Base 1.11.0 - (optional)uv__signal_loop_cleanup@Base 1.11.0 - (optional)uv__signal_loop_fork@Base 1.18.0 - (optional)uv__socket@Base 1.11.0 - (optional)uv__socket_sockopt@Base 1.11.0 - (optional)uv__strdup@Base 1.11.0 - (optional)uv__stream_close@Base 1.11.0 - (optional)uv__stream_destroy@Base 1.11.0 - (optional)uv__stream_flush_write_queue@Base 1.11.0 - (optional)uv__stream_init@Base 1.11.0 - (optional)uv__stream_open@Base 1.11.0 - (optional)uv__strndup@Base 1.11.0 - (optional)uv__tcp_bind@Base 1.11.0 - (optional)uv__tcp_close@Base 1.11.0 - (optional)uv__tcp_connect@Base 1.11.0 - (optional)uv__tcp_keepalive@Base 1.11.0 - (optional)uv__tcp_nodelay@Base 1.11.0 - (optional)uv__timer_close@Base 1.11.0 - (optional)uv__udp_bind@Base 1.11.0 - (optional)uv__udp_close@Base 1.11.0 - (optional)uv__udp_finish_close@Base 1.11.0 - (optional)uv__udp_recv_start@Base 1.11.0 - (optional)uv__udp_recv_stop@Base 1.11.0 - (optional)uv__udp_send@Base 1.11.0 - (optional)uv__udp_try_send@Base 1.11.0 - (optional)uv__work_done@Base 1.11.0 - (optional)uv__work_submit@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__loop_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__loop_configure@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__make_close_pending@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__make_pipe@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__make_socketpair@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__malloc@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__next_timeout@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__nonblock_fcntl@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__nonblock_ioctl@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__open_cloexec@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__open_file@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__pipe2@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__pipe_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__platform_invalidate_fd@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__platform_loop_delete@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__platform_loop_init@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__poll_close@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__preadv@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__prepare_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__process_close@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__pwritev@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__realloc@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__recvmmsg@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__recvmsg@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__run_check@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__run_idle@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__run_prepare@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__run_timers@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=linux-any|optional)uv__sendmmsg@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__server_io@Base 1.11.0 +#MISSING: 1.40.0-1# (arch=!hurd-any !kfreebsd-any|optional)uv__set_process_title@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__signal_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__signal_global_once_init@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__signal_loop_cleanup@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__signal_loop_fork@Base 1.18.0 +#MISSING: 1.40.0-1# (optional)uv__socket@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__socket_sockopt@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__strdup@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__stream_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__stream_destroy@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__stream_flush_write_queue@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__stream_init@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__stream_open@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__strndup@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__tcp_bind@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__tcp_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__tcp_connect@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__tcp_keepalive@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__tcp_nodelay@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__timer_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_bind@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_finish_close@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_recv_start@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_recv_stop@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_send@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__udp_try_send@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__work_done@Base 1.11.0 +#MISSING: 1.40.0-1# (optional)uv__work_submit@Base 1.11.0 uv_accept@Base 1.4.2 uv_async_init@Base 1.4.2 uv_async_send@Base 1.4.2 @@ -161,10 +161,12 @@ uv_fs_get_ptr@Base 1.20.2 uv_fs_get_result@Base 1.20.2 uv_fs_get_statbuf@Base 1.20.2 + uv_fs_get_system_error@Base 1.38.0 uv_fs_get_type@Base 1.20.2 uv_fs_lchown@Base 1.21.0 uv_fs_link@Base 1.4.2 uv_fs_lstat@Base 1.4.2 + uv_fs_lutime@Base 1.38.0 uv_fs_mkdir@Base 1.4.2 uv_fs_mkdtemp@Base 1.4.2 uv_fs_mkstemp@Base 1.34.2 @@ -229,6 +231,7 @@ uv_key_get@Base 1.4.2 uv_key_set@Base 1.4.2 uv_kill@Base 1.4.2 + uv_library_shutdown@Base 1.38.0 uv_listen@Base 1.4.2 (arch=!hurd-any)uv_loadavg@Base 1.4.2 uv_loop_alive@Base 1.4.2 @@ -241,6 +244,7 @@ uv_loop_new@Base 1.4.2 uv_loop_set_data@Base 1.20.2 uv_loop_size@Base 1.4.2 + uv_metrics_idle_time@Base 1.39.0 uv_mutex_destroy@Base 1.4.2 uv_mutex_init@Base 1.4.2 uv_mutex_init_recursive@Base 1.18.0 @@ -271,7 +275,7 @@ uv_pipe_getpeername@Base 1.4.2 uv_pipe_getsockname@Base 1.4.2 uv_pipe_init@Base 1.4.2 - uv_pipe_listen@Base 1.11.0 +#MISSING: 1.38.0-2# uv_pipe_listen@Base 1.11.0 uv_pipe_open@Base 1.4.2 uv_pipe_pending_count@Base 1.4.2 uv_pipe_pending_instances@Base 1.4.2 @@ -337,7 +341,7 @@ uv_tcp_init@Base 1.4.2 uv_tcp_init_ex@Base 1.7.0 uv_tcp_keepalive@Base 1.4.2 - uv_tcp_listen@Base 1.11.0 +#MISSING: 1.38.0-2# uv_tcp_listen@Base 1.11.0 uv_tcp_nodelay@Base 1.4.2 uv_tcp_open@Base 1.4.2 uv_tcp_simultaneous_accepts@Base 1.4.2 @@ -347,6 +351,7 @@ uv_thread_join@Base 1.4.2 uv_thread_self@Base 1.4.2 uv_timer_again@Base 1.4.2 + uv_timer_get_due_in@Base 1.40.0 uv_timer_get_repeat@Base 1.4.2 uv_timer_init@Base 1.4.2 uv_timer_set_repeat@Base 1.4.2 @@ -354,7 +359,7 @@ uv_timer_stop@Base 1.4.2 uv_translate_sys_error@Base 1.11.0 uv_try_write@Base 1.4.2 - uv_try_write_cb@Base 1.11.0 +#MISSING: 1.38.0-2# uv_try_write_cb@Base 1.11.0 uv_tty_get_vterm_state@Base 1.33.1 uv_tty_get_winsize@Base 1.4.2 uv_tty_init@Base 1.4.2 @@ -381,6 +386,7 @@ uv_udp_set_source_membership@Base 1.33.1 uv_udp_set_ttl@Base 1.4.2 uv_udp_try_send@Base 1.4.2 + uv_udp_using_recvmmsg@Base 1.39.0 uv_unref@Base 1.4.2 uv_update_time@Base 1.4.2 (arch=!hurd-any)uv_uptime@Base 1.4.2 diff -Nru libuv1-1.34.2/debian/patches/disable_ipv6_test.patch libuv1-1.40.0/debian/patches/disable_ipv6_test.patch --- libuv1-1.34.2/debian/patches/disable_ipv6_test.patch 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/patches/disable_ipv6_test.patch 2021-02-14 11:38:29.000000000 +0000 @@ -4,8 +4,8 @@ Description: export RES_OPTIONS = attempts:0 makes this test fail --- a/test/test-getnameinfo.c +++ b/test/test-getnameinfo.c -@@ -84,6 +84,8 @@ - TEST_IMPL(getnameinfo_basic_ip6) { +@@ -99,6 +99,8 @@ + int r; + RETURN_SKIP("DNS request disabled in ipv6 test"); diff -Nru libuv1-1.34.2/debian/patches/path_max_zero_st_size libuv1-1.40.0/debian/patches/path_max_zero_st_size --- libuv1-1.34.2/debian/patches/path_max_zero_st_size 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/patches/path_max_zero_st_size 2021-02-14 11:38:29.000000000 +0000 @@ -74,7 +74,7 @@ --- a/src/unix/fs.c +++ b/src/unix/fs.c -@@ -690,6 +690,17 @@ +@@ -712,6 +712,17 @@ maxlen = uv__fs_pathmax_size(req->path); #endif diff -Nru libuv1-1.34.2/debian/patches/python2.diff libuv1-1.40.0/debian/patches/python2.diff --- libuv1-1.34.2/debian/patches/python2.diff 2020-01-22 07:35:58.000000000 +0000 +++ libuv1-1.40.0/debian/patches/python2.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Index: b/gyp_uv.py -=================================================================== ---- a/gyp_uv.py -+++ b/gyp_uv.py -@@ -1,4 +1,4 @@ --#!/usr/bin/env python -+#!/usr/bin/python2 - - import os - import platform -Index: b/tools/make_dist_html.py -=================================================================== ---- a/tools/make_dist_html.py -+++ b/tools/make_dist_html.py -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python2 - - from __future__ import print_function - diff -Nru libuv1-1.34.2/debian/patches/series libuv1-1.40.0/debian/patches/series --- libuv1-1.34.2/debian/patches/series 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/patches/series 2021-02-14 11:38:29.000000000 +0000 @@ -3,4 +3,3 @@ disable_ipv6_test.patch path_max_zero_st_size skip-multicast-test -python2.diff diff -Nru libuv1-1.34.2/debian/README.source libuv1-1.40.0/debian/README.source --- libuv1-1.34.2/debian/README.source 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/README.source 2021-02-14 11:38:29.000000000 +0000 @@ -37,7 +37,7 @@ step without forgetting the --git-no-purge flag) - dpkg-gensymbols -plibuv1 - review the diff (see links below) -- create a patch : dpkg-gensymbols -plibuv1 | perl -p -E 's/([\d.]+)-\d[^#\n]*/$1/;' > /tmp/sym.patch +- create a patch : dpkg-gensymbols -plibuv1 |perl -p -E 's/([\d.]+)-\d[^#\n]*/$1/ if /^\+ /; s/~\d[^#\n]*//;' > /tmp/sym.patch - cd - - apply the patch: patch debian/libuv1.symbols /tmp/sym.patch @@ -51,7 +51,7 @@ Note: only committed changes are used by gbp buildpackage Update the changelog: -- gbp dch -Ra +- gbp dch -Ra --commit Once everything is fine, build a source package and tag: - gbp buildpackage -S --git-tag @@ -62,4 +62,4 @@ For more details, see https://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.import.upstream-git.html#gbp.import.upstream.git.notarball - -- Dominique Dumont , Thu, 31 Oct 2019 12:14:14 +0100 + -- Dominique Dumont , Fri, 22 May 2020 18:55:50 +0200 diff -Nru libuv1-1.34.2/debian/rules libuv1-1.40.0/debian/rules --- libuv1-1.34.2/debian/rules 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/rules 2021-02-14 11:38:29.000000000 +0000 @@ -19,25 +19,20 @@ # tell glibc to disable dns requests for the tests export RES_OPTIONS = attempts:0 -%: - dh $@ --with autoreconf +$(info "Note: Increasing timeout of time sensitive tests") +export UV_TEST_TIMEOUT_MULTIPLIER = 2 -override_dh_autoreconf: - dh_autoreconf ./autogen.sh +%: + dh $@ --without autoreconf override_dh_strip: dh_strip --dbgsym-migration='$(SOPKG)-dbg (<< 1.11.0-1~)' -override_dh_clean: - dh_clean - # Clean autoreconf files - $(RM) -- ltmain.sh m4/libtool.m4 - find m4 -name 'lt*.m4' -delete - # Testsuite is not robust enough, ignore errors on non-linux override_dh_auto_test: ifeq ($(DEB_BUILD_ARCH_OS),linux) - dh_auto_test +# tests fail if they are run in parallel + dh_auto_test --no-parallel else -dh_auto_test endif diff -Nru libuv1-1.34.2/debian/tests/control libuv1-1.40.0/debian/tests/control --- libuv1-1.34.2/debian/tests/control 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Tests: run-tests -Restrictions: allow-stderr -Depends: @, gyp:native, build-essential diff -Nru libuv1-1.34.2/debian/tests/run-tests libuv1-1.40.0/debian/tests/run-tests --- libuv1-1.34.2/debian/tests/run-tests 2020-02-07 23:54:36.000000000 +0000 +++ libuv1-1.40.0/debian/tests/run-tests 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -#!/bin/bash - -set -e - -echo "creating makefile for tests" -./gyp_uv.py -f make - -if [ -n "${DEB_HOST_GNU_TYPE:-}" ]; then - CROSS_COMPILE=${DEB_HOST_GNU_TYPE}- -else - CROSS_COMPILE= -fi - -echo "creating test binaries" -make -C out CC=${CROSS_COMPILE}gcc LINK=${CROSS_COMPILE}gcc - -echo "Runing tests" -./out/Debug/run-tests - -echo "tests are done" diff -Nru libuv1-1.34.2/docs/code/multi-echo-server/main.c libuv1-1.40.0/docs/code/multi-echo-server/main.c --- libuv1-1.34.2/docs/code/multi-echo-server/main.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/code/multi-echo-server/main.c 2020-09-25 00:34:43.000000000 +0000 @@ -70,7 +70,7 @@ child_worker_count = cpu_count; - workers = calloc(sizeof(struct child_worker), cpu_count); + workers = calloc(cpu_count, sizeof(struct child_worker)); while (cpu_count--) { struct child_worker *worker = &workers[cpu_count]; uv_pipe_init(loop, &worker->pipe, 1); diff -Nru libuv1-1.34.2/docs/src/api.rst libuv1-1.40.0/docs/src/api.rst --- libuv1-1.34.2/docs/src/api.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/api.rst 2020-09-25 00:34:43.000000000 +0000 @@ -32,4 +32,5 @@ dll threading misc + metrics diff -Nru libuv1-1.34.2/docs/src/async.rst libuv1-1.40.0/docs/src/async.rst --- libuv1-1.34.2/docs/src/async.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/async.rst 2020-09-25 00:34:43.000000000 +0000 @@ -51,7 +51,7 @@ loop thread. .. note:: - :c:func:`uv_async_send` is `async-signal-safe `_. + :c:func:`uv_async_send` is `async-signal-safe `_. It's safe to call this function from a signal handler. .. warning:: diff -Nru libuv1-1.34.2/docs/src/check.rst libuv1-1.40.0/docs/src/check.rst --- libuv1-1.34.2/docs/src/check.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/check.rst 2020-09-25 00:34:43.000000000 +0000 @@ -33,14 +33,22 @@ .. c:function:: int uv_check_init(uv_loop_t* loop, uv_check_t* check) - Initialize the handle. + Initialize the handle. This function always succeeds. + + :returns: 0 .. c:function:: int uv_check_start(uv_check_t* check, uv_check_cb cb) - Start the handle with the given callback. + Start the handle with the given callback. This function always succeeds, + except when `cb` is `NULL`. + + :returns: 0 on success, or `UV_EINVAL` when `cb == NULL`. .. c:function:: int uv_check_stop(uv_check_t* check) Stop the handle, the callback will no longer be called. + This function always succeeds. + + :returns: 0 .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff -Nru libuv1-1.34.2/docs/src/errors.rst libuv1-1.40.0/docs/src/errors.rst --- libuv1-1.34.2/docs/src/errors.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/errors.rst 2020-09-25 00:34:43.000000000 +0000 @@ -319,11 +319,23 @@ too many links +.. c:macro:: UV_ENOTTY + + inappropriate ioctl for device + +.. c:macro:: UV_EFTYPE + + inappropriate file type or format + +.. c:macro:: UV_EILSEQ + + illegal byte sequence + API --- -.. c:function:: UV_ERRNO_MAP(iter_macro) +.. c:macro:: UV_ERRNO_MAP(iter_macro) Macro that expands to a series of invocations of `iter_macro` for each of the error constants above. `iter_macro` is invoked with two diff -Nru libuv1-1.34.2/docs/src/fs.rst libuv1-1.40.0/docs/src/fs.rst --- libuv1-1.34.2/docs/src/fs.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/fs.rst 2020-09-25 00:34:43.000000000 +0000 @@ -58,7 +58,7 @@ uv_timespec_t st_birthtim; } uv_stat_t; -.. c:type:: uv_fs_type +.. c:enum:: uv_fs_type File system request type. @@ -100,7 +100,8 @@ UV_FS_OPENDIR, UV_FS_READDIR, UV_FS_CLOSEDIR, - UV_FS_MKSTEMP + UV_FS_MKSTEMP, + UV_FS_LUTIME } uv_fs_type; .. c:type:: uv_statfs_t @@ -121,7 +122,7 @@ uint64_t f_spare[4]; } uv_statfs_t; -.. c:type:: uv_dirent_t +.. c:enum:: uv_dirent_t Cross platform (reduced) equivalent of ``struct dirent``. Used in :c:func:`uv_fs_scandir_next`. @@ -402,12 +403,17 @@ .. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) .. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) +.. c:function:: int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) - Equivalent to :man:`utime(2)` and :man:`futimes(3)` respectively. + Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively. .. note:: - AIX: This function only works for AIX 7.1 and newer. It can still be called on older - versions but will return ``UV_ENOSYS``. + z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return + ``UV_ENOSYS``. + + .. note:: + AIX: `uv_fs_futime()` and `uv_fs_lutime()` functions only work for AIX 7.1 and newer. + They can still be called on older versions but will return ``UV_ENOSYS``. .. versionchanged:: 1.10.0 sub-second precission is supported on Windows @@ -486,6 +492,13 @@ .. versionadded:: 1.19.0 +.. c:function:: int uv_fs_get_system_error(const uv_fs_t* req) + + Returns the platform specific error code - `GetLastError()` value on Windows + and `-(req->result)` on other platforms. + + .. versionadded:: 1.38.0 + .. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) Returns `req->ptr`. @@ -522,8 +535,8 @@ For a OS-dependent handle, get the file descriptor in the C runtime. On UNIX, returns the ``os_fd`` intact. On Windows, this calls `_open_osfhandle `_. - Note that the return value is still owned by the CRT, - any attempts to close it or to use it after closing the handle may lead to malfunction. + Note that this consumes the argument, any attempts to close it or to use it + after closing the return value may lead to malfunction. .. versionadded:: 1.23.0 diff -Nru libuv1-1.34.2/docs/src/guide/filesystem.rst libuv1-1.40.0/docs/src/guide/filesystem.rst --- libuv1-1.34.2/docs/src/guide/filesystem.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/guide/filesystem.rst 2020-09-25 00:34:43.000000000 +0000 @@ -33,7 +33,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) ``flags`` and ``mode`` are standard -`Unix flags `_. +`Unix flags `_. libuv takes care of converting to the appropriate Windows flags. File descriptors are closed using diff -Nru libuv1-1.34.2/docs/src/guide/networking.rst libuv1-1.40.0/docs/src/guide/networking.rst --- libuv1-1.34.2/docs/src/guide/networking.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/guide/networking.rst 2020-09-25 00:34:43.000000000 +0000 @@ -200,7 +200,7 @@ If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and your callback won't be invoked at all. All arguments can be freed immediately after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` -structures are documented in `the getaddrinfo man page `_. The +structures are documented in `the getaddrinfo man page `_. The callback can be ``NULL`` in which case the function will run synchronously. In the resolver callback, you can pick any IP from the linked list of ``struct @@ -235,7 +235,7 @@ times, with each address being reported once. .. _c-ares: https://c-ares.haxx.se -.. _getaddrinfo: https://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html +.. _getaddrinfo: https://man7.org/linux/man-pages/man3/getaddrinfo.3.html .. _User Datagram Protocol: https://en.wikipedia.org/wiki/User_Datagram_Protocol .. _DHCP: https://tools.ietf.org/html/rfc2131 diff -Nru libuv1-1.34.2/docs/src/guide/processes.rst libuv1-1.40.0/docs/src/guide/processes.rst --- libuv1-1.34.2/docs/src/guide/processes.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/guide/processes.rst 2020-09-25 00:34:43.000000000 +0000 @@ -266,10 +266,10 @@ This is intended for the purpose of allowing multiple libuv processes to communicate with IPC. This is discussed below. -.. _pipe(7): http://man7.org/linux/man-pages/man7/pipe.7.html -.. _mkfifo(1): http://man7.org/linux/man-pages/man1/mkfifo.1.html -.. _socketpair(2): http://man7.org/linux/man-pages/man2/socketpair.2.html -.. _Unix Domain Socket: http://man7.org/linux/man-pages/man7/unix.7.html +.. _pipe(7): https://man7.org/linux/man-pages/man7/pipe.7.html +.. _mkfifo(1): https://man7.org/linux/man-pages/man1/mkfifo.1.html +.. _socketpair(2): https://man7.org/linux/man-pages/man2/socketpair.2.html +.. _Unix Domain Socket: https://man7.org/linux/man-pages/man7/unix.7.html .. _Named Pipe: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes diff -Nru libuv1-1.34.2/docs/src/guide/threads.rst libuv1-1.40.0/docs/src/guide/threads.rst --- libuv1-1.34.2/docs/src/guide/threads.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/guide/threads.rst 2020-09-25 00:34:43.000000000 +0000 @@ -293,7 +293,7 @@ .. rubric:: progress/main.c .. literalinclude:: ../../code/progress/main.c :linenos: - :lines: 7-8,34- + :lines: 7-8,35- :emphasize-lines: 2,11 The async thread communication works *on loops* so although any thread can be @@ -318,7 +318,7 @@ .. rubric:: progress/main.c .. literalinclude:: ../../code/progress/main.c :linenos: - :lines: 10-23 + :lines: 10-24 :emphasize-lines: 7-8 In the download function, we modify the progress indicator and queue the message @@ -328,7 +328,7 @@ .. rubric:: progress/main.c .. literalinclude:: ../../code/progress/main.c :linenos: - :lines: 30-33 + :lines: 31-34 The callback is a standard libuv pattern, extracting the data from the watcher. @@ -337,7 +337,7 @@ .. rubric:: progress/main.c .. literalinclude:: ../../code/progress/main.c :linenos: - :lines: 25-28 + :lines: 26-29 :emphasize-lines: 3 After this example, which showed the abuse of the ``data`` field, bnoordhuis_ diff -Nru libuv1-1.34.2/docs/src/guide/utilities.rst libuv1-1.40.0/docs/src/guide/utilities.rst --- libuv1-1.34.2/docs/src/guide/utilities.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/guide/utilities.rst 2020-09-25 00:34:43.000000000 +0000 @@ -243,7 +243,7 @@ you so desire. ``start_timeout`` will be called immediately the first time by libcurl, so -things are set in motion. This simply starts a libuv `timer `_ which +things are set in motion. This simply starts a libuv `timer <#timers>`_ which drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it times out. ``curl_multi_socket_action`` is what drives libcurl, and what we call whenever sockets change state. But before we go into that, we need to poll diff -Nru libuv1-1.34.2/docs/src/handle.rst libuv1-1.40.0/docs/src/handle.rst --- libuv1-1.34.2/docs/src/handle.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/handle.rst 2020-09-25 00:34:43.000000000 +0000 @@ -20,7 +20,7 @@ The base libuv handle type. -.. c:type:: uv_handle_type +.. c:enum:: uv_handle_type The kind of the libuv handle. @@ -104,7 +104,7 @@ API --- -.. c:function:: UV_HANDLE_TYPE_MAP(iter_macro) +.. c:macro:: UV_HANDLE_TYPE_MAP(iter_macro) Macro that expands to a series of invocations of `iter_macro` for each of the handle types. `iter_macro` is invoked with two diff -Nru libuv1-1.34.2/docs/src/idle.rst libuv1-1.40.0/docs/src/idle.rst --- libuv1-1.34.2/docs/src/idle.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/idle.rst 2020-09-25 00:34:43.000000000 +0000 @@ -41,14 +41,22 @@ .. c:function:: int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) - Initialize the handle. + Initialize the handle. This function always succeeds. + + :returns: 0 .. c:function:: int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) - Start the handle with the given callback. + Start the handle with the given callback. This function always succeeds, + except when `cb` is `NULL`. + + :returns: 0 on success, or `UV_EINVAL` when `cb == NULL`. .. c:function:: int uv_idle_stop(uv_idle_t* idle) Stop the handle, the callback will no longer be called. + This function always succeeds. + + :returns: 0 .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff -Nru libuv1-1.34.2/docs/src/loop.rst libuv1-1.40.0/docs/src/loop.rst --- libuv1-1.34.2/docs/src/loop.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/loop.rst 2020-09-25 00:34:43.000000000 +0000 @@ -16,7 +16,7 @@ Loop data type. -.. c:type:: uv_run_mode +.. c:enum:: uv_run_mode Mode used to run the loop with :c:func:`uv_run`. @@ -68,6 +68,13 @@ to suppress unnecessary wakeups when using a sampling profiler. Requesting other signals will fail with UV_EINVAL. + - UV_METRICS_IDLE_TIME: Accumulate the amount of idle time the event loop + spends in the event provider. + + This option is necessary to use :c:func:`uv_metrics_idle_time`. + + .. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option. + .. c:function:: int uv_loop_close(uv_loop_t* loop) Releases all internal loop resources. Call this function only when the loop diff -Nru libuv1-1.34.2/docs/src/metrics.rst libuv1-1.40.0/docs/src/metrics.rst --- libuv1-1.34.2/docs/src/metrics.rst 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/docs/src/metrics.rst 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,27 @@ + +.. _metrics: + +Metrics operations +====================== + +libuv provides a metrics API to track the amount of time the event loop has +spent idle in the kernel's event provider. + +API +--- + +.. c:function:: uint64_t uv_metrics_idle_time(uv_loop_t* loop) + + Retrieve the amount of time the event loop has been idle in the kernel's + event provider (e.g. ``epoll_wait``). The call is thread safe. + + The return value is the accumulated time spent idle in the kernel's event + provider starting from when the :c:type:`uv_loop_t` was configured to + collect the idle time. + + .. note:: + The event loop will not begin accumulating the event provider's idle + time until calling :c:type:`uv_loop_configure` with + :c:type:`UV_METRICS_IDLE_TIME`. + + .. versionadded:: 1.39.0 diff -Nru libuv1-1.34.2/docs/src/misc.rst libuv1-1.40.0/docs/src/misc.rst --- libuv1-1.34.2/docs/src/misc.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/misc.rst 2020-09-25 00:34:43.000000000 +0000 @@ -131,11 +131,11 @@ char* model; int speed; struct uv_cpu_times_s { - uint64_t user; - uint64_t nice; - uint64_t sys; - uint64_t idle; - uint64_t irq; + uint64_t user; /* milliseconds */ + uint64_t nice; /* milliseconds */ + uint64_t sys; /* milliseconds */ + uint64_t idle; /* milliseconds */ + uint64_t irq; /* milliseconds */ } cpu_times; } uv_cpu_info_t; @@ -233,6 +233,24 @@ sure the allocator is changed while no memory was allocated with the previous allocator, or that they are compatible. + .. warning:: Allocator must be thread-safe. + +.. c:function:: void uv_library_shutdown(void); + + .. versionadded:: 1.38.0 + + Release any global state that libuv is holding onto. Libuv will normally + do so automatically when it is unloaded but it can be instructed to perform + cleanup manually. + + .. warning:: Only call :c:func:`uv_library_shutdown()` once. + + .. warning:: Don't call :c:func:`uv_library_shutdown()` when there are + still event loops or I/O requests active. + + .. warning:: Don't call libuv functions after calling + :c:func:`uv_library_shutdown()`. + .. c:function:: uv_buf_t uv_buf_init(char* base, unsigned int len) Constructor for :c:type:`uv_buf_t`. @@ -243,27 +261,51 @@ .. c:function:: char** uv_setup_args(int argc, char** argv) - Store the program arguments. Required for getting / setting the process title. + Store the program arguments. Required for getting / setting the process title + or the executable path. 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) Gets the title of the current process. You *must* call `uv_setup_args` - before calling this function. If `buffer` is `NULL` or `size` is zero, - `UV_EINVAL` is returned. If `size` cannot accommodate the process title and - terminating `NULL` character, the function returns `UV_ENOBUFS`. + before calling this function on Unix and AIX systems. If `uv_setup_args` + has not been called on systems that require it, then `UV_ENOBUFS` is + returned. If `buffer` is `NULL` or `size` is zero, `UV_EINVAL` is returned. + If `size` cannot accommodate the process title and terminating `nul` + character, the function returns `UV_ENOBUFS`. + + .. note:: + On BSD systems, `uv_setup_args` is needed for getting the initial process + title. The process title returned will be an empty string until either + `uv_setup_args` or `uv_set_process_title` is called. .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + .. versionchanged:: 1.39.0 now returns an error if `uv_setup_args` is needed + but hasn't been called. + .. c:function:: int uv_set_process_title(const char* title) Sets the current process title. You *must* call `uv_setup_args` before - calling this function. On platforms with a fixed size buffer for the process - title the contents of `title` will be copied to the buffer and truncated if - larger than the available space. Other platforms will return `UV_ENOMEM` if - they cannot allocate enough space to duplicate the contents of `title`. + calling this function on Unix and AIX systems. If `uv_setup_args` has not + been called on systems that require it, then `UV_ENOBUFS` is returned. On + platforms with a fixed size buffer for the process title the contents of + `title` will be copied to the buffer and truncated if larger than the + available space. Other platforms will return `UV_ENOMEM` if they cannot + allocate enough space to duplicate the contents of `title`. .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + .. versionchanged:: 1.39.0 now returns an error if `uv_setup_args` is needed + but hasn't been called. + .. c:function:: int uv_resident_set_memory(size_t* rss) Gets the resident set size (RSS) for the current process. @@ -398,7 +440,8 @@ .. c:function:: int uv_exepath(char* buffer, size_t* size) - Gets the executable path. + Gets the executable path. You *must* call `uv_setup_args` before calling + this function. .. c:function:: int uv_cwd(char* buffer, size_t* size) @@ -475,11 +518,11 @@ .. c:function:: uint64_t uv_get_free_memory(void) - Gets memory information (in bytes). + Gets the amount of free memory available in the system, as reported by the kernel (in bytes). .. c:function:: uint64_t uv_get_total_memory(void) - Gets memory information (in bytes). + Gets the total amount of physical memory in the system (in bytes). .. c:function:: uint64_t uv_get_constrained_memory(void) @@ -640,6 +683,16 @@ On Windows, setting `PRIORITY_HIGHEST` will only work for elevated user, for others it will be silently reduced to `PRIORITY_HIGH`. + .. note:: + On IBM i PASE, the highest process priority is -10. The constant + `UV_PRIORITY_HIGHEST` is -10, `UV_PRIORITY_HIGH` is -7, + `UV_PRIORITY_ABOVE_NORMAL` is -4, `UV_PRIORITY_NORMAL` is 0, + `UV_PRIORITY_BELOW_NORMAL` is 15 and `UV_PRIORITY_LOW` is 39. + + .. note:: + On IBM i PASE, you are not allowed to change your priority unless you + have the \*JOBCTL special authority (even to lower it). + .. versionadded:: 1.23.0 .. c:function:: int uv_os_uname(uv_utsname_t* buffer) diff -Nru libuv1-1.34.2/docs/src/pipe.rst libuv1-1.40.0/docs/src/pipe.rst --- libuv1-1.34.2/docs/src/pipe.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/pipe.rst 2020-09-25 00:34:43.000000000 +0000 @@ -24,6 +24,8 @@ .. 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 @@ 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 -Nru libuv1-1.34.2/docs/src/prepare.rst libuv1-1.40.0/docs/src/prepare.rst --- libuv1-1.34.2/docs/src/prepare.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/prepare.rst 2020-09-25 00:34:43.000000000 +0000 @@ -33,14 +33,22 @@ .. c:function:: int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) - Initialize the handle. + Initialize the handle. This function always succeeds. + + :returns: 0 .. c:function:: int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) - Start the handle with the given callback. + Start the handle with the given callback. This function always succeeds, + except when `cb` is `NULL`. + + :returns: 0 on success, or `UV_EINVAL` when `cb == NULL`. .. c:function:: int uv_prepare_stop(uv_prepare_t* prepare) Stop the handle, the callback will no longer be called. + This function always succeeds. + + :returns: 0 .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff -Nru libuv1-1.34.2/docs/src/process.rst libuv1-1.40.0/docs/src/process.rst --- libuv1-1.34.2/docs/src/process.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/process.rst 2020-09-25 00:34:43.000000000 +0000 @@ -102,7 +102,7 @@ } data; } uv_stdio_container_t; -.. c:type:: uv_stdio_flags +.. c:enum:: uv_stdio_flags Flags specifying how a stdio should be transmitted to the child process. @@ -131,43 +131,43 @@ Public members ^^^^^^^^^^^^^^ -.. c:member:: uv_process_t.pid +.. c:member:: int uv_process_t.pid The PID of the spawned process. It's set after calling :c:func:`uv_spawn`. .. note:: The :c:type:`uv_handle_t` members also apply. -.. c:member:: uv_process_options_t.exit_cb +.. c:member:: uv_exit_cb uv_process_options_t.exit_cb Callback called after the process exits. -.. c:member:: uv_process_options_t.file +.. c:member:: const char* uv_process_options_t.file Path pointing to the program to be executed. -.. c:member:: uv_process_options_t.args +.. c:member:: char** uv_process_options_t.args Command line arguments. args[0] should be the path to the program. On Windows this uses `CreateProcess` which concatenates the arguments into a string this can cause some strange errors. See the ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`. -.. c:member:: uv_process_options_t.env +.. c:member:: char** uv_process_options_t.env Environment for the new process. If NULL the parents environment is used. -.. c:member:: uv_process_options_t.cwd +.. c:member:: const char* uv_process_options_t.cwd Current working directory for the subprocess. -.. c:member:: uv_process_options_t.flags +.. c:member:: unsigned int uv_process_options_t.flags Various flags that control how :c:func:`uv_spawn` behaves. See :c:type:`uv_process_flags`. -.. c:member:: uv_process_options_t.stdio_count -.. c:member:: uv_process_options_t.stdio +.. c:member:: int uv_process_options_t.stdio_count +.. c:member:: uv_stdio_container_t* uv_process_options_t.stdio The `stdio` field points to an array of :c:type:`uv_stdio_container_t` structs that describe the file descriptors that will be made available to @@ -178,8 +178,8 @@ On Windows file descriptors greater than 2 are available to the child process only if the child processes uses the MSVCRT runtime. -.. c:member:: uv_process_options_t.uid -.. c:member:: uv_process_options_t.gid +.. c:member:: uv_uid_t uv_process_options_t.uid +.. c:member:: uv_gid_t uv_process_options_t.gid Libuv can change the child process' user/group id. This happens only when the appropriate bits are set in the flags fields. @@ -188,14 +188,13 @@ This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error to ``UV_ENOTSUP``. -.. c:member:: uv_stdio_container_t.flags +.. c:member:: uv_stdio_flags uv_stdio_container_t.flags - Flags specifying how the stdio container should be passed to the child. See - :c:type:`uv_stdio_flags`. + Flags specifying how the stdio container should be passed to the child. -.. c:member:: uv_stdio_container_t.data +.. c:member:: union @0 uv_stdio_container_t.data - Union containing either the stream or fd to be passed on to the child + Union containing either the `stream` or `fd` to be passed on to the child process. diff -Nru libuv1-1.34.2/docs/src/request.rst libuv1-1.40.0/docs/src/request.rst --- libuv1-1.34.2/docs/src/request.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/request.rst 2020-09-25 00:34:43.000000000 +0000 @@ -53,7 +53,7 @@ API --- -.. c:function:: UV_REQ_TYPE_MAP(iter_macro) +.. c:macro:: UV_REQ_TYPE_MAP(iter_macro) Macro that expands to a series of invocations of `iter_macro` for each of the request types. `iter_macro` is invoked with two @@ -69,8 +69,8 @@ Returns 0 on success, or an error code < 0 on failure. Only cancellation of :c:type:`uv_fs_t`, :c:type:`uv_getaddrinfo_t`, - :c:type:`uv_getnameinfo_t` and :c:type:`uv_work_t` requests is - currently supported. + :c:type:`uv_getnameinfo_t`, :c:type:`uv_random_t` and :c:type:`uv_work_t` + requests is currently supported. Cancelled requests have their callbacks invoked some time in the future. It's **not** safe to free the memory associated with the request until the @@ -80,8 +80,9 @@ * A :c:type:`uv_fs_t` request has its req->result field set to `UV_ECANCELED`. - * A :c:type:`uv_work_t`, :c:type:`uv_getaddrinfo_t` or c:type:`uv_getnameinfo_t` - request has its callback invoked with status == `UV_ECANCELED`. + * A :c:type:`uv_work_t`, :c:type:`uv_getaddrinfo_t`, + :c:type:`uv_getnameinfo_t` or :c:type:`uv_random_t` request has its + callback invoked with status == `UV_ECANCELED`. .. c:function:: size_t uv_req_size(uv_req_type type) diff -Nru libuv1-1.34.2/docs/src/sphinx-plugins/manpage.py libuv1-1.40.0/docs/src/sphinx-plugins/manpage.py --- libuv1-1.34.2/docs/src/sphinx-plugins/manpage.py 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/sphinx-plugins/manpage.py 2020-09-25 00:34:43.000000000 +0000 @@ -18,7 +18,7 @@ def make_link_node(rawtext, app, name, manpage_num, options): ref = app.config.man_url_regex if not ref: - ref = "http://man7.org/linux/man-pages/man%s/%s.%s.html" %(manpage_num, name, manpage_num) + ref = "https://man7.org/linux/man-pages/man%s/%s.%s.html" %(manpage_num, name, manpage_num) else: s = Template(ref) ref = s.substitute(num=manpage_num, topic=name) Binary files /tmp/tmp7Ypqu1/9racujQXzV/libuv1-1.34.2/docs/src/static/diagrams.key/Data/st0-311.jpg and /tmp/tmp7Ypqu1/UB_zZmZxP9/libuv1-1.40.0/docs/src/static/diagrams.key/Data/st0-311.jpg differ Binary files /tmp/tmp7Ypqu1/9racujQXzV/libuv1-1.34.2/docs/src/static/diagrams.key/Data/st1-475.jpg and /tmp/tmp7Ypqu1/UB_zZmZxP9/libuv1-1.40.0/docs/src/static/diagrams.key/Data/st1-475.jpg differ diff -Nru libuv1-1.34.2/docs/src/tcp.rst libuv1-1.40.0/docs/src/tcp.rst --- libuv1-1.34.2/docs/src/tcp.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/tcp.rst 2020-09-25 00:34:43.000000000 +0000 @@ -60,6 +60,11 @@ 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 -Nru libuv1-1.34.2/docs/src/timer.rst libuv1-1.40.0/docs/src/timer.rst --- libuv1-1.34.2/docs/src/timer.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/timer.rst 2020-09-25 00:34:43.000000000 +0000 @@ -78,4 +78,11 @@ Get the timer repeat value. +.. c:function:: uint64_t uv_timer_get_due_in(const uv_timer_t* handle) + + Get the timer due value or 0 if it has expired. The time is relative to + :c:func:`uv_now()`. + + .. versionadded:: 1.40.0 + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff -Nru libuv1-1.34.2/docs/src/tty.rst libuv1-1.40.0/docs/src/tty.rst --- libuv1-1.34.2/docs/src/tty.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/tty.rst 2020-09-25 00:34:43.000000000 +0000 @@ -16,7 +16,7 @@ TTY handle type. -.. c:type:: uv_tty_mode_t +.. c:enum:: uv_tty_mode_t .. versionadded:: 1.2.0 @@ -33,7 +33,8 @@ UV_TTY_MODE_IO } uv_tty_mode_t; -.. c:type:: uv_tty_vtermstate_t +.. c:enum:: uv_tty_vtermstate_t + Console virtual terminal mode type: :: diff -Nru libuv1-1.34.2/docs/src/udp.rst libuv1-1.40.0/docs/src/udp.rst --- libuv1-1.34.2/docs/src/udp.rst 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/docs/src/udp.rst 2020-09-25 00:34:43.000000000 +0000 @@ -41,7 +41,22 @@ * (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, so the buffer provided + * must not be freed by the recv_cb callback. + */ + UV_UDP_MMSG_CHUNK = 8, + /* + * Indicates that the buffer provided has been fully utilized by recvmmsg and + * that it should now be freed by the recv_cb callback. When this flag is set + * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. + */ + UV_UDP_MMSG_FREE = 16, + /* + * Indicates that recvmmsg should be used, if available. + */ + UV_UDP_RECVMMSG = 256 }; .. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status) @@ -62,19 +77,26 @@ * `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. + When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set, + those must not be freed. There will be a final callback with `nread` set to 0, + `addr` set to NULL and the buffer pointing at the initially allocated data with + the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE` flag set. + The callee can now safely free the provided buffer. + + .. versionchanged:: 1.40.0 added the `UV_UDP_MMSG_FREE` flag. + .. note:: The receive callback will be called with `nread` == 0 and `addr` == NULL when there is nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is received. -.. c:type:: uv_membership +.. c:enum:: uv_membership Membership type for a multicast address. @@ -115,12 +137,17 @@ .. c:function:: int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) - Initialize the handle with the specified flags. At the moment the lower 8 bits - of the `flags` parameter are used as the socket domain. A socket will be created - for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created, - just like :c:func:`uv_udp_init`. + Initialize the handle with the specified flags. The lower 8 bits of the `flags` + parameter are used as the socket domain. A socket will be created for the given domain. + If the specified domain is ``AF_UNSPEC`` no socket is created, just like :c:func:`uv_udp_init`. + + The remaining bits can be used to set one of these flags: + + * `UV_UDP_RECVMMSG`: if set, and the platform supports it, :man:`recvmmsg(2)` will + be used. .. versionadded:: 1.7.0 + .. versionchanged:: 1.37.0 added the `UV_UDP_RECVMMSG` flag. .. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) @@ -366,6 +393,23 @@ :returns: 0 on success, or an error code < 0 on failure. + .. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms). + The use of this feature requires a buffer larger than + 2 * 64KB to be passed to `alloc_cb`. + .. versionchanged:: 1.37.0 :man:`recvmmsg(2)` support is no longer enabled implicitly, + it must be explicitly requested by passing the `UV_UDP_RECVMMSG` flag to + :c:func:`uv_udp_init_ex`. + .. versionchanged:: 1.39.0 :c:func:`uv_udp_using_recvmmsg` can be used in `alloc_cb` to + determine if a buffer sized for use with :man:`recvmmsg(2)` should be + allocated for the current handle/platform. + +.. c:function:: int uv_udp_using_recvmmsg(uv_udp_t* handle) + + Returns 1 if the UDP handle was created with the `UV_UDP_RECVMMSG` flag + and the platform supports :man:`recvmmsg(2)`, 0 otherwise. + + .. versionadded:: 1.39.0 + .. c:function:: int uv_udp_recv_stop(uv_udp_t* handle) Stop listening for incoming datagrams. diff -Nru libuv1-1.34.2/.github/workflows/CI.yml libuv1-1.40.0/.github/workflows/CI.yml --- libuv1-1.34.2/.github/workflows/CI.yml 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/.github/workflows/CI.yml 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,69 @@ +name: CI + +on: [push, pull_request] + +jobs: + build-android: + runs-on: ubuntu-latest + container: reactnativecommunity/react-native-android:2020-5-20 + steps: + - uses: actions/checkout@v2 + - name: Envinfo + run: npx envinfo + - name: Build android arm64 + # see build options you can use in https://developer.android.com/ndk/guides/cmake + run: | + mkdir build && cd build + $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-21 .. + $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build . + + build-cross-qemu: + runs-on: ubuntu-latest + name: build-cross-qemu-${{ matrix.config.target }} + + strategy: + fail-fast: false + matrix: + config: + - {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static } + - {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm-static } + - {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static } + - {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64-static } + - {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static } + - {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static } + - {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le-static } + - {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x-static } + - {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips-static } + - {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64-static } + - {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel-static } + - {target: mips64el,toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el-static } + - {target: alpha, toolchain: gcc-alpha-linux-gnu, cc: alpha-linux-gnu-gcc, qemu: qemu-alpha-static } + - {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static} + - {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static} + - {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static} + - {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static} + + steps: + - uses: actions/checkout@v2 + - name: Install QEMU + # this ensure install latest qemu on ubuntu, apt get version is old + env: + QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu" + QEMU_VER: "qemu-user-static_4\\.2-.*_amd64.deb$" + run: | + DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1` + wget $QEMU_SRC/$DEB + sudo dpkg -i $DEB + - name: Install ${{ matrix.config.toolchain }} + run: | + sudo apt update + sudo apt install ${{ matrix.config.toolchain }} -y + - name: Build + run: | + mkdir build + cd build && cmake .. -DBUILD_TESTING=ON -DQEMU=ON -DCMAKE_C_COMPILER=${{ matrix.config.cc }} + cmake --build . + ls -lh + - name: Test + run: | + ${{ matrix.config.qemu }} build/uv_run_tests_a diff -Nru libuv1-1.34.2/.gitignore libuv1-1.40.0/.gitignore --- libuv1-1.34.2/.gitignore 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/.gitignore 2020-09-25 00:34:43.000000000 +0000 @@ -37,11 +37,6 @@ Makefile Makefile.in -# Generated by gyp for android -*.target.mk -/android-toolchain - -/out/ /build/ /test/.libs/ @@ -72,6 +67,7 @@ # Clion / IntelliJ project files /.idea/ +cmake-build-debug/ *.xcodeproj *.xcworkspace diff -Nru libuv1-1.34.2/gyp_uv.py libuv1-1.40.0/gyp_uv.py --- libuv1-1.34.2/gyp_uv.py 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/gyp_uv.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -import os -import platform -import sys - -try: - import multiprocessing.synchronize - gyp_parallel_support = True -except ImportError: - gyp_parallel_support = False - - -CC = os.environ.get('CC', 'cc') -script_dir = os.path.dirname(__file__) -uv_root = os.path.normpath(script_dir) -output_dir = os.path.join(os.path.abspath(uv_root), 'out') - -sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib')) -try: - import gyp -except ImportError: - print('You need to install gyp in build/gyp first. See the README.') - sys.exit(42) - - -def host_arch(): - machine = platform.machine() - if machine == 'i386': return 'ia32' - if machine == 'AMD64': return 'x64' - if machine == 'x86_64': return 'x64' - if machine.startswith('arm'): return 'arm' - if machine.startswith('mips'): return 'mips' - return machine # Return as-is and hope for the best. - - -def run_gyp(args): - rc = gyp.main(args) - if rc != 0: - print('Error running GYP') - sys.exit(rc) - - -if __name__ == '__main__': - args = sys.argv[1:] - args.extend('-I common.gypi test/test.gyp'.split(' ')) - args.append('--depth=' + uv_root) - - # There's a bug with windows which doesn't allow this feature. - if sys.platform != 'win32': - if '-f' not in args: - args.extend('-f make'.split()) - if 'eclipse' not in args and 'ninja' not in args: - args.extend(['-Goutput_dir=' + output_dir]) - args.extend(['--generator-output', output_dir]) - - if not any(a.startswith('-Dhost_arch=') for a in args): - args.append('-Dhost_arch=%s' % host_arch()) - - if not any(a.startswith('-Dtarget_arch=') for a in args): - args.append('-Dtarget_arch=%s' % host_arch()) - - if not any(a.startswith('-Duv_library=') for a in args): - args.append('-Duv_library=static_library') - - # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize - # so gyp must be run with --no-parallel - if not gyp_parallel_support: - args.append('--no-parallel') - - gyp_args = list(args) - print(gyp_args) - run_gyp(gyp_args) diff -Nru libuv1-1.34.2/include/uv/errno.h libuv1-1.40.0/include/uv/errno.h --- libuv1-1.34.2/include/uv/errno.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/include/uv/errno.h 2020-09-25 00:34:43.000000000 +0000 @@ -317,7 +317,7 @@ #if defined(EPROTO) && !defined(_WIN32) # define UV__EPROTO UV__ERR(EPROTO) #else -# define UV__EPROTO UV__ERR(4046) +# define UV__EPROTO (-4046) #endif #if defined(EPROTONOSUPPORT) && !defined(_WIN32) diff -Nru libuv1-1.34.2/include/uv/unix.h libuv1-1.40.0/include/uv/unix.h --- libuv1-1.34.2/include/uv/unix.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/include/uv/unix.h 2020-09-25 00:34:43.000000000 +0000 @@ -69,6 +69,8 @@ # include "uv/posix.h" #elif defined(__HAIKU__) # include "uv/posix.h" +#elif defined(__QNX__) +# include "uv/posix.h" #endif #ifndef NI_MAXHOST diff -Nru libuv1-1.34.2/include/uv/version.h libuv1-1.40.0/include/uv/version.h --- libuv1-1.34.2/include/uv/version.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/include/uv/version.h 2020-09-25 00:34:43.000000000 +0000 @@ -26,13 +26,13 @@ * Versions with the same major number are ABI stable. API is allowed to * evolve between minor releases, but only in a backwards compatible way. * Make sure you update the -soname directives in configure.ac - * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but * not UV_VERSION_PATCH.) */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 34 -#define UV_VERSION_PATCH 2 +#define UV_VERSION_MINOR 40 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff -Nru libuv1-1.34.2/include/uv/win.h libuv1-1.40.0/include/uv/win.h --- libuv1-1.34.2/include/uv/win.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/include/uv/win.h 2020-09-25 00:34:43.000000000 +0000 @@ -517,7 +517,7 @@ /* 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 -Nru libuv1-1.34.2/include/uv.h libuv1-1.40.0/include/uv.h --- libuv1-1.34.2/include/uv.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/include/uv.h 2020-09-25 00:34:43.000000000 +0000 @@ -247,7 +247,8 @@ typedef struct uv_statfs_s uv_statfs_t; typedef enum { - UV_LOOP_BLOCK_SIGNAL + UV_LOOP_BLOCK_SIGNAL = 0, + UV_METRICS_IDLE_TIME } uv_loop_option; typedef enum { @@ -265,6 +266,8 @@ typedef void* (*uv_calloc_func)(size_t count, size_t size); typedef void (*uv_free_func)(void* ptr); +UV_EXTERN void uv_library_shutdown(void); + UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, @@ -605,7 +608,23 @@ * (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, so the buffer provided + * must not be freed by the recv_cb callback. + */ + UV_UDP_MMSG_CHUNK = 8, + /* + * Indicates that the buffer provided has been fully utilized by recvmmsg and + * that it should now be freed by the recv_cb callback. When this flag is set + * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. + */ + UV_UDP_MMSG_FREE = 16, + + /* + * Indicates that recvmmsg should be used, if available. + */ + UV_UDP_RECVMMSG = 256 }; typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); @@ -681,6 +700,7 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb); +UV_EXTERN int uv_udp_using_recvmmsg(const uv_udp_t* handle); UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle); @@ -851,6 +871,7 @@ UV_EXTERN int uv_timer_again(uv_timer_t* handle); UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat); UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); +UV_EXTERN uint64_t uv_timer_get_due_in(const uv_timer_t* handle); /* @@ -1059,11 +1080,11 @@ struct uv_cpu_times_s { - uint64_t user; - uint64_t nice; - uint64_t sys; - uint64_t idle; - uint64_t irq; + uint64_t user; /* milliseconds */ + uint64_t nice; /* milliseconds */ + uint64_t sys; /* milliseconds */ + uint64_t idle; /* milliseconds */ + uint64_t irq; /* milliseconds */ }; struct uv_cpu_info_s { @@ -1177,12 +1198,22 @@ UV_EXTERN uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); -#define UV_PRIORITY_LOW 19 -#define UV_PRIORITY_BELOW_NORMAL 10 -#define UV_PRIORITY_NORMAL 0 -#define UV_PRIORITY_ABOVE_NORMAL -7 -#define UV_PRIORITY_HIGH -14 -#define UV_PRIORITY_HIGHEST -20 +#if defined(__PASE__) +/* On IBM i PASE, the highest process priority is -10 */ +# define UV_PRIORITY_LOW 39 /* RUNPTY(99) */ +# define UV_PRIORITY_BELOW_NORMAL 15 /* RUNPTY(50) */ +# define UV_PRIORITY_NORMAL 0 /* RUNPTY(20) */ +# define UV_PRIORITY_ABOVE_NORMAL -4 /* RUNTY(12) */ +# define UV_PRIORITY_HIGH -7 /* RUNPTY(6) */ +# define UV_PRIORITY_HIGHEST -10 /* RUNPTY(1) */ +#else +# define UV_PRIORITY_LOW 19 +# define UV_PRIORITY_BELOW_NORMAL 10 +# define UV_PRIORITY_NORMAL 0 +# define UV_PRIORITY_ABOVE_NORMAL -7 +# define UV_PRIORITY_HIGH -14 +# define UV_PRIORITY_HIGHEST -20 +#endif UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); @@ -1221,6 +1252,7 @@ UV_EXTERN int uv_os_uname(uv_utsname_t* buffer); +UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop); typedef enum { UV_FS_UNKNOWN = -1, @@ -1259,7 +1291,8 @@ UV_FS_READDIR, UV_FS_CLOSEDIR, UV_FS_STATFS, - UV_FS_MKSTEMP + UV_FS_MKSTEMP, + UV_FS_LUTIME } uv_fs_type; struct uv_dir_s { @@ -1284,6 +1317,7 @@ UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*); UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); +UV_EXTERN int uv_fs_get_system_error(const uv_fs_t*); UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); @@ -1432,6 +1466,12 @@ double atime, double mtime, uv_fs_cb cb); +UV_EXTERN int uv_fs_lutime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb); UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1744,9 +1784,11 @@ unsigned int active_handles; void* handle_queue[2]; union { - void* unused[2]; + void* unused; unsigned int count; } active_reqs; + /* Internal storage for future extensions. */ + void* internal_fields; /* Internal flag to signal loop stop. */ unsigned int stop_flag; UV_LOOP_PRIVATE_FIELDS diff -Nru libuv1-1.34.2/libuv-static.pc.in libuv1-1.40.0/libuv-static.pc.in --- libuv1-1.34.2/libuv-static.pc.in 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/libuv-static.pc.in 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: libuv-static +Version: @PACKAGE_VERSION@ +Description: multi-platform support library with a focus on asynchronous I/O. +URL: http://libuv.org/ + +Libs: -L${libdir} -luv_a @LIBS@ +Cflags: -I${includedir} diff -Nru libuv1-1.34.2/m4/ax_pthread.m4 libuv1-1.40.0/m4/ax_pthread.m4 --- libuv1-1.34.2/m4/ax_pthread.m4 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/m4/ax_pthread.m4 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,485 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 24 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff -Nru libuv1-1.34.2/m4/.gitignore libuv1-1.40.0/m4/.gitignore --- libuv1-1.34.2/m4/.gitignore 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/m4/.gitignore 2020-09-25 00:34:43.000000000 +0000 @@ -1,4 +1,5 @@ # Ignore libtoolize-generated files. *.m4 !as_case.m4 +!ax_pthread.m4 !libuv-check-flags.m4 diff -Nru libuv1-1.34.2/.mailmap libuv1-1.40.0/.mailmap --- libuv1-1.34.2/.mailmap 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/.mailmap 2020-09-25 00:34:43.000000000 +0000 @@ -17,6 +17,7 @@ Isaac Z. Schlueter Jason Williams Jesse Gorzinski +Jesse Gorzinski Justin Venus Keno Fischer Keno Fischer @@ -26,6 +27,7 @@ Marc Schlaich Michael Michael Neumann +Michael Penick Nicholas Vavilov Nick Logan Rasmus Christian Pedersen @@ -40,10 +42,12 @@ Saúl Ibarra Corretgé Saúl Ibarra Corretgé Shigeki Ohtsu +TK-one Timothy J. Fontaine Yasuhiro Matsumoto Yazhong Liu Yuki Okumura +gengjiawen jBarz jBarz ptlomholt diff -Nru libuv1-1.34.2/MAINTAINERS.md libuv1-1.40.0/MAINTAINERS.md --- libuv1-1.34.2/MAINTAINERS.md 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/MAINTAINERS.md 2020-09-25 00:34:43.000000000 +0000 @@ -17,6 +17,8 @@ - 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 -Nru libuv1-1.34.2/Makefile.am libuv1-1.40.0/Makefile.am --- libuv1-1.34.2/Makefile.am 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/Makefile.am 2020-09-25 00:34:43.000000000 +0000 @@ -123,17 +123,9 @@ include \ docs \ img \ - android-configure-arm \ - android-configure-arm64 \ - android-configure-x86 \ - android-configure-x86_64 \ CONTRIBUTING.md \ LICENSE \ - README.md \ - vcbuild.bat \ - common.gypi \ - gyp_uv.py \ - uv.gyp + README.md @@ -211,6 +203,7 @@ test/test-loop-stop.c \ test/test-loop-time.c \ test/test-loop-configure.c \ + test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ test/test-osx-select.c \ @@ -267,6 +260,7 @@ test/test-tcp-flags.c \ test/test-tcp-open.c \ test/test-tcp-read-stop.c \ + test/test-tcp-read-stop-start.c \ test/test-tcp-shutdown-after-write.c \ test/test-tcp-unexpected-read.c \ test/test-tcp-oob.c \ @@ -277,6 +271,7 @@ test/test-tcp-try-write.c \ test/test-tcp-try-write-error.c \ test/test-tcp-write-queue-order.c \ + test/test-test-macros.c \ test/test-thread-equal.c \ test/test-thread.c \ test/test-threadpool-cancel.c \ @@ -286,6 +281,7 @@ 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 \ @@ -293,6 +289,7 @@ test/test-udp-create-socket-early.c \ test/test-udp-dgram-too-big.c \ test/test-udp-ipv6.c \ + test/test-udp-mmsg.c \ test/test-udp-multicast-interface.c \ test/test-udp-multicast-interface6.c \ test/test-udp-multicast-join.c \ @@ -303,6 +300,7 @@ test/test-udp-send-and-recv.c \ test/test-udp-send-hang-loop.c \ test/test-udp-send-immediate.c \ + test/test-udp-sendmmsg-error.c \ test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ test/test-uname.c \ @@ -345,7 +343,8 @@ endif if OS390 -test_run_tests_CFLAGS += -D_UNIX03_THREADS \ +test_run_tests_CFLAGS += -D_ISOC99_SOURCE \ + -D_UNIX03_THREADS \ -D_UNIX03_SOURCE \ -D_OPEN_SYS_IF_EXT=1 \ -D_OPEN_SYS_SOCK_IPV6 \ @@ -379,12 +378,12 @@ libuv_la_SOURCES += src/unix/aix-common.c \ src/unix/ibmi.c \ src/unix/posix-poll.c \ - src/unix/no-fsevents.c \ - src/unix/no-proctitle.c + src/unix/no-fsevents.c endif if ANDROID uvinclude_HEADERS += include/uv/android-ifaddrs.h +libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/android-ifaddrs.c \ src/unix/linux-core.c \ src/unix/linux-inotify.c \ @@ -392,8 +391,7 @@ src/unix/procfs-exepath.c \ src/unix/pthread-fixes.c \ src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c \ - src/unix/sysinfo-loadavg.c + src/unix/random-sysctl-linux.c endif if CYGWIN @@ -415,8 +413,9 @@ libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/darwin.c \ src/unix/darwin-proctitle.c \ + src/unix/darwin-stub.h \ + src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ src/unix/proctitle.c \ @@ -473,8 +472,7 @@ src/unix/procfs-exepath.c \ src/unix/proctitle.c \ src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c \ - src/unix/sysinfo-loadavg.c + src/unix/random-sysctl-linux.c test_run_tests_LDFLAGS += -lutil endif diff -Nru libuv1-1.34.2/README.md libuv1-1.40.0/README.md --- libuv1-1.34.2/README.md 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/README.md 2020-09-25 00:34:43.000000000 +0000 @@ -152,47 +152,14 @@ ## Build Instructions -For GCC there are two build methods: via autotools or via [GYP][]. -GYP is a meta-build system which can generate MSVS, Makefile, and XCode -backends. It is best used for integration into other projects. +For UNIX-like platforms, including macOS, there are two build methods: +autotools or [CMake][]. -To build with autotools: - -```bash -$ sh autogen.sh -$ ./configure -$ make -$ make check -$ make install -``` - -To build with [CMake](https://cmake.org/): - -```bash -$ mkdir -p out/cmake ; cd out/cmake # create build directory -$ cmake ../.. -DBUILD_TESTING=ON # generate project with test -$ cmake --build . # build -$ ctest -C Debug --output-on-failure # run tests - -# Or manually run tests: -$ ./out/cmake/uv_run_tests # shared library build -$ ./out/cmake/uv_run_tests_a # static library build -``` - -To build with GYP, first run: - -```bash -$ git clone https://chromium.googlesource.com/external/gyp build/gyp -``` - -### Windows +For Windows, [CMake][] is the only supported build method and has the +following prerequisites: -Prerequisites: +
-* [Python 2.6 or 2.7][] as it is required - by [GYP][]. - If python is not in your path, set the environment variable `PYTHON` to its - location. For example: `set PYTHON=C:\Python27\python.exe` * One of: * [Visual C++ Build Tools][] * [Visual Studio 2015 Update 3][], all editions @@ -205,67 +172,44 @@ [Git for Windows][] includes Git Bash and tools which can be included in the global `PATH`. -To build, launch a git shell (e.g. Cmd or PowerShell), run `vcbuild.bat` -(to build with VS2017 you need to explicitly add a `vs2017` argument), -which will checkout the GYP code into `build/gyp`, generate `uv.sln` -as well as the necesery related project files, and start building. +
-```console -> vcbuild -``` - -Or: - -```console -> vcbuild vs2017 -``` - -To run the tests: - -```console -> vcbuild test -``` - -To see all the options that could passed to `vcbuild`: - -```console -> vcbuild help -vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] -Examples: - vcbuild.bat : builds debug build - vcbuild.bat test : builds debug build and runs tests - vcbuild.bat release bench: builds release build and runs benchmarks -``` - - -### Unix - -For Debug builds (recommended) run: +To build with autotools: ```bash -$ ./gyp_uv.py -f make -$ make -C out +$ sh autogen.sh +$ ./configure +$ make +$ make check +$ make install ``` -For Release builds run: +To build with [CMake][]: ```bash -$ ./gyp_uv.py -f make -$ BUILDTYPE=Release make -C out -``` +$ mkdir -p build -Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. +$ (cd build && cmake .. -DBUILD_TESTING=ON) # generate project with tests +$ cmake --build build # add `-j ` with cmake >= 3.12 -### OS X +# Run tests: +$ (cd build && ctest -C Debug --output-on-failure) -Run: +# Or manually run tests: +$ build/uv_run_tests # shared library build +$ build/uv_run_tests_a # static library build +``` + +To cross-compile with [CMake][] (unsupported but generally works): ```bash -$ ./gyp_uv.py -f xcode -$ xcodebuild -ARCHS="x86_64" -project out/uv.xcodeproj -configuration Release -alltargets +$ cmake ../.. \ + -DCMAKE_SYSTEM_NAME=Windows \ + -DCMAKE_SYSTEM_VERSION=6.1 \ + -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc ``` -Using Homebrew: +### Install with Homebrew ```bash $ brew install --HEAD libuv @@ -277,103 +221,48 @@ "ARCHS" flag. You can specify more than one by delimiting with a space (e.g. "x86_64 i386"). -### Android - -Run: - -For arm - -```bash -$ source ./android-configure-arm NDK_PATH gyp [API_LEVEL] -$ make -C out -``` - -or for arm64 - -```bash -$ source ./android-configure-arm64 NDK_PATH gyp [API_LEVEL] -$ make -C out -``` - -or for x86 - -```bash -$ source ./android-configure-x86 NDK_PATH gyp [API_LEVEL] -$ make -C out -``` - -or for x86_64 - -```bash -$ source ./android-configure-x86_64 NDK_PATH gyp [API_LEVEL] -$ make -C out -``` - -The default API level is 24, but a different one can be selected as follows: - -```bash -$ source ./android-configure-arm ~/android-ndk-r15b gyp 21 -$ make -C out -``` - -Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and -`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically. - -### Using Ninja - -To use ninja for build on ninja supported platforms, run: - -```bash -$ ./gyp_uv.py -f ninja -$ ninja -C out/Debug #for debug build OR -$ ninja -C out/Release -``` - - ### Running tests -#### Build - -Build (includes tests): +Some tests are timing sensitive. Relaxing test timeouts may be necessary +on slow or overloaded machines: ```bash -$ ./gyp_uv.py -f make -$ make -C out -``` - -#### Run all tests - -```bash -$ ./out/Debug/run-tests +$ env UV_TEST_TIMEOUT_MULTIPLIER=2 build/uv_run_tests # 10s instead of 5s ``` #### Run one test The list of all tests is in `test/test-list.h`. -This invocation will cause the `run-tests` driver to fork and execute `TEST_NAME` in a child process: +This invocation will cause the test driver to fork and execute `TEST_NAME` in +a child process: ```bash -$ ./out/Debug/run-tests TEST_NAME +$ build/uv_run_tests_a TEST_NAME ``` -This invocation will cause the `run-tests` driver to execute the test within the `run-tests` process: +This invocation will cause the test driver to execute the test in +the same process: ```bash -$ ./out/Debug/run-tests TEST_NAME TEST_NAME +$ build/uv_run_tests_a TEST_NAME TEST_NAME ``` #### Debugging tools -When running the test from within the `run-tests` process (`run-tests TEST_NAME TEST_NAME`), tools like gdb and valgrind work normally. -When running the test from a child of the `run-tests` process (`run-tests TEST_NAME`), use these tools in a fork-aware manner. +When running the test from within the test driver process +(`build/uv_run_tests_a TEST_NAME TEST_NAME`), tools like gdb and valgrind +work normally. + +When running the test from a child of the test driver process +(`build/uv_run_tests_a TEST_NAME`), use these tools in a fork-aware manner. ##### Fork-aware gdb Use the [follow-fork-mode](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) setting: ``` -$ gdb --args out/Debug/run-tests TEST_NAME +$ gdb --args build/uv_run_tests_a TEST_NAME (gdb) set follow-fork-mode child ... @@ -384,13 +273,14 @@ Use the `--trace-children=yes` parameter: ```bash -$ valgrind --trace-children=yes -v --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memcheck-%p.log out/Debug/run-tests TEST_NAME +$ valgrind --trace-children=yes -v --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memcheck-%p.log build/uv_run_tests_a TEST_NAME ``` ### Running benchmarks See the section on running tests. -The benchmark driver is `out/Debug/run-benchmarks` and the benchmarks are listed in `test/benchmark-list.h`. +The benchmark driver is `./uv_run_benchmarks_a` and the benchmarks are +listed in `test/benchmark-list.h`. ## Supported Platforms @@ -406,8 +296,6 @@ [IBM documentation](http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/) describes the package in more detail. -AIX support for filesystem events is not compiled when building with `gyp`. - ### z/OS Notes z/OS creates System V semaphores and message queues. These persist on the system @@ -419,12 +307,10 @@ See the [guidelines for contributing][]. +[CMake]: https://cmake.org/ [node.js]: http://nodejs.org/ -[GYP]: http://code.google.com/p/gyp/ [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png -[x32]: https://en.wikipedia.org/wiki/X32_ABI -[Python 2.6 or 2.7]: https://www.python.org/downloads/ [Visual C++ Build Tools]: https://visualstudio.microsoft.com/visual-cpp-build-tools/ [Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ [Visual Studio 2017]: https://www.visualstudio.com/downloads/ diff -Nru libuv1-1.34.2/src/random.c libuv1-1.40.0/src/random.c --- libuv1-1.34.2/src/random.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/random.c 2020-09-25 00:34:43.000000000 +0000 @@ -33,7 +33,7 @@ #if defined(__PASE__) rc = uv__random_readpath("/dev/urandom", buf, buflen); -#elif defined(_AIX) +#elif defined(_AIX) || defined(__QNX__) rc = uv__random_readpath("/dev/random", buf, buflen); #elif defined(__APPLE__) || defined(__OpenBSD__) || \ (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) diff -Nru libuv1-1.34.2/src/strscpy.c libuv1-1.40.0/src/strscpy.c --- libuv1-1.34.2/src/strscpy.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/strscpy.c 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "strscpy.h" #include /* SSIZE_MAX */ diff -Nru libuv1-1.34.2/src/strscpy.h libuv1-1.40.0/src/strscpy.h --- libuv1-1.34.2/src/strscpy.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/strscpy.h 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #ifndef UV_STRSCPY_H_ #define UV_STRSCPY_H_ diff -Nru libuv1-1.34.2/src/threadpool.c libuv1-1.40.0/src/threadpool.c --- libuv1-1.34.2/src/threadpool.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/threadpool.c 2020-09-25 00:34:43.000000000 +0000 @@ -160,8 +160,8 @@ } +void uv__threadpool_cleanup(void) { #ifndef _WIN32 -UV_DESTRUCTOR(static void cleanup(void)) { unsigned int i; if (nthreads == 0) @@ -181,8 +181,8 @@ threads = NULL; nthreads = 0; -} #endif +} static void init_threads(void) { diff -Nru libuv1-1.34.2/src/timer.c libuv1-1.40.0/src/timer.c --- libuv1-1.34.2/src/timer.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/timer.c 2020-09-25 00:34:43.000000000 +0000 @@ -51,12 +51,7 @@ /* Compare start_id when both have the same timeout. start_id is * allocated with loop->timer_counter in uv_timer_start(). */ - if (a->start_id < b->start_id) - return 1; - if (b->start_id < a->start_id) - return 0; - - return 0; + return a->start_id < b->start_id; } @@ -87,7 +82,7 @@ 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), @@ -135,6 +130,14 @@ } +uint64_t uv_timer_get_due_in(const uv_timer_t* handle) { + if (handle->loop->time >= handle->timeout) + return 0; + + return handle->timeout - handle->loop->time; +} + + int uv__next_timeout(const uv_loop_t* loop) { const struct heap_node* heap_node; const uv_timer_t* handle; diff -Nru libuv1-1.34.2/src/unix/aix.c libuv1-1.40.0/src/unix/aix.c --- libuv1-1.34.2/src/unix/aix.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/aix.c 2020-09-25 00:34:43.000000000 +0000 @@ -65,14 +65,15 @@ #define RDWR_BUF_SIZE 4096 #define EQ(a,b) (strcmp(a,b) == 0) -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +char* original_exepath = NULL; +uv_mutex_t process_title_mutex; +uv_once_t process_title_mutex_once = UV_ONCE_INIT; static void* args_mem = NULL; static char** process_argv = NULL; static int process_argc = 0; static char* process_title_ptr = NULL; -static void init_process_title_mutex_once(void) { +void init_process_title_mutex_once(void) { uv_mutex_init(&process_title_mutex); } @@ -145,6 +146,8 @@ int i; int rc; int add_failed; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -214,7 +217,21 @@ base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + nfds = pollset_poll(loop->backend_fd, events, ARRAY_SIZE(events), @@ -227,6 +244,15 @@ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + if (timeout == -1) + continue; + if (timeout > 0) + goto update_timeout; + } + assert(timeout != -1); return; } @@ -236,6 +262,11 @@ abort(); } + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == -1) continue; @@ -280,16 +311,25 @@ /* Run signal watchers last. This also affects child process watchers * because those are implemented in terms of signal watchers. */ - if (w == &loop->signal_io_watcher) + if (w == &loop->signal_io_watcher) { have_signals = 1; - else + } else { + uv__metrics_update_idle_time(loop); w->cb(loop, w, pe->revents); + } nevents++; } - if (have_signals != 0) + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; @@ -830,6 +870,7 @@ char** uv_setup_args(int argc, char** argv) { + char exepath[UV__PATH_MAX]; char** new_argv; size_t size; char* s; @@ -845,6 +886,15 @@ process_argv = argv; process_argc = argc; + /* Use argv[0] to determine value for uv_exepath(). */ + size = sizeof(exepath); + if (uv__search_path(argv[0], exepath, &size) == 0) { + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + original_exepath = uv__strdup(exepath); + uv_mutex_unlock(&process_title_mutex); + } + /* Calculate how much memory we need for the argv strings. */ size = 0; for (i = 0; i < argc; i++) @@ -875,6 +925,10 @@ int uv_set_process_title(const char* title) { char* new_title; + /* If uv_setup_args wasn't called or failed, we can't continue. */ + if (process_argv == NULL || args_mem == NULL) + return UV_ENOBUFS; + /* We cannot free this pointer when libuv shuts down, * the process may still be using it. */ @@ -908,6 +962,10 @@ if (buffer == NULL || size == 0) return UV_EINVAL; + /* If uv_setup_args wasn't called, we can't continue. */ + if (process_argv == NULL) + return UV_ENOBUFS; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -926,7 +984,7 @@ } -UV_DESTRUCTOR(static void free_args_mem(void)) { +void uv__process_title_cleanup(void) { uv__free(args_mem); /* Keep valgrind happy. */ args_mem = NULL; } diff -Nru libuv1-1.34.2/src/unix/aix-common.c libuv1-1.40.0/src/unix/aix-common.c --- libuv1-1.34.2/src/unix/aix-common.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/aix-common.c 2020-09-25 00:34:43.000000000 +0000 @@ -22,42 +22,23 @@ #include "uv.h" #include "internal.h" -#include #include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include - -#include #include -#include -#include -#include -#include -#include +extern char* original_exepath; +extern uv_mutex_t process_title_mutex; +extern uv_once_t process_title_mutex_once; +extern void init_process_title_mutex_once(void); uint64_t uv__hrtime(uv_clocktype_t type) { uint64_t G = 1000000000; @@ -78,80 +59,31 @@ */ int uv_exepath(char* buffer, size_t* size) { int res; - char args[PATH_MAX]; - char abspath[PATH_MAX]; - size_t abspath_size; + char args[UV__PATH_MAX]; + size_t cached_len; struct procsinfo pi; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - pi.pi_pid = getpid(); - res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) - return UV_EINVAL; - - /* - * Possibilities for args: - * i) an absolute path such as: /home/user/myprojects/nodejs/node - * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable - * to its location. - */ - - /* Case i) and ii) absolute or relative paths */ - if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) - return UV__ERR(errno); - - abspath_size = strlen(abspath); - + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + if (original_exepath != NULL) { + cached_len = strlen(original_exepath); *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); + if (*size > cached_len) + *size = cached_len; + memcpy(buffer, original_exepath, *size); buffer[*size] = '\0'; - + uv_mutex_unlock(&process_title_mutex); return 0; - } else { - /* Case iii). Search PATH environment variable */ - char trypath[PATH_MAX]; - char *clonedpath = NULL; - char *token = NULL; - char *path = getenv("PATH"); - - if (path == NULL) - return UV_EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return UV_ENOMEM; - - token = strtok(clonedpath, ":"); - while (token != NULL) { - snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { - /* Check the match is executable */ - if (access(abspath, X_OK) == 0) { - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - uv__free(clonedpath); - return 0; - } - } - token = strtok(NULL, ":"); - } - uv__free(clonedpath); + } + uv_mutex_unlock(&process_title_mutex); + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); - /* Out of tokens (path entries), and no match found */ + if (res < 0) return UV_EINVAL; - } + + return uv__search_path(args, buffer, size); } diff -Nru libuv1-1.34.2/src/unix/android-ifaddrs.c libuv1-1.40.0/src/unix/android-ifaddrs.c --- libuv1-1.34.2/src/unix/android-ifaddrs.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/android-ifaddrs.c 2020-09-25 00:34:43.000000000 +0000 @@ -470,13 +470,14 @@ { case IFA_ADDRESS: case IFA_LOCAL: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) { /* Make room for netmask */ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); l_addedNetmask = 1; } - break; + break; case IFA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); break; diff -Nru libuv1-1.34.2/src/unix/async.c libuv1-1.40.0/src/unix/async.c --- libuv1-1.34.2/src/unix/async.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/async.c 2020-09-25 00:34:43.000000000 +0000 @@ -32,10 +32,14 @@ #include #include #include +#include /* sched_yield() */ + +#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) { @@ -78,20 +82,32 @@ /* Only call this from the event loop thread. */ static int uv__async_spin(uv_async_t* handle) { + int i; int rc; for (;;) { - /* rc=0 -- handle is not pending. - * rc=1 -- handle is pending, other thread is still working with it. - * rc=2 -- handle is pending, other thread is done. + /* 997 is not completely chosen at random. It's a prime number, acyclical + * by nature, and should therefore hopefully dampen sympathetic resonance. */ - rc = cmpxchgi(&handle->pending, 2, 0); + for (i = 0; i < 997; i++) { + /* rc=0 -- handle is not pending. + * rc=1 -- handle is pending, other thread is still working with it. + * rc=2 -- handle is pending, other thread is done. + */ + rc = cmpxchgi(&handle->pending, 2, 0); - if (rc != 1) - return rc; + if (rc != 1) + return rc; - /* Other thread is busy with this handle, spin until it's done. */ - cpu_relax(); + /* Other thread is busy with this handle, spin until it's done. */ + cpu_relax(); + } + + /* Yield the CPU. We may have preempted the other thread while it's + * inside the critical section and if it's running on the same CPU + * as us, we'll just burn CPU cycles until the end of our time slice. + */ + sched_yield(); } } @@ -190,36 +206,18 @@ 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 +251,3 @@ 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 -Nru libuv1-1.34.2/src/unix/atomic-ops.h libuv1-1.40.0/src/unix/atomic-ops.h --- libuv1-1.34.2/src/unix/atomic-ops.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/atomic-ops.h 2020-09-25 00:34:43.000000000 +0000 @@ -53,6 +53,8 @@ UV_UNUSED(static void cpu_relax(void)) { #if defined(__i386__) || defined(__x86_64__) __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ +#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) + __asm__ volatile("yield"); #endif } diff -Nru libuv1-1.34.2/src/unix/bsd-ifaddrs.c libuv1-1.40.0/src/unix/bsd-ifaddrs.c --- libuv1-1.34.2/src/unix/bsd-ifaddrs.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/bsd-ifaddrs.c 2020-09-25 00:34:43.000000000 +0000 @@ -113,7 +113,9 @@ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); } - if (ent->ifa_netmask->sa_family == AF_INET6) { + if (ent->ifa_netmask == NULL) { + memset(&address->netmask, 0, sizeof(address->netmask)); + } else if (ent->ifa_netmask->sa_family == AF_INET6) { address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); } else { address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); diff -Nru libuv1-1.34.2/src/unix/bsd-proctitle.c libuv1-1.40.0/src/unix/bsd-proctitle.c --- libuv1-1.34.2/src/unix/bsd-proctitle.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/bsd-proctitle.c 2020-09-25 00:34:43.000000000 +0000 @@ -37,6 +37,13 @@ } +void uv__process_title_cleanup(void) { + /* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex) + * and reset process_title_mutex_once? + */ +} + + char** uv_setup_args(int argc, char** argv) { process_title = argc > 0 ? uv__strdup(argv[0]) : NULL; return argv; diff -Nru libuv1-1.34.2/src/unix/core.c libuv1-1.40.0/src/unix/core.c --- libuv1-1.34.2/src/unix/core.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/core.c 2020-09-25 00:34:43.000000000 +0000 @@ -71,24 +71,12 @@ # include # include # include -# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# if defined(__FreeBSD__) # 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 -# include /* for dlsym */ #endif #if defined(__MVS__) @@ -96,7 +84,8 @@ #endif #if defined(__linux__) -#include +# include +# define uv__accept4 accept4 #endif static int uv__run_pending(uv_loop_t* loop); @@ -179,9 +168,7 @@ 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); @@ -229,15 +216,23 @@ #if defined(IOV_MAX) return IOV_MAX; #elif defined(_SC_IOV_MAX) - static int iovmax = -1; - if (iovmax == -1) { - iovmax = sysconf(_SC_IOV_MAX); - /* On some embedded devices (arm-linux-uclibc based ip camera), - * sysconf(_SC_IOV_MAX) can not get the correct value. The return - * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. - */ - if (iovmax == -1) iovmax = 1; - } + static int iovmax_cached = -1; + int iovmax; + + iovmax = uv__load_relaxed(&iovmax_cached); + if (iovmax != -1) + return iovmax; + + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + iovmax = sysconf(_SC_IOV_MAX); + if (iovmax == -1) + iovmax = 1; + + uv__store_relaxed(&iovmax_cached, iovmax); + return iovmax; #else return 1024; @@ -246,6 +241,8 @@ 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 +265,20 @@ 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: @@ -373,6 +383,14 @@ timeout = uv_backend_timeout(loop); uv__io_poll(loop, timeout); + + /* Run one final update on the provider_idle_time in case uv__io_poll + * returned because the timeout expired, but no events were received. This + * call will be ignored if the provider_entry_time was either never set (if + * the timeout == 0) or was already updated b/c an event was received. + */ + uv__metrics_update_idle_time(loop); + uv__run_check(loop); uv__run_closing_handles(loop); @@ -472,52 +490,32 @@ 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: + do +#ifdef uv__accept4 + peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); +#else + peerfd = accept(sockfd, NULL, NULL); #endif + while (peerfd == -1 && errno == EINTR); - peerfd = accept(sockfd, NULL, NULL); - if (peerfd == -1) { - if (errno == EINTR) - continue; - return UV__ERR(errno); - } + if (peerfd == -1) + return UV__ERR(errno); - err = uv__cloexec(peerfd, 1); - if (err == 0) - err = uv__nonblock(peerfd, 1); - - 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 +531,7 @@ #if defined(__APPLE__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" -#if defined(__LP64__) +#if defined(__LP64__) || TARGET_OS_IPHONE extern int close$NOCANCEL(int); return close$NOCANCEL(fd); #else @@ -676,7 +674,7 @@ int* end; #if defined(__linux__) static int no_msg_cmsg_cloexec; - if (no_msg_cmsg_cloexec == 0) { + if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) { rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ if (rc != -1) return rc; @@ -685,7 +683,7 @@ rc = recvmsg(fd, msg, flags); if (rc == -1) return UV__ERR(errno); - no_msg_cmsg_cloexec = 1; + uv__store_relaxed(&no_msg_cmsg_cloexec, 1); } else { rc = recvmsg(fd, msg, flags); } @@ -849,8 +847,8 @@ } nwatchers = next_power_of_two(len + 2) - 2; - watchers = uv__realloc(loop->watchers, - (nwatchers + 2) * sizeof(loop->watchers[0])); + watchers = uv__reallocf(loop->watchers, + (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) abort(); @@ -1031,54 +1029,30 @@ 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 } @@ -1180,13 +1154,6 @@ size_t shell_size; long initsize; int r; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); - - getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); - if (getpwuid_r == NULL) - return UV_ENOSYS; -#endif if (pwd == NULL) return UV_EINVAL; @@ -1296,7 +1263,7 @@ *envitems = uv__calloc(i, sizeof(**envitems)); - if (envitems == NULL) + if (*envitems == NULL) return UV_ENOMEM; for (j = 0, cnt = 0; j < i; j++) { @@ -1569,3 +1536,78 @@ assert(rc == 0); } + +int uv__search_path(const char* prog, char* buf, size_t* buflen) { + char abspath[UV__PATH_MAX]; + size_t abspath_size; + char trypath[UV__PATH_MAX]; + char* cloned_path; + char* path_env; + char* token; + + if (buf == NULL || buflen == NULL || *buflen == 0) + return UV_EINVAL; + + /* + * Possibilities for prog: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(prog, '/') != NULL) { + if (realpath(prog, abspath) != abspath) + return UV__ERR(errno); + + abspath_size = strlen(abspath); + + *buflen -= 1; + if (*buflen > abspath_size) + *buflen = abspath_size; + + memcpy(buf, abspath, *buflen); + buf[*buflen] = '\0'; + + return 0; + } + + /* Case iii). Search PATH environment variable */ + cloned_path = NULL; + token = NULL; + path_env = getenv("PATH"); + + if (path_env == NULL) + return UV_EINVAL; + + cloned_path = uv__strdup(path_env); + if (cloned_path == NULL) + return UV_ENOMEM; + + token = strtok(cloned_path, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *buflen -= 1; + if (*buflen > abspath_size) + *buflen = abspath_size; + + memcpy(buf, abspath, *buflen); + buf[*buflen] = '\0'; + + uv__free(cloned_path); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(cloned_path); + + /* Out of tokens (path entries), and no match found */ + return UV_EINVAL; +} diff -Nru libuv1-1.34.2/src/unix/darwin.c libuv1-1.40.0/src/unix/darwin.c --- libuv1-1.34.2/src/unix/darwin.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/darwin.c 2020-09-25 00:34:43.000000000 +0000 @@ -25,6 +25,7 @@ #include #include +#include #include #include #include /* _NSGetExecutablePath */ @@ -32,6 +33,15 @@ #include #include /* sysconf */ +#if !TARGET_OS_IPHONE +#include "darwin-stub.h" +#endif + +static uv_once_t once = UV_ONCE_INIT; +static uint64_t (*time_func)(void); +static mach_timebase_info_data_t timebase; + +typedef unsigned char UInt8; int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; @@ -48,15 +58,19 @@ } -uint64_t uv__hrtime(uv_clocktype_t type) { - static mach_timebase_info_data_t info; - - if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || - ACCESS_ONCE(uint32_t, info.denom) == 0) && - mach_timebase_info(&info) != KERN_SUCCESS) +static void uv__hrtime_init_once(void) { + if (KERN_SUCCESS != mach_timebase_info(&timebase)) abort(); - return mach_absolute_time() * info.numer / info.denom; + time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time"); + if (time_func == NULL) + time_func = mach_absolute_time; +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + uv_once(&once, uv__hrtime_init_once); + return time_func() * timebase.numer / timebase.denom; } @@ -171,17 +185,149 @@ return 0; } +static int uv__get_cpu_speed(uint64_t* speed) { + /* IOKit */ + void (*pIOObjectRelease)(io_object_t); + kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*); + CFMutableDictionaryRef (*pIOServiceMatching)(const char*); + kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t, + CFMutableDictionaryRef, + io_iterator_t*); + io_service_t (*pIOIteratorNext)(io_iterator_t); + CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t, + CFStringRef, + CFAllocatorRef, + IOOptionBits); + + /* CoreFoundation */ + CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); + CFStringEncoding (*pCFStringGetSystemEncoding)(void); + UInt8 *(*pCFDataGetBytePtr)(CFDataRef); + CFIndex (*pCFDataGetLength)(CFDataRef); + void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*); + void (*pCFRelease)(CFTypeRef); + + void* core_foundation_handle; + void* iokit_handle; + int err; + + kern_return_t kr; + mach_port_t mach_port; + io_iterator_t it; + io_object_t service; + + mach_port = 0; + + err = UV_ENOENT; + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/" + "Versions/A/IOKit", + RTLD_LAZY | RTLD_LOCAL); + + if (core_foundation_handle == NULL || iokit_handle == NULL) + goto out; + +#define V(handle, symbol) \ + do { \ + *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ + if (p ## symbol == NULL) \ + goto out; \ + } \ + while (0) + V(iokit_handle, IOMasterPort); + V(iokit_handle, IOServiceMatching); + V(iokit_handle, IOServiceGetMatchingServices); + V(iokit_handle, IOIteratorNext); + V(iokit_handle, IOObjectRelease); + V(iokit_handle, IORegistryEntryCreateCFProperty); + V(core_foundation_handle, CFStringCreateWithCString); + V(core_foundation_handle, CFStringGetSystemEncoding); + V(core_foundation_handle, CFDataGetBytePtr); + V(core_foundation_handle, CFDataGetLength); + V(core_foundation_handle, CFDataGetBytes); + V(core_foundation_handle, CFRelease); +#undef V + +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) + + kr = pIOMasterPort(MACH_PORT_NULL, &mach_port); + assert(kr == KERN_SUCCESS); + CFMutableDictionaryRef classes_to_match + = pIOServiceMatching("IOPlatformDevice"); + kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it); + assert(kr == KERN_SUCCESS); + service = pIOIteratorNext(it); + + CFStringRef device_type_str = S("device_type"); + CFStringRef clock_frequency_str = S("clock-frequency"); + + while (service != 0) { + CFDataRef data; + data = pIORegistryEntryCreateCFProperty(service, + device_type_str, + NULL, + 0); + if (data) { + const UInt8* raw = pCFDataGetBytePtr(data); + if (strncmp((char*)raw, "cpu", 3) == 0 || + strncmp((char*)raw, "processor", 9) == 0) { + CFDataRef freq_ref; + freq_ref = pIORegistryEntryCreateCFProperty(service, + clock_frequency_str, + NULL, + 0); + if (freq_ref) { + uint32_t freq; + CFIndex len = pCFDataGetLength(freq_ref); + CFRange range; + range.location = 0; + range.length = len; + + pCFDataGetBytes(freq_ref, range, (UInt8*)&freq); + *speed = freq; + pCFRelease(freq_ref); + pCFRelease(data); + break; + } + } + pCFRelease(data); + } + + service = pIOIteratorNext(it); + } + + pIOObjectRelease(it); + + err = 0; +out: + if (core_foundation_handle != NULL) + dlclose(core_foundation_handle); + + if (iokit_handle != NULL) + dlclose(iokit_handle); + + mach_port_deallocate(mach_task_self(), mach_port); + + return err; +} + int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks); char model[512]; - uint64_t cpuspeed; size_t size; unsigned int i; natural_t numcpus; mach_msg_type_number_t msg_type; processor_cpu_load_info_data_t *info; uv_cpu_info_t* cpu_info; + uint64_t cpuspeed; + int err; size = sizeof(model); if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && @@ -189,9 +335,9 @@ return UV__ERR(errno); } - size = sizeof(cpuspeed); - if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) - return UV__ERR(errno); + err = uv__get_cpu_speed(&cpuspeed); + if (err < 0) + return err; if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, (processor_info_array_t*)&info, diff -Nru libuv1-1.34.2/src/unix/darwin-proctitle.c libuv1-1.40.0/src/unix/darwin-proctitle.c --- libuv1-1.34.2/src/unix/darwin-proctitle.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/darwin-proctitle.c 2020-09-25 00:34:43.000000000 +0000 @@ -30,8 +30,7 @@ #include #if !TARGET_OS_IPHONE -# include -# include +#include "darwin-stub.h" #endif diff -Nru libuv1-1.34.2/src/unix/darwin-stub.h libuv1-1.40.0/src/unix/darwin-stub.h --- libuv1-1.34.2/src/unix/darwin-stub.h 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/src/unix/darwin-stub.h 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,113 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_DARWIN_STUB_H_ +#define UV_DARWIN_STUB_H_ + +#include + +struct CFArrayCallBacks; +struct CFRunLoopSourceContext; +struct FSEventStreamContext; +struct CFRange; + +typedef double CFAbsoluteTime; +typedef double CFTimeInterval; +typedef int FSEventStreamEventFlags; +typedef int OSStatus; +typedef long CFIndex; +typedef struct CFArrayCallBacks CFArrayCallBacks; +typedef struct CFRunLoopSourceContext CFRunLoopSourceContext; +typedef struct FSEventStreamContext FSEventStreamContext; +typedef uint32_t FSEventStreamCreateFlags; +typedef uint64_t FSEventStreamEventId; +typedef unsigned CFStringEncoding; +typedef void* CFAllocatorRef; +typedef void* CFArrayRef; +typedef void* CFBundleRef; +typedef void* CFDataRef; +typedef void* CFDictionaryRef; +typedef void* CFMutableDictionaryRef; +typedef struct CFRange CFRange; +typedef void* CFRunLoopRef; +typedef void* CFRunLoopSourceRef; +typedef void* CFStringRef; +typedef void* CFTypeRef; +typedef void* FSEventStreamRef; + +typedef uint32_t IOOptionBits; +typedef unsigned int io_iterator_t; +typedef unsigned int io_object_t; +typedef unsigned int io_service_t; +typedef unsigned int io_registry_entry_t; + + +typedef void (*FSEventStreamCallback)(const FSEventStreamRef, + void*, + size_t, + void*, + const FSEventStreamEventFlags*, + const FSEventStreamEventId*); + +struct CFRunLoopSourceContext { + CFIndex version; + void* info; + void* pad[7]; + void (*perform)(void*); +}; + +struct FSEventStreamContext { + CFIndex version; + void* info; + void* pad[3]; +}; + +struct CFRange { + CFIndex location; + CFIndex length; +}; + +static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100; +static const OSStatus noErr = 0; + +static const FSEventStreamEventId kFSEventStreamEventIdSinceNow = -1; + +static const int kFSEventStreamCreateFlagNoDefer = 2; +static const int kFSEventStreamCreateFlagFileEvents = 16; + +static const int kFSEventStreamEventFlagEventIdsWrapped = 8; +static const int kFSEventStreamEventFlagHistoryDone = 16; +static const int kFSEventStreamEventFlagItemChangeOwner = 0x4000; +static const int kFSEventStreamEventFlagItemCreated = 0x100; +static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x2000; +static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x400; +static const int kFSEventStreamEventFlagItemIsDir = 0x20000; +static const int kFSEventStreamEventFlagItemModified = 0x1000; +static const int kFSEventStreamEventFlagItemRemoved = 0x200; +static const int kFSEventStreamEventFlagItemRenamed = 0x800; +static const int kFSEventStreamEventFlagItemXattrMod = 0x8000; +static const int kFSEventStreamEventFlagKernelDropped = 4; +static const int kFSEventStreamEventFlagMount = 64; +static const int kFSEventStreamEventFlagRootChanged = 32; +static const int kFSEventStreamEventFlagUnmount = 128; +static const int kFSEventStreamEventFlagUserDropped = 2; + +#endif /* UV_DARWIN_STUB_H_ */ diff -Nru libuv1-1.34.2/src/unix/freebsd.c libuv1-1.40.0/src/unix/freebsd.c --- libuv1-1.34.2/src/unix/freebsd.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/freebsd.c 2020-09-25 00:34:43.000000000 +0000 @@ -56,31 +56,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } - -#ifdef __DragonFly__ -int uv_exepath(char* buffer, size_t* size) { - char abspath[PATH_MAX * 2 + 1]; - ssize_t abspath_size; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); - if (abspath_size < 0) - return UV__ERR(errno); - - assert(abspath_size > 0); - *size -= 1; - - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - return 0; -} -#else int uv_exepath(char* buffer, size_t* size) { char abspath[PATH_MAX * 2 + 1]; int mib[4]; @@ -110,7 +85,6 @@ return 0; } -#endif uint64_t uv_get_free_memory(void) { int freecount; @@ -288,3 +262,21 @@ uv__free(cp_times); return 0; } + + +int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { +#if __FreeBSD__ >= 11 + return sendmmsg(fd, mmsg, vlen, /* flags */ 0); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { +#if __FreeBSD__ >= 11 + return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */); +#else + return errno = ENOSYS, -1; +#endif +} diff -Nru libuv1-1.34.2/src/unix/fs.c libuv1-1.40.0/src/unix/fs.c --- libuv1-1.34.2/src/unix/fs.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/fs.c 2020-09-25 00:34:43.000000000 +0000 @@ -79,7 +79,11 @@ defined(__NetBSD__) # include # include -#elif defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__) +#elif defined(__sun) || \ + defined(__MVS__) || \ + defined(__NetBSD__) || \ + defined(__HAIKU__) || \ + defined(__QNX__) # include #else # include @@ -205,6 +209,20 @@ } +UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { + struct timespec ts; + ts.tv_sec = time; + ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000; + return ts; +} + +UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { + struct timeval tv; + tv.tv_sec = time; + tv.tv_usec = (uint64_t)(time * 1000000) % 1000000; + return tv; +} + static ssize_t uv__fs_futime(uv_fs_t* req) { #if defined(__linux__) \ || defined(_AIX71) \ @@ -213,15 +231,9 @@ * for the sake of consistency with other platforms. */ struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - return utimensat(req->file, NULL, ts, 0); -#else + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); return futimens(req->file, ts); -#endif #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ @@ -230,10 +242,8 @@ || defined(__OpenBSD__) \ || defined(__sun) struct timeval tv[2]; - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + tv[0] = uv__fs_to_timeval(req->atime); + tv[1] = uv__fs_to_timeval(req->mtime); # if defined(__sun) return futimesat(req->file, NULL, tv); # else @@ -300,13 +310,14 @@ if (path_length < pattern_size || strcmp(path + path_length - pattern_size, pattern)) { errno = EINVAL; - return -1; + r = -1; + goto clobber; } uv_once(&once, uv__mkostemp_initonce); #ifdef O_CLOEXEC - if (no_cloexec_support == 0 && uv__mkostemp != NULL) { + if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) { r = uv__mkostemp(path, O_CLOEXEC); if (r >= 0) @@ -315,11 +326,11 @@ /* If mkostemp() returns EINVAL, it means the kernel doesn't support O_CLOEXEC, so we just fallback to mkstemp() below. */ if (errno != EINVAL) - return r; + goto clobber; /* We set the static variable so that next calls don't even try to use mkostemp. */ - no_cloexec_support = 1; + uv__store_relaxed(&no_cloexec_support, 1); } #endif /* O_CLOEXEC */ @@ -341,6 +352,9 @@ if (req->cb != NULL) uv_rwlock_rdunlock(&req->loop->cloexec_lock); +clobber: + if (r < 0) + path[0] = '\0'; return r; } @@ -450,7 +464,7 @@ result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) - if (no_preadv) retry: + if (uv__load_relaxed(&no_preadv)) retry: # endif { result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off); @@ -462,7 +476,7 @@ req->nbufs, req->off); if (result == -1 && errno == ENOSYS) { - no_preadv = 1; + uv__store_relaxed(&no_preadv, 1); goto retry; } } @@ -619,7 +633,11 @@ static int uv__fs_statfs(uv_fs_t* req) { uv_statfs_t* stat_fs; -#if defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__) +#if defined(__sun) || \ + defined(__MVS__) || \ + defined(__NetBSD__) || \ + defined(__HAIKU__) || \ + defined(__QNX__) struct statvfs buf; if (0 != statvfs(req->path, &buf)) @@ -636,7 +654,12 @@ return -1; } -#if defined(__sun) || defined(__MVS__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) +#if defined(__sun) || \ + defined(__MVS__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(__HAIKU__) || \ + defined(__QNX__) stat_fs->f_type = 0; /* f_type is not supported. */ #else stat_fs->f_type = buf.f_type; @@ -666,7 +689,6 @@ ssize_t maxlen; ssize_t len; char* buf; - char* newbuf; #if defined(_POSIX_PATH_MAX) || defined(PATH_MAX) maxlen = uv__fs_pathmax_size(req->path); @@ -710,14 +732,10 @@ /* Uncommon case: resize to make room for the trailing nul byte. */ if (len == maxlen) { - newbuf = uv__realloc(buf, len + 1); + buf = uv__reallocf(buf, len + 1); - if (newbuf == NULL) { - uv__free(buf); + if (buf == NULL) return -1; - } - - buf = newbuf; } buf[len] = '\0'; @@ -882,8 +900,27 @@ ssize_t r; off = req->off; + +#ifdef __linux__ + { + static int copy_file_range_support = 1; + + if (copy_file_range_support) { + r = uv__fs_copy_file_range(in_fd, NULL, out_fd, &off, req->bufsml[0].len, 0); + + if (r == -1 && errno == ENOSYS) { + errno = 0; + copy_file_range_support = 0; + } else { + goto ok; + } + } + } +#endif + r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len); +ok: /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but * it still writes out data. Fortunately, we can detect it by checking if * the offset has been updated. @@ -977,10 +1014,8 @@ * for the sake of consistency with other platforms. */ struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); #elif defined(__APPLE__) \ || defined(__DragonFly__) \ @@ -989,10 +1024,8 @@ || defined(__NetBSD__) \ || defined(__OpenBSD__) struct timeval tv[2]; - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + tv[0] = uv__fs_to_timeval(req->atime); + tv[1] = uv__fs_to_timeval(req->mtime); return utimes(req->path, tv); #elif defined(_AIX) \ && !defined(_AIX71) @@ -1015,6 +1048,31 @@ } +static ssize_t uv__fs_lutime(uv_fs_t* req) { +#if defined(__linux__) || \ + defined(_AIX71) || \ + defined(__sun) || \ + defined(__HAIKU__) + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) + struct timeval tv[2]; + tv[0] = uv__fs_to_timeval(req->atime); + tv[1] = uv__fs_to_timeval(req->mtime); + return lutimes(req->path, tv); +#else + errno = ENOSYS; + return -1; +#endif +} + + static ssize_t uv__fs_write(uv_fs_t* req) { #if defined(__linux__) static int no_pwritev; @@ -1084,9 +1142,10 @@ int dst_flags; int result; int err; - size_t bytes_to_send; - int64_t in_offset; - ssize_t bytes_written; + off_t bytes_to_send; + off_t in_offset; + off_t bytes_written; + size_t bytes_chunk; dstfd = -1; err = 0; @@ -1104,7 +1163,7 @@ goto out; } - dst_flags = O_WRONLY | O_CREAT | O_TRUNC; + dst_flags = O_WRONLY | O_CREAT; if (req->flags & UV_FS_COPYFILE_EXCL) dst_flags |= O_EXCL; @@ -1123,16 +1182,26 @@ goto out; } - /* Get the destination file's mode. */ - if (fstat(dstfd, &dst_statsbuf)) { - err = UV__ERR(errno); - goto out; - } + /* If the file is not being opened exclusively, verify that the source and + destination are not the same file. If they are the same, bail out early. */ + if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) { + /* Get the destination file's mode. */ + if (fstat(dstfd, &dst_statsbuf)) { + err = UV__ERR(errno); + goto out; + } - /* Check if srcfd and dstfd refer to the same file */ - if (src_statsbuf.st_dev == dst_statsbuf.st_dev && - src_statsbuf.st_ino == dst_statsbuf.st_ino) { - goto out; + /* Check if srcfd and dstfd refer to the same file */ + if (src_statsbuf.st_dev == dst_statsbuf.st_dev && + src_statsbuf.st_ino == dst_statsbuf.st_ino) { + goto out; + } + + /* Truncate the file in case the destination already existed. */ + if (ftruncate(dstfd, 0) != 0) { + err = UV__ERR(errno); + goto out; + } } if (fchmod(dstfd, src_statsbuf.st_mode) == -1) { @@ -1185,7 +1254,10 @@ bytes_to_send = src_statsbuf.st_size; in_offset = 0; while (bytes_to_send != 0) { - uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_to_send, NULL); + bytes_chunk = SSIZE_MAX; + if (bytes_to_send < (off_t) bytes_chunk) + bytes_chunk = bytes_to_send; + uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_chunk, NULL); bytes_written = fs_req.result; uv_fs_req_cleanup(&fs_req); @@ -1325,7 +1397,7 @@ int mode; int rc; - if (no_statx) + if (uv__load_relaxed(&no_statx)) return UV_ENOSYS; dirfd = AT_FDCWD; @@ -1358,7 +1430,7 @@ * implemented, rc might return 1 with 0 set as the error code in which * case we return ENOSYS. */ - no_statx = 1; + uv__store_relaxed(&no_statx, 1); return UV_ENOSYS; } @@ -1528,6 +1600,7 @@ X(FSYNC, uv__fs_fsync(req)); X(FTRUNCATE, ftruncate(req->file, req->off)); X(FUTIME, uv__fs_futime(req)); + X(LUTIME, uv__fs_lutime(req)); X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); X(LINK, link(req->path, req->new_path)); X(MKDIR, mkdir(req->path, req->mode)); @@ -1714,6 +1787,19 @@ POST; } +int uv_fs_lutime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(LUTIME); + PATH; + req->atime = atime; + req->mtime = mtime; + POST; +} + int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { INIT(LSTAT); @@ -1987,7 +2073,7 @@ /* Only necessary for asychronous requests, i.e., requests with a callback. * Synchronous ones don't copy their arguments and have req->path and - * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and + * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and * UV_FS_MKSTEMP are the exception to the rule, they always allocate memory. */ if (req->path != NULL && @@ -2042,3 +2128,7 @@ PATH; POST; } + +int uv_fs_get_system_error(const uv_fs_t* req) { + return -req->result; +} diff -Nru libuv1-1.34.2/src/unix/fsevents.c libuv1-1.40.0/src/unix/fsevents.c --- libuv1-1.34.2/src/unix/fsevents.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/fsevents.c 2020-09-25 00:34:43.000000000 +0000 @@ -41,34 +41,33 @@ #else /* TARGET_OS_IPHONE */ +#include "darwin-stub.h" + #include #include #include #include -#include -#include - -/* These are macros to avoid "initializer element is not constant" errors - * with old versions of gcc. - */ -#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \ - kFSEventStreamEventFlagItemModified | \ - kFSEventStreamEventFlagItemInodeMetaMod | \ - kFSEventStreamEventFlagItemChangeOwner | \ - kFSEventStreamEventFlagItemXattrMod) - -#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \ - kFSEventStreamEventFlagItemRemoved | \ - kFSEventStreamEventFlagItemRenamed) - -#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \ - kFSEventStreamEventFlagKernelDropped | \ - kFSEventStreamEventFlagEventIdsWrapped | \ - kFSEventStreamEventFlagHistoryDone | \ - kFSEventStreamEventFlagMount | \ - kFSEventStreamEventFlagUnmount | \ - kFSEventStreamEventFlagRootChanged) +static const int kFSEventsModified = + kFSEventStreamEventFlagItemChangeOwner | + kFSEventStreamEventFlagItemFinderInfoMod | + kFSEventStreamEventFlagItemInodeMetaMod | + kFSEventStreamEventFlagItemModified | + kFSEventStreamEventFlagItemXattrMod; + +static const int kFSEventsRenamed = + kFSEventStreamEventFlagItemCreated | + kFSEventStreamEventFlagItemRemoved | + kFSEventStreamEventFlagItemRenamed; + +static const int kFSEventsSystem = + kFSEventStreamEventFlagUserDropped | + kFSEventStreamEventFlagKernelDropped | + kFSEventStreamEventFlagEventIdsWrapped | + kFSEventStreamEventFlagHistoryDone | + kFSEventStreamEventFlagMount | + kFSEventStreamEventFlagUnmount | + kFSEventStreamEventFlagRootChanged; typedef struct uv__fsevents_event_s uv__fsevents_event_t; typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; @@ -148,7 +147,7 @@ static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, CFRunLoopRef, CFStringRef); -static Boolean (*pFSEventStreamStart)(FSEventStreamRef); +static int (*pFSEventStreamStart)(FSEventStreamRef); static void (*pFSEventStreamStop)(FSEventStreamRef); #define UV__FSEVENTS_PROCESS(handle, block) \ @@ -215,7 +214,7 @@ /* Runs in CF thread, when there're events in FSEventStream */ -static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, +static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, void* info, size_t numEvents, void* eventPaths, @@ -340,11 +339,8 @@ FSEventStreamCreateFlags flags; /* Initialize context */ - ctx.version = 0; + memset(&ctx, 0, sizeof(ctx)); ctx.info = loop; - ctx.retain = NULL; - ctx.release = NULL; - ctx.copyDescription = NULL; latency = 0.05; diff -Nru libuv1-1.34.2/src/unix/ibmi.c libuv1-1.40.0/src/unix/ibmi.c --- libuv1-1.34.2/src/unix/ibmi.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/ibmi.c 2020-09-25 00:34:43.000000000 +0000 @@ -58,6 +58,9 @@ #include #include +char* original_exepath = NULL; +uv_mutex_t process_title_mutex; +uv_once_t process_title_mutex_once = UV_ONCE_INIT; typedef struct { int bytes_available; @@ -171,6 +174,9 @@ dst[i] = a2e[' ']; } +void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} static int get_ibmi_system_status(SSTS0200* rcvr) { /* rcvrlen is input parameter 2 to QWCRSSTS */ @@ -225,22 +231,7 @@ 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; } @@ -474,3 +465,37 @@ uv__free(addresses); } + +char** uv_setup_args(int argc, char** argv) { + char exepath[UV__PATH_MAX]; + char* s; + size_t size; + + if (argc > 0) { + /* Use argv[0] to determine value for uv_exepath(). */ + size = sizeof(exepath); + if (uv__search_path(argv[0], exepath, &size) == 0) { + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + original_exepath = uv__strdup(exepath); + uv_mutex_unlock(&process_title_mutex); + } + } + + return argv; +} + +int uv_set_process_title(const char* title) { + return 0; +} + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return UV_EINVAL; + + buffer[0] = '\0'; + return 0; +} + +void uv__process_title_cleanup(void) { +} \ No newline at end of file diff -Nru libuv1-1.34.2/src/unix/internal.h libuv1-1.40.0/src/unix/internal.h --- libuv1-1.34.2/src/unix/internal.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/internal.h 2020-09-25 00:34:43.000000000 +0000 @@ -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 @@ -61,9 +62,7 @@ # include #endif -#if defined(_POSIX_PATH_MAX) -# define UV__PATH_MAX _POSIX_PATH_MAX -#elif defined(PATH_MAX) +#if defined(PATH_MAX) # define UV__PATH_MAX PATH_MAX #else # define UV__PATH_MAX 8192 @@ -105,10 +104,8 @@ #if defined(__clang__) || \ defined(__GNUC__) || \ defined(__INTEL_COMPILER) -# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration # define UV_UNUSED(declaration) __attribute__((unused)) declaration #else -# define UV_DESTRUCTOR(declaration) declaration # define UV_UNUSED(declaration) declaration #endif @@ -269,6 +266,7 @@ uv_handle_type uv__handle_type(int fd); FILE* uv__open_file(const char* path); int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__search_path(const char* prog, char* buf, size_t* buflen); /* random */ int uv__random_devurandom(void* buf, size_t buflen); @@ -284,13 +282,12 @@ #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 +325,20 @@ 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); +int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); +#else +#define HAVE_MMSG 0 +#endif + + #endif /* UV_UNIX_INTERNAL_H_ */ diff -Nru libuv1-1.34.2/src/unix/kqueue.c libuv1-1.40.0/src/unix/kqueue.c --- libuv1-1.34.2/src/unix/kqueue.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/kqueue.c 2020-09-25 00:34:43.000000000 +0000 @@ -82,7 +82,7 @@ process. So we sidestep the issue by pretending like we never started it in the first place. */ - uv__has_forked_with_cfrunloop = 1; + uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1); uv__free(loop->cf_state); loop->cf_state = NULL; } @@ -129,6 +129,8 @@ int fd; int op; int i; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -202,7 +204,21 @@ base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + for (;; nevents = 0) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; @@ -228,6 +244,15 @@ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + if (timeout == -1) + continue; + if (timeout > 0) + goto update_timeout; + } + assert(timeout != -1); return; } @@ -236,6 +261,11 @@ if (errno != EINTR) abort(); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == 0) return; @@ -276,6 +306,7 @@ if (ev->filter == EVFILT_VNODE) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); + uv__metrics_update_idle_time(loop); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; @@ -337,16 +368,25 @@ /* Run signal watchers last. This also affects child process watchers * because those are implemented in terms of signal watchers. */ - if (w == &loop->signal_io_watcher) + if (w == &loop->signal_io_watcher) { have_signals = 1; - else + } else { + uv__metrics_update_idle_time(loop); w->cb(loop, w, revents); + } nevents++; } - if (have_signals != 0) + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; @@ -487,7 +527,7 @@ if (!(statbuf.st_mode & S_IFDIR)) goto fallback; - if (!uv__has_forked_with_cfrunloop) { + if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) { int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); @@ -522,8 +562,9 @@ uv__handle_stop(handle); #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (!uv__has_forked_with_cfrunloop && handle->cf_cb != NULL) - r = uv__fsevents_close(handle); + if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) + if (handle->cf_cb != NULL) + r = uv__fsevents_close(handle); #endif if (handle->event_watcher.fd != -1) { diff -Nru libuv1-1.34.2/src/unix/linux-core.c libuv1-1.40.0/src/unix/linux-core.c --- libuv1-1.34.2/src/unix/linux-core.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/linux-core.c 2020-09-25 00:34:43.000000000 +0000 @@ -85,17 +85,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { int fd; - - /* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21, - * a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all - * architectures, we just use that instead. - */ -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - fd = -1; - errno = ENOSYS; -#else fd = epoll_create1(O_CLOEXEC); -#endif /* epoll_create1() can fail either because it's not implemented (old kernel) * or because it doesn't understand the O_CLOEXEC flag. @@ -208,8 +198,10 @@ * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; - static int no_epoll_pwait; - static int no_epoll_wait; + static int no_epoll_pwait_cached; + static int no_epoll_wait_cached; + int no_epoll_pwait; + int no_epoll_wait; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; @@ -226,6 +218,8 @@ int fd; int op; int i; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -281,7 +275,31 @@ count = 48; /* Benchmarks suggest this gives the best throughput. */ real_timeout = timeout; + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + user_timeout = 0; + } + + /* You could argue there is a dependency between these two but + * ultimately we don't care about their ordering with respect + * to one another. Worst case, we make a few system calls that + * could have been avoided because another thread already knows + * they fail with ENOSYS. Hardly the end of the world. + */ + no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); + no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + /* See the comment for max_safe_timeout for an explanation of why * this is necessary. Executive summary: kernel bug workaround. */ @@ -293,25 +311,24 @@ abort(); if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - nfds = -1; - errno = ENOSYS; -#else nfds = epoll_pwait(loop->backend_fd, events, ARRAY_SIZE(events), timeout, &sigset); -#endif - if (nfds == -1 && errno == ENOSYS) + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_pwait_cached, 1); no_epoll_pwait = 1; + } } else { nfds = epoll_wait(loop->backend_fd, events, ARRAY_SIZE(events), timeout); - if (nfds == -1 && errno == ENOSYS) + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_wait_cached, 1); no_epoll_wait = 1; + } } if (sigmask != 0 && no_epoll_pwait != 0) @@ -327,6 +344,14 @@ if (nfds == 0) { assert(timeout != -1); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == -1) + continue; + if (timeout == 0) return; @@ -346,6 +371,11 @@ if (errno != EINTR) abort(); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == -1) continue; @@ -425,17 +455,26 @@ /* Run signal watchers last. This also affects child process watchers * because those are implemented in terms of signal watchers. */ - if (w == &loop->signal_io_watcher) + if (w == &loop->signal_io_watcher) { have_signals = 1; - else + } else { + uv__metrics_update_idle_time(loop); w->cb(loop, w, pe->events); + } nevents++; } } - if (have_signals != 0) + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; @@ -483,18 +522,22 @@ /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE * when it has microsecond granularity or better (unlikely). */ - if (type == UV_CLOCK_FAST && fast_clock_id == -1) { - if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 && - t.tv_nsec <= 1 * 1000 * 1000) { - fast_clock_id = CLOCK_MONOTONIC_COARSE; - } else { - fast_clock_id = CLOCK_MONOTONIC; - } - } + clock_id = CLOCK_MONOTONIC; + if (type != UV_CLOCK_FAST) + goto done; + + clock_id = uv__load_relaxed(&fast_clock_id); + if (clock_id != -1) + goto done; clock_id = CLOCK_MONOTONIC; - if (type == UV_CLOCK_FAST) - clock_id = fast_clock_id; + if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t)) + if (t.tv_nsec <= 1 * 1000 * 1000) + clock_id = CLOCK_MONOTONIC_COARSE; + + uv__store_relaxed(&fast_clock_id, clock_id); + +done: if (clock_gettime(clock_id, &t)) return 0; /* Not really possible. */ @@ -768,7 +811,8 @@ unsigned int numcpus, uv_cpu_info_t* ci) { struct uv_cpu_times_s ts; - uint64_t clock_ticks; + unsigned int ticks; + unsigned int multiplier; uint64_t user; uint64_t nice; uint64_t sys; @@ -779,9 +823,10 @@ uint64_t len; char buf[1024]; - clock_ticks = sysconf(_SC_CLK_TCK); - assert(clock_ticks != (uint64_t) -1); - assert(clock_ticks != 0); + ticks = (unsigned int)sysconf(_SC_CLK_TCK); + multiplier = ((uint64_t)1000L / ticks); + assert(ticks != (unsigned int) -1); + assert(ticks != 0); rewind(statfile_fp); @@ -823,11 +868,11 @@ &irq)) abort(); - ts.user = clock_ticks * user; - ts.nice = clock_ticks * nice; - ts.sys = clock_ticks * sys; - ts.idle = clock_ticks * idle; - ts.irq = clock_ticks * irq; + ts.user = user * multiplier; + ts.nice = nice * multiplier; + ts.sys = sys * multiplier; + ts.idle = idle * multiplier; + ts.irq = irq * multiplier; ci[num++].cpu_times = ts; } assert(num == numcpus); @@ -980,43 +1025,51 @@ } -static uint64_t uv__read_proc_meminfo(const char* what) { - uint64_t rc; +static int uv__slurp(const char* filename, char* buf, size_t len) { ssize_t n; - char* p; int fd; - char buf[4096]; /* Large enough to hold all of /proc/meminfo. */ - rc = 0; - fd = uv__open_cloexec("/proc/meminfo", O_RDONLY); + assert(len > 0); + fd = uv__open_cloexec(filename, O_RDONLY); if (fd < 0) - return 0; + return fd; - n = read(fd, buf, sizeof(buf) - 1); + do + n = read(fd, buf, len - 1); + while (n == -1 && errno == EINTR); - if (n <= 0) - goto out; + if (uv__close_nocheckstdio(fd)) + abort(); + + if (n < 0) + return UV__ERR(errno); buf[n] = '\0'; - p = strstr(buf, what); - if (p == NULL) - goto out; + return 0; +} - p += strlen(what); - if (1 != sscanf(p, "%" PRIu64 " kB", &rc)) - goto out; +static uint64_t uv__read_proc_meminfo(const char* what) { + uint64_t rc; + char* p; + char buf[4096]; /* Large enough to hold all of /proc/meminfo. */ - rc *= 1024; + if (uv__slurp("/proc/meminfo", buf, sizeof(buf))) + return 0; -out: + p = strstr(buf, what); - if (uv__close_nocheckstdio(fd)) - abort(); + if (p == NULL) + return 0; - return rc; + p += strlen(what); + + rc = 0; + sscanf(p, "%" PRIu64 " kB", &rc); + + return rc * 1024; } @@ -1054,28 +1107,13 @@ static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) { char filename[256]; - uint64_t rc; - int fd; - ssize_t n; char buf[32]; /* Large enough to hold an encoded uint64_t. */ - - snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param); + uint64_t rc; rc = 0; - fd = uv__open_cloexec(filename, O_RDONLY); - - if (fd < 0) - return 0; - - n = read(fd, buf, sizeof(buf) - 1); - - if (n > 0) { - buf[n] = '\0'; + snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param); + if (0 == uv__slurp(filename, buf, sizeof(buf))) sscanf(buf, "%" PRIu64, &rc); - } - - if (uv__close_nocheckstdio(fd)) - abort(); return rc; } @@ -1089,3 +1127,20 @@ */ return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes"); } + + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + char buf[128]; /* Large enough to hold all of /proc/loadavg. */ + + if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf))) + if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2])) + return; + + if (sysinfo(&info) < 0) + return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} diff -Nru libuv1-1.34.2/src/unix/linux-inotify.c libuv1-1.40.0/src/unix/linux-inotify.c --- libuv1-1.34.2/src/unix/linux-inotify.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/linux-inotify.c 2020-09-25 00:34:43.000000000 +0000 @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -64,45 +65,17 @@ 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 @@ 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 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 @@ /* 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 @@ 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 -Nru libuv1-1.34.2/src/unix/linux-syscalls.c libuv1-1.40.0/src/unix/linux-syscalls.c --- libuv1-1.34.2/src/unix/linux-syscalls.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/linux-syscalls.c 2020-09-25 00:34:43.000000000 +0000 @@ -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,91 +34,9 @@ # 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 -# elif defined(__i386__) -# define __NR_recvmmsg 337 # elif defined(__arm__) # define __NR_recvmmsg (UV_SYSCALL_BASE + 365) # endif @@ -140,8 +45,6 @@ #ifndef __NR_sendmmsg # if defined(__x86_64__) # define __NR_sendmmsg 307 -# elif defined(__i386__) -# define __NR_sendmmsg 345 # elif defined(__arm__) # define __NR_sendmmsg (UV_SYSCALL_BASE + 374) # endif @@ -187,6 +90,24 @@ # endif #endif /* __NR_pwritev */ +#ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined(__s390__) +# define __NR_copy_file_range 375 +# elif defined(__arm__) +# define __NR_copy_file_range (UV_SYSCALL_BASE + 391) +# elif defined(__aarch64__) +# define __NR_copy_file_range 285 +# elif defined(__powerpc__) +# define __NR_copy_file_range 379 +# elif defined(__arc__) +# define __NR_copy_file_range 285 +# endif +#endif /* __NR_copy_file_range */ + #ifndef __NR_statx # if defined(__x86_64__) # define __NR_statx 332 @@ -219,123 +140,53 @@ # endif #endif /* __NR_getrandom */ -int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { +struct uv__mmsghdr; + +int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { #if defined(__i386__) unsigned long args[4]; - int r; + int rc; 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) + args[1] = (unsigned long) mmsg; + args[2] = (unsigned long) vlen; + args[3] = /* flags */ 0; + + /* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */ + rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args); + if (rc == -1) if (errno == EINVAL) - if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) - errno = ENOSYS; + errno = ENOSYS; - return r; -#elif defined(__NR_accept4) - return syscall(__NR_accept4, fd, addr, addrlen, flags); + return rc; +#elif defined(__NR_sendmmsg) + return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0); #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 -} - - -int uv__sendmmsg(int fd, - struct uv__mmsghdr* mmsg, - unsigned int vlen, - unsigned int flags) { -#if defined(__NR_sendmmsg) - return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags); -#else - return errno = ENOSYS, -1; -#endif -} +int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { +#if defined(__i386__) + unsigned long args[5]; + int rc; + args[0] = (unsigned long) fd; + args[1] = (unsigned long) mmsg; + args[2] = (unsigned long) vlen; + args[3] = /* flags */ 0; + args[4] = /* timeout */ 0; + + /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ + rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); + if (rc == -1) + if (errno == EINVAL) + errno = ENOSYS; -int uv__recvmmsg(int fd, - struct uv__mmsghdr* mmsg, - unsigned int vlen, - unsigned int flags, - struct timespec* timeout) { -#if defined(__NR_recvmmsg) - return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout); + return rc; +#elif defined(__NR_recvmmsg) + return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); #else return errno = ENOSYS, -1; #endif @@ -366,6 +217,28 @@ #else return errno = ENOSYS, -1; #endif +} + + +ssize_t +uv__fs_copy_file_range(int fd_in, + ssize_t* off_in, + int fd_out, + ssize_t* off_out, + size_t len, + unsigned int flags) +{ +#ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + flags); +#else + return errno = ENOSYS, -1; +#endif } diff -Nru libuv1-1.34.2/src/unix/linux-syscalls.h libuv1-1.40.0/src/unix/linux-syscalls.h --- libuv1-1.34.2/src/unix/linux-syscalls.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/linux-syscalls.h 2020-09-25 00:34:43.000000000 +0000 @@ -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,39 +61,16 @@ 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); +ssize_t +uv__fs_copy_file_range(int fd_in, + ssize_t* off_in, + int fd_out, + ssize_t* off_out, + size_t len, + unsigned int flags); int uv__statx(int dirfd, const char* path, int flags, diff -Nru libuv1-1.34.2/src/unix/loop.c libuv1-1.40.0/src/unix/loop.c --- libuv1-1.34.2/src/unix/loop.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/loop.c 2020-09-25 00:34:43.000000000 +0000 @@ -28,6 +28,7 @@ #include int uv_loop_init(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; void* saved_data; int err; @@ -36,6 +37,15 @@ memset(loop, 0, sizeof(*loop)); loop->data = saved_data; + lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + if (lfields == NULL) + return UV_ENOMEM; + loop->internal_fields = lfields; + + err = uv_mutex_init(&lfields->loop_metrics.lock); + if (err) + goto fail_metrics_mutex_init; + heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->idle_handles); @@ -66,7 +76,7 @@ err = uv__platform_loop_init(loop); if (err) - return err; + goto fail_platform_init; uv__signal_global_once_init(); err = uv_signal_init(loop, &loop->child_watcher); @@ -106,6 +116,15 @@ fail_signal_init: uv__platform_loop_delete(loop); +fail_platform_init: + uv_mutex_destroy(&lfields->loop_metrics.lock); + +fail_metrics_mutex_init: + uv__free(lfields); + loop->internal_fields = NULL; + + uv__free(loop->watchers); + loop->nwatchers = 0; return err; } @@ -144,6 +163,8 @@ void uv__loop_close(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; + uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); uv__async_stop(loop); @@ -179,10 +200,23 @@ uv__free(loop->watchers); loop->watchers = NULL; loop->nwatchers = 0; + + lfields = uv__get_internal_fields(loop); + uv_mutex_destroy(&lfields->loop_metrics.lock); + uv__free(lfields); + loop->internal_fields = NULL; } int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + uv__loop_internal_fields_t* lfields; + + lfields = uv__get_internal_fields(loop); + if (option == UV_METRICS_IDLE_TIME) { + lfields->flags |= UV_METRICS_IDLE_TIME; + return 0; + } + if (option != UV_LOOP_BLOCK_SIGNAL) return UV_ENOSYS; diff -Nru libuv1-1.34.2/src/unix/no-proctitle.c libuv1-1.40.0/src/unix/no-proctitle.c --- libuv1-1.34.2/src/unix/no-proctitle.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/no-proctitle.c 2020-09-25 00:34:43.000000000 +0000 @@ -29,6 +29,9 @@ return argv; } +void uv__process_title_cleanup(void) { +} + int uv_set_process_title(const char* title) { return 0; } diff -Nru libuv1-1.34.2/src/unix/openbsd.c libuv1-1.40.0/src/unix/openbsd.c --- libuv1-1.34.2/src/unix/openbsd.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/openbsd.c 2020-09-25 00:34:43.000000000 +0000 @@ -61,7 +61,6 @@ int uv_exepath(char* buffer, size_t* size) { int mib[4]; char **argsbuf = NULL; - char **argsbuf_tmp; size_t argsbuf_size = 100U; size_t exepath_size; pid_t mypid; @@ -73,10 +72,9 @@ mypid = getpid(); for (;;) { err = UV_ENOMEM; - argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size); - if (argsbuf_tmp == NULL) + argsbuf = uv__reallocf(argsbuf, argsbuf_size); + if (argsbuf == NULL) goto out; - argsbuf = argsbuf_tmp; mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; mib[2] = mypid; @@ -185,7 +183,7 @@ 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 +204,15 @@ 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 -Nru libuv1-1.34.2/src/unix/os390.c libuv1-1.40.0/src/unix/os390.c --- libuv1-1.34.2/src/unix/os390.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/os390.c 2020-09-25 00:34:43.000000000 +0000 @@ -254,8 +254,6 @@ int uv_exepath(char* buffer, size_t* size) { int res; char args[PATH_MAX]; - char abspath[PATH_MAX]; - size_t abspath_size; int pid; if (buffer == NULL || size == NULL || *size == 0) @@ -266,69 +264,7 @@ if (res < 0) return UV_EINVAL; - /* - * Possibilities for args: - * i) an absolute path such as: /home/user/myprojects/nodejs/node - * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable - * to its location. - */ - - /* Case i) and ii) absolute or relative paths */ - if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) - return UV__ERR(errno); - - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - return 0; - } else { - /* Case iii). Search PATH environment variable */ - char trypath[PATH_MAX]; - char* clonedpath = NULL; - char* token = NULL; - char* path = getenv("PATH"); - - if (path == NULL) - return UV_EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return UV_ENOMEM; - - token = strtok(clonedpath, ":"); - while (token != NULL) { - snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { - /* Check the match is executable */ - if (access(abspath, X_OK) == 0) { - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - uv__free(clonedpath); - return 0; - } - } - token = strtok(NULL, ":"); - } - uv__free(clonedpath); - - /* Out of tokens (path entries), and no match found */ - return UV_EINVAL; - } + return uv__search_path(args, buffer, size); } @@ -818,6 +754,8 @@ int fd; int op; int i; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -870,8 +808,22 @@ real_timeout = timeout; int nevents = 0; + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + nfds = 0; for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; @@ -887,12 +839,21 @@ if (nfds == 0) { assert(timeout != -1); - if (timeout > 0) { - timeout = real_timeout - timeout; - continue; + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; } - return; + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; } if (nfds == -1) { @@ -900,6 +861,11 @@ if (errno != EINTR) abort(); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == -1) continue; @@ -923,7 +889,7 @@ continue; ep = loop->ep; - if (fd == ep->msg_queue) { + if (pe->is_msg) { os390_message_queue_handler(ep); continue; } @@ -954,6 +920,7 @@ pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { + uv__metrics_update_idle_time(loop); w->cb(loop, w, pe->events); nevents++; } @@ -961,6 +928,11 @@ loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ diff -Nru libuv1-1.34.2/src/unix/os390-syscalls.c libuv1-1.40.0/src/unix/os390-syscalls.c --- libuv1-1.34.2/src/unix/os390-syscalls.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/os390-syscalls.c 2020-09-25 00:34:43.000000000 +0000 @@ -33,7 +33,6 @@ #pragma linkage(BPX4CTW, OS) #pragma linkage(BPX1CTW, OS) -static int number_of_epolls; static QUEUE global_epoll_queue; static uv_mutex_t global_epoll_lock; static uv_once_t once = UV_ONCE_INIT; @@ -43,6 +42,7 @@ 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 +62,17 @@ 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 +84,16 @@ *namelist = nl; return count; + +error: + while (count > 0) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; } @@ -119,7 +127,7 @@ } newsize = next_power_of_two(len); - newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); + newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0])); if (newlst == NULL) abort(); @@ -269,6 +277,8 @@ return 0; } +#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd)) +#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int maxevents, int timeout) { @@ -277,18 +287,41 @@ int pollret; int reventcount; int nevents; + struct pollfd msg_fd; + int i; + + if (!lst || !lst->items || !events) { + errno = EFAULT; + return -1; + } - _SET_FDS_MSGS(size, 1, lst->size - 1); + if (lst->size > EP_MAX_PFDS) { + errno = EINVAL; + return -1; + } + + if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) { + errno = EINVAL; + return -1; + } + + if (lst->size > 0) + _SET_FDS_MSGS(size, 1, lst->size - 1); + else + _SET_FDS_MSGS(size, 0, 0); pfds = lst->items; pollret = poll(pfds, size, timeout); if (pollret <= 0) return pollret; + assert(lst->size > 0); + pollret = _NFDS(pollret) + _NMSGS(pollret); reventcount = 0; nevents = 0; - for (int i = 0; + msg_fd = pfds[lst->size - 1]; + for (i = 0; i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; struct pollfd* pfd; @@ -299,6 +332,7 @@ ev.fd = pfd->fd; ev.events = pfd->revents; + ev.is_msg = 0; if (pfd->revents & POLLIN && pfd->revents & POLLOUT) reventcount += 2; else if (pfd->revents & (POLLIN | POLLOUT)) @@ -308,6 +342,10 @@ events[nevents++] = ev; } + if (msg_fd.revents != 0 && msg_fd.fd != -1) + if (i == lst->size) + events[nevents - 1].is_msg = 1; + return nevents; } @@ -369,10 +407,12 @@ * Don't leak EAGAIN, that just means the timeout expired. */ if (rv == -1) - if (err != EAGAIN) + if (err == EAGAIN) + rv = 0; + else errno = err; - if (rem != NULL && (rv == 0 || err == EINTR || err == EAGAIN)) { + if (rem != NULL && (rv == 0 || err == EINTR)) { rem->tv_nsec = nanorem; rem->tv_sec = secrem; } @@ -517,3 +557,28 @@ else return p - str; } + + +int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) { + UNREACHABLE(); +} + + +int sem_destroy(UV_PLATFORM_SEM_T* semid) { + UNREACHABLE(); +} + + +int sem_post(UV_PLATFORM_SEM_T* semid) { + UNREACHABLE(); +} + + +int sem_trywait(UV_PLATFORM_SEM_T* semid) { + UNREACHABLE(); +} + + +int sem_wait(UV_PLATFORM_SEM_T* semid) { + UNREACHABLE(); +} diff -Nru libuv1-1.34.2/src/unix/os390-syscalls.h libuv1-1.40.0/src/unix/os390-syscalls.h --- libuv1-1.34.2/src/unix/os390-syscalls.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/os390-syscalls.h 2020-09-25 00:34:43.000000000 +0000 @@ -40,6 +40,7 @@ struct epoll_event { int events; int fd; + int is_msg; }; typedef struct { @@ -64,5 +65,10 @@ char *mkdtemp(char* path); ssize_t os390_readlink(const char* path, char* buf, size_t len); size_t strnlen(const char* str, size_t maxlen); +int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value); +int sem_destroy(UV_PLATFORM_SEM_T* semid); +int sem_post(UV_PLATFORM_SEM_T* semid); +int sem_trywait(UV_PLATFORM_SEM_T* semid); +int sem_wait(UV_PLATFORM_SEM_T* semid); #endif /* UV_OS390_SYSCALL_H_ */ diff -Nru libuv1-1.34.2/src/unix/pipe.c libuv1-1.40.0/src/unix/pipe.c --- libuv1-1.34.2/src/unix/pipe.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/pipe.c 2020-09-25 00:34:43.000000000 +0000 @@ -95,8 +95,12 @@ 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 -Nru libuv1-1.34.2/src/unix/posix-poll.c libuv1-1.40.0/src/unix/posix-poll.c --- libuv1-1.34.2/src/unix/posix-poll.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/posix-poll.c 2020-09-25 00:34:43.000000000 +0000 @@ -61,7 +61,7 @@ return; n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; - p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); + p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds)); if (p == NULL) abort(); @@ -144,6 +144,8 @@ int have_signals; struct pollfd* pe; int fd; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -177,11 +179,25 @@ assert(timeout >= -1); time_base = loop->time; + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + /* Loop calls to poll() and processing of results. If we get some * results from poll() but they turn out not to be interesting to * our caller then we need to loop around and poll() again. */ for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + if (pset != NULL) if (pthread_sigmask(SIG_BLOCK, pset, NULL)) abort(); @@ -197,6 +213,15 @@ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + if (timeout == -1) + continue; + if (timeout > 0) + goto update_timeout; + } + assert(timeout != -1); return; } @@ -205,6 +230,11 @@ if (errno != EINTR) abort(); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == -1) continue; @@ -254,6 +284,7 @@ if (w == &loop->signal_io_watcher) { have_signals = 1; } else { + uv__metrics_update_idle_time(loop); w->cb(loop, w, pe->revents); } @@ -261,8 +292,15 @@ } } - if (have_signals != 0) + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } loop->poll_fds_iterating = 0; diff -Nru libuv1-1.34.2/src/unix/process.c libuv1-1.40.0/src/unix/process.c --- libuv1-1.34.2/src/unix/process.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/process.c 2020-09-25 00:34:43.000000000 +0000 @@ -112,72 +112,64 @@ } -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); - - if (flags & UV__F_NONBLOCK) { - uv__nonblock(fds[0], 1); - uv__nonblock(fds[1], 1); + err = uv__cloexec(fds[0], 1); + if (err == 0) + err = uv__cloexec(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 @@ 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 -Nru libuv1-1.34.2/src/unix/proctitle.c libuv1-1.40.0/src/unix/proctitle.c --- libuv1-1.34.2/src/unix/proctitle.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/proctitle.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 @@ char** uv_setup_args(int argc, char** argv) { + struct uv__process_title pt; char** new_argv; size_t size; char* s; @@ -50,53 +53,73 @@ 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; + + /* If uv_setup_args wasn't called or failed, we can't continue. */ + if (args_mem == NULL) + return UV_ENOBUFS; + + 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; @@ -107,6 +130,10 @@ if (buffer == NULL || size == 0) return UV_EINVAL; + /* If uv_setup_args wasn't called or failed, we can't continue. */ + if (args_mem == NULL) + return UV_ENOBUFS; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -126,7 +153,7 @@ } -UV_DESTRUCTOR(static void free_args_mem(void)) { +void uv__process_title_cleanup(void) { uv__free(args_mem); /* Keep valgrind happy. */ args_mem = NULL; } diff -Nru libuv1-1.34.2/src/unix/pthread-fixes.c libuv1-1.40.0/src/unix/pthread-fixes.c --- libuv1-1.34.2/src/unix/pthread-fixes.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/pthread-fixes.c 2020-09-25 00:34:43.000000000 +0000 @@ -30,6 +30,8 @@ */ /* Android versions < 4.1 have a broken pthread_sigmask. */ +#include "uv-common.h" + #include #include #include @@ -38,13 +40,13 @@ static int workaround; int err; - if (workaround) { + if (uv__load_relaxed(&workaround)) { return sigprocmask(how, set, oset); } else { err = pthread_sigmask(how, set, oset); if (err) { if (err == EINVAL && sigprocmask(how, set, oset) == 0) { - workaround = 1; + uv__store_relaxed(&workaround, 1); return 0; } else { return -1; diff -Nru libuv1-1.34.2/src/unix/qnx.c libuv1-1.40.0/src/unix/qnx.c --- libuv1-1.34.2/src/unix/qnx.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/src/unix/qnx.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,137 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +static void +get_mem_info(uint64_t* totalmem, uint64_t* freemem) { + mem_info_t msg; + + memset(&msg, 0, sizeof(msg)); + msg.i.type = _MEM_INFO; + msg.i.fd = -1; + + if (MsgSend(MEMMGR_COID, &msg.i, sizeof(msg.i), &msg.o, sizeof(msg.o)) + != -1) { + *totalmem = msg.o.info.__posix_tmi_total; + *freemem = msg.o.info.posix_tmi_length; + } else { + *totalmem = 0; + *freemem = 0; + } +} + + +void uv_loadavg(double avg[3]) { + avg[0] = 0.0; + avg[1] = 0.0; + avg[2] = 0.0; +} + + +int uv_exepath(char* buffer, size_t* size) { + char path[PATH_MAX]; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + realpath(_cmdname(NULL), path); + strlcpy(buffer, path, *size); + *size = strlen(buffer); + return 0; +} + + +uint64_t uv_get_free_memory(void) { + uint64_t totalmem; + uint64_t freemem; + get_mem_info(&totalmem, &freemem); + return freemem; +} + + +uint64_t uv_get_total_memory(void) { + uint64_t totalmem; + uint64_t freemem; + get_mem_info(&totalmem, &freemem); + return totalmem; +} + + +uint64_t uv_get_constrained_memory(void) { + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + int fd; + procfs_asinfo asinfo; + + fd = uv__open_cloexec("/proc/self/ctl", O_RDONLY); + if (fd == -1) + return UV__ERR(errno); + + if (devctl(fd, DCMD_PROC_ASINFO, &asinfo, sizeof(asinfo), 0) == -1) { + uv__close(fd); + return UV__ERR(errno); + } + + uv__close(fd); + *rss = asinfo.rss; + return 0; +} + + +int uv_uptime(double* uptime) { + struct qtime_entry* qtime = _SYSPAGE_ENTRY(_syspage_ptr, qtime); + *uptime = (qtime->nsec / 1000000000.0); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + struct cpuinfo_entry* cpuinfo = + (struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, new_cpuinfo); + size_t cpuinfo_size = _SYSPAGE_ELEMENT_SIZE(_syspage_ptr, cpuinfo); + struct strings_entry* strings = _SYSPAGE_ENTRY(_syspage_ptr, strings); + int num_cpus = _syspage_ptr->num_cpu; + int i; + + *count = num_cpus; + *cpu_infos = uv__malloc(num_cpus * sizeof(**cpu_infos)); + if (*cpu_infos == NULL) + return UV_ENOMEM; + + for (i = 0; i < num_cpus; i++) { + (*cpu_infos)[i].model = strdup(&strings->data[cpuinfo->name]); + (*cpu_infos)[i].speed = cpuinfo->speed; + SYSPAGE_ARRAY_ADJ_OFFSET(cpuinfo, cpuinfo, cpuinfo_size); + } + + return 0; +} diff -Nru libuv1-1.34.2/src/unix/signal.c libuv1-1.40.0/src/unix/signal.c --- libuv1-1.34.2/src/unix/signal.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/signal.c 2020-09-25 00:34:43.000000000 +0000 @@ -77,7 +77,7 @@ } -UV_DESTRUCTOR(static void uv__signal_global_fini(void)) { +void uv__signal_cleanup(void) { /* We can only use signal-safe functions here. * That includes read/write and close, fortunately. * We do all of this directly here instead of resetting @@ -98,7 +98,7 @@ static void uv__signal_global_reinit(void) { - uv__signal_global_fini(); + uv__signal_cleanup(); if (uv__make_pipe(uv__signal_lock_pipefd, 0)) abort(); @@ -143,6 +143,8 @@ if (sigfillset(&new_mask)) abort(); + /* to shut up valgrind */ + sigemptyset(saved_sigmask); if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask)) abort(); @@ -331,16 +333,7 @@ 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 +465,6 @@ 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 +554,5 @@ 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 -Nru libuv1-1.34.2/src/unix/sunos.c libuv1-1.40.0/src/unix/sunos.c --- libuv1-1.34.2/src/unix/sunos.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/sunos.c 2020-09-25 00:34:43.000000000 +0000 @@ -154,6 +154,7 @@ sigset_t set; uint64_t base; uint64_t diff; + uint64_t idle_poll; unsigned int nfds; unsigned int i; int saved_errno; @@ -162,6 +163,8 @@ int count; int err; int fd; + int user_timeout; + int reset_timeout; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -199,7 +202,21 @@ base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; @@ -242,6 +259,11 @@ SAVE_ERRNO(uv__update_time(loop)); if (events[0].portev_source == 0) { + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + if (timeout == 0) return; @@ -282,10 +304,12 @@ /* Run signal watchers last. This also affects child process watchers * because those are implemented in terms of signal watchers. */ - if (w == &loop->signal_io_watcher) + if (w == &loop->signal_io_watcher) { have_signals = 1; - else + } else { + uv__metrics_update_idle_time(loop); w->cb(loop, w, pe->portev_events); + } nevents++; @@ -297,8 +321,15 @@ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } - if (have_signals != 0) + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; diff -Nru libuv1-1.34.2/src/unix/tcp.c libuv1-1.40.0/src/unix/tcp.c --- libuv1-1.34.2/src/unix/tcp.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/tcp.c 2020-09-25 00:34:43.000000000 +0000 @@ -326,16 +326,19 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { - static int single_accept = -1; + static int single_accept_cached = -1; unsigned long flags; + int single_accept; int err; if (tcp->delayed_error) return tcp->delayed_error; + single_accept = uv__load_relaxed(&single_accept_cached); if (single_accept == -1) { const char* val = getenv("UV_TCP_SINGLE_ACCEPT"); single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */ + uv__store_relaxed(&single_accept_cached, single_accept); } if (single_accept) @@ -379,8 +382,16 @@ 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 -Nru libuv1-1.34.2/src/unix/thread.c libuv1-1.40.0/src/unix/thread.c --- libuv1-1.34.2/src/unix/thread.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/thread.c 2020-09-25 00:34:43.000000000 +0000 @@ -172,10 +172,11 @@ #if defined(__APPLE__) || defined(__linux__) struct rlimit lim; - if (getrlimit(RLIMIT_STACK, &lim)) - abort(); - - if (lim.rlim_cur != RLIM_INFINITY) { + /* getrlimit() can fail on some aarch64 systems due to a glibc bug where + * the system call wrapper invokes the wrong system call. Don't treat + * that as fatal, just use the default stack size instead. + */ + if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) { /* pthread_attr_setstacksize() expects page-aligned values. */ lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); @@ -708,11 +709,9 @@ if (err) return UV__ERR(err); -#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); if (err) goto error2; -#endif err = pthread_cond_init(cond, &attr); if (err) @@ -804,16 +803,7 @@ #endif ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - - /* - * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, - * but has this alternative function instead. - */ - r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); -#else r = pthread_cond_timedwait(cond, mutex, &ts); -#endif /* __ANDROID_API__ */ #endif diff -Nru libuv1-1.34.2/src/unix/tty.c libuv1-1.40.0/src/unix/tty.c --- libuv1-1.34.2/src/unix/tty.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/tty.c 2020-09-25 00:34:43.000000000 +0000 @@ -34,6 +34,34 @@ #define IMAXBEL 0 #endif +#if defined(__PASE__) +/* On IBM i PASE, for better compatibility with running interactive programs in + * a 5250 environment, isatty() will return true for the stdin/stdout/stderr + * streams created by QSH/QP2TERM. + * + * For more, see docs on PASE_STDIO_ISATTY in + * https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm + * + * This behavior causes problems for Node as it expects that if isatty() returns + * true that TTY ioctls will be supported by that fd (which is not an + * unreasonable expectation) and when they don't it crashes with assertion + * errors. + * + * Here, we create our own version of isatty() that uses ioctl() to identify + * whether the fd is *really* a TTY or not. + */ +static int isreallyatty(int file) { + int rc; + + rc = !ioctl(file, TXISATTY + 0x81, NULL); + if (!rc && errno != EBADF) + errno = ENOTTY; + + return rc; +} +#define isatty(fd) isreallyatty(fd) +#endif + static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; @@ -293,14 +321,7 @@ if (file < 0) return UV_UNKNOWN_HANDLE; -#if defined(__PASE__) - /* On IBMi PASE isatty() always returns true for stdin, stdout and stderr. - * Use ioctl() instead to identify whether it's actually a TTY. - */ - if (!ioctl(file, TXISATTY + 0x81, NULL) || errno != ENOTTY) -#else if (isatty(file)) -#endif return UV_TTY; if (fstat(file, &s)) diff -Nru libuv1-1.34.2/src/unix/udp.c libuv1-1.40.0/src/unix/udp.c --- libuv1-1.34.2/src/unix/udp.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/unix/udp.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 @@ -40,6 +42,11 @@ # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif +union uv__sockaddr { + struct sockaddr_in6 in6; + struct sockaddr_in in; + struct sockaddr addr; +}; static void uv__udp_run_completed(uv_udp_t* handle); static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); @@ -49,6 +56,36 @@ 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); + if (ret == 0 || errno != ENOSYS) { + uv__sendmmsg_avail = 1; + uv__recvmmsg_avail = 1; + } else { + ret = uv__recvmmsg(s, NULL, 0); + 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 +185,64 @@ } } +#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]); + msgs[k].msg_hdr.msg_control = NULL; + msgs[k].msg_hdr.msg_controllen = 0; + msgs[k].msg_hdr.msg_flags = 0; + } + + do + nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks); + 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 { + /* pass each chunk to the application */ + for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) { + flags = UV_UDP_MMSG_CHUNK; + if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC) + flags |= UV_UDP_PARTIAL; + + 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); + } + + /* one last callback so the original buffer is freed */ + if (handle->recv_cb != NULL) + handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); + } + return nread; +} +#endif static void uv__udp_recvmsg(uv_udp_t* handle) { struct sockaddr_storage peer; @@ -167,13 +262,22 @@ 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 + if (uv_udp_using_recvmmsg(handle)) { + 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 +303,120 @@ 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); + 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(&handle->write_queue)) { + 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 +466,6 @@ } } - /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. * @@ -367,11 +569,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags) { - union { - struct sockaddr_in6 in6; - struct sockaddr_in in; - struct sockaddr addr; - } taddr; + union uv__sockaddr taddr; socklen_t addrlen; if (handle->io_watcher.fd != -1) @@ -653,7 +851,11 @@ } -#if !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__OpenBSD__) && \ + !defined(__NetBSD__) && \ + !defined(__ANDROID__) && \ + !defined(__DragonFly__) & \ + !defined(__QNX__) static int uv__udp_set_source_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, const char* interface_addr, @@ -724,8 +926,10 @@ mreq.gsr_interface = 0; } - memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group)); - memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source)); + STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr)); + STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr)); + memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr)); + memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr)); if (membership == UV_JOIN_GROUP) optname = MCAST_JOIN_SOURCE_GROUP; @@ -747,26 +951,17 @@ #endif -int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { - int domain; - int err; +int uv__udp_init_ex(uv_loop_t* loop, + uv_udp_t* handle, + unsigned flags, + int domain) { int fd; - /* Use the lower 8 bits for the domain */ - domain = flags & 0xFF; - if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return UV_EINVAL; - - if (flags & ~0xFF) - return UV_EINVAL; - + fd = -1; if (domain != AF_UNSPEC) { - err = uv__socket(domain, SOCK_DGRAM, 0); - if (err < 0) - return err; - fd = err; - } else { - fd = -1; + fd = uv__socket(domain, SOCK_DGRAM, 0); + if (fd < 0) + return fd; } uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); @@ -782,8 +977,14 @@ } -int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { - return uv_udp_init_ex(loop, handle, AF_UNSPEC); +int uv_udp_using_recvmmsg(const uv_udp_t* handle) { +#if HAVE_MMSG + if (handle->flags & UV_HANDLE_UDP_RECVMMSG) { + uv_once(&once, uv__udp_mmsg_init); + return uv__recvmmsg_avail; + } +#endif + return 0; } @@ -842,42 +1043,37 @@ const char* interface_addr, const char* source_addr, uv_membership membership) { -#if !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__OpenBSD__) && \ + !defined(__NetBSD__) && \ + !defined(__ANDROID__) && \ + !defined(__DragonFly__) && \ + !defined(__QNX__) int err; - struct sockaddr_storage mcast_addr; - struct sockaddr_in* mcast_addr4; - struct sockaddr_in6* mcast_addr6; - struct sockaddr_storage src_addr; - struct sockaddr_in* src_addr4; - struct sockaddr_in6* src_addr6; - - mcast_addr4 = (struct sockaddr_in*)&mcast_addr; - mcast_addr6 = (struct sockaddr_in6*)&mcast_addr; - src_addr4 = (struct sockaddr_in*)&src_addr; - src_addr6 = (struct sockaddr_in6*)&src_addr; + union uv__sockaddr mcast_addr; + union uv__sockaddr src_addr; - err = uv_ip4_addr(multicast_addr, 0, mcast_addr4); + err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in); if (err) { - err = uv_ip6_addr(multicast_addr, 0, mcast_addr6); + err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6); if (err) return err; - err = uv_ip6_addr(source_addr, 0, src_addr6); + err = uv_ip6_addr(source_addr, 0, &src_addr.in6); if (err) return err; return uv__udp_set_source_membership6(handle, - mcast_addr6, + &mcast_addr.in6, interface_addr, - src_addr6, + &src_addr.in6, membership); } - - err = uv_ip4_addr(source_addr, 0, src_addr4); + + err = uv_ip4_addr(source_addr, 0, &src_addr.in); if (err) return err; return uv__udp_set_source_membership4(handle, - mcast_addr4, + &mcast_addr.in, interface_addr, - src_addr4, + &src_addr.in, membership); #else return UV_ENOSYS; @@ -889,7 +1085,7 @@ int option4, int option6, const void* val, - size_t size) { + socklen_t size) { int r; if (handle->flags & UV_HANDLE_IPV6) @@ -958,7 +1154,7 @@ * and use the general uv__setsockopt_maybe_char call on other platforms. */ #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ - defined(__MVS__) + defined(__MVS__) || defined(__QNX__) return uv__setsockopt(handle, IP_TTL, @@ -967,7 +1163,7 @@ sizeof(ttl)); #else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || - defined(__MVS__)) */ + defined(__MVS__) || defined(__QNX__)) */ return uv__setsockopt_maybe_char(handle, IP_TTL, @@ -975,7 +1171,7 @@ ttl); #endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || - defined(__MVS__) */ + defined(__MVS__) || defined(__QNX__) */ } @@ -987,7 +1183,7 @@ * and use the general uv__setsockopt_maybe_char call otherwise. */ #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ - defined(__MVS__) + defined(__MVS__) || defined(__QNX__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, @@ -995,7 +1191,7 @@ &ttl, sizeof(ttl)); #endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ - defined(__MVS__) */ + defined(__MVS__) || defined(__QNX__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -1012,7 +1208,7 @@ * and use the general uv__setsockopt_maybe_char call otherwise. */ #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ - defined(__MVS__) + defined(__MVS__) || defined(__QNX__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, @@ -1020,7 +1216,7 @@ &on, sizeof(on)); #endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) || - defined(__MVS__) */ + defined(__MVS__) || defined(__QNX__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, diff -Nru libuv1-1.34.2/src/uv-common.c libuv1-1.40.0/src/uv-common.c --- libuv1-1.34.2/src/uv-common.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/uv-common.c 2020-09-25 00:34:43.000000000 +0000 @@ -100,6 +100,17 @@ return NULL; } +void* uv__reallocf(void* ptr, size_t size) { + void* newptr; + + newptr = uv__realloc(ptr, size); + if (newptr == NULL) + if (size > 0) + uv__free(ptr); + + return newptr; +} + int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, @@ -282,6 +293,36 @@ } +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) { + unsigned extra_flags; + int domain; + int rc; + + /* Use the lower 8 bits for the domain. */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return UV_EINVAL; + + /* Use the higher bits for extra flags. */ + extra_flags = flags & ~0xFF; + if (extra_flags & ~UV_UDP_RECVMMSG) + return UV_EINVAL; + + rc = uv__udp_init_ex(loop, handle, flags, domain); + + if (rc == 0) + if (extra_flags & UV_UDP_RECVMMSG) + handle->flags |= UV_HANDLE_UDP_RECVMMSG; + + return rc; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags) { @@ -810,3 +851,78 @@ uv__free(cpu_infos); } + + +#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */ +__attribute__((destructor)) +#endif +void uv_library_shutdown(void) { + static int was_shutdown; + + if (uv__load_relaxed(&was_shutdown)) + return; + + uv__process_title_cleanup(); + uv__signal_cleanup(); + uv__threadpool_cleanup(); + uv__store_relaxed(&was_shutdown, 1); +} + + +void uv__metrics_update_idle_time(uv_loop_t* loop) { + uv__loop_metrics_t* loop_metrics; + uint64_t entry_time; + uint64_t exit_time; + + if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME)) + return; + + loop_metrics = uv__get_loop_metrics(loop); + + /* The thread running uv__metrics_update_idle_time() is always the same + * thread that sets provider_entry_time. So it's unnecessary to lock before + * retrieving this value. + */ + if (loop_metrics->provider_entry_time == 0) + return; + + exit_time = uv_hrtime(); + + uv_mutex_lock(&loop_metrics->lock); + entry_time = loop_metrics->provider_entry_time; + loop_metrics->provider_entry_time = 0; + loop_metrics->provider_idle_time += exit_time - entry_time; + uv_mutex_unlock(&loop_metrics->lock); +} + + +void uv__metrics_set_provider_entry_time(uv_loop_t* loop) { + uv__loop_metrics_t* loop_metrics; + uint64_t now; + + if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME)) + return; + + now = uv_hrtime(); + loop_metrics = uv__get_loop_metrics(loop); + uv_mutex_lock(&loop_metrics->lock); + loop_metrics->provider_entry_time = now; + uv_mutex_unlock(&loop_metrics->lock); +} + + +uint64_t uv_metrics_idle_time(uv_loop_t* loop) { + uv__loop_metrics_t* loop_metrics; + uint64_t entry_time; + uint64_t idle_time; + + loop_metrics = uv__get_loop_metrics(loop); + uv_mutex_lock(&loop_metrics->lock); + idle_time = loop_metrics->provider_idle_time; + entry_time = loop_metrics->provider_entry_time; + uv_mutex_unlock(&loop_metrics->lock); + + if (entry_time > 0) + idle_time += uv_hrtime() - entry_time; + return idle_time; +} diff -Nru libuv1-1.34.2/src/uv-common.h libuv1-1.40.0/src/uv-common.h --- libuv1-1.34.2/src/uv-common.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/uv-common.h 2020-09-25 00:34:43.000000000 +0000 @@ -60,6 +60,14 @@ #define STATIC_ASSERT(expr) \ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) +#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7) +#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED) +#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED) +#else +#define uv__load_relaxed(p) (*p) +#define uv__store_relaxed(p, v) do *p = v; while (0) +#endif + /* Handle flags. Some flags are specific to Windows or UNIX. */ enum { /* Used by all handles. */ @@ -104,6 +112,7 @@ /* Only used by uv_udp_t handles. */ UV_HANDLE_UDP_PROCESSING = 0x01000000, UV_HANDLE_UDP_CONNECTED = 0x02000000, + UV_HANDLE_UDP_RECVMMSG = 0x04000000, /* Only used by uv_pipe_t handles. */ UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000, @@ -138,6 +147,11 @@ unsigned int addrlen, uv_connect_cb cb); +int uv__udp_init_ex(uv_loop_t* loop, + uv_udp_t* handle, + unsigned flags, + int domain); + int uv__udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen, @@ -200,6 +214,10 @@ void uv__run_timers(uv_loop_t* loop); void uv__timer_close(uv_timer_t* handle); +void uv__process_title_cleanup(void); +void uv__signal_cleanup(void); +void uv__threadpool_cleanup(void); + #define uv__has_active_reqs(loop) \ ((loop)->active_reqs.count > 0) @@ -315,6 +333,12 @@ } \ while (0) +#define uv__get_internal_fields(loop) \ + ((uv__loop_internal_fields_t*) loop->internal_fields) + +#define uv__get_loop_metrics(loop) \ + (&uv__get_internal_fields(loop)->loop_metrics) + /* Allocator prototypes */ void *uv__calloc(size_t count, size_t size); char *uv__strdup(const char* s); @@ -322,5 +346,23 @@ void* uv__malloc(size_t size); void uv__free(void* ptr); void* uv__realloc(void* ptr, size_t size); +void* uv__reallocf(void* ptr, size_t size); + +typedef struct uv__loop_metrics_s uv__loop_metrics_t; +typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t; + +struct uv__loop_metrics_s { + uint64_t provider_entry_time; + uint64_t provider_idle_time; + uv_mutex_t lock; +}; + +void uv__metrics_update_idle_time(uv_loop_t* loop); +void uv__metrics_set_provider_entry_time(uv_loop_t* loop); + +struct uv__loop_internal_fields_s { + unsigned int flags; + uv__loop_metrics_t loop_metrics; +}; #endif /* UV_COMMON_H_ */ diff -Nru libuv1-1.34.2/src/uv-data-getter-setters.c libuv1-1.40.0/src/uv-data-getter-setters.c --- libuv1-1.34.2/src/uv-data-getter-setters.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/uv-data-getter-setters.c 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "uv.h" const char* uv_handle_type_name(uv_handle_type type) { diff -Nru libuv1-1.34.2/src/win/core.c libuv1-1.40.0/src/win/core.c --- libuv1-1.34.2/src/win/core.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/core.c 2020-09-25 00:34:43.000000000 +0000 @@ -222,6 +222,7 @@ int uv_loop_init(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; struct heap* timer_heap; int err; @@ -233,6 +234,15 @@ if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); + lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + if (lfields == NULL) + return UV_ENOMEM; + loop->internal_fields = lfields; + + err = uv_mutex_init(&lfields->loop_metrics.lock); + if (err) + goto fail_metrics_mutex_init; + /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. */ @@ -297,6 +307,11 @@ loop->timer_heap = NULL; fail_timers_alloc: + uv_mutex_destroy(&lfields->loop_metrics.lock); + +fail_metrics_mutex_init: + uv__free(lfields); + loop->internal_fields = NULL; CloseHandle(loop->iocp); loop->iocp = INVALID_HANDLE_VALUE; @@ -317,6 +332,7 @@ void uv__loop_close(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; size_t i; uv__loops_remove(loop); @@ -347,11 +363,24 @@ uv__free(loop->timer_heap); loop->timer_heap = NULL; + lfields = uv__get_internal_fields(loop); + uv_mutex_destroy(&lfields->loop_metrics.lock); + uv__free(lfields); + loop->internal_fields = NULL; + CloseHandle(loop->iocp); } int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + uv__loop_internal_fields_t* lfields; + + lfields = uv__get_internal_fields(loop); + if (option == UV_METRICS_IDLE_TIME) { + lfields->flags |= UV_METRICS_IDLE_TIME; + return 0; + } + return UV_ENOSYS; } @@ -393,16 +422,44 @@ uv_req_t* req; int repeat; uint64_t timeout_time; + uint64_t user_timeout; + int reset_timeout; timeout_time = loop->time + timeout; + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + for (repeat = 0; ; repeat++) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + GetQueuedCompletionStatus(loop->iocp, &bytes, &key, &overlapped, timeout); + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + /* Placed here because on success the loop will break whether there is an + * empty package or not, or if GetQueuedCompletionStatus returned early then + * the timeout will be updated and the loop will run again. In either case + * the idle time will need to be updated. + */ + uv__metrics_update_idle_time(loop); + if (overlapped) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); @@ -445,16 +502,44 @@ ULONG i; int repeat; uint64_t timeout_time; + uint64_t user_timeout; + int reset_timeout; timeout_time = loop->time + timeout; + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + for (repeat = 0; ; repeat++) { - success = GetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + /* Placed here because on success the loop will break whether there is an + * empty package or not, or if GetQueuedCompletionStatus returned early then + * the timeout will be updated and the loop will run again. In either case + * the idle time will need to be updated. + */ + uv__metrics_update_idle_time(loop); if (success) { for (i = 0; i < count; i++) { @@ -534,6 +619,12 @@ else uv__poll_wine(loop, timeout); + /* Run one final update on the provider_idle_time in case uv__poll* + * returned because the timeout expired, but no events were received. This + * call will be ignored if the provider_entry_time was either never set (if + * the timeout == 0) or was already updated b/c an event was received. + */ + uv__metrics_update_idle_time(loop); uv_check_invoke(loop); uv_process_endgames(loop); diff -Nru libuv1-1.34.2/src/win/detect-wakeup.c libuv1-1.40.0/src/win/detect-wakeup.c --- libuv1-1.34.2/src/win/detect-wakeup.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/detect-wakeup.c 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "uv.h" #include "internal.h" #include "winapi.h" diff -Nru libuv1-1.34.2/src/win/error.c libuv1-1.40.0/src/win/error.c --- libuv1-1.34.2/src/win/error.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/error.c 2020-09-25 00:34:43.000000000 +0000 @@ -72,6 +72,7 @@ case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; case ERROR_ELEVATION_REQUIRED: return UV_EACCES; + case ERROR_CANT_ACCESS_FILE: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff -Nru libuv1-1.34.2/src/win/fs.c libuv1-1.40.0/src/win/fs.c --- libuv1-1.34.2/src/win/fs.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/fs.c 2020-09-25 00:34:43.000000000 +0000 @@ -70,10 +70,7 @@ #define SET_REQ_RESULT(req, result_value) \ do { \ req->result = (result_value); \ - if (req->result == -1) { \ - req->sys_errno_ = _doserrno; \ - req->result = uv_translate_sys_error(req->sys_errno_); \ - } \ + assert(req->result != -1); \ } while (0) #define SET_REQ_WIN32_ERROR(req, sys_errno) \ @@ -257,6 +254,7 @@ req->loop = loop; req->flags = 0; req->fs_type = fs_type; + req->sys_errno_ = 0; req->result = 0; req->ptr = NULL; req->path = NULL; @@ -321,6 +319,8 @@ WCHAR* w_target; DWORD w_target_len; DWORD bytes; + size_t i; + size_t len; if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, @@ -405,6 +405,38 @@ w_target += 4; w_target_len -= 4; + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) { + /* String #3 in the list has the target filename. */ + if (reparse_data->AppExecLinkReparseBuffer.StringCount < 3) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + w_target = reparse_data->AppExecLinkReparseBuffer.StringList; + /* The StringList buffer contains a list of strings separated by "\0", */ + /* with "\0\0" terminating the list. Move to the 3rd string in the list: */ + for (i = 0; i < 2; ++i) { + len = wcslen(w_target); + if (len == 0) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + w_target += len + 1; + } + w_target_len = wcslen(w_target); + if (w_target_len == 0) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + /* Make sure it is an absolute path. */ + if (!(w_target_len >= 3 && + ((w_target[0] >= L'a' && w_target[0] <= L'z') || + (w_target[0] >= L'A' && w_target[0] <= L'Z')) && + w_target[1] == L':' && + w_target[2] == L'\\')) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + } else { /* Reparse tag does not indicate a symlink. */ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); @@ -695,14 +727,14 @@ assert(errno == EBADF); SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); } else { - req->result = 0; + SET_REQ_RESULT(req, 0); } } LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep, int* perror) { - if (excode != EXCEPTION_IN_PAGE_ERROR) { + if (excode != (LONG)EXCEPTION_IN_PAGE_ERROR) { return EXCEPTION_CONTINUE_SEARCH; } @@ -781,10 +813,10 @@ for (index = 0; index < req->fs.info.nbufs && done_read < read_size; ++index) { - int err = 0; size_t this_read_size = MIN(req->fs.info.bufs[index].len, read_size - done_read); #ifdef _MSC_VER + int err = 0; __try { #endif memcpy(req->fs.info.bufs[index].base, @@ -903,7 +935,7 @@ (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR); size_t write_size, done_write; unsigned int index; - LARGE_INTEGER zero, pos, end_pos; + LARGE_INTEGER pos, end_pos; size_t view_offset; LARGE_INTEGER view_base; void* view; @@ -928,7 +960,6 @@ return; } - zero.QuadPart = 0; if (force_append) { pos = fd_info->size; } else if (req->fs.info.offset == -1) { @@ -979,8 +1010,8 @@ done_write = 0; for (index = 0; index < req->fs.info.nbufs; ++index) { - int err = 0; #ifdef _MSC_VER + int err = 0; __try { #endif memcpy((char*)view + view_offset + done_write, @@ -1093,7 +1124,10 @@ void fs__rmdir(uv_fs_t* req) { int result = _wrmdir(req->file.pathw); - SET_REQ_RESULT(req, result); + if (result == -1) + SET_REQ_WIN32_ERROR(req, _doserrno); + else + SET_REQ_RESULT(req, 0); } @@ -1186,12 +1220,12 @@ void fs__mkdir(uv_fs_t* req) { /* TODO: use req->mode. */ - req->result = _wmkdir(req->file.pathw); - if (req->result == -1) { - req->sys_errno_ = _doserrno; - req->result = req->sys_errno_ == ERROR_INVALID_NAME - ? UV_EINVAL - : uv_translate_sys_error(req->sys_errno_); + if (CreateDirectoryW(req->file.pathw, NULL)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + if (req->sys_errno_ == ERROR_INVALID_NAME) + req->result = UV_EINVAL; } } @@ -1207,19 +1241,21 @@ unsigned int tries, i; size_t len; uint64_t v; - + char* path; + + path = req->path; len = wcslen(req->file.pathw); ep = req->file.pathw + len; if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); - return; + goto clobber; } tries = TMP_MAX; do { if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) { SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE); - break; + goto clobber; } cp = ep - num_x; @@ -1230,25 +1266,29 @@ if (func(req)) { if (req->result >= 0) { - len = strlen(req->path); - wcstombs((char*) req->path + len - num_x, ep - num_x, num_x); + len = strlen(path); + wcstombs(path + len - num_x, ep - num_x, num_x); } - break; + return; } } while (--tries); - if (tries == 0) { - SET_REQ_RESULT(req, -1); - } + SET_REQ_WIN32_ERROR(req, GetLastError()); + +clobber: + path[0] = '\0'; } static int fs__mkdtemp_func(uv_fs_t* req) { - if (_wmkdir(req->file.pathw) == 0) { + DWORD error; + if (CreateDirectoryW(req->file.pathw, NULL)) { SET_REQ_RESULT(req, 0); return 1; - } else if (errno != EEXIST) { - SET_REQ_RESULT(req, -1); + } + error = GetLastError(); + if (error != ERROR_ALREADY_EXISTS) { + SET_REQ_WIN32_ERROR(req, error); return 1; } @@ -1369,7 +1409,7 @@ /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER. * This should be reported back as UV_ENOTDIR. */ - if (status == STATUS_INVALID_PARAMETER) + if (status == (NTSTATUS)STATUS_INVALID_PARAMETER) goto not_a_directory_error; while (NT_SUCCESS(status)) { @@ -1860,7 +1900,7 @@ } req->ptr = &req->statbuf; - req->result = 0; + SET_REQ_RESULT(req, 0); } @@ -1895,7 +1935,7 @@ } req->ptr = &req->statbuf; - req->result = 0; + SET_REQ_RESULT(req, 0); } @@ -2122,7 +2162,10 @@ static void fs__chmod(uv_fs_t* req) { int result = _wchmod(req->file.pathw, req->fs.info.mode); - SET_REQ_RESULT(req, result); + if (result == -1) + SET_REQ_WIN32_ERROR(req, _doserrno); + else + SET_REQ_RESULT(req, 0); } @@ -2225,32 +2268,66 @@ return 0; } - -static void fs__utime(uv_fs_t* req) { +INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, + double atime, + double mtime, + int do_lutime) { HANDLE handle; + DWORD flags; + DWORD ret; - handle = CreateFileW(req->file.pathw, + flags = FILE_FLAG_BACKUP_SEMANTICS; + if (do_lutime) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } + + handle = CreateFileW(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, + flags, NULL); if (handle == INVALID_HANDLE_VALUE) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + ret = GetLastError(); + } else if (fs__utime_handle(handle, atime, mtime) != 0) { + ret = GetLastError(); + } else { + ret = 0; } - if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - CloseHandle(handle); + CloseHandle(handle); + return ret; +} + +INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) { + DWORD error; + + error = fs__utime_impl_from_path(req->file.pathw, + req->fs.time.atime, + req->fs.time.mtime, + do_lutime); + + if (error != 0) { + if (do_lutime && + (error == ERROR_SYMLINK_NOT_SUPPORTED || + error == ERROR_NOT_A_REPARSE_POINT)) { + /* Opened file is a reparse point but not a symlink. Try again. */ + fs__utime_impl(req, 0); + } else { + /* utime failed. */ + SET_REQ_WIN32_ERROR(req, error); + } + return; } - CloseHandle(handle); + SET_REQ_RESULT(req, 0); +} - req->result = 0; +static void fs__utime(uv_fs_t* req) { + fs__utime_impl(req, /* do_lutime */ 0); } @@ -2271,17 +2348,20 @@ return; } - req->result = 0; + SET_REQ_RESULT(req, 0); +} + +static void fs__lutime(uv_fs_t* req) { + fs__utime_impl(req, /* do_lutime */ 1); } static void fs__link(uv_fs_t* req) { DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL); - if (r == 0) { + if (r == 0) SET_REQ_WIN32_ERROR(req, GetLastError()); - } else { - req->result = 0; - } + else + SET_REQ_RESULT(req, 0); } @@ -2601,17 +2681,17 @@ static void fs__chown(uv_fs_t* req) { - req->result = 0; + SET_REQ_RESULT(req, 0); } static void fs__fchown(uv_fs_t* req) { - req->result = 0; + SET_REQ_RESULT(req, 0); } static void fs__lchown(uv_fs_t* req) { - req->result = 0; + SET_REQ_RESULT(req, 0); } @@ -2621,14 +2701,62 @@ DWORD bytes_per_sector; DWORD free_clusters; DWORD total_clusters; + WCHAR* pathw; - if (0 == GetDiskFreeSpaceW(req->file.pathw, + pathw = req->file.pathw; +retry_get_disk_free_space: + if (0 == GetDiskFreeSpaceW(pathw, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + DWORD err; + WCHAR* fpart; + size_t len; + DWORD ret; + BOOL is_second; + + err = GetLastError(); + is_second = pathw != req->file.pathw; + if (err != ERROR_DIRECTORY || is_second) { + if (is_second) + uv__free(pathw); + + SET_REQ_WIN32_ERROR(req, err); + return; + } + + len = MAX_PATH + 1; + pathw = uv__malloc(len * sizeof(*pathw)); + if (pathw == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + return; + } +retry_get_full_path_name: + ret = GetFullPathNameW(req->file.pathw, + len, + pathw, + &fpart); + if (ret == 0) { + uv__free(pathw); + SET_REQ_WIN32_ERROR(req, err); + return; + } else if (ret > len) { + len = ret; + pathw = uv__reallocf(pathw, len * sizeof(*pathw)); + if (pathw == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + return; + } + goto retry_get_full_path_name; + } + if (fpart != 0) + *fpart = L'\0'; + + goto retry_get_disk_free_space; + } + if (pathw != req->file.pathw) { + uv__free(pathw); } stat_fs = uv__malloc(sizeof(*stat_fs)); @@ -2670,6 +2798,7 @@ XX(FTRUNCATE, ftruncate) XX(UTIME, utime) XX(FUTIME, futime) + XX(LUTIME, lutime) XX(ACCESS, access) XX(CHMOD, chmod) XX(FCHMOD, fchmod) @@ -2707,7 +2836,7 @@ if (status == UV_ECANCELED) { assert(req->result == 0); - req->result = UV_ECANCELED; + SET_REQ_UV_ERROR(req, UV_ECANCELED, 0); } req->cb(req); @@ -2753,7 +2882,8 @@ INIT(UV_FS_OPEN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.info.file_flags = flags; @@ -2778,8 +2908,10 @@ uv_fs_cb cb) { INIT(UV_FS_READ); - if (bufs == NULL || nbufs == 0) + if (bufs == NULL || nbufs == 0) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; + } req->file.fd = fd; @@ -2788,8 +2920,10 @@ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->fs.info.bufs == NULL) + if (req->fs.info.bufs == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); return UV_ENOMEM; + } memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); @@ -2807,8 +2941,10 @@ uv_fs_cb cb) { INIT(UV_FS_WRITE); - if (bufs == NULL || nbufs == 0) + if (bufs == NULL || nbufs == 0) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; + } req->file.fd = fd; @@ -2817,8 +2953,10 @@ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->fs.info.bufs == NULL) + if (req->fs.info.bufs == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); return UV_ENOMEM; + } memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); @@ -2834,7 +2972,8 @@ INIT(UV_FS_UNLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -2848,7 +2987,8 @@ INIT(UV_FS_MKDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.info.mode = mode; @@ -2864,8 +3004,10 @@ INIT(UV_FS_MKDTEMP); err = fs__capture_path(req, tpl, NULL, TRUE); - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } POST; } @@ -2879,8 +3021,10 @@ INIT(UV_FS_MKSTEMP); err = fs__capture_path(req, tpl, NULL, TRUE); - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } POST; } @@ -2892,7 +3036,8 @@ INIT(UV_FS_RMDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -2906,7 +3051,8 @@ INIT(UV_FS_SCANDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.info.file_flags = flags; @@ -2921,8 +3067,10 @@ INIT(UV_FS_OPENDIR); err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } POST; } @@ -2935,6 +3083,7 @@ if (dir == NULL || dir->dirents == NULL || dir->dir_handle == INVALID_HANDLE_VALUE) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; } @@ -2947,8 +3096,10 @@ uv_dir_t* dir, uv_fs_cb cb) { INIT(UV_FS_CLOSEDIR); - if (dir == NULL) + if (dir == NULL) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; + } req->ptr = dir; POST; } @@ -2960,7 +3111,8 @@ INIT(UV_FS_LINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -2974,7 +3126,8 @@ INIT(UV_FS_SYMLINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.info.file_flags = flags; @@ -2989,7 +3142,8 @@ INIT(UV_FS_READLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3003,12 +3157,14 @@ INIT(UV_FS_REALPATH); if (!path) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; } err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3022,7 +3178,8 @@ INIT(UV_FS_CHOWN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3043,8 +3200,10 @@ INIT(UV_FS_LCHOWN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } + POST; } @@ -3055,7 +3214,8 @@ INIT(UV_FS_STAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3068,7 +3228,8 @@ INIT(UV_FS_LSTAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3089,7 +3250,8 @@ INIT(UV_FS_RENAME); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } POST; @@ -3132,13 +3294,15 @@ if (flags & ~(UV_FS_COPYFILE_EXCL | UV_FS_COPYFILE_FICLONE | UV_FS_COPYFILE_FICLONE_FORCE)) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return UV_EINVAL; } err = fs__capture_path(req, path, new_path, cb != NULL); - - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } req->fs.info.file_flags = flags; POST; @@ -3165,8 +3329,10 @@ INIT(UV_FS_ACCESS); err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } req->fs.info.mode = flags; POST; @@ -3180,7 +3346,8 @@ INIT(UV_FS_CHMOD); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.info.mode = mode; @@ -3204,7 +3371,8 @@ INIT(UV_FS_UTIME); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { - return uv_translate_sys_error(err); + SET_REQ_WIN32_ERROR(req, err); + return req->result; } req->fs.time.atime = atime; @@ -3222,6 +3390,22 @@ POST; } +int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, + double mtime, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LUTIME); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } + + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + POST; +} + int uv_fs_statfs(uv_loop_t* loop, uv_fs_t* req, @@ -3231,8 +3415,14 @@ INIT(UV_FS_STATFS); err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) - return uv_translate_sys_error(err); + if (err) { + SET_REQ_WIN32_ERROR(req, err); + return req->result; + } POST; } + +int uv_fs_get_system_error(const uv_fs_t* req) { + return req->sys_errno_; +} diff -Nru libuv1-1.34.2/src/win/fs-event.c libuv1-1.40.0/src/win/fs-event.c --- libuv1-1.34.2/src/win/fs-event.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/fs-event.c 2020-09-25 00:34:43.000000000 +0000 @@ -83,6 +83,7 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file) { size_t len, i; + DWORD dir_len; if (filename == NULL) { if (dir != NULL) @@ -97,12 +98,16 @@ if (i == 0) { if (dir) { - *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + dir_len = GetCurrentDirectoryW(0, NULL); + if (dir_len == 0) { + return -1; + } + *dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!GetCurrentDirectoryW(MAX_PATH, *dir)) { + if (!GetCurrentDirectoryW(dir_len, *dir)) { uv__free(*dir); *dir = NULL; return -1; @@ -155,9 +160,11 @@ int name_size, is_path_dir, size; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; - WCHAR short_path_buffer[MAX_PATH]; + DWORD short_path_buffer_len; + WCHAR *short_path_buffer; WCHAR* short_path, *long_path; + short_path = NULL; if (uv__is_active(handle)) return UV_EINVAL; @@ -230,13 +237,23 @@ */ /* Convert to short path. */ + short_path_buffer = NULL; + short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0); + if (short_path_buffer_len == 0) { + goto short_path_done; + } + short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR)); + if (short_path_buffer == NULL) { + goto short_path_done; + } if (GetShortPathNameW(pathw, short_path_buffer, - ARRAY_SIZE(short_path_buffer))) { - short_path = short_path_buffer; - } else { - short_path = NULL; + short_path_buffer_len) == 0) { + uv__free(short_path_buffer); + short_path_buffer = NULL; } +short_path_done: + short_path = short_path_buffer; if (uv_split_path(pathw, &dir, &handle->filew) != 0) { last_error = GetLastError(); @@ -346,6 +363,8 @@ if (uv__is_active(handle)) uv__handle_stop(handle); + uv__free(short_path); + return uv_translate_sys_error(last_error); } diff -Nru libuv1-1.34.2/src/win/fs-fd-hash-inl.h libuv1-1.40.0/src/win/fs-fd-hash-inl.h --- libuv1-1.34.2/src/win/fs-fd-hash-inl.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/fs-fd-hash-inl.h 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #ifndef UV_WIN_FS_FD_HASH_INL_H_ #define UV_WIN_FS_FD_HASH_INL_H_ @@ -53,7 +74,8 @@ INLINE static void uv__fd_hash_init(void) { - int i, err; + size_t i; + int err; err = uv_mutex_init(&uv__fd_hash_mutex); if (err) { diff -Nru libuv1-1.34.2/src/win/internal.h libuv1-1.40.0/src/win/internal.h --- libuv1-1.34.2/src/win/internal.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/internal.h 2020-09-25 00:34:43.000000000 +0000 @@ -266,7 +266,7 @@ */ void uv__util_init(void); -uint64_t uv__hrtime(double scale); +uint64_t uv__hrtime(unsigned int scale); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); diff -Nru libuv1-1.34.2/src/win/pipe.c libuv1-1.40.0/src/win/pipe.c --- libuv1-1.34.2/src/win/pipe.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/pipe.c 2020-09-25 00:34:43.000000000 +0000 @@ -244,9 +244,8 @@ return 0; error: - if (pipeHandle != INVALID_HANDLE_VALUE) { + if (pipeHandle != INVALID_HANDLE_VALUE) CloseHandle(pipeHandle); - } return err; } @@ -264,8 +263,9 @@ 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 +312,7 @@ /* 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 +326,38 @@ } +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 +490,7 @@ 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; } @@ -521,7 +553,7 @@ /* Convert name to UTF16. */ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = (WCHAR*)uv__malloc(nameSize); + handle->name = uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } @@ -540,13 +572,10 @@ * 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 +585,6 @@ 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 +597,6 @@ 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); } @@ -605,9 +620,8 @@ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); - if (pipeHandle != INVALID_HANDLE_VALUE) { + if (pipeHandle != INVALID_HANDLE_VALUE) break; - } SwitchToThread(); } @@ -639,7 +653,7 @@ /* Convert name to UTF16. */ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = (WCHAR*)uv__malloc(nameSize); + handle->name = uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } @@ -827,29 +841,11 @@ 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 +900,7 @@ 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 +921,7 @@ 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 +952,10 @@ 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 +1132,7 @@ } 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 +1150,9 @@ } 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 +1186,16 @@ /* 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 +1330,16 @@ 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 +1388,6 @@ 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 +1396,8 @@ 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 +1408,16 @@ /* 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 +1444,8 @@ } 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(); } @@ -2138,7 +2145,7 @@ if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); - assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1); + assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1); } return 0; } diff -Nru libuv1-1.34.2/src/win/poll.c libuv1-1.40.0/src/win/poll.c --- libuv1-1.34.2/src/win/poll.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/poll.c 2020-09-25 00:34:43.000000000 +0000 @@ -134,32 +134,6 @@ } -static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { - AFD_POLL_INFO afd_poll_info; - int result; - - afd_poll_info.Exclusive = TRUE; - afd_poll_info.NumberOfHandles = 1; - afd_poll_info.Timeout.QuadPart = INT64_MAX; - afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; - afd_poll_info.Handles[0].Status = 0; - afd_poll_info.Handles[0].Events = AFD_POLL_ALL; - - result = uv_msafd_poll(handle->socket, - &afd_poll_info, - uv__get_afd_poll_info_dummy(), - uv__get_overlapped_dummy()); - - if (result == SOCKET_ERROR) { - DWORD error = WSAGetLastError(); - if (error != WSA_IO_PENDING) - return error; - } - - return 0; -} - - static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { unsigned char mask_events; @@ -226,44 +200,6 @@ } -static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { - assert(handle->type == UV_POLL); - assert(!(handle->flags & UV_HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); - - handle->events = events; - - if (handle->events != 0) { - uv__handle_start(handle); - } else { - uv__handle_stop(handle); - } - - if ((handle->events & ~(handle->submitted_events_1 | - handle->submitted_events_2)) != 0) { - uv__fast_poll_submit_poll_req(handle->loop, handle); - } - - return 0; -} - - -static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { - handle->events = 0; - uv__handle_closing(handle); - - if (handle->submitted_events_1 == 0 && - handle->submitted_events_2 == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); - return 0; - } else { - /* Cancel outstanding poll requests by executing another, unique poll - * request that forces the outstanding ones to return. */ - return uv__fast_poll_cancel_poll_req(loop, handle); - } -} - - static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, WSAPROTOCOL_INFOW* protocol_info) { SOCKET sock = 0; @@ -469,41 +405,6 @@ } -static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { - assert(handle->type == UV_POLL); - assert(!(handle->flags & UV_HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); - - handle->events = events; - - if (handle->events != 0) { - uv__handle_start(handle); - } else { - uv__handle_stop(handle); - } - - if ((handle->events & - ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { - uv__slow_poll_submit_poll_req(handle->loop, handle); - } - - return 0; -} - - -static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { - handle->events = 0; - uv__handle_closing(handle); - - if (handle->submitted_events_1 == 0 && - handle->submitted_events_2 == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); - } - - return 0; -} - - int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd)); } @@ -582,35 +483,43 @@ } -int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { - int err; +static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) { + int submitted_events; - if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { - err = uv__fast_poll_set(handle->loop, handle, events); - } else { - err = uv__slow_poll_set(handle->loop, handle, events); - } + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV_HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + + handle->events = events; + handle->poll_cb = cb; - if (err) { - return uv_translate_sys_error(err); + if (handle->events == 0) { + uv__handle_stop(handle); + return 0; } - handle->poll_cb = cb; + uv__handle_start(handle); + submitted_events = handle->submitted_events_1 | handle->submitted_events_2; + + if (handle->events & ~submitted_events) { + if (handle->flags & UV_HANDLE_POLL_SLOW) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } else { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + } return 0; } -int uv_poll_stop(uv_poll_t* handle) { - int err; +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + return uv__poll_set(handle, events, cb); +} - if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { - err = uv__fast_poll_set(handle->loop, handle, 0); - } else { - err = uv__slow_poll_set(handle->loop, handle, 0); - } - return uv_translate_sys_error(err); +int uv_poll_stop(uv_poll_t* handle) { + return uv__poll_set(handle, 0, handle->poll_cb); } @@ -624,11 +533,43 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { - if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { - return uv__fast_poll_close(loop, handle); - } else { - return uv__slow_poll_close(loop, handle); + AFD_POLL_INFO afd_poll_info; + DWORD error; + int result; + + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return 0; + } + + if (handle->flags & UV_HANDLE_POLL_SLOW) + return 0; + + /* Cancel outstanding poll requests by executing another, unique poll + * request that forces the outstanding ones to return. */ + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + uv__get_afd_poll_info_dummy(), + uv__get_overlapped_dummy()); + + if (result == SOCKET_ERROR) { + error = WSAGetLastError(); + if (error != WSA_IO_PENDING) + return uv_translate_sys_error(error); } + + return 0; } diff -Nru libuv1-1.34.2/src/win/process.c libuv1-1.40.0/src/win/process.c --- libuv1-1.34.2/src/win/process.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/process.c 2020-09-25 00:34:43.000000000 +0000 @@ -58,7 +58,6 @@ E_V("USERPROFILE"), E_V("WINDIR"), }; -static size_t n_required_vars = ARRAY_SIZE(required_vars); static HANDLE uv_global_job_handle_; @@ -692,7 +691,7 @@ WCHAR* dst_copy; WCHAR** ptr_copy; WCHAR** env_copy; - DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*)); + DWORD required_vars_value_len[ARRAY_SIZE(required_vars)]; /* first pass: determine size in UTF-16 */ for (env = env_block; *env; env++) { @@ -745,7 +744,7 @@ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp); /* third pass: check for required variables */ - for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) { + for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) { int cmp; if (!*ptr_copy) { cmp = -1; @@ -778,10 +777,10 @@ } for (ptr = dst, ptr_copy = env_copy, i = 0; - *ptr_copy || i < n_required_vars; + *ptr_copy || i < ARRAY_SIZE(required_vars); ptr += len) { int cmp; - if (i >= n_required_vars) { + if (i >= ARRAY_SIZE(required_vars)) { cmp = 1; } else if (!*ptr_copy) { cmp = -1; diff -Nru libuv1-1.34.2/src/win/signal.c libuv1-1.40.0/src/win/signal.c --- libuv1-1.34.2/src/win/signal.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/signal.c 2020-09-25 00:34:43.000000000 +0000 @@ -46,6 +46,11 @@ } +void uv__signal_cleanup(void) { + /* TODO(bnoordhuis) Undo effects of uv_signal_init()? */ +} + + static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { /* Compare signums first so all watchers with the same signnum end up * adjacent. */ diff -Nru libuv1-1.34.2/src/win/tcp.c libuv1-1.40.0/src/win/tcp.c --- libuv1-1.34.2/src/win/tcp.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/tcp.c 2020-09-25 00:34:43.000000000 +0000 @@ -251,7 +251,7 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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); } @@ -522,16 +523,15 @@ &req->u.io.overlapped, NULL); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; req->u.io.overlapped.InternalHigh = bytes; - handle->reqs_pending++; uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, @@ -544,7 +544,6 @@ /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); - handle->reqs_pending++; } } @@ -612,8 +611,8 @@ 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 +627,7 @@ 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 +736,9 @@ * 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"); } } @@ -749,6 +748,40 @@ return 0; } +static int uv__is_loopback(const struct sockaddr_storage* storage) { + const struct sockaddr_in* in4; + const struct sockaddr_in6* in6; + int i; + + if (storage->ss_family == AF_INET) { + in4 = (const struct sockaddr_in*) storage; + return in4->sin_addr.S_un.S_un_b.s_b1 == 127; + } + if (storage->ss_family == AF_INET6) { + in6 = (const struct sockaddr_in6*) storage; + for (i = 0; i < 7; ++i) { + if (in6->sin6_addr.u.Word[i] != 0) + return 0; + } + return in6->sin6_addr.u.Word[7] == htons(1); + } + return 0; +} + +// Check if Windows version is 10.0.16299 or later +static int uv__is_fast_loopback_fail_supported() { + OSVERSIONINFOW os_info; + if (!pRtlGetVersion) + return 0; + pRtlGetVersion(&os_info); + if (os_info.dwMajorVersion < 10) + return 0; + if (os_info.dwMajorVersion > 10) + return 1; + if (os_info.dwMinorVersion > 0) + return 1; + return os_info.dwBuildNumber >= 16299; +} static int uv_tcp_try_connect(uv_connect_t* req, uv_tcp_t* handle, @@ -756,6 +789,7 @@ unsigned int addrlen, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; + TCP_INITIAL_RTO_PARAMETERS retransmit_ioctl; const struct sockaddr* bind_addr; struct sockaddr_storage converted; BOOL success; @@ -791,6 +825,25 @@ } } + /* This makes connect() fail instantly if the target port on the localhost + * is not reachable, instead of waiting for 2s. We do not care if this fails. + * This only works on Windows version 10.0.16299 and later. + */ + if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) { + memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl)); + retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; + retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; + WSAIoctl(handle->socket, + SIO_TCP_INITIAL_RTO, + &retransmit_ioctl, + sizeof(retransmit_ioctl), + NULL, + 0, + &bytes, + NULL, + NULL); + } + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; @@ -862,7 +915,7 @@ 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 +1133,7 @@ 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 -Nru libuv1-1.34.2/src/win/tty.c libuv1-1.40.0/src/win/tty.c --- libuv1-1.34.2/src/win/tty.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/tty.c 2020-09-25 00:34:43.000000000 +0000 @@ -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_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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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; } @@ -497,6 +517,7 @@ status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); if (status == TRAP_REQUESTED) { SET_REQ_SUCCESS(req); + InterlockedExchange(&uv__read_console_status, COMPLETED); req->u.io.overlapped.InternalHigh = 0; POST_COMPLETION_FOR_REQ(loop, req); return 0; @@ -1230,7 +1251,7 @@ 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 +1272,12 @@ /* 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 +1300,13 @@ /* 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 +1645,31 @@ 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 +1697,7 @@ 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 +1813,7 @@ 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 +1831,193 @@ } } + } 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 if (utf8_codepoint == ';') { - /* Denotes the end of an argument. */ - if (ansi_parser_state & ANSI_IN_ARG) { - ansi_parser_state &= ~ANSI_IN_ARG; + } 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; + } - } 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; + } + + } else if (utf8_codepoint == ';') { + /* Denotes the end of an argument. */ + if (ansi_parser_state & ANSI_IN_ARG) { + ansi_parser_state &= ~ANSI_IN_ARG; + 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 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; - /* Command byte */ + } 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; + } + + } 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 +2026,11 @@ 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 +2038,8 @@ 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 +2048,8 @@ 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 +2072,17 @@ 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; } @@ -2018,13 +2122,6 @@ abort(); } - /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows - * console doesn't really support UTF-16, so just emit the replacement - * character. */ - if (utf8_codepoint > 0xffff) { - utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; - } - if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) { /* EOL conversion - emit \r\n when we see \n. */ @@ -2051,6 +2148,12 @@ ENSURE_BUFFER_SPACE(1); utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; previous_eol = 0; + } else { + ENSURE_BUFFER_SPACE(2); + utf8_codepoint -= 0x10000; + utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800); + utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00); + previous_eol = 0; } } } @@ -2309,6 +2412,7 @@ uv__tty_console_signal_resize(); ResetEvent(uv__tty_console_resized); } + return 0; } static void uv__tty_console_signal_resize(void) { diff -Nru libuv1-1.34.2/src/win/udp.c libuv1-1.40.0/src/win/udp.c --- libuv1-1.34.2/src/win/udp.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/udp.c 2020-09-25 00:34:43.000000000 +0000 @@ -125,17 +125,10 @@ } -int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { - int domain; - - /* Use the lower 8 bits for the domain */ - domain = flags & 0xFF; - if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return UV_EINVAL; - - if (flags & ~0xFF) - return UV_EINVAL; - +int uv__udp_init_ex(uv_loop_t* loop, + uv_udp_t* handle, + unsigned flags, + int domain) { uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP); handle->socket = INVALID_SOCKET; handle->reqs_pending = 0; @@ -174,11 +167,6 @@ } -int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { - return uv_udp_init_ex(loop, handle, AF_UNSPEC); -} - - void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { uv_udp_recv_stop(handle); closesocket(handle->socket); @@ -201,6 +189,11 @@ } +int uv_udp_using_recvmmsg(const uv_udp_t* handle) { + return 0; +} + + static int uv_udp_maybe_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen, @@ -764,6 +757,9 @@ int optname; int err; + STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr)); + STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr)); + if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) return UV_EINVAL; @@ -786,8 +782,8 @@ mreq.gsr_interface = 0; } - memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group)); - memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source)); + memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr)); + memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr)); if (membership == UV_JOIN_GROUP) optname = MCAST_JOIN_SOURCE_GROUP; @@ -1077,7 +1073,7 @@ err = connect(handle->socket, addr, addrlen); if (err) - return uv_translate_sys_error(err); + return uv_translate_sys_error(WSAGetLastError()); handle->flags |= UV_HANDLE_UDP_CONNECTED; @@ -1093,7 +1089,7 @@ err = connect(handle->socket, &addr, sizeof(addr)); if (err) - return uv_translate_sys_error(err); + return uv_translate_sys_error(WSAGetLastError()); handle->flags &= ~UV_HANDLE_UDP_CONNECTED; return 0; diff -Nru libuv1-1.34.2/src/win/util.c libuv1-1.40.0/src/win/util.c --- libuv1-1.34.2/src/win/util.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/util.c 2020-09-25 00:34:43.000000000 +0000 @@ -30,12 +30,14 @@ #include "uv.h" #include "internal.h" +/* clang-format off */ #include #include #include #include #include #include +/* clang-format on */ #include #include @@ -60,15 +62,15 @@ #endif -/* Maximum environment variable size, including the terminating null */ -#define MAX_ENV_VAR_LENGTH 32767 +/* A RtlGenRandom() by any other name... */ +extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength); /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; static CRITICAL_SECTION process_title_lock; -/* Interval (in seconds) of the high-resolution clock. */ -static double hrtime_interval_ = 0; +/* Frequency of the high-resolution clock. */ +static uint64_t hrtime_frequency_ = 0; /* @@ -84,9 +86,9 @@ * and precompute its reciprocal. */ if (QueryPerformanceFrequency(&perf_frequency)) { - hrtime_interval_ = 1.0 / perf_frequency.QuadPart; + hrtime_frequency_ = perf_frequency.QuadPart; } else { - hrtime_interval_= 0; + uv_fatal_error(GetLastError(), "QueryPerformanceFrequency"); } } @@ -151,20 +153,26 @@ int uv_cwd(char* buffer, size_t* size) { DWORD utf16_len; - WCHAR utf16_buffer[MAX_PATH]; + WCHAR *utf16_buffer; int r; if (buffer == NULL || size == NULL) { return UV_EINVAL; } - utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + utf16_len = GetCurrentDirectoryW(0, NULL); if (utf16_len == 0) { return uv_translate_sys_error(GetLastError()); - } else if (utf16_len > MAX_PATH) { - /* This should be impossible; however the CRT has a code path to deal with - * this scenario, so I added a check anyway. */ - return UV_EIO; + } + utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR)); + if (utf16_buffer == NULL) { + return UV_ENOMEM; + } + + utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer); + if (utf16_len == 0) { + uv__free(utf16_buffer); + return uv_translate_sys_error(GetLastError()); } /* utf16_len contains the length, *not* including the terminating null. */ @@ -188,8 +196,10 @@ NULL, NULL); if (r == 0) { + uv__free(utf16_buffer); return uv_translate_sys_error(GetLastError()); } else if (r > (int) *size) { + uv__free(utf16_buffer); *size = r; return UV_ENOBUFS; } @@ -203,6 +213,8 @@ *size > INT_MAX ? INT_MAX : (int) *size, NULL, NULL); + uv__free(utf16_buffer); + if (r == 0) { return uv_translate_sys_error(GetLastError()); } @@ -213,43 +225,61 @@ int uv_chdir(const char* dir) { - WCHAR utf16_buffer[MAX_PATH]; - size_t utf16_len; + WCHAR *utf16_buffer; + size_t utf16_len, new_utf16_len; WCHAR drive_letter, env_var[4]; if (dir == NULL) { return UV_EINVAL; } + utf16_len = MultiByteToWideChar(CP_UTF8, + 0, + dir, + -1, + NULL, + 0); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } + utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR)); + if (utf16_buffer == NULL) { + return UV_ENOMEM; + } + if (MultiByteToWideChar(CP_UTF8, 0, dir, -1, utf16_buffer, - MAX_PATH) == 0) { - DWORD error = GetLastError(); - /* The maximum length of the current working directory is 260 chars, - * including terminating null. If it doesn't fit, the path name must be too - * long. */ - if (error == ERROR_INSUFFICIENT_BUFFER) { - return UV_ENAMETOOLONG; - } else { - return uv_translate_sys_error(error); - } + utf16_len) == 0) { + uv__free(utf16_buffer); + return uv_translate_sys_error(GetLastError()); } if (!SetCurrentDirectoryW(utf16_buffer)) { + uv__free(utf16_buffer); return uv_translate_sys_error(GetLastError()); } /* Windows stores the drive-local path in an "hidden" environment variable, * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update * this, so we'll have to do it. */ - utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer); + if (new_utf16_len > utf16_len ) { + uv__free(utf16_buffer); + utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR)); + if (utf16_buffer == NULL) { + /* When updating the environment variable fails, return UV_OK anyway. + * We did successfully change current working directory, only updating + * hidden env variable failed. */ + return 0; + } + new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer); + } if (utf16_len == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (utf16_len > MAX_PATH) { - return UV_EIO; + uv__free(utf16_buffer); + return 0; } /* The returned directory should not have a trailing slash, unless it points @@ -281,11 +311,10 @@ env_var[2] = L':'; env_var[3] = L'\0'; - if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { - return uv_translate_sys_error(GetLastError()); - } + SetEnvironmentVariableW(env_var, utf16_buffer); } + uv__free(utf16_buffer); return 0; } @@ -358,6 +387,10 @@ } +void uv__process_title_cleanup(void) { +} + + int uv_set_process_title(const char* title) { int err; int length; @@ -459,23 +492,25 @@ return uv__hrtime(UV__NANOSEC); } -uint64_t uv__hrtime(double scale) { +uint64_t uv__hrtime(unsigned int scale) { LARGE_INTEGER counter; + double scaled_freq; + double result; - /* If the performance interval is zero, there's no support. */ - if (hrtime_interval_ == 0) { - return 0; - } - + assert(hrtime_frequency_ != 0); + assert(scale != 0); if (!QueryPerformanceCounter(&counter)) { - return 0; + uv_fatal_error(GetLastError(), "QueryPerformanceCounter"); } + assert(counter.QuadPart != 0); /* Because we have no guarantee about the order of magnitude of the * performance counter interval, integer math could cause this computation * to overflow. Therefore we resort to floating point math. */ - return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale); + scaled_freq = (double) hrtime_frequency_ / scale; + result = (double) counter.QuadPart / scaled_freq; + return (uint64_t) result; } @@ -1160,20 +1195,29 @@ int uv_os_tmpdir(char* buffer, size_t* size) { - wchar_t path[MAX_PATH + 2]; + wchar_t *path; DWORD bufsize; size_t len; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - len = GetTempPathW(ARRAY_SIZE(path), path); + len = 0; + len = GetTempPathW(0, NULL); + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } + /* Include space for terminating null char. */ + len += 1; + path = uv__malloc(len * sizeof(wchar_t)); + if (path == NULL) { + return UV_ENOMEM; + } + len = GetTempPathW(len, path); if (len == 0) { + uv__free(path); return uv_translate_sys_error(GetLastError()); - } else if (len > ARRAY_SIZE(path)) { - /* This should not be possible */ - return UV_EIO; } /* The returned directory should not have a trailing slash, unless it points @@ -1188,8 +1232,10 @@ bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); if (bufsize == 0) { + uv__free(path); return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { + uv__free(path); *size = bufsize; return UV_ENOBUFS; } @@ -1203,6 +1249,7 @@ *size, NULL, NULL); + uv__free(path); if (bufsize == 0) return uv_translate_sys_error(GetLastError()); @@ -1322,7 +1369,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { HANDLE token; wchar_t username[UNLEN + 1]; - wchar_t path[MAX_PATH]; + wchar_t *path; DWORD bufsize; int r; @@ -1333,15 +1380,24 @@ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) return uv_translate_sys_error(GetLastError()); - bufsize = ARRAY_SIZE(path); - if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + bufsize = 0; + GetUserProfileDirectoryW(token, NULL, &bufsize); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { r = GetLastError(); CloseHandle(token); + return uv_translate_sys_error(r); + } - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_ENOMEM; + path = uv__malloc(bufsize * sizeof(wchar_t)); + if (path == NULL) { + CloseHandle(token); + return UV_ENOMEM; + } + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + uv__free(path); return uv_translate_sys_error(r); } @@ -1351,6 +1407,7 @@ bufsize = ARRAY_SIZE(username); if (!GetUserNameW(username, &bufsize)) { r = GetLastError(); + uv__free(path); /* This should not be possible */ if (r == ERROR_INSUFFICIENT_BUFFER) @@ -1361,6 +1418,7 @@ pwd->homedir = NULL; r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); + uv__free(path); if (r != 0) return r; @@ -1402,7 +1460,7 @@ for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++); *envitems = uv__calloc(i, sizeof(**envitems)); - if (envitems == NULL) { + if (*envitems == NULL) { FreeEnvironmentStringsW(env); return UV_ENOMEM; } @@ -1458,7 +1516,9 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { - wchar_t var[MAX_ENV_VAR_LENGTH]; + wchar_t fastvar[512]; + wchar_t* var; + DWORD varlen; wchar_t* name_w; DWORD bufsize; size_t len; @@ -1472,25 +1532,52 @@ if (r != 0) return r; - SetLastError(ERROR_SUCCESS); - len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); + var = fastvar; + varlen = ARRAY_SIZE(fastvar); + + for (;;) { + SetLastError(ERROR_SUCCESS); + len = GetEnvironmentVariableW(name_w, var, varlen); + + if (len < varlen) + break; + + /* Try repeatedly because we might have been preempted by another thread + * modifying the environment variable just as we're trying to read it. + */ + if (var != fastvar) + uv__free(var); + + varlen = 1 + len; + var = uv__malloc(varlen * sizeof(*var)); + + if (var == NULL) { + r = UV_ENOMEM; + goto fail; + } + } + uv__free(name_w); - assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ + name_w = NULL; if (len == 0) { r = GetLastError(); - if (r != ERROR_SUCCESS) - return uv_translate_sys_error(r); + if (r != ERROR_SUCCESS) { + r = uv_translate_sys_error(r); + goto fail; + } } /* Check how much space we need */ bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); + r = uv_translate_sys_error(GetLastError()); + goto fail; } else if (bufsize > *size) { *size = bufsize; - return UV_ENOBUFS; + r = UV_ENOBUFS; + goto fail; } /* Convert to UTF-8 */ @@ -1503,11 +1590,23 @@ NULL, NULL); - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto fail; + } *size = bufsize - 1; - return 0; + r = 0; + +fail: + + if (name_w != NULL) + uv__free(name_w); + + if (var != fastvar) + uv__free(var); + + return r; } @@ -1709,7 +1808,9 @@ pRtlGetVersion(&os_info); } else { /* Silence GetVersionEx() deprecation warning. */ + #ifdef _MSC_VER #pragma warning(suppress : 4996) + #endif if (GetVersionExW(&os_info) == 0) { r = uv_translate_sys_error(GetLastError()); goto error; @@ -1776,7 +1877,7 @@ "MINGW32_NT-%u.%u", (unsigned int) os_info.dwMajorVersion, (unsigned int) os_info.dwMinorVersion); - assert(r < sizeof(buffer->sysname)); + assert((size_t)r < sizeof(buffer->sysname)); #else uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname)); #endif @@ -1788,7 +1889,7 @@ (unsigned int) os_info.dwMajorVersion, (unsigned int) os_info.dwMinorVersion, (unsigned int) os_info.dwBuildNumber); - assert(r < sizeof(buffer->release)); + assert((size_t)r < sizeof(buffer->release)); /* Populate the machine field. */ GetSystemInfo(&system_info); @@ -1862,13 +1963,10 @@ } int uv__random_rtlgenrandom(void* buf, size_t buflen) { - if (pRtlGenRandom == NULL) - return UV_ENOSYS; - if (buflen == 0) return 0; - if (pRtlGenRandom(buf, buflen) == FALSE) + if (SystemFunction036(buf, buflen) == FALSE) return UV_EIO; return 0; diff -Nru libuv1-1.34.2/src/win/winapi.c libuv1-1.40.0/src/win/winapi.c --- libuv1-1.34.2/src/win/winapi.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/winapi.c 2020-09-25 00:34:43.000000000 +0000 @@ -36,9 +36,6 @@ sNtQuerySystemInformation pNtQuerySystemInformation; sNtQueryInformationProcess pNtQueryInformationProcess; -/* Advapi32 function pointers */ -sRtlGenRandom pRtlGenRandom; - /* Kernel32 function pointers */ sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; @@ -54,7 +51,6 @@ HMODULE powrprof_module; HMODULE user32_module; HMODULE kernel32_module; - HMODULE advapi32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -138,12 +134,4 @@ pSetWinEventHook = (sSetWinEventHook) GetProcAddress(user32_module, "SetWinEventHook"); } - - advapi32_module = GetModuleHandleA("advapi32.dll"); - if (advapi32_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); - } - - pRtlGenRandom = - (sRtlGenRandom) GetProcAddress(advapi32_module, "SystemFunction036"); } diff -Nru libuv1-1.34.2/src/win/winapi.h libuv1-1.40.0/src/win/winapi.h --- libuv1-1.34.2/src/win/winapi.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/src/win/winapi.h 2020-09-25 00:34:43.000000000 +0000 @@ -4152,6 +4152,10 @@ struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; + struct { + ULONG StringCount; + WCHAR StringList[1]; + } AppExecLinkReparseBuffer; }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif @@ -4517,6 +4521,9 @@ #ifndef IO_REPARSE_TAG_SYMLINK # define IO_REPARSE_TAG_SYMLINK (0xA000000CL) #endif +#ifndef IO_REPARSE_TAG_APPEXECLINK +# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL) +#endif typedef VOID (NTAPI *PIO_APC_ROUTINE) (PVOID ApcContext, @@ -4590,11 +4597,6 @@ PULONG ReturnLength); /* - * Advapi32 headers - */ -typedef BOOLEAN (WINAPI *sRtlGenRandom)(PVOID Buffer, ULONG BufferLength); - -/* * Kernel32 headers */ #ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS @@ -4724,6 +4726,18 @@ DWORD idThread, UINT dwflags); +/* From mstcpip.h */ +typedef struct _TCP_INITIAL_RTO_PARAMETERS { + USHORT Rtt; + UCHAR MaxSynRetransmissions; +} TCP_INITIAL_RTO_PARAMETERS, *PTCP_INITIAL_RTO_PARAMETERS; + +#ifndef TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS +# define TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS ((UCHAR) -2) +#endif +#ifndef SIO_TCP_INITIAL_RTO +# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17) +#endif /* Ntdll function pointers */ extern sRtlGetVersion pRtlGetVersion; @@ -4736,9 +4750,6 @@ extern sNtQuerySystemInformation pNtQuerySystemInformation; extern sNtQueryInformationProcess pNtQueryInformationProcess; -/* Advapi32 function pointers */ -extern sRtlGenRandom pRtlGenRandom; - /* Kernel32 function pointers */ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; diff -Nru libuv1-1.34.2/SUPPORTED_PLATFORMS.md libuv1-1.40.0/SUPPORTED_PLATFORMS.md --- libuv1-1.34.2/SUPPORTED_PLATFORMS.md 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/SUPPORTED_PLATFORMS.md 2020-09-25 00:34:43.000000000 +0000 @@ -47,8 +47,9 @@ file inside ``src/unix/`` unless it's already done in a common file, in which case adding an `ifdef` is fine. -Two build systems are supported: autotools and GYP. Ideally both need to be -supported, but if GYP does not support the new platform it can be left out. +Two build systems are supported: autotools and cmake. Ideally both need to be +supported, but if one of the two does not support the new platform it can be +left out. ### Windows diff -Nru libuv1-1.34.2/test/benchmark-list.h libuv1-1.40.0/test/benchmark-list.h --- libuv1-1.34.2/test/benchmark-list.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/benchmark-list.h 2020-09-25 00:34:43.000000000 +0000 @@ -23,6 +23,7 @@ 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 -Nru libuv1-1.34.2/test/benchmark-multi-accept.c libuv1-1.40.0/test/benchmark-multi-accept.c --- libuv1-1.34.2/test/benchmark-multi-accept.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/benchmark-multi-accept.c 2020-09-25 00:34:43.000000000 +0000 @@ -218,8 +218,12 @@ } 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 -Nru libuv1-1.34.2/test/benchmark-ping-udp.c libuv1-1.40.0/test/benchmark-ping-udp.c --- libuv1-1.34.2/test/benchmark-ping-udp.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/benchmark-ping-udp.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 -Nru libuv1-1.34.2/test/echo-server.c libuv1-1.40.0/test/echo-server.c --- libuv1-1.34.2/test/echo-server.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/echo-server.c 2020-09-25 00:34:43.000000000 +0000 @@ -37,6 +37,7 @@ 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 @@ 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 @@ 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 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 @@ 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 -Nru libuv1-1.34.2/test/run-benchmarks.c libuv1-1.40.0/test/run-benchmarks.c --- libuv1-1.34.2/test/run-benchmarks.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/run-benchmarks.c 2020-09-25 00:34:43.000000000 +0000 @@ -33,8 +33,7 @@ int main(int argc, char **argv) { - if (platform_init(argc, argv)) - return EXIT_FAILURE; + platform_init(argc, argv); switch (argc) { case 1: return run_tests(1); diff -Nru libuv1-1.34.2/test/runner.c libuv1-1.40.0/test/runner.c --- libuv1-1.34.2/test/runner.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/runner.c 2020-09-25 00:34:43.000000000 +0000 @@ -20,6 +20,7 @@ */ #include +#include #include #include "runner.h" @@ -167,6 +168,7 @@ 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 @@ 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 -Nru libuv1-1.34.2/test/runner.h libuv1-1.40.0/test/runner.h --- libuv1-1.34.2/test/runner.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/runner.h 2020-09-25 00:34:43.000000000 +0000 @@ -84,11 +84,7 @@ #define TEST_HELPER HELPER_ENTRY #define BENCHMARK_HELPER HELPER_ENTRY -#ifdef PATH_MAX -extern char executable_path[PATH_MAX]; -#else extern char executable_path[4096]; -#endif /* * Include platform-dependent definitions @@ -136,7 +132,7 @@ */ /* Do platform-specific initialization. */ -int platform_init(int argc, char** argv); +void platform_init(int argc, char** argv); /* Invoke "argv[0] test-name [test-part]". Store process info in *p. Make sure * that all stdio output of the processes is buffered up. */ diff -Nru libuv1-1.34.2/test/runner-unix.c libuv1-1.40.0/test/runner-unix.c --- libuv1-1.34.2/test/runner-unix.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/runner-unix.c 2020-09-25 00:34:43.000000000 +0000 @@ -26,7 +26,7 @@ #include /* uintptr_t */ #include -#include /* readlink, usleep */ +#include /* usleep */ #include /* strdup */ #include #include @@ -67,18 +67,12 @@ /* Do platform-specific initialization. */ -int platform_init(int argc, char **argv) { +void platform_init(int argc, char **argv) { /* Disable stdio output buffering. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); signal(SIGPIPE, SIG_IGN); - - if (realpath(argv[0], executable_path) == NULL) { - perror("realpath"); - return -1; - } - - return 0; + snprintf(executable_path, sizeof(executable_path), "%s", argv[0]); } diff -Nru libuv1-1.34.2/test/runner-win.c libuv1-1.40.0/test/runner-win.c --- libuv1-1.34.2/test/runner-win.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/runner-win.c 2020-09-25 00:34:43.000000000 +0000 @@ -43,7 +43,7 @@ /* Do platform-specific initialization. */ -int platform_init(int argc, char **argv) { +void platform_init(int argc, char **argv) { /* Disable the "application crashed" popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -67,8 +67,6 @@ setvbuf(stderr, NULL, _IONBF, 0); strcpy(executable_path, argv[0]); - - return 0; } diff -Nru libuv1-1.34.2/test/run-tests.c libuv1-1.40.0/test/run-tests.c --- libuv1-1.34.2/test/run-tests.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/run-tests.c 2020-09-25 00:34:43.000000000 +0000 @@ -45,6 +45,7 @@ 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); @@ -58,9 +59,7 @@ } #endif - if (platform_init(argc, argv)) - return EXIT_FAILURE; - + platform_init(argc, argv); argv = uv_setup_args(argc, argv); switch (argc) { @@ -210,7 +209,11 @@ 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 +238,11 @@ } #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 -Nru libuv1-1.34.2/test/task.h libuv1-1.40.0/test/task.h --- libuv1-1.34.2/test/task.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/task.h 2020-09-25 00:34:43.000000000 +0000 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #if defined(_MSC_VER) && _MSC_VER < 1600 # include "uv/stdint-msvc2008.h" @@ -109,6 +111,138 @@ } \ } while (0) +#define ASSERT_BASE(a, operator, b, type, conv) \ + do { \ + type eval_a = (type) (a); \ + type eval_b = (type) (b); \ + if (!(eval_a operator eval_b)) { \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: `%s %s %s` " \ + "(%"conv" %s %"conv")\n", \ + __FILE__, \ + __LINE__, \ + #a, \ + #operator, \ + #b, \ + eval_a, \ + #operator, \ + eval_b); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_BASE_STR(expr, a, operator, b, type, conv) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: `%s %s %s` " \ + "(%"conv" %s %"conv")\n", \ + __FILE__, \ + __LINE__, \ + #a, \ + #operator, \ + #b, \ + (type)a, \ + #operator, \ + (type)b); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_BASE_LEN(expr, a, operator, b, conv, len) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: `%s %s %s` " \ + "(%.*"#conv" %s %.*"#conv")\n", \ + __FILE__, \ + __LINE__, \ + #a, \ + #operator, \ + #b, \ + (int)len, \ + a, \ + #operator, \ + (int)len, \ + b); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_BASE_HEX(expr, a, operator, b, size) \ + do { \ + if (!(expr)) { \ + int i; \ + unsigned char* a_ = (unsigned char*)a; \ + unsigned char* b_ = (unsigned char*)b; \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: `%s %s %s` (", \ + __FILE__, \ + __LINE__, \ + #a, \ + #operator, \ + #b); \ + for (i = 0; i < size; ++i) { \ + if (i > 0) fprintf(stderr, ":"); \ + fprintf(stderr, "%02X", a_[i]); \ + } \ + fprintf(stderr, " %s ", #operator); \ + for (i = 0; i < size; ++i) { \ + if (i > 0) fprintf(stderr, ":"); \ + fprintf(stderr, "%02X", b_[i]); \ + } \ + fprintf(stderr, ")\n"); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_INT_BASE(a, operator, b, type, conv) \ + ASSERT_BASE(a, operator, b, type, conv) + +#define ASSERT_EQ(a, b) ASSERT_INT_BASE(a, ==, b, int64_t, PRId64) +#define ASSERT_GE(a, b) ASSERT_INT_BASE(a, >=, b, int64_t, PRId64) +#define ASSERT_GT(a, b) ASSERT_INT_BASE(a, >, b, int64_t, PRId64) +#define ASSERT_LE(a, b) ASSERT_INT_BASE(a, <=, b, int64_t, PRId64) +#define ASSERT_LT(a, b) ASSERT_INT_BASE(a, <, b, int64_t, PRId64) +#define ASSERT_NE(a, b) ASSERT_INT_BASE(a, !=, b, int64_t, PRId64) + +#define ASSERT_UINT64_EQ(a, b) ASSERT_INT_BASE(a, ==, b, uint64_t, PRIu64) +#define ASSERT_UINT64_GE(a, b) ASSERT_INT_BASE(a, >=, b, uint64_t, PRIu64) +#define ASSERT_UINT64_GT(a, b) ASSERT_INT_BASE(a, >, b, uint64_t, PRIu64) +#define ASSERT_UINT64_LE(a, b) ASSERT_INT_BASE(a, <=, b, uint64_t, PRIu64) +#define ASSERT_UINT64_LT(a, b) ASSERT_INT_BASE(a, <, b, uint64_t, PRIu64) +#define ASSERT_UINT64_NE(a, b) ASSERT_INT_BASE(a, !=, b, uint64_t, PRIu64) + +#define ASSERT_STR_EQ(a, b) \ + ASSERT_BASE_STR(strcmp(a, b) == 0, a, == , b, char*, "s") + +#define ASSERT_STR_NE(a, b) \ + ASSERT_BASE_STR(strcmp(a, b) != 0, a, !=, b, char*, "s") + +#define ASSERT_MEM_EQ(a, b, size) \ + ASSERT_BASE_LEN(memcmp(a, b, size) == 0, a, ==, b, s, size) + +#define ASSERT_MEM_NE(a, b, size) \ + ASSERT_BASE_LEN(memcmp(a, b, size) != 0, a, !=, b, s, size) + +#define ASSERT_MEM_HEX_EQ(a, b, size) \ + ASSERT_BASE_HEX(memcmp(a, b, size) == 0, a, ==, b, size) + +#define ASSERT_MEM_HEX_NE(a, b, size) \ + ASSERT_BASE_HEX(memcmp(a, b, size) != 0, a, !=, b, size) + +#define ASSERT_NULL(a) \ + ASSERT_BASE(a, ==, NULL, void*, "p") + +#define ASSERT_NOT_NULL(a) \ + ASSERT_BASE(a, !=, NULL, void*, "p") + +#define ASSERT_PTR_EQ(a, b) \ + ASSERT_BASE(a, ==, b, void*, "p") + +#define ASSERT_PTR_NE(a, b) \ + ASSERT_BASE(a, !=, b, void*, "p") + /* This macro cleans up the main loop. This is used to avoid valgrind * warnings about memory being "leaked" by the main event loop. */ @@ -116,6 +250,7 @@ do { \ close_loop(uv_default_loop()); \ ASSERT(0 == uv_loop_close(uv_default_loop())); \ + uv_library_shutdown(); \ } while (0) /* Just sugar for wrapping the main() for a task or helper. */ diff -Nru libuv1-1.34.2/test/test-close-fd.c libuv1-1.40.0/test/test-close-fd.c --- libuv1-1.34.2/test/test-close-fd.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-close-fd.c 2020-09-25 00:34:43.000000000 +0000 @@ -28,13 +28,13 @@ static unsigned int read_cb_called; -static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static char slab[1]; buf->base = slab; buf->len = sizeof(slab); } -static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { switch (++read_cb_called) { case 1: ASSERT(nread == 1); diff -Nru libuv1-1.34.2/test/test-connection-fail.c libuv1-1.40.0/test/test-connection-fail.c --- libuv1-1.34.2/test/test-connection-fail.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-connection-fail.c 2020-09-25 00:34:43.000000000 +0000 @@ -120,6 +120,11 @@ * expect an error. */ TEST_IMPL(connection_fail) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + connection_fail(on_connect_with_close); ASSERT(timer_close_cb_calls == 0); @@ -136,6 +141,11 @@ * attempt. */ TEST_IMPL(connection_fail_doesnt_auto_close) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; r = uv_timer_init(uv_default_loop(), &timer); diff -Nru libuv1-1.34.2/test/test-cwd-and-chdir.c libuv1-1.40.0/test/test-cwd-and-chdir.c --- libuv1-1.34.2/test/test-cwd-and-chdir.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-cwd-and-chdir.c 2020-09-25 00:34:43.000000000 +0000 @@ -23,8 +23,7 @@ #include "task.h" #include -#define PATHMAX 1024 -extern char executable_path[]; +#define PATHMAX 4096 TEST_IMPL(cwd_and_chdir) { char buffer_orig[PATHMAX]; diff -Nru libuv1-1.34.2/test/test-dlerror.c libuv1-1.40.0/test/test-dlerror.c --- libuv1-1.34.2/test/test-dlerror.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-dlerror.c 2020-09-25 00:34:43.000000000 +0000 @@ -42,7 +42,7 @@ msg = uv_dlerror(&lib); ASSERT(msg != NULL); -#ifndef __OpenBSD__ +#if !defined(__OpenBSD__) && !defined(__QNX__) ASSERT(strstr(msg, path) != NULL); #endif ASSERT(strstr(msg, dlerror_no_error) == NULL); @@ -50,7 +50,7 @@ /* Should return the same error twice in a row. */ msg = uv_dlerror(&lib); ASSERT(msg != NULL); -#ifndef __OpenBSD__ +#if !defined(__OpenBSD__) && !defined(__QNX__) ASSERT(strstr(msg, path) != NULL); #endif ASSERT(strstr(msg, dlerror_no_error) == NULL); diff -Nru libuv1-1.34.2/test/test-env-vars.c libuv1-1.40.0/test/test-env-vars.c --- libuv1-1.34.2/test/test-env-vars.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-env-vars.c 2020-09-25 00:34:43.000000000 +0000 @@ -142,5 +142,29 @@ r = uv_os_unsetenv(name2); ASSERT(r == 0); + for (i = 1; i <= 4; i++) { + size_t n; + char* p; + + n = i * 32768; + size = n + 1; + + p = malloc(size); + ASSERT_NOT_NULL(p); + + memset(p, 'x', n); + p[n] = '\0'; + + ASSERT_EQ(0, uv_os_setenv(name, p)); + ASSERT_EQ(0, uv_os_getenv(name, p, &size)); + ASSERT_EQ(n, size); + + for (n = 0; n < size; n++) + ASSERT_EQ('x', p[n]); + + ASSERT_EQ(0, uv_os_unsetenv(name)); + free(p); + } + return 0; } diff -Nru libuv1-1.34.2/test/test-fs.c libuv1-1.40.0/test/test-fs.c --- libuv1-1.34.2/test/test-fs.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-fs.c 2020-09-25 00:34:43.000000000 +0000 @@ -28,12 +28,8 @@ #include #include /* INT_MAX, PATH_MAX, IOV_MAX */ -/* FIXME we shouldn't need to branch in this file */ -#if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(__sun) || \ - defined(_AIX) || defined(__MVS__) || \ - defined(__HAIKU__) -#include /* unlink, rmdir, etc. */ +#ifndef _WIN32 +# include /* unlink, rmdir, etc. */ #else # include # include @@ -55,7 +51,7 @@ #endif #define TOO_LONG_NAME_LENGTH 65536 -#define PATHMAX 1024 +#define PATHMAX 4096 typedef struct { const char* path; @@ -95,6 +91,7 @@ static int realpath_cb_count; static int utime_cb_count; static int futime_cb_count; +static int lutime_cb_count; static int statfs_cb_count; static uv_loop_t* loop; @@ -309,6 +306,12 @@ # 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 || req->result == UV_EPERM); # else ASSERT(req->result == UV_EPERM); # endif @@ -800,12 +803,19 @@ return 0; } -static void check_utime(const char* path, double atime, double mtime) { +static void check_utime(const char* path, + double atime, + double mtime, + int test_lutime) { uv_stat_t* s; uv_fs_t req; int r; - r = uv_fs_stat(loop, &req, path, NULL); + if (test_lutime) + r = uv_fs_lstat(loop, &req, path, NULL); + else + r = uv_fs_stat(loop, &req, path, NULL); + ASSERT(r == 0); ASSERT(req.result == 0); @@ -826,7 +836,7 @@ ASSERT(req->fs_type == UV_FS_UTIME); c = req->data; - check_utime(c->path, c->atime, c->mtime); + check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0); uv_fs_req_cleanup(req); utime_cb_count++; @@ -841,13 +851,27 @@ ASSERT(req->fs_type == UV_FS_FUTIME); c = req->data; - check_utime(c->path, c->atime, c->mtime); + check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0); uv_fs_req_cleanup(req); futime_cb_count++; } +static void lutime_cb(uv_fs_t* req) { + utime_check_t* c; + + ASSERT(req->result == 0); + ASSERT(req->fs_type == UV_FS_LUTIME); + + c = req->data; + check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 1); + + uv_fs_req_cleanup(req); + lutime_cb_count++; +} + + TEST_IMPL(fs_file_async) { int r; @@ -1262,7 +1286,10 @@ ASSERT(strcmp(mkstemp_req1.path, mkstemp_req2.path) != 0); /* invalid template returns EINVAL */ - ASSERT(uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL) == UV_EINVAL); + ASSERT_EQ(UV_EINVAL, uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL)); + + /* Make sure that path is empty string */ + ASSERT_EQ(0, strlen(mkstemp_req3.path)); /* We can write to the opened file */ iov = uv_buf_init(test_buf, sizeof(test_buf)); @@ -2223,7 +2250,12 @@ #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); @@ -2420,6 +2452,57 @@ MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(fs_lstat_windows_store_apps) { + uv_loop_t* loop; + char localappdata[MAX_PATH]; + char windowsapps_path[MAX_PATH]; + char file_path[MAX_PATH]; + size_t len; + int r; + uv_fs_t req; + uv_fs_t stat_req; + uv_dirent_t dirent; + + loop = uv_default_loop(); + ASSERT_NOT_NULL(loop); + len = sizeof(localappdata); + r = uv_os_getenv("LOCALAPPDATA", localappdata, &len); + if (r == UV_ENOENT) { + MAKE_VALGRIND_HAPPY(); + return TEST_SKIP; + } + ASSERT_EQ(r, 0); + r = snprintf(windowsapps_path, + sizeof(localappdata), + "%s\\Microsoft\\WindowsApps", + localappdata); + ASSERT_GT(r, 0); + if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) { + /* If we cannot read the directory, skip the test. */ + MAKE_VALGRIND_HAPPY(); + return TEST_SKIP; + } + if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) { + MAKE_VALGRIND_HAPPY(); + return TEST_SKIP; + } + while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) { + if (dirent.type != UV_DIRENT_LINK) { + continue; + } + if (snprintf(file_path, + sizeof(file_path), + "%s\\%s", + windowsapps_path, + dirent.name) < 0) { + continue; + } + ASSERT_EQ(uv_fs_lstat(loop, &stat_req, file_path, NULL), 0); + } + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif @@ -2459,7 +2542,7 @@ r = uv_fs_stat(NULL, &req, path, NULL); ASSERT(r == 0); ASSERT(req.result == 0); - check_utime(path, atime, mtime); + check_utime(path, atime, mtime, /* test_lutime */ 0); uv_fs_req_cleanup(&req); atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ @@ -2565,7 +2648,7 @@ r = uv_fs_stat(NULL, &req, path, NULL); ASSERT(r == 0); ASSERT(req.result == 0); - check_utime(path, atime, mtime); + check_utime(path, atime, mtime, /* test_lutime */ 0); uv_fs_req_cleanup(&req); atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ @@ -2589,6 +2672,84 @@ } +TEST_IMPL(fs_lutime) { + utime_check_t checkme; + const char* path = "test_file"; + const char* symlink_path = "test_file_symlink"; + double atime; + double mtime; + uv_fs_t req; + int r, s; + + + /* Setup */ + loop = uv_default_loop(); + unlink(path); + r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + uv_fs_req_cleanup(&req); + uv_fs_close(loop, &req, r, NULL); + + unlink(symlink_path); + s = uv_fs_symlink(NULL, &req, path, symlink_path, 0, NULL); +#ifdef _WIN32 + if (s == UV_EPERM) { + /* + * Creating a symlink before Windows 10 Creators Update was only allowed + * when running elevated console (with admin rights) + */ + RETURN_SKIP( + "Symlink creation requires elevated console (with admin rights)"); + } +#endif + ASSERT(s == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* Test the synchronous version. */ + atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + + checkme.atime = atime; + checkme.mtime = mtime; + checkme.path = symlink_path; + req.data = &checkme; + + r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); +#if (defined(_AIX) && !defined(_AIX71)) || \ + defined(__MVS__) + ASSERT(r == UV_ENOSYS); + RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); +#endif + ASSERT(r == 0); + lutime_cb(&req); + ASSERT(lutime_cb_count == 1); + + /* Test the asynchronous version. */ + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ + + checkme.atime = atime; + checkme.mtime = mtime; + checkme.path = symlink_path; + + r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(lutime_cb_count == 2); + + /* Cleanup. */ + unlink(path); + unlink(symlink_path); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_stat_missing_path) { uv_fs_t req; int r; @@ -3723,7 +3884,7 @@ } #ifdef _WIN32 -static void fs_file_pos_common() { +static void fs_file_pos_common(void) { int r; iov = uv_buf_init("abc", 3); @@ -4236,3 +4397,21 @@ return 0; } + +TEST_IMPL(fs_get_system_error) { + uv_fs_t req; + int r; + int system_error; + + r = uv_fs_statfs(NULL, &req, "non_existing_file", NULL); + ASSERT(r != 0); + + system_error = uv_fs_get_system_error(&req); +#ifdef _WIN32 + ASSERT(system_error == ERROR_FILE_NOT_FOUND); +#else + ASSERT(system_error == ENOENT); +#endif + + return 0; +} diff -Nru libuv1-1.34.2/test/test-fs-copyfile.c libuv1-1.40.0/test/test-fs-copyfile.c --- libuv1-1.34.2/test/test-fs-copyfile.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-fs-copyfile.c 2020-09-25 00:34:43.000000000 +0000 @@ -25,7 +25,7 @@ #if defined(__unix__) || defined(__POSIX__) || \ defined(__APPLE__) || defined(__sun) || \ defined(_AIX) || defined(__MVS__) || \ - defined(__HAIKU__) + defined(__HAIKU__) || defined(__QNX__) #include /* unlink, etc. */ #else # include @@ -125,6 +125,11 @@ r = uv_fs_copyfile(NULL, &req, src, src, 0, NULL); ASSERT(r == 0); uv_fs_req_cleanup(&req); + /* Verify that the src file did not get truncated. */ + r = uv_fs_stat(NULL, &req, src, NULL); + ASSERT_EQ(r, 0); + ASSERT_EQ(req.statbuf.st_size, 12); + uv_fs_req_cleanup(&req); unlink(src); /* Copies file synchronously. Creates new file. */ @@ -199,8 +204,11 @@ 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 -Nru libuv1-1.34.2/test/test-fs-event.c libuv1-1.40.0/test/test-fs-event.c --- libuv1-1.34.2/test/test-fs-event.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-fs-event.c 2020-09-25 00:34:43.000000000 +0000 @@ -285,6 +285,12 @@ 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 @@ 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 -Nru libuv1-1.34.2/test/test-fs-open-flags.c libuv1-1.40.0/test/test-fs-open-flags.c --- libuv1-1.34.2/test/test-fs-open-flags.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-fs-open-flags.c 2020-09-25 00:34:43.000000000 +0000 @@ -58,7 +58,7 @@ static char dummy_file[FILE_NAME_SIZE]; static char empty_dir[] = "empty_dir"; -static void setup() { +static void setup(void) { int r; /* empty_dir */ @@ -73,7 +73,7 @@ uv_fs_req_cleanup(&mkdir_req); } -static void refresh() { +static void refresh(void) { int r; /* absent_file */ @@ -119,7 +119,7 @@ uv_fs_req_cleanup(&close_req); } -static void cleanup() { +static void cleanup(void) { unlink(absent_file); unlink(empty_file); unlink(dummy_file); diff -Nru libuv1-1.34.2/test/test-getaddrinfo.c libuv1-1.40.0/test/test-getaddrinfo.c --- libuv1-1.34.2/test/test-getaddrinfo.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-getaddrinfo.c 2020-09-25 00:34:43.000000000 +0000 @@ -39,6 +39,7 @@ static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { + ASSERT(fail_cb_called == 0); ASSERT(status < 0); ASSERT(res == NULL); @@ -81,6 +82,11 @@ TEST_IMPL(getaddrinfo_fail) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + uv_getaddrinfo_t req; ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), @@ -106,6 +112,10 @@ TEST_IMPL(getaddrinfo_fail_sync) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif uv_getaddrinfo_t req; /* Use a FQDN by ending in a period */ @@ -123,6 +133,11 @@ TEST_IMPL(getaddrinfo_basic) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t)); @@ -144,6 +159,10 @@ TEST_IMPL(getaddrinfo_basic_sync) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif uv_getaddrinfo_t req; ASSERT(0 == uv_getaddrinfo(uv_default_loop(), @@ -160,6 +179,11 @@ TEST_IMPL(getaddrinfo_concurrent) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int i, r; int* data; diff -Nru libuv1-1.34.2/test/test-get-currentexe.c libuv1-1.40.0/test/test-get-currentexe.c --- libuv1-1.34.2/test/test-get-currentexe.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-get-currentexe.c 2020-09-25 00:34:43.000000000 +0000 @@ -23,28 +23,34 @@ #include "task.h" #include -#define PATHMAX 1024 +#ifndef _WIN32 +#include +#endif + +#define PATHMAX 4096 extern char executable_path[]; TEST_IMPL(get_currentexe) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + char buffer[PATHMAX]; + char path[PATHMAX]; size_t size; char* match; - char* path; int r; size = sizeof(buffer) / sizeof(buffer[0]); r = uv_exepath(buffer, &size); ASSERT(!r); - /* uv_exepath can return an absolute path on darwin, so if the test runner - * was run with a relative prefix of "./", we need to strip that prefix off - * executable_path or we'll fail. */ - if (executable_path[0] == '.' && executable_path[1] == '/') { - path = executable_path + 2; - } else { - path = executable_path; - } +#ifdef _WIN32 + snprintf(path, sizeof(path), "%s", executable_path); +#else + ASSERT(NULL != realpath(executable_path, path)); +#endif match = strstr(buffer, path); /* Verify that the path returned from uv_exepath is a subdirectory of @@ -82,5 +88,19 @@ ASSERT(buffer[0] != '\0'); ASSERT(buffer[1] == '\0'); + /* Verify uv_exepath is not affected by uv_set_process_title(). */ + r = uv_set_process_title("foobar"); + ASSERT_EQ(r, 0); + size = sizeof(buffer); + r = uv_exepath(buffer, &size); + ASSERT_EQ(r, 0); + + match = strstr(buffer, path); + /* Verify that the path returned from uv_exepath is a subdirectory of + * executable_path. + */ + ASSERT_NOT_NULL(match); + ASSERT_STR_EQ(match, path); + ASSERT_EQ(size, strlen(buffer)); return 0; } diff -Nru libuv1-1.34.2/test/test-gethostname.c libuv1-1.40.0/test/test-gethostname.c --- libuv1-1.34.2/test/test-gethostname.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-gethostname.c 2020-09-25 00:34:43.000000000 +0000 @@ -51,7 +51,7 @@ size = UV_MAXHOSTNAMESIZE; r = uv_os_gethostname(buf, &size); ASSERT(r == 0); - ASSERT(size > 1 && size == strlen(buf)); + ASSERT(size > 0 && size == strlen(buf)); ASSERT(size + 1 == enobufs_size); return 0; diff -Nru libuv1-1.34.2/test/test-get-memory.c libuv1-1.40.0/test/test-get-memory.c --- libuv1-1.34.2/test/test-get-memory.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-get-memory.c 2020-09-25 00:34:43.000000000 +0000 @@ -32,14 +32,13 @@ (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 -Nru libuv1-1.34.2/test/test-getnameinfo.c libuv1-1.40.0/test/test-getnameinfo.c --- libuv1-1.34.2/test/test-getnameinfo.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-getnameinfo.c 2020-09-25 00:34:43.000000000 +0000 @@ -46,6 +46,11 @@ TEST_IMPL(getnameinfo_basic_ip4) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; r = uv_ip4_addr(address_ip4, port, &addr4); @@ -66,6 +71,11 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4)); ASSERT(0 == uv_getnameinfo(uv_default_loop(), @@ -82,6 +92,11 @@ TEST_IMPL(getnameinfo_basic_ip6) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; r = uv_ip6_addr(address_ip6, port, &addr6); diff -Nru libuv1-1.34.2/test/test-get-passwd.c libuv1-1.40.0/test/test-get-passwd.c --- libuv1-1.34.2/test/test-get-passwd.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-get-passwd.c 2020-09-25 00:34:43.000000000 +0000 @@ -24,6 +24,11 @@ #include TEST_IMPL(get_passwd) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + uv_passwd_t pwd; size_t len; int r; @@ -38,7 +43,9 @@ ASSERT(pwd.shell == NULL); #else len = strlen(pwd.shell); +# ifndef __PASE__ ASSERT(len > 0); +# endif #endif len = strlen(pwd.homedir); diff -Nru libuv1-1.34.2/test/test-getters-setters.c libuv1-1.40.0/test/test-getters-setters.c --- libuv1-1.34.2/test/test-getters-setters.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-getters-setters.c 2020-09-25 00:34:43.000000000 +0000 @@ -1,3 +1,24 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "uv.h" #include "task.h" #include diff -Nru libuv1-1.34.2/test/test.gyp libuv1-1.40.0/test/test.gyp --- libuv1-1.34.2/test/test.gyp 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test.gyp 1970-01-01 00:00:00.000000000 +0000 @@ -1,293 +0,0 @@ -{ - 'targets': [ - { - 'target_name': 'run-tests', - 'type': 'executable', - 'dependencies': [ '../uv.gyp:libuv' ], - 'sources': [ - 'blackhole-server.c', - 'echo-server.c', - 'run-tests.c', - 'runner.c', - 'runner.h', - 'test-get-loadavg.c', - 'task.h', - 'test-active.c', - 'test-async.c', - 'test-async-null-cb.c', - 'test-callback-stack.c', - 'test-callback-order.c', - 'test-close-fd.c', - 'test-close-order.c', - 'test-connect-unspecified.c', - 'test-connection-fail.c', - 'test-cwd-and-chdir.c', - 'test-default-loop-close.c', - 'test-delayed-accept.c', - 'test-eintr-handling.c', - 'test-error.c', - 'test-embed.c', - 'test-emfile.c', - 'test-env-vars.c', - 'test-fail-always.c', - 'test-fork.c', - 'test-fs.c', - 'test-fs-readdir.c', - 'test-fs-copyfile.c', - 'test-fs-event.c', - 'test-fs-fd-hash.c', - 'test-fs-open-flags.c', - 'test-fs-poll.c', - 'test-getters-setters.c', - 'test-get-currentexe.c', - 'test-get-memory.c', - 'test-get-passwd.c', - 'test-getaddrinfo.c', - 'test-gethostname.c', - 'test-getnameinfo.c', - 'test-getsockname.c', - 'test-gettimeofday.c', - 'test-handle-fileno.c', - 'test-homedir.c', - 'test-hrtime.c', - 'test-idle.c', - 'test-idna.c', - 'test-ip4-addr.c', - 'test-ip6-addr.c', - 'test-ipc-heavy-traffic-deadlock-bug.c', - 'test-ipc-send-recv.c', - 'test-ipc.c', - 'test-list.h', - 'test-loop-handles.c', - 'test-loop-alive.c', - 'test-loop-close.c', - 'test-loop-stop.c', - 'test-loop-time.c', - 'test-loop-configure.c', - 'test-walk-handles.c', - 'test-watcher-cross-stop.c', - 'test-multiple-listen.c', - 'test-osx-select.c', - 'test-pass-always.c', - 'test-ping-pong.c', - 'test-pipe-bind-error.c', - 'test-pipe-connect-error.c', - 'test-pipe-connect-multiple.c', - 'test-pipe-connect-prepare.c', - 'test-pipe-getsockname.c', - 'test-pipe-pending-instances.c', - 'test-pipe-sendmsg.c', - 'test-pipe-server-close.c', - 'test-pipe-close-stdout-read-stdin.c', - 'test-pipe-set-non-blocking.c', - 'test-pipe-set-fchmod.c', - 'test-platform-output.c', - 'test-poll.c', - 'test-poll-close.c', - 'test-poll-close-doesnt-corrupt-stack.c', - 'test-poll-closesocket.c', - 'test-poll-oob.c', - 'test-process-priority.c', - 'test-process-title.c', - 'test-process-title-threadsafe.c', - 'test-queue-foreach-delete.c', - 'test-random.c', - 'test-ref.c', - 'test-run-nowait.c', - 'test-run-once.c', - 'test-semaphore.c', - 'test-shutdown-close.c', - 'test-shutdown-eof.c', - 'test-shutdown-twice.c', - 'test-signal.c', - 'test-signal-multiple-loops.c', - 'test-signal-pending-on-close.c', - 'test-socket-buffer-size.c', - 'test-spawn.c', - 'test-strscpy.c', - 'test-stdio-over-pipes.c', - 'test-tcp-alloc-cb-fail.c', - 'test-tcp-bind-error.c', - 'test-tcp-bind6-error.c', - 'test-tcp-close.c', - 'test-tcp-close-accept.c', - 'test-tcp-close-reset.c', - 'test-tcp-close-while-connecting.c', - 'test-tcp-create-socket-early.c', - 'test-tcp-connect-error-after-write.c', - 'test-tcp-shutdown-after-write.c', - 'test-tcp-flags.c', - 'test-tcp-connect-error.c', - 'test-tcp-connect-timeout.c', - 'test-tcp-connect6-error.c', - 'test-tcp-open.c', - 'test-tcp-write-to-half-open-connection.c', - 'test-tcp-write-after-connect.c', - 'test-tcp-writealot.c', - 'test-tcp-write-fail.c', - 'test-tcp-try-write.c', - 'test-tcp-try-write-error.c', - 'test-tcp-unexpected-read.c', - 'test-tcp-oob.c', - 'test-tcp-read-stop.c', - 'test-tcp-write-queue-order.c', - 'test-threadpool.c', - 'test-threadpool-cancel.c', - 'test-thread-equal.c', - 'test-tmpdir.c', - 'test-mutexes.c', - 'test-thread.c', - 'test-barrier.c', - 'test-condvar.c', - 'test-timer-again.c', - 'test-timer-from-check.c', - 'test-timer.c', - 'test-tty-duplicate-key.c', - 'test-tty.c', - 'test-udp-alloc-cb-fail.c', - 'test-udp-bind.c', - 'test-udp-connect.c', - 'test-udp-create-socket-early.c', - 'test-udp-dgram-too-big.c', - 'test-udp-ipv6.c', - 'test-udp-open.c', - 'test-udp-options.c', - 'test-udp-send-and-recv.c', - 'test-udp-send-hang-loop.c', - 'test-udp-send-immediate.c', - 'test-udp-send-unreachable.c', - 'test-udp-multicast-join.c', - 'test-udp-multicast-join6.c', - 'test-dlerror.c', - 'test-udp-multicast-ttl.c', - 'test-udp-multicast-interface.c', - 'test-udp-multicast-interface6.c', - 'test-udp-try-send.c', - 'test-uname.c', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'runner-win.c', - 'runner-win.h', - '../src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'sources': [ - 'runner-unix.c', - 'runner-unix.h', - ], - 'conditions': [ - [ 'OS != "zos"', { - 'defines': [ '_GNU_SOURCE' ], - 'cflags': [ '-Wno-long-long' ], - 'xcode_settings': { - 'WARNING_CFLAGS': [ '-Wno-long-long' ] - } - }], - ]}, - ], - [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { - 'link_settings': { - 'libraries': [ '-lutil' ], - }, - }], - [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE - 'defines': [ - '__EXTENSIONS__', - '_XOPEN_SOURCE=500', - ], - }], - [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE - 'defines': [ - '_ALL_SOURCE', - '_XOPEN_SOURCE=500', - ], - }], - [ 'OS == "zos"', { - 'cflags': [ '-qxplink' ], - 'ldflags': [ '-qxplink' ], - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, - - { - 'target_name': 'run-benchmarks', - 'type': 'executable', - 'dependencies': [ '../uv.gyp:libuv' ], - 'sources': [ - 'benchmark-async.c', - 'benchmark-async-pummel.c', - 'benchmark-fs-stat.c', - 'benchmark-getaddrinfo.c', - 'benchmark-list.h', - 'benchmark-loop-count.c', - 'benchmark-million-async.c', - 'benchmark-million-timers.c', - 'benchmark-multi-accept.c', - 'benchmark-ping-pongs.c', - 'benchmark-pound.c', - 'benchmark-pump.c', - 'benchmark-sizes.c', - 'benchmark-spawn.c', - 'benchmark-thread.c', - 'benchmark-tcp-write-batch.c', - 'benchmark-udp-pummel.c', - 'dns-server.c', - 'echo-server.c', - 'blackhole-server.c', - 'run-benchmarks.c', - 'runner.c', - 'runner.h', - 'task.h', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'runner-win.c', - 'runner-win.h', - '../src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], - 'sources': [ - 'runner-unix.c', - 'runner-unix.h', - ] - }], - [ 'OS == "zos"', { - 'cflags': [ '-qxplink' ], - 'ldflags': [ '-qxplink' ], - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, - ], -} diff -Nru libuv1-1.34.2/test/test-homedir.c libuv1-1.40.0/test/test-homedir.c --- libuv1-1.34.2/test/test-homedir.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-homedir.c 2020-09-25 00:34:43.000000000 +0000 @@ -23,7 +23,7 @@ #include "task.h" #include -#define PATHMAX 1024 +#define PATHMAX 4096 #define SMALLPATH 1 TEST_IMPL(homedir) { diff -Nru libuv1-1.34.2/test/test-ipc.c libuv1-1.40.0/test/test-ipc.c --- libuv1-1.34.2/test/test-ipc.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-ipc.c 2020-09-25 00:34:43.000000000 +0000 @@ -79,16 +79,16 @@ if (!local_conn_accepted) { /* Accept the connection and close it. Also and close the server. */ - ASSERT(status == 0); - ASSERT((uv_stream_t*)&tcp_server == server); + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(&tcp_server, server); conn = malloc(sizeof(*conn)); - ASSERT(conn); + ASSERT_NOT_NULL(conn); r = uv_tcp_init(server->loop, conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_close((uv_handle_t*)conn, close_server_conn_cb); uv_close((uv_handle_t*)server, NULL); @@ -102,8 +102,8 @@ int term_signal) { printf("exit_cb\n"); exit_cb_called++; - ASSERT(exit_status == 0); - ASSERT(term_signal == 0); + ASSERT_EQ(exit_status, 0); + ASSERT_EQ(term_signal, 0); uv_close((uv_handle_t*)process, NULL); } @@ -134,18 +134,17 @@ for (i = 0; i < CONN_COUNT; i++) { conn = malloc(sizeof(*conn)); - ASSERT(conn); + ASSERT_NOT_NULL(conn); r = uv_tcp_init(uv_default_loop(), &conn->conn); - ASSERT(r == 0); - - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_EQ(r, 0); + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_connect(&conn->conn_req, (uv_tcp_t*) &conn->conn, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); conn->conn.data = conn; } @@ -182,36 +181,38 @@ pending = uv_pipe_pending_type(pipe); if (!tcp_server_listening) { - ASSERT(1 == uv_pipe_pending_count(pipe)); - ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE); + ASSERT_EQ(1, uv_pipe_pending_count(pipe)); + ASSERT_GT(nread, 0); + ASSERT_NOT_NULL(buf->base); + ASSERT_NE(pending, UV_UNKNOWN_HANDLE); read_cb_called++; /* Accept the pending TCP server, and start listening on it. */ - ASSERT(pending == UV_TCP); + ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); tcp_server_listening = 1; /* Make sure that the expected data is correctly multiplexed. */ - ASSERT(memcmp("hello\n", buf->base, nread) == 0); + ASSERT_MEM_EQ("hello\n", buf->base, nread); outbuf = uv_buf_init("world\n", 6); r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); /* Create a bunch of connections to get both servers to accept. */ make_many_connections(); } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) { /* Remote server has accepted a connection. Close the channel. */ - ASSERT(0 == uv_pipe_pending_count(pipe)); - ASSERT(pending == UV_UNKNOWN_HANDLE); + ASSERT_EQ(0, uv_pipe_pending_count(pipe)); + ASSERT_EQ(pending, UV_UNKNOWN_HANDLE); remote_conn_accepted = 1; uv_close((uv_handle_t*)&channel, NULL); } @@ -247,37 +248,39 @@ fprintf(stderr, "got %d bytes\n", (int)nread); - ASSERT(uv_pipe_pending_count(pipe) > 0); + ASSERT_GT(uv_pipe_pending_count(pipe), 0); pending = uv_pipe_pending_type(pipe); - ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE); + ASSERT_GT(nread, 0); + ASSERT_NOT_NULL(buf->base); + ASSERT_NE(pending, UV_UNKNOWN_HANDLE); read_cb_called++; if (read_cb_called == 1) { /* Accept the first TCP server, and start listening on it. */ - ASSERT(pending == UV_TCP); + ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } else if (read_cb_called == 2) { /* Accept the second TCP server, and start listening on it. */ - ASSERT(pending == UV_TCP); + ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server2); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection); - ASSERT(r == UV_EADDRINUSE); + ASSERT_EQ(r, UV_EADDRINUSE); uv_close((uv_handle_t*)&tcp_server, NULL); uv_close((uv_handle_t*)&tcp_server2, NULL); - ASSERT(0 == uv_pipe_pending_count(pipe)); + ASSERT_EQ(0, uv_pipe_pending_count(pipe)); uv_close((uv_handle_t*)&channel, NULL); } @@ -296,12 +299,12 @@ uv_stdio_container_t stdio[3]; r = uv_pipe_init(uv_default_loop(), channel, 1); - ASSERT(r == 0); - ASSERT(channel->ipc); + ASSERT_EQ(r, 0); + ASSERT_NE(channel->ipc, 0); exepath_size = sizeof(exepath); r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); + ASSERT_EQ(r, 0); exepath[exepath_size] = '\0'; args[0] = exepath; @@ -323,13 +326,13 @@ stdio[2].data.fd = 2; r = uv_spawn(uv_default_loop(), process, &options); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } static void on_tcp_write(uv_write_t* req, int status) { - ASSERT(status == 0); - ASSERT(req->handle == (uv_stream_t*)&tcp_connection); + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(req->handle, &tcp_connection); tcp_write_cb_called++; } @@ -343,9 +346,9 @@ static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread > 0); - ASSERT(memcmp("hello again\n", buf->base, nread) == 0); - ASSERT(tcp == (uv_stream_t*)&tcp_connection); + ASSERT_GT(nread, 0); + ASSERT_MEM_EQ("hello again\n", buf->base, nread); + ASSERT_PTR_EQ(tcp, &tcp_connection); free(buf->base); tcp_read_cb_called++; @@ -382,31 +385,33 @@ fprintf(stderr, "got %d bytes\n", (int)nread); - ASSERT(1 == uv_pipe_pending_count(pipe)); + ASSERT_EQ(1, uv_pipe_pending_count(pipe)); pending = uv_pipe_pending_type(pipe); - ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE); + ASSERT_GT(nread, 0); + ASSERT_NOT_NULL(buf->base); + ASSERT_NE(pending, UV_UNKNOWN_HANDLE); read_cb_called++; /* Accept the pending TCP connection */ - ASSERT(pending == UV_TCP); + ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept(handle, (uv_stream_t*)&tcp_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); /* Make sure that the expected data is correctly multiplexed. */ - ASSERT(memcmp("hello\n", buf->base, nread) == 0); + ASSERT_MEM_EQ("hello\n", buf->base, nread); /* Write/read to/from the connection */ outbuf = uv_buf_init("world\n", 6); r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1, on_tcp_write); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read); - ASSERT(r == 0); + ASSERT_EQ(r, 0); free(buf->base); } @@ -448,7 +453,7 @@ uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); MAKE_VALGRIND_HAPPY(); return 0; @@ -460,10 +465,10 @@ RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_listen_before_write", on_read); - ASSERT(local_conn_accepted == 1); - ASSERT(remote_conn_accepted == 1); - ASSERT(read_cb_called == 1); - ASSERT(exit_cb_called == 1); + ASSERT_EQ(local_conn_accepted, 1); + ASSERT_EQ(remote_conn_accepted, 1); + ASSERT_EQ(read_cb_called, 1); + ASSERT_EQ(exit_cb_called, 1); return r; } @@ -473,10 +478,10 @@ RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_listen_after_write", on_read); - ASSERT(local_conn_accepted == 1); - ASSERT(remote_conn_accepted == 1); - ASSERT(read_cb_called == 1); - ASSERT(exit_cb_called == 1); + ASSERT_EQ(local_conn_accepted, 1); + ASSERT_EQ(remote_conn_accepted, 1); + ASSERT_EQ(read_cb_called, 1); + ASSERT_EQ(exit_cb_called, 1); return r; } @@ -486,10 +491,10 @@ RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection); - ASSERT(read_cb_called == 1); - ASSERT(tcp_write_cb_called == 1); - ASSERT(tcp_read_cb_called == 1); - ASSERT(exit_cb_called == 1); + ASSERT_EQ(read_cb_called, 1); + ASSERT_EQ(tcp_write_cb_called, 1); + ASSERT_EQ(tcp_read_cb_called, 1); + ASSERT_EQ(exit_cb_called, 1); return r; } @@ -497,7 +502,7 @@ TEST_IMPL(ipc_closed_handle) { int r; r = run_ipc_test("ipc_helper_closed_handle", on_read_closed_handle); - ASSERT(r == 0); + ASSERT_EQ(r, 0); return 0; } #endif @@ -509,20 +514,20 @@ int r; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_simultaneous_accepts(&server, 1); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); - ASSERT(r == 0); - ASSERT(server.reqs_pending == 32); + ASSERT_EQ(r, 0); + ASSERT_EQ(server.reqs_pending, 32); MAKE_VALGRIND_HAPPY(); return 0; @@ -534,20 +539,20 @@ int r; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_simultaneous_accepts(&server, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); - ASSERT(r == 0); - ASSERT(server.reqs_pending == 1); + ASSERT_EQ(r, 0); + ASSERT_EQ(server.reqs_pending, 1); MAKE_VALGRIND_HAPPY(); return 0; @@ -558,8 +563,8 @@ RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice); - ASSERT(read_cb_called == 2); - ASSERT(exit_cb_called == 1); + ASSERT_EQ(read_cb_called, 2); + ASSERT_EQ(exit_cb_called, 1); return r; } #endif @@ -567,7 +572,7 @@ TEST_IMPL(ipc_send_zero) { int r; r = run_ipc_test("ipc_helper_send_zero", on_read_send_zero); - ASSERT(r == 0); + ASSERT_EQ(r, 0); return 0; } @@ -589,7 +594,7 @@ static void tcp_connection_write_cb(uv_write_t* req, int status) { - ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle); + ASSERT_PTR_EQ(&conn.conn, req->handle); uv_close((uv_handle_t*)req->handle, close_cb); uv_close((uv_handle_t*)&channel, close_cb); uv_close((uv_handle_t*)&tcp_server, close_cb); @@ -598,7 +603,7 @@ static void closed_handle_large_write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_EQ(status, 0); ASSERT(closed_handle_data_read = LARGE_SIZE); if (++write_reqs_completed == ARRAY_SIZE(write_reqs)) { write_reqs_completed = 0; @@ -609,13 +614,13 @@ static void closed_handle_write_cb(uv_write_t* req, int status) { - ASSERT(status == UV_EBADF); + ASSERT_EQ(status, UV_EBADF); closed_handle_write = 1; } static void send_zero_write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_EQ(status, 0); send_zero_write++; } @@ -635,15 +640,15 @@ abort(); } - ASSERT(nread > 0); - ASSERT(memcmp("world\n", buf->base, nread) == 0); + ASSERT_GT(nread, 0); + ASSERT_MEM_EQ("world\n", buf->base, nread); on_pipe_read_called++; free(buf->base); /* Write to the socket */ outbuf = uv_buf_init("hello again\n", 12); r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); tcp_conn_read_cb_called++; } @@ -652,9 +657,9 @@ static void connect_child_process_cb(uv_connect_t* req, int status) { int r; - ASSERT(status == 0); + ASSERT_EQ(status, 0); r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } @@ -667,21 +672,21 @@ * Accept the connection and close it. Also let the other * side know. */ - ASSERT(status == 0); - ASSERT((uv_stream_t*)&tcp_server == server); + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(&tcp_server, server); r = uv_tcp_init(server->loop, &conn.conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept(server, (uv_stream_t*)&conn.conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_close((uv_handle_t*)&conn.conn, close_cb); buf = uv_buf_init("accepted_connection\n", 20); r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, NULL, conn_notify_write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); connection_accepted = 1; } @@ -693,28 +698,28 @@ uv_buf_t buf; uv_tcp_t* conn; - ASSERT(status == 0); - ASSERT((uv_stream_t*)&tcp_server == server); + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(&tcp_server, server); conn = malloc(sizeof(*conn)); - ASSERT(conn); + ASSERT_NOT_NULL(conn); r = uv_tcp_init(server->loop, conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); /* Send the accepted connection to the other process */ buf = uv_buf_init("hello\n", 6); r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)conn, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_read_start((uv_stream_t*) conn, on_read_alloc, on_tcp_child_process_read); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_close((uv_handle_t*)conn, close_cb); } @@ -729,44 +734,44 @@ int r; uv_buf_t buf; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_open(&channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); + ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); if (!listen_after_write) { r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } buf = uv_buf_init("hello\n", 6); r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); if (listen_after_write) { r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } notify_parent_process(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(connection_accepted == 1); - ASSERT(close_cb_called == 3); + ASSERT_EQ(connection_accepted, 1); + ASSERT_EQ(close_cb_called, 3); MAKE_VALGRIND_HAPPY(); return 0; @@ -783,43 +788,43 @@ struct sockaddr_in addr; r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_open(&channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); + ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); /* Make a connection to the server */ r = uv_tcp_init(uv_default_loop(), &conn.conn); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_connect(&conn.conn_req, (uv_tcp_t*) &conn.conn, (const struct sockaddr*) &addr, connect_child_process_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(tcp_conn_read_cb_called == 1); - ASSERT(tcp_conn_write_cb_called == 1); - ASSERT(close_cb_called == 4); + ASSERT_EQ(tcp_conn_read_cb_called, 1); + ASSERT_EQ(tcp_conn_write_cb_called, 1); + ASSERT_EQ(close_cb_called, 4); MAKE_VALGRIND_HAPPY(); return 0; @@ -836,7 +841,7 @@ &large_buf, 1, closed_handle_large_write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); i++; } while (channel.write_queue_size == 0 && i < ARRAY_SIZE(write_reqs)); @@ -849,12 +854,12 @@ struct sockaddr_in addr; r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_write2(&write_req, (uv_stream_t*)&channel, @@ -862,7 +867,7 @@ 1, (uv_stream_t*)&tcp_server, closed_handle_write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_close((uv_handle_t*)&tcp_server, NULL); } @@ -874,21 +879,21 @@ large_buf = uv_buf_init(buffer, LARGE_SIZE); r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_open(&channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); + ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); if (write_until_data_queued() > 0) send_handle_and_close(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(closed_handle_write == 1); + ASSERT_EQ(closed_handle_write, 1); MAKE_VALGRIND_HAPPY(); return 0; @@ -904,38 +909,38 @@ int r; uv_buf_t buf; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_open(&channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); + ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); buf = uv_buf_init("hello\n", 6); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_init(uv_default_loop(), &tcp_server2); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server2, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); MAKE_VALGRIND_HAPPY(); return 0; @@ -948,13 +953,13 @@ zero_buf = uv_buf_init(0, 0); r = uv_pipe_init(uv_default_loop(), &channel, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_open(&channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); + ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); r = uv_write(&write_req, (uv_stream_t*)&channel, @@ -962,12 +967,12 @@ 1, send_zero_write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(send_zero_write == 1); + ASSERT_EQ(send_zero_write, 1); MAKE_VALGRIND_HAPPY(); return 0; diff -Nru libuv1-1.34.2/test/test-list.h libuv1-1.40.0/test/test-list.h --- libuv1-1.34.2/test/test-list.h 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-list.h 2020-09-25 00:34:43.000000000 +0000 @@ -56,10 +56,27 @@ 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) @@ -110,6 +127,8 @@ TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) +TEST_DECLARE (tcp_local_connect_timeout) +TEST_DECLARE (tcp6_local_connect_timeout) TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close_reset_accepted) @@ -128,6 +147,7 @@ TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_read_stop) +TEST_DECLARE (tcp_read_stop_start) TEST_DECLARE (tcp_bind6_error_addrinuse) TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) @@ -145,6 +165,7 @@ TEST_DECLARE (udp_send_hang_loop) TEST_DECLARE (udp_send_immediate) TEST_DECLARE (udp_send_unreachable) +TEST_DECLARE (udp_mmsg) TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_join6) TEST_DECLARE (udp_multicast_ttl) @@ -163,6 +184,7 @@ #ifndef _WIN32 TEST_DECLARE (udp_send_unix) #endif +TEST_DECLARE (udp_sendmmsg_error) TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) @@ -242,6 +264,7 @@ 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) @@ -262,6 +285,7 @@ TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_udp) TEST_DECLARE (gettimeofday) +TEST_DECLARE (test_macros) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) TEST_DECLARE (socket_buffer_size) @@ -328,6 +352,7 @@ #ifdef _WIN32 TEST_DECLARE (fs_symlink_junction) TEST_DECLARE (fs_non_symlink_reparse_point) +TEST_DECLARE (fs_lstat_windows_store_apps) TEST_DECLARE (fs_open_flags) #endif #if defined(_WIN32) && !defined(USING_UV_SHARED) @@ -335,6 +360,7 @@ #endif TEST_DECLARE (fs_utime) TEST_DECLARE (fs_futime) +TEST_DECLARE (fs_lutime) TEST_DECLARE (fs_file_open_append) TEST_DECLARE (fs_statfs) TEST_DECLARE (fs_stat_missing_path) @@ -390,6 +416,7 @@ TEST_DECLARE (fs_fchmod_archive_readonly) TEST_DECLARE (fs_invalid_mkdir_name) #endif +TEST_DECLARE (fs_get_system_error) TEST_DECLARE (strscpy) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) @@ -453,6 +480,7 @@ 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__ @@ -495,12 +523,17 @@ TEST_DECLARE (utf8_decode1) TEST_DECLARE (uname) +TEST_DECLARE (metrics_idle_time) +TEST_DECLARE (metrics_idle_time_thread) +TEST_DECLARE (metrics_idle_time_zero) + TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) #if 0 TEST_ENTRY (callback_order) #endif + TEST_ENTRY (test_macros) TEST_ENTRY (close_order) TEST_ENTRY (run_once) TEST_ENTRY (run_nowait) @@ -545,10 +578,27 @@ 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) @@ -632,6 +682,8 @@ TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect_timeout) + TEST_ENTRY (tcp_local_connect_timeout) + TEST_ENTRY (tcp6_local_connect_timeout) TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close_reset_accepted) @@ -653,6 +705,8 @@ TEST_ENTRY (tcp_read_stop) TEST_HELPER (tcp_read_stop, tcp4_echo_server) + TEST_ENTRY (tcp_read_stop_start) + TEST_ENTRY (tcp_bind6_error_addrinuse) TEST_ENTRY (tcp_bind6_error_addrnotavail) TEST_ENTRY (tcp_bind6_error_fault) @@ -676,19 +730,19 @@ TEST_ENTRY (udp_options) TEST_ENTRY (udp_options6) TEST_ENTRY (udp_no_autobind) + TEST_ENTRY (udp_mmsg) TEST_ENTRY (udp_multicast_interface) TEST_ENTRY (udp_multicast_interface6) TEST_ENTRY (udp_multicast_join) TEST_ENTRY (udp_multicast_join6) TEST_ENTRY (udp_multicast_ttl) + TEST_ENTRY (udp_sendmmsg_error) 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 +842,7 @@ TEST_ENTRY (get_currentexe) TEST_ENTRY (process_title) + TEST_ENTRY (process_title_big_argv) TEST_ENTRY (process_title_threadsafe) TEST_ENTRY (cwd_and_chdir) @@ -804,7 +859,7 @@ TEST_ENTRY (tmpdir) - TEST_ENTRY_CUSTOM (hrtime, 0, 0, 10000) + TEST_ENTRY_CUSTOM (hrtime, 0, 0, 20000) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) TEST_ENTRY_CUSTOM (getaddrinfo_fail_sync, 0, 0, 10000) @@ -903,6 +958,7 @@ 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 @@ -933,6 +989,7 @@ TEST_ENTRY (fs_chown) TEST_ENTRY (fs_utime) TEST_ENTRY (fs_futime) + TEST_ENTRY (fs_lutime) TEST_ENTRY (fs_readlink) TEST_ENTRY (fs_realpath) TEST_ENTRY (fs_symlink) @@ -940,6 +997,7 @@ #ifdef _WIN32 TEST_ENTRY (fs_symlink_junction) TEST_ENTRY (fs_non_symlink_reparse_point) + TEST_ENTRY (fs_lstat_windows_store_apps) TEST_ENTRY (fs_open_flags) #endif #if defined(_WIN32) && !defined(USING_UV_SHARED) @@ -969,7 +1027,7 @@ TEST_ENTRY (fs_event_close_with_pending_event) TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_event_start_and_close) - TEST_ENTRY (fs_event_error_reporting) + TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000) TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_scandir_empty_dir) TEST_ENTRY (fs_scandir_non_existent_dir) @@ -998,6 +1056,7 @@ TEST_ENTRY (fs_fchmod_archive_readonly) TEST_ENTRY (fs_invalid_mkdir_name) #endif + TEST_ENTRY (fs_get_system_error) TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (strscpy) @@ -1056,6 +1115,10 @@ TEST_ENTRY (idna_toascii) #endif + TEST_ENTRY (metrics_idle_time) + TEST_ENTRY (metrics_idle_time_thread) + TEST_ENTRY (metrics_idle_time_zero) + #if 0 /* These are for testing the test runner. */ TEST_ENTRY (fail_always) diff -Nru libuv1-1.34.2/test/test-metrics.c libuv1-1.40.0/test/test-metrics.c --- libuv1-1.34.2/test/test-metrics.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-metrics.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,135 @@ +/* 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 /* memset */ + +#define UV_NS_TO_MS 1000000 + + +static void timer_spin_cb(uv_timer_t* handle) { + uint64_t t; + + (*(int*) handle->data)++; + t = uv_hrtime(); + /* Spin for 500 ms to spin loop time out of the delta check. */ + while (uv_hrtime() - t < 600 * UV_NS_TO_MS) { } +} + + +TEST_IMPL(metrics_idle_time) { + const uint64_t timeout = 1000; + uv_timer_t timer; + uint64_t idle_time; + int cntr; + + cntr = 0; + timer.data = &cntr; + + ASSERT_EQ(0, uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); + ASSERT_EQ(0, uv_timer_start(&timer, timer_spin_cb, timeout, 0)); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_GT(cntr, 0); + + idle_time = uv_metrics_idle_time(uv_default_loop()); + + /* Permissive check that the idle time matches within the timeout ±500 ms. */ + ASSERT((idle_time <= (timeout + 500) * UV_NS_TO_MS) && + (idle_time >= (timeout - 500) * UV_NS_TO_MS)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void metrics_routine_cb(void* arg) { + const uint64_t timeout = 1000; + uv_loop_t loop; + uv_timer_t timer; + uint64_t idle_time; + int cntr; + + cntr = 0; + timer.data = &cntr; + + ASSERT_EQ(0, uv_loop_init(&loop)); + ASSERT_EQ(0, uv_loop_configure(&loop, UV_METRICS_IDLE_TIME)); + ASSERT_EQ(0, uv_timer_init(&loop, &timer)); + ASSERT_EQ(0, uv_timer_start(&timer, timer_spin_cb, timeout, 0)); + + ASSERT_EQ(0, uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_GT(cntr, 0); + + idle_time = uv_metrics_idle_time(&loop); + + /* Only checking that idle time is greater than the lower bound since there + * may have been thread contention, causing the event loop to be delayed in + * the idle phase longer than expected. + */ + ASSERT_GE(idle_time, (timeout - 500) * UV_NS_TO_MS); + + close_loop(&loop); + ASSERT_EQ(0, uv_loop_close(&loop)); +} + + +TEST_IMPL(metrics_idle_time_thread) { + uv_thread_t threads[5]; + int i; + + for (i = 0; i < 5; i++) { + ASSERT_EQ(0, uv_thread_create(&threads[i], metrics_routine_cb, NULL)); + } + + for (i = 0; i < 5; i++) { + uv_thread_join(&threads[i]); + } + + return 0; +} + + +static void timer_noop_cb(uv_timer_t* handle) { + (*(int*) handle->data)++; +} + + +TEST_IMPL(metrics_idle_time_zero) { + uv_timer_t timer; + int cntr; + + cntr = 0; + timer.data = &cntr; + ASSERT_EQ(0, uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); + ASSERT_EQ(0, uv_timer_start(&timer, timer_noop_cb, 0, 0)); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_GT(cntr, 0); + ASSERT_EQ(0, uv_metrics_idle_time(uv_default_loop())); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff -Nru libuv1-1.34.2/test/test-ping-pong.c libuv1-1.40.0/test/test-ping-pong.c --- libuv1-1.34.2/test/test-ping-pong.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-ping-pong.c 2020-09-25 00:34:43.000000000 +0000 @@ -70,14 +70,14 @@ } -static void pinger_after_write(uv_write_t *req, int status) { +static void pinger_after_write(uv_write_t* req, int status) { ASSERT(status == 0); free(req); } static void pinger_write_ping(pinger_t* pinger) { - uv_write_t *req; + uv_write_t* req; uv_buf_t bufs[sizeof PING - 1]; int i, nbufs; @@ -112,7 +112,7 @@ ssize_t i; pinger_t* pinger; - pinger = (pinger_t*)stream->data; + pinger = (pinger_t*) stream->data; if (nread < 0) { ASSERT(nread == UV_EOF); @@ -148,8 +148,8 @@ } -static void pinger_on_connect(uv_connect_t *req, int status) { - pinger_t *pinger = (pinger_t*)req->handle->data; +static void pinger_on_connect(uv_connect_t* req, int status) { + pinger_t* pinger = (pinger_t*)req->handle->data; pinger_on_connect_count++; @@ -169,10 +169,10 @@ static void tcp_pinger_v6_new(int vectored_writes) { int r; struct sockaddr_in6 server_addr; - pinger_t *pinger; + pinger_t* pinger; - ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr)); + ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); ASSERT(pinger != NULL); pinger->vectored_writes = vectored_writes; @@ -200,7 +200,7 @@ static void tcp_pinger_new(int vectored_writes) { int r; struct sockaddr_in server_addr; - pinger_t *pinger; + pinger_t* pinger; ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); @@ -229,9 +229,9 @@ static void pipe_pinger_new(int vectored_writes) { int r; - pinger_t *pinger; + pinger_t* pinger; - pinger = (pinger_t*)malloc(sizeof(*pinger)); + pinger = malloc(sizeof(*pinger)); ASSERT(pinger != NULL); pinger->vectored_writes = vectored_writes; pinger->state = 0; diff -Nru libuv1-1.34.2/test/test-pipe-set-non-blocking.c libuv1-1.40.0/test/test-pipe-set-non-blocking.c --- libuv1-1.34.2/test/test-pipe-set-non-blocking.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-pipe-set-non-blocking.c 2020-09-25 00:34:43.000000000 +0000 @@ -24,29 +24,35 @@ #else /* !_WIN32 */ -#include -#include -#include +#include /* memset */ +#include /* close */ #include -#include -#include +#include struct thread_ctx { uv_barrier_t barrier; - int fd; + uv_file fd; }; static void thread_main(void* arg) { struct thread_ctx* ctx; + uv_fs_t req; + uv_buf_t bufs[1]; char buf[4096]; ssize_t n; + int uv_errno; + + bufs[0] = uv_buf_init(buf, sizeof(buf)); ctx = arg; uv_barrier_wait(&ctx->barrier); - do - n = read(ctx->fd, buf, sizeof(buf)); - while (n > 0 || (n == -1 && errno == EINTR)); + uv_sleep(100); /* make sure we are forcing the writer to block a bit */ + do { + uv_errno = uv_fs_read(NULL, &req, ctx->fd, bufs, 1, -1, NULL); + n = req.result; + uv_fs_req_cleanup(&req); + } while (n > 0 || (n == -1 && uv_errno == UV_EINTR)); ASSERT(n == 0); } @@ -58,15 +64,16 @@ size_t nwritten; char data[4096]; uv_buf_t buf; - int fd[2]; + uv_file fd[2]; int n; ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd)); - ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0])); + ASSERT(0 == uv_pipe_open(&pipe_handle, fd[1])); ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1)); + fd[1] = -1; /* fd[1] is owned by pipe_handle now. */ - ctx.fd = fd[1]; + ctx.fd = fd[0]; ASSERT(0 == uv_barrier_init(&ctx.barrier, 2)); ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); uv_barrier_wait(&ctx.barrier); @@ -89,7 +96,8 @@ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(0 == uv_thread_join(&thread)); - ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */ + ASSERT(0 == close(fd[0])); /* fd[1] is closed by uv_close(). */ + fd[0] = -1; uv_barrier_destroy(&ctx.barrier); MAKE_VALGRIND_HAPPY(); diff -Nru libuv1-1.34.2/test/test-platform-output.c libuv1-1.40.0/test/test-platform-output.c --- libuv1-1.34.2/test/test-platform-output.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-platform-output.c 2020-09-25 00:34:43.000000000 +0000 @@ -25,6 +25,11 @@ TEST_IMPL(platform_output) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + char buffer[512]; size_t rss; size_t size; diff -Nru libuv1-1.34.2/test/test-poll.c libuv1-1.40.0/test/test-poll.c --- libuv1-1.34.2/test/test-poll.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-poll.c 2020-09-25 00:34:43.000000000 +0000 @@ -222,7 +222,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } @@ -575,10 +592,19 @@ MAKE_VALGRIND_HAPPY(); } - + +/* Issuing a shutdown() on IBM i PASE with parameter SHUT_WR + * also sends a normal close sequence to the partner program. + * This leads to timing issues and ECONNRESET failures in the + * test 'poll_duplex' and 'poll_unidirectional'. + * + * https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/apis/shutdn.htm + */ TEST_IMPL(poll_duplex) { #if defined(NO_SELF_CONNECT) RETURN_SKIP(NO_SELF_CONNECT); +#elif defined(__PASE__) + RETURN_SKIP("API shutdown() may lead to timing issue on IBM i PASE"); #endif test_mode = DUPLEX; start_poll_test(); @@ -589,6 +615,8 @@ TEST_IMPL(poll_unidirectional) { #if defined(NO_SELF_CONNECT) RETURN_SKIP(NO_SELF_CONNECT); +#elif defined(__PASE__) + RETURN_SKIP("API shutdown() may lead to timing issue on IBM i PASE"); #endif test_mode = UNIDIRECTIONAL; start_poll_test(); diff -Nru libuv1-1.34.2/test/test-process-title.c libuv1-1.40.0/test/test-process-title.c --- libuv1-1.34.2/test/test-process-title.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-process-title.c 2020-09-25 00:34:43.000000000 +0000 @@ -74,3 +74,62 @@ 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 -Nru libuv1-1.34.2/test/test-process-title-threadsafe.c libuv1-1.40.0/test/test-process-title-threadsafe.c --- libuv1-1.34.2/test/test-process-title-threadsafe.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-process-title-threadsafe.c 2020-09-25 00:34:43.000000000 +0000 @@ -39,15 +39,27 @@ }; static void getter_thread_body(void* arg) { + uv_sem_t* getter_sem; char buffer[512]; + size_t len; - for (;;) { + getter_sem = arg; + + while (UV_EAGAIN == uv_sem_trywait(getter_sem)) { ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); + + /* The maximum size of the process title on some platforms depends on + * the total size of the argv vector. It's therefore possible to read + * back a title that's shorter than what we submitted. + */ + len = strlen(buffer); + ASSERT_GT(len, 0); + ASSERT( - 0 == strcmp(buffer, titles[0]) || - 0 == strcmp(buffer, titles[1]) || - 0 == strcmp(buffer, titles[2]) || - 0 == strcmp(buffer, titles[3])); + 0 == strncmp(buffer, titles[0], len) || + 0 == strncmp(buffer, titles[1], len) || + 0 == strncmp(buffer, titles[2], len) || + 0 == strncmp(buffer, titles[3], len)); uv_sleep(0); } @@ -69,6 +81,7 @@ TEST_IMPL(process_title_threadsafe) { uv_thread_t setter_threads[4]; uv_thread_t getter_thread; + uv_sem_t getter_sem; int i; #if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ @@ -77,7 +90,10 @@ #endif ASSERT(0 == uv_set_process_title(titles[0])); - ASSERT(0 == uv_thread_create(&getter_thread, getter_thread_body, NULL)); + + ASSERT_EQ(0, uv_sem_init(&getter_sem, 0)); + ASSERT_EQ(0, + uv_thread_create(&getter_thread, getter_thread_body, &getter_sem)); for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) ASSERT(0 == uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); @@ -85,5 +101,9 @@ for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) ASSERT(0 == uv_thread_join(&setter_threads[i])); + uv_sem_post(&getter_sem); + ASSERT_EQ(0, uv_thread_join(&getter_thread)); + uv_sem_destroy(&getter_sem); + return 0; } diff -Nru libuv1-1.34.2/test/test-signal-multiple-loops.c libuv1-1.40.0/test/test-signal-multiple-loops.c --- libuv1-1.34.2/test/test-signal-multiple-loops.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-signal-multiple-loops.c 2020-09-25 00:34:43.000000000 +0000 @@ -200,6 +200,11 @@ thread setup occasionally. */ RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); #endif +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + // See https://github.com/libuv/libuv/issues/2859 + RETURN_SKIP("QEMU's signal emulation code is notoriously tricky"); +#endif uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS]; uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS]; enum signal_action action; diff -Nru libuv1-1.34.2/test/test-signal-pending-on-close.c libuv1-1.40.0/test/test-signal-pending-on-close.c --- libuv1-1.34.2/test/test-signal-pending-on-close.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-signal-pending-on-close.c 2020-09-25 00:34:43.000000000 +0000 @@ -34,6 +34,11 @@ 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 @@ 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 -Nru libuv1-1.34.2/test/test-spawn.c libuv1-1.40.0/test/test-spawn.c --- libuv1-1.34.2/test/test-spawn.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-spawn.c 2020-09-25 00:34:43.000000000 +0000 @@ -71,7 +71,7 @@ exit_cb_called++; ASSERT(exit_status == 1); ASSERT(term_signal == 0); - uv_close((uv_handle_t*)process, close_cb); + uv_close((uv_handle_t*) process, close_cb); } @@ -104,7 +104,7 @@ #else ASSERT(no_term_signal || term_signal == SIGTERM); #endif - uv_close((uv_handle_t*)process, close_cb); + uv_close((uv_handle_t*) process, close_cb); /* * Sending signum == 0 should check if the @@ -135,7 +135,7 @@ output_used += nread; } else if (nread < 0) { ASSERT(nread == UV_EOF); - uv_close((uv_handle_t*)tcp, close_cb); + uv_close((uv_handle_t*) tcp, close_cb); } } @@ -150,7 +150,7 @@ static void write_cb(uv_write_t* req, int status) { ASSERT(status == 0); - uv_close((uv_handle_t*)req->handle, close_cb); + uv_close((uv_handle_t*) req->handle, close_cb); } @@ -172,8 +172,8 @@ static void timer_cb(uv_timer_t* handle) { - uv_process_kill(&process, /* SIGTERM */ 15); - uv_close((uv_handle_t*)handle, close_cb); + uv_process_kill(&process, SIGTERM); + uv_close((uv_handle_t*) handle, close_cb); } @@ -236,13 +236,14 @@ char* env[1]; /* The autotools dynamic library build requires the presence of - * DYLD_LIBARY_PATH (macOS) or LD_LIBRARY_PATH (other Unices) + * DYLD_LIBARY_PATH (macOS) or LD_LIBRARY_PATH/LIBPATH (other Unices) * in the environment, but of course that doesn't work with * the empty environment that we're testing here. */ if (NULL != getenv("DYLD_LIBRARY_PATH") || - NULL != getenv("LD_LIBRARY_PATH")) { - RETURN_SKIP("doesn't work with DYLD_LIBRARY_PATH/LD_LIBRARY_PATH"); + NULL != getenv("LD_LIBRARY_PATH") || + NULL != getenv("LIBPATH")) { + RETURN_SKIP("doesn't work with DYLD_LIBRARY_PATH/LD_LIBRARY_PATH/LIBPATH"); } init_process_options("spawn_helper1", exit_cb); @@ -290,7 +291,7 @@ options.stdio = stdio; options.stdio[0].flags = UV_IGNORE; options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio[1].data.stream = (uv_stream_t*) &out; options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); @@ -594,9 +595,9 @@ uv_pipe_init(uv_default_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[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[1].data.stream = (uv_stream_t*) &out; options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); @@ -604,7 +605,7 @@ buf.base = buffer; buf.len = sizeof(buffer); - r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); ASSERT(r == 0); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); @@ -635,7 +636,7 @@ options.stdio[1].flags = UV_IGNORE; options.stdio[2].flags = UV_IGNORE; options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[3].data.stream = (uv_stream_t*)&pipe; + options.stdio[3].data.stream = (uv_stream_t*) &pipe; options.stdio_count = 4; r = uv_spawn(uv_default_loop(), &process, &options); @@ -676,7 +677,7 @@ /* Make sure that we can listen on a socket that was * passed down from the parent process */ - r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL); + r = uv_listen((uv_stream_t*) &tcp, SOMAXCONN, NULL); ASSERT(r == 0); return 1; @@ -702,10 +703,10 @@ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); #ifdef _WIN32 - r = uv_fileno((uv_handle_t*)&tcp_server, &handle); + r = uv_fileno((uv_handle_t*) &tcp_server, &handle); fd = _open_osfhandle((intptr_t) handle, 0); #else - r = uv_fileno((uv_handle_t*)&tcp_server, &fd); + r = uv_fileno((uv_handle_t*) &tcp_server, &fd); #endif ASSERT(r == 0); ASSERT(fd > 0); @@ -832,7 +833,7 @@ r = uv_spawn(uv_default_loop(), &process, &options); ASSERT(r == 0); - uv_unref((uv_handle_t*)&process); + uv_unref((uv_handle_t*) &process); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); @@ -844,7 +845,7 @@ r = uv_kill(process.pid, 0); ASSERT(r == 0); - r = uv_kill(process.pid, 15); + r = uv_kill(process.pid, SIGTERM); ASSERT(r == 0); MAKE_VALGRIND_HAPPY(); @@ -873,11 +874,11 @@ options.stdio = stdio; options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - options.stdio[0].data.stream = (uv_stream_t*)∈ + 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[1].data.stream = (uv_stream_t*) &out; options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[2].data.stream = (uv_stream_t*)&err; + options.stdio[2].data.stream = (uv_stream_t*) &err; options.stdio_count = 3; r = uv_spawn(uv_default_loop(), &process, &options); @@ -924,9 +925,9 @@ uv_pipe_init(uv_default_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[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[1].data.stream = (uv_stream_t*) &out; options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); @@ -938,10 +939,10 @@ r = uv_process_kill(&process, 0); ASSERT(r == 0); - r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); ASSERT(r == 0); - r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read); + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); ASSERT(r == 0); ASSERT(exit_cb_called == 0); @@ -971,9 +972,9 @@ uv_pipe_init(uv_default_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[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[1].data.stream = (uv_stream_t*) &out; options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); @@ -985,10 +986,10 @@ r = uv_process_kill(&process, 0); ASSERT(r == 0); - r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); ASSERT(r == 0); - r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read); + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); ASSERT(r == 0); ASSERT(exit_cb_called == 0); @@ -1076,7 +1077,7 @@ ASSERT(r == 0); /* Kill the process. */ - r = uv_kill(process.pid, /* SIGTERM */ 15); + r = uv_kill(process.pid, SIGTERM); ASSERT(r == 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -1104,7 +1105,7 @@ options.stdio = stdio; options.stdio[0].flags = UV_IGNORE; options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio[1].data.stream = (uv_stream_t*) &out; options.stdio_count = 2; /* Create a pipe that'll cause a collision. */ @@ -1420,6 +1421,8 @@ 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 +1431,19 @@ 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; @@ -1461,6 +1472,8 @@ 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,11 +1482,15 @@ 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; @@ -1672,7 +1689,7 @@ */ #if defined(__APPLE__) static const char dyld_path_var[] = "DYLD_LIBRARY_PATH"; -#elif defined __MVS__ +#elif defined(__MVS__) || defined(__PASE__) static const char dyld_path_var[] = "LIBPATH"; #else static const char dyld_path_var[] = "LD_LIBRARY_PATH"; @@ -1804,32 +1821,32 @@ ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir); child_stdio[0].flags = UV_INHERIT_STREAM; - child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child; + child_stdio[0].data.stream = (uv_stream_t *) &pipe_stdin_child; child_stdio[1].flags = UV_INHERIT_STREAM; - child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child; + child_stdio[1].data.stream = (uv_stream_t *) &pipe_stdout_child; options.stdio = child_stdio; options.stdio_count = 2; ASSERT(uv_spawn(loop, &child_req, &options) == 0); - uv_close((uv_handle_t*)&pipe_stdin_child, NULL); - uv_close((uv_handle_t*)&pipe_stdout_child, NULL); + uv_close((uv_handle_t*) &pipe_stdin_child, NULL); + uv_close((uv_handle_t*) &pipe_stdout_child, NULL); - buf = uv_buf_init((char*)ubuf, sizeof ubuf); + buf = uv_buf_init((char*) ubuf, sizeof ubuf); for (i = 0; i < sizeof ubuf; ++i) ubuf[i] = i & 255u; memset(output, 0, sizeof ubuf); r = uv_write(&write_req, - (uv_stream_t*)&pipe_stdin_parent, + (uv_stream_t*) &pipe_stdin_parent, &buf, 1, write_cb); ASSERT(r == 0); - r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read); + r = uv_read_start((uv_stream_t*) &pipe_stdout_parent, on_alloc, on_read); ASSERT(r == 0); r = uv_run(loop, UV_RUN_DEFAULT); diff -Nru libuv1-1.34.2/test/test-stdio-over-pipes.c libuv1-1.40.0/test/test-stdio-over-pipes.c --- libuv1-1.34.2/test/test-stdio-over-pipes.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-stdio-over-pipes.c 2020-09-25 00:34:43.000000000 +0000 @@ -94,7 +94,7 @@ } -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 @@ 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 @@ } -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 @@ 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 @@ 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 @@ 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 @@ 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, &stdout_pipe, 0); + r = uv_pipe_init(loop, &stdin_pipe2, 0); + ASSERT(r == 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_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*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2), + on_read_alloc, + on_pipe_read); + ASSERT(r == 0); - uv_ref((uv_handle_t*)&stdout_pipe); - uv_ref((uv_handle_t*)&stdin_pipe); + uv_run(loop, UV_RUN_DEFAULT); - r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); - ASSERT(r == 0); + 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 -Nru libuv1-1.34.2/test/test-tcp-connect-timeout.c libuv1-1.40.0/test/test-tcp-connect-timeout.c --- libuv1-1.34.2/test/test-tcp-connect-timeout.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-tcp-connect-timeout.c 2020-09-25 00:34:43.000000000 +0000 @@ -89,3 +89,108 @@ MAKE_VALGRIND_HAPPY(); return 0; } + +/* Make sure connect fails instantly if the target is nonexisting + * local port. + */ + +static void connect_local_cb(uv_connect_t* req, int status) { + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_NE(status, UV_ECANCELED); + connect_cb_called++; +} + +static int is_supported_system(void) { + int semver[3]; + int min_semver[3] = {10, 0, 16299}; + int cnt; + uv_utsname_t uname; + ASSERT_EQ(uv_os_uname(&uname), 0); + if (strcmp(uname.sysname, "Windows_NT") == 0) { + cnt = sscanf(uname.release, "%d.%d.%d", &semver[0], &semver[1], &semver[2]); + if (cnt != 3) { + return 0; + } + // relase >= 10.0.16299 + for (cnt = 0; cnt < 3; ++cnt) { + if (semver[cnt] > min_semver[cnt]) + return 1; + if (semver[cnt] < min_semver[cnt]) + return 0; + } + return 1; + } + return 1; +} + +TEST_IMPL(tcp_local_connect_timeout) { + struct sockaddr_in addr; + int r; + + if (!is_supported_system()) { + RETURN_SKIP("Unsupported system"); + } + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT_EQ(r, 0); + + /* Give it 1s to timeout. */ + r = uv_timer_start(&timer, timer_cb, 1000, 0); + ASSERT_EQ(r, 0); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT_EQ(r, 0); + + r = uv_tcp_connect(&connect_req, + &conn, + (const struct sockaddr*) &addr, + connect_local_cb); + if (r == UV_ENETUNREACH) + RETURN_SKIP("Network unreachable."); + ASSERT_EQ(r, 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tcp6_local_connect_timeout) { + struct sockaddr_in6 addr; + int r; + + if (!is_supported_system()) { + RETURN_SKIP("Unsupported system"); + } + if (!can_ipv6()) { + RETURN_SKIP("IPv6 not supported"); + } + + ASSERT_EQ(0, uv_ip6_addr("::1", 9999, &addr)); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT_EQ(r, 0); + + /* Give it 1s to timeout. */ + r = uv_timer_start(&timer, timer_cb, 1000, 0); + ASSERT_EQ(r, 0); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT_EQ(r, 0); + + r = uv_tcp_connect(&connect_req, + &conn, + (const struct sockaddr*) &addr, + connect_local_cb); + if (r == UV_ENETUNREACH) + RETURN_SKIP("Network unreachable."); + ASSERT_EQ(r, 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT_EQ(r, 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff -Nru libuv1-1.34.2/test/test-tcp-read-stop-start.c libuv1-1.40.0/test/test-tcp-read-stop-start.c --- libuv1-1.34.2/test/test-tcp-read-stop-start.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-tcp-read-stop-start.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,136 @@ +/* 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" + +static uv_tcp_t server; +static uv_tcp_t connection; +static int read_cb_called = 0; + +static uv_tcp_t client; +static uv_connect_t connect_req; + + +static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); + +static void on_write_close_immediately(uv_write_t* req, int status) { + ASSERT(0 == status); + + uv_close((uv_handle_t*)req->handle, NULL); /* Close immediately */ + free(req); +} + +static void on_write(uv_write_t* req, int status) { + ASSERT(0 == status); + + free(req); +} + +static void do_write(uv_stream_t* stream, uv_write_cb cb) { + uv_write_t* req = malloc(sizeof(*req)); + uv_buf_t buf; + buf.base = "1234578"; + buf.len = 8; + ASSERT(0 == uv_write(req, stream, &buf, 1, cb)); +} + +static void on_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void on_read1(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + ASSERT(nread >= 0); + + /* Do write on a half open connection to force WSAECONNABORTED (on Windows) + * in the subsequent uv_read_start() + */ + do_write(stream, on_write); + + ASSERT(0 == uv_read_stop(stream)); + + ASSERT(0 == uv_read_start(stream, on_alloc, on_read2)); + + read_cb_called++; +} + +static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + ASSERT(nread < 0); + + uv_close((uv_handle_t*)stream, NULL); + uv_close((uv_handle_t*)&server, NULL); + + read_cb_called++; +} + +static void on_connection(uv_stream_t* server, int status) { + ASSERT(0 == status); + + ASSERT(0 == uv_tcp_init(server->loop, &connection)); + + ASSERT(0 == uv_accept(server, (uv_stream_t* )&connection)); + + ASSERT(0 == uv_read_start((uv_stream_t*)&connection, on_alloc, on_read1)); +} + +static void on_connect(uv_connect_t* req, int status) { + ASSERT(0 == status); + + do_write((uv_stream_t*)&client, on_write_close_immediately); +} + +TEST_IMPL(tcp_read_stop_start) { + uv_loop_t* loop = uv_default_loop(); + + { /* Server */ + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(loop, &server)); + + ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) & addr, 0)); + + ASSERT(0 == uv_listen((uv_stream_t*)&server, 10, on_connection)); + } + + { /* Client */ + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(loop, &client)); + + ASSERT(0 == uv_tcp_connect(&connect_req, &client, + (const struct sockaddr*) & addr, on_connect)); + } + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(read_cb_called >= 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff -Nru libuv1-1.34.2/test/test-tcp-write-after-connect.c libuv1-1.40.0/test/test-tcp-write-after-connect.c --- libuv1-1.34.2/test/test-tcp-write-after-connect.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-tcp-write-after-connect.c 2020-09-25 00:34:43.000000000 +0000 @@ -43,6 +43,11 @@ TEST_IMPL(tcp_write_after_connect) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + struct sockaddr_in sa; ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); ASSERT(0 == uv_loop_init(&loop)); diff -Nru libuv1-1.34.2/test/test-test-macros.c libuv1-1.40.0/test/test-test-macros.c --- libuv1-1.34.2/test/test-test-macros.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-test-macros.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,42 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" + +int test_macros_evil(void) { + static int x; + return x++; +} + + +TEST_IMPL(test_macros) { + char* a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char* b = "ABCDEFGHIJKLMNOPQRSTUVWXYz"; + char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + i = test_macros_evil(); + ASSERT_STR_NE(a, b); + ASSERT_STR_EQ(a, c); + ASSERT_EQ(i + 1, test_macros_evil()); + ASSERT_EQ(i + 2, test_macros_evil()); + return 0; +} diff -Nru libuv1-1.34.2/test/test-thread.c libuv1-1.40.0/test/test-thread.c --- libuv1-1.34.2/test/test-thread.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-thread.c 2020-09-25 00:34:43.000000000 +0000 @@ -78,6 +78,10 @@ static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif struct getaddrinfo_req* req; ASSERT(status == 0); @@ -163,6 +167,11 @@ * that each "finished" callback is run in its originating thread. */ TEST_IMPL(threadpool_multiple_event_loops) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + struct test_thread threads[8]; size_t i; int r; diff -Nru libuv1-1.34.2/test/test-timer.c libuv1-1.40.0/test/test-timer.c --- libuv1-1.34.2/test/test-timer.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-timer.c 2020-09-25 00:34:43.000000000 +0000 @@ -161,6 +161,7 @@ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); ASSERT(0 == uv_timer_get_repeat(&handle)); + ASSERT_UINT64_LE(0, uv_timer_get_due_in(&handle)); ASSERT(0 == uv_is_active((uv_handle_t*) &handle)); MAKE_VALGRIND_HAPPY(); @@ -232,6 +233,9 @@ ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0)); ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0)); ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0)); + ASSERT_UINT64_EQ(1, uv_timer_get_due_in(&tiny_timer)); + ASSERT_UINT64_EQ(281474976710655, uv_timer_get_due_in(&huge_timer1)); + ASSERT_UINT64_LE(0, uv_timer_get_due_in(&huge_timer2)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(); return 0; diff -Nru libuv1-1.34.2/test/test-tmpdir.c libuv1-1.40.0/test/test-tmpdir.c --- libuv1-1.34.2/test/test-tmpdir.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-tmpdir.c 2020-09-25 00:34:43.000000000 +0000 @@ -23,7 +23,7 @@ #include "task.h" #include -#define PATHMAX 1024 +#define PATHMAX 4096 #define SMALLPATH 1 TEST_IMPL(tmpdir) { diff -Nru libuv1-1.34.2/test/test-tty.c libuv1-1.40.0/test/test-tty.c --- libuv1-1.34.2/test/test-tty.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-tty.c 2020-09-25 00:34:43.000000000 +0000 @@ -360,6 +360,8 @@ if (fd != -1) { ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); ASSERT(0 == close(fd)); + /* test EBADF handling */ + ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); } /* Bug on AIX where '/dev/random' returns 1 from isatty() */ @@ -420,6 +422,11 @@ } TEST_IMPL(tty_pty) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + #if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ diff -Nru libuv1-1.34.2/test/test-tty-escape-sequence-processing.c libuv1-1.40.0/test/test-tty-escape-sequence-processing.c --- libuv1-1.34.2/test/test-tty-escape-sequence-processing.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-tty-escape-sequence-processing.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 -Nru libuv1-1.34.2/test/test-udp-connect.c libuv1-1.40.0/test/test-udp-connect.c --- libuv1-1.34.2/test/test-udp-connect.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-connect.c 2020-09-25 00:34:43.000000000 +0000 @@ -98,6 +98,10 @@ 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; @@ -120,6 +124,17 @@ buf = uv_buf_init("EXIT", 4); + // connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &tmp_addr)); + r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); +#ifdef _WIN32 + ASSERT_EQ(r, UV_EADDRNOTAVAIL); +#else + ASSERT_EQ(r, 0); + r = uv_udp_connect(&client, NULL); + ASSERT_EQ(r, 0); +#endif + ASSERT(0 == uv_ip4_addr("8.8.8.8", TEST_PORT, &ext_addr)); ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &lo_addr)); diff -Nru libuv1-1.34.2/test/test-udp-ipv6.c libuv1-1.40.0/test/test-udp-ipv6.c --- libuv1-1.34.2/test/test-udp-ipv6.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-ipv6.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 -Nru libuv1-1.34.2/test/test-udp-mmsg.c libuv1-1.40.0/test/test-udp-mmsg.c --- libuv1-1.34.2/test/test-udp-mmsg.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-mmsg.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,142 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &recver || (uv_udp_t*)(handle) == &sender) + +#define BUFFER_MULTIPLIER 4 +#define MAX_DGRAM_SIZE (64 * 1024) +#define NUM_SENDS 8 +#define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER) + +static uv_udp_t recver; +static uv_udp_t sender; +static int recv_cb_called; +static int close_cb_called; +static int alloc_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + size_t buffer_size; + CHECK_HANDLE(handle); + + /* Only allocate enough room for multiple dgrams if we can actually recv them */ + buffer_size = MAX_DGRAM_SIZE; + if (uv_udp_using_recvmmsg((uv_udp_t*)handle)) + buffer_size *= BUFFER_MULTIPLIER; + + /* Actually malloc to exercise free'ing the buffer later */ + buf->base = malloc(buffer_size); + ASSERT(buf->base != NULL); + buf->len = buffer_size; + alloc_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(uv_is_closing(handle)); + close_cb_called++; +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + ASSERT_GE(nread, 0); + + /* free and return if this is a mmsg free-only callback invocation */ + if (flags & UV_UDP_MMSG_FREE) { + ASSERT_EQ(nread, 0); + ASSERT(addr == NULL); + free(rcvbuf->base); + return; + } + + ASSERT_EQ(nread, 4); + ASSERT(addr != NULL); + ASSERT_MEM_EQ("PING", rcvbuf->base, nread); + + recv_cb_called++; + if (recv_cb_called == NUM_SENDS) { + uv_close((uv_handle_t*)handle, close_cb); + uv_close((uv_handle_t*)&sender, close_cb); + } + + /* Don't free if the buffer could be reused via mmsg */ + if (rcvbuf && !(flags & UV_UDP_MMSG_CHUNK)) + free(rcvbuf->base); +} + + +TEST_IMPL(udp_mmsg) { + struct sockaddr_in addr; + uv_buf_t buf; + int i; + + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT_EQ(0, uv_udp_init_ex(uv_default_loop(), &recver, + AF_UNSPEC | UV_UDP_RECVMMSG)); + + ASSERT_EQ(0, uv_udp_bind(&recver, (const struct sockaddr*) &addr, 0)); + + ASSERT_EQ(0, uv_udp_recv_start(&recver, alloc_cb, recv_cb)); + + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &sender)); + + buf = uv_buf_init("PING", 4); + for (i = 0; i < NUM_SENDS; i++) { + ASSERT_EQ(4, uv_udp_try_send(&sender, &buf, 1, (const struct sockaddr*) &addr)); + } + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(close_cb_called, 2); + ASSERT_EQ(recv_cb_called, NUM_SENDS); + + ASSERT_EQ(sender.send_queue_size, 0); + ASSERT_EQ(recver.send_queue_size, 0); + + printf("%d allocs for %d recvs\n", alloc_cb_called, recv_cb_called); + + /* On platforms that don't support mmsg, each recv gets its own alloc */ + if (uv_udp_using_recvmmsg(&recver)) + ASSERT_EQ(alloc_cb_called, EXPECTED_MMSG_ALLOCS); + else + ASSERT_EQ(alloc_cb_called, recv_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff -Nru libuv1-1.34.2/test/test-udp-multicast-interface6.c libuv1-1.40.0/test/test-udp-multicast-interface6.c --- libuv1-1.34.2/test/test-udp-multicast-interface6.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-multicast-interface6.c 2020-09-25 00:34:43.000000000 +0000 @@ -54,6 +54,11 @@ TEST_IMPL(udp_multicast_interface6) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; uv_udp_send_t req; uv_buf_t buf; diff -Nru libuv1-1.34.2/test/test-udp-multicast-interface.c libuv1-1.40.0/test/test-udp-multicast-interface.c --- libuv1-1.34.2/test/test-udp-multicast-interface.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-multicast-interface.c 2020-09-25 00:34:43.000000000 +0000 @@ -54,6 +54,11 @@ TEST_IMPL(udp_multicast_interface) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + int r; uv_udp_send_t req; uv_buf_t buf; diff -Nru libuv1-1.34.2/test/test-udp-multicast-join6.c libuv1-1.40.0/test/test-udp-multicast-join6.c --- libuv1-1.34.2/test/test-udp-multicast-join6.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-multicast-join6.c 2020-09-25 00:34:43.000000000 +0000 @@ -193,6 +193,10 @@ ASSERT(r == 0); +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); ASSERT(r == 0); diff -Nru libuv1-1.34.2/test/test-udp-options.c libuv1-1.40.0/test/test-udp-options.c --- libuv1-1.34.2/test/test-udp-options.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-options.c 2020-09-25 00:34:43.000000000 +0000 @@ -128,12 +128,16 @@ ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); #endif ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1)); +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0")); uv_close((uv_handle_t*) &h, NULL); /* Test a non-lazily initialized socket. */ - ASSERT(0 == uv_udp_init_ex(loop, &h2, AF_INET)); + ASSERT(0 == uv_udp_init_ex(loop, &h2, AF_INET | UV_UDP_RECVMMSG)); ASSERT(0 == uv_udp_set_multicast_ttl(&h2, 32)); ASSERT(0 == uv_udp_set_broadcast(&h2, 1)); diff -Nru libuv1-1.34.2/test/test-udp-sendmmsg-error.c libuv1-1.40.0/test/test-udp-sendmmsg-error.c --- libuv1-1.34.2/test/test-udp-sendmmsg-error.c 1970-01-01 00:00:00.000000000 +0000 +++ libuv1-1.40.0/test/test-udp-sendmmsg-error.c 2020-09-25 00:34:43.000000000 +0000 @@ -0,0 +1,75 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +#define DATAGRAMS 6 + +static uv_udp_t client; +static uv_udp_send_t req[DATAGRAMS]; + +static int send_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + ASSERT_PTR_EQ(handle, &client); + ASSERT(uv_is_closing(handle)); + close_cb_called++; +} + + +static void send_cb(uv_udp_send_t* req, int status) { + if (status != 0) + ASSERT_EQ(status, UV_ECONNREFUSED); + + if (++send_cb_called == DATAGRAMS) + uv_close((uv_handle_t*)&client, close_cb); +} + + +TEST_IMPL(udp_sendmmsg_error) { + struct sockaddr_in addr; + uv_buf_t buf; + int i; + + ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &client)); + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_EQ(0, uv_udp_connect(&client, (const struct sockaddr*)&addr)); + + buf = uv_buf_init("TEST", 4); + for (i = 0; i < DATAGRAMS; ++i) + ASSERT_EQ(0, uv_udp_send(&req[i], &client, &buf, 1, NULL, send_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(1, close_cb_called); + ASSERT_EQ(DATAGRAMS, send_cb_called); + + ASSERT_EQ(0, client.send_queue_size); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff -Nru libuv1-1.34.2/test/test-watcher-cross-stop.c libuv1-1.40.0/test/test-watcher-cross-stop.c --- libuv1-1.34.2/test/test-watcher-cross-stop.c 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/test/test-watcher-cross-stop.c 2020-09-25 00:34:43.000000000 +0000 @@ -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 -Nru libuv1-1.34.2/uv.gyp libuv1-1.40.0/uv.gyp --- libuv1-1.34.2/uv.gyp 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/uv.gyp 1970-01-01 00:00:00.000000000 +0000 @@ -1,368 +0,0 @@ -{ - 'variables': { - 'conditions': [ - ['OS=="win"', { - 'shared_unix_defines': [ ], - }, { - 'shared_unix_defines': [ - '_LARGEFILE_SOURCE', - '_FILE_OFFSET_BITS=64', - ], - }], - ['OS in "mac ios"', { - 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], - }, { - 'shared_mac_defines': [ ], - }], - ['OS=="zos"', { - 'shared_zos_defines': [ - '_UNIX03_THREADS', - '_UNIX03_SOURCE', - '_UNIX03_WITHDRAWN', - '_OPEN_SYS_IF_EXT', - '_OPEN_SYS_SOCK_EXT3', - '_OPEN_SYS_SOCK_IPV6', - '_OPEN_MSGQ_EXT', - '_XOPEN_SOURCE_EXTENDED', - '_ALL_SOURCE', - '_LARGE_TIME_API', - '_OPEN_SYS_FILE_EXT', - '_AE_BIMODAL', - 'PATH_MAX=255' - ], - }, { - 'shared_zos_defines': [ ], - }], - ], - }, - - 'targets': [ - { - 'target_name': 'libuv', - 'type': '<(uv_library)', - 'include_dirs': [ - 'include', - 'src/', - ], - 'defines': [ - '<@(shared_mac_defines)', - '<@(shared_unix_defines)', - '<@(shared_zos_defines)', - ], - 'direct_dependent_settings': { - 'defines': [ - '<@(shared_mac_defines)', - '<@(shared_unix_defines)', - '<@(shared_zos_defines)', - ], - 'include_dirs': [ 'include' ], - 'conditions': [ - ['OS == "linux"', { - 'defines': [ '_POSIX_C_SOURCE=200112' ], - }], - ], - }, - 'sources': [ - 'common.gypi', - 'include/uv.h', - 'include/uv/tree.h', - 'include/uv/errno.h', - 'include/uv/threadpool.h', - 'include/uv/version.h', - 'src/fs-poll.c', - 'src/heap-inl.h', - 'src/idna.c', - 'src/idna.h', - 'src/inet.c', - 'src/queue.h', - 'src/random.c', - 'src/strscpy.c', - 'src/strscpy.h', - 'src/threadpool.c', - 'src/timer.c', - 'src/uv-data-getter-setters.c', - 'src/uv-common.c', - 'src/uv-common.h', - 'src/version.c' - ], - 'xcode_settings': { - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'WARNING_CFLAGS': [ - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - 'OTHER_CFLAGS': [ '-g', '--std=gnu89' ], - }, - 'conditions': [ - [ 'OS=="win"', { - 'defines': [ - '_WIN32_WINNT=0x0600', - '_GNU_SOURCE', - ], - 'sources': [ - 'include/uv/win.h', - 'src/win/async.c', - 'src/win/atomicops-inl.h', - 'src/win/core.c', - 'src/win/detect-wakeup.c', - 'src/win/dl.c', - 'src/win/error.c', - 'src/win/fs.c', - 'src/win/fs-event.c', - 'src/win/getaddrinfo.c', - 'src/win/getnameinfo.c', - 'src/win/handle.c', - 'src/win/handle-inl.h', - 'src/win/internal.h', - 'src/win/loop-watcher.c', - 'src/win/pipe.c', - 'src/win/thread.c', - 'src/win/poll.c', - 'src/win/process.c', - 'src/win/process-stdio.c', - 'src/win/req-inl.h', - 'src/win/signal.c', - 'src/win/snprintf.c', - 'src/win/stream.c', - 'src/win/stream-inl.h', - 'src/win/tcp.c', - 'src/win/tty.c', - 'src/win/udp.c', - 'src/win/util.c', - 'src/win/winapi.c', - 'src/win/winapi.h', - 'src/win/winsock.c', - 'src/win/winsock.h', - ], - 'link_settings': { - 'libraries': [ - '-ladvapi32', - '-liphlpapi', - '-lpsapi', - '-lshell32', - '-luser32', - '-luserenv', - '-lws2_32' - ], - }, - }, { # Not Windows i.e. POSIX - 'sources': [ - 'include/uv/unix.h', - 'include/uv/linux.h', - 'include/uv/sunos.h', - 'include/uv/darwin.h', - 'include/uv/bsd.h', - 'include/uv/aix.h', - 'src/unix/async.c', - 'src/unix/atomic-ops.h', - 'src/unix/core.c', - 'src/unix/dl.c', - 'src/unix/fs.c', - 'src/unix/getaddrinfo.c', - 'src/unix/getnameinfo.c', - 'src/unix/internal.h', - 'src/unix/loop.c', - 'src/unix/loop-watcher.c', - 'src/unix/pipe.c', - 'src/unix/poll.c', - 'src/unix/process.c', - 'src/unix/random-devurandom.c', - 'src/unix/signal.c', - 'src/unix/spinlock.h', - 'src/unix/stream.c', - 'src/unix/tcp.c', - 'src/unix/thread.c', - 'src/unix/tty.c', - 'src/unix/udp.c', - ], - 'link_settings': { - 'libraries': [ '-lm' ], - 'conditions': [ - ['OS=="solaris"', { - 'ldflags': [ '-pthreads' ], - }], - [ 'OS=="zos" and uv_library=="shared_library"', { - 'ldflags': [ '-Wl,DLL' ], - }], - ['OS != "solaris" and OS != "android" and OS != "zos"', { - 'ldflags': [ '-pthread' ], - }], - ], - }, - 'conditions': [ - ['uv_library=="shared_library"', { - 'conditions': [ - ['OS=="zos"', { - 'cflags': [ '-qexportall' ], - }, { - 'cflags': [ '-fPIC' ], - }], - ], - }], - ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { - # This will cause gyp to set soname - # Must correspond with UV_VERSION_MAJOR - # in include/uv/version.h - 'product_extension': 'so.1', - }], - ], - }], - [ 'OS in "linux mac ios android zos"', { - 'sources': [ 'src/unix/proctitle.c' ], - }], - [ 'OS != "zos"', { - 'cflags': [ - '-fvisibility=hidden', - '-g', - '--std=gnu89', - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - }], - [ 'OS in "mac ios"', { - 'sources': [ - 'src/unix/darwin.c', - 'src/unix/fsevents.c', - 'src/unix/darwin-proctitle.c', - 'src/unix/random-getentropy.c', - ], - 'defines': [ - '_DARWIN_USE_64_BIT_INODE=1', - '_DARWIN_UNLIMITED_SELECT=1', - ] - }], - [ 'OS=="linux"', { - 'defines': [ '_GNU_SOURCE' ], - 'sources': [ - 'src/unix/linux-core.c', - 'src/unix/linux-inotify.c', - 'src/unix/linux-syscalls.c', - 'src/unix/linux-syscalls.h', - 'src/unix/procfs-exepath.c', - 'src/unix/random-getrandom.c', - 'src/unix/random-sysctl-linux.c', - 'src/unix/sysinfo-loadavg.c', - ], - 'link_settings': { - 'libraries': [ '-ldl', '-lrt' ], - }, - }], - [ 'OS=="android"', { - 'sources': [ - 'src/unix/linux-core.c', - 'src/unix/linux-inotify.c', - 'src/unix/linux-syscalls.c', - 'src/unix/linux-syscalls.h', - 'src/unix/pthread-fixes.c', - 'src/unix/android-ifaddrs.c', - 'src/unix/procfs-exepath.c', - 'src/unix/random-getrandom.c', - 'src/unix/random-sysctl-linux.c', - 'src/unix/sysinfo-loadavg.c', - ], - 'link_settings': { - 'libraries': [ '-ldl' ], - }, - }], - [ 'OS=="solaris"', { - 'sources': [ - 'src/unix/no-proctitle.c', - 'src/unix/sunos.c', - ], - 'defines': [ - '__EXTENSIONS__', - '_XOPEN_SOURCE=500', - ], - 'link_settings': { - 'libraries': [ - '-lkstat', - '-lnsl', - '-lsendfile', - '-lsocket', - ], - }, - }], - [ 'OS=="aix"', { - 'variables': { - 'os_name': ' + + + + true + + + diff -Nru libuv1-1.34.2/vcbuild.bat libuv1-1.40.0/vcbuild.bat --- libuv1-1.34.2/vcbuild.bat 2020-01-23 14:20:02.000000000 +0000 +++ libuv1-1.40.0/vcbuild.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -@echo off - -cd %~dp0 - -if /i "%1"=="help" goto help -if /i "%1"=="--help" goto help -if /i "%1"=="-help" goto help -if /i "%1"=="/help" goto help -if /i "%1"=="?" goto help -if /i "%1"=="-?" goto help -if /i "%1"=="--?" goto help -if /i "%1"=="/?" goto help - -@rem Process arguments. -set config= -set target=Build -set target_arch=ia32 -set target_env= -set noprojgen= -set nobuild= -set run= -set vs_toolset=x86 -set msbuild_platform=WIN32 -set library=static_library - -:next-arg -if "%1"=="" goto args-done -if /i "%1"=="debug" set config=Debug&goto arg-ok -if /i "%1"=="release" set config=Release&goto arg-ok -if /i "%1"=="test" set run=run-tests.exe&goto arg-ok -if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok -if /i "%1"=="clean" set target=Clean&goto arg-ok -if /i "%1"=="vs2017" set target_env=vs2017&goto arg-ok -if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok -if /i "%1"=="nobuild" set nobuild=1&goto arg-ok -if /i "%1"=="x86" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="ia32" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="x64" set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64&goto arg-ok -if /i "%1"=="shared" set library=shared_library&goto arg-ok -if /i "%1"=="static" set library=static_library&goto arg-ok -:arg-ok -shift -goto next-arg -:args-done - -if defined WindowsSDKDir goto select-target -if defined VCINSTALLDIR goto select-target - -@rem Look for Visual Studio 2017 only if explicitly requested. -if "%target_env%" NEQ "vs2017" goto vs-set-2015 -echo Looking for Visual Studio 2017 -@rem Check if VS2017 is already setup, and for the requested arch. -if "_%VisualStudioVersion%_" == "_15.0_" if "_%VSCMD_ARG_TGT_ARCH%_"=="_%vs_toolset%_" goto found_vs2017 -set "VSINSTALLDIR=" -call tools\vswhere_usability_wrapper.cmd -if "_%VCINSTALLDIR%_" == "__" goto vs-set-2015 -@rem Need to clear VSINSTALLDIR for vcvarsall to work as expected. -@rem Keep current working directory after call to vcvarsall -set "VSCMD_START_DIR=%CD%" -set vcvars_call="%VCINSTALLDIR%\Auxiliary\Build\vcvarsall.bat" %vs_toolset% -echo calling: %vcvars_call% -call %vcvars_call% - -:found_vs2017 -echo Found MSVS version %VisualStudioVersion% -if %VSCMD_ARG_TGT_ARCH%==x64 set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64 -set GYP_MSVS_VERSION=2017 -goto select-target - - -@rem Look for Visual Studio 2015 -:vs-set-2015 -if not defined VS140COMNTOOLS goto vc-set-2013 -if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013 -call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% -set GYP_MSVS_VERSION=2015 -echo Using Visual Studio 2015 -goto select-target - -:vc-set-2013 -@rem Look for Visual Studio 2013 -if not defined VS120COMNTOOLS goto vc-set-2012 -if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 -call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% -set GYP_MSVS_VERSION=2013 -echo Using Visual Studio 2013 -goto select-target - -:vc-set-2012 -@rem Look for Visual Studio 2012 -if not defined VS110COMNTOOLS goto vc-set-2010 -if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 -call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% -set GYP_MSVS_VERSION=2012 -echo Using Visual Studio 2012 -goto select-target - -:vc-set-2010 -@rem Look for Visual Studio 2010 -if not defined VS100COMNTOOLS goto vc-set-2008 -if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008 -call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% -set GYP_MSVS_VERSION=2010 -echo Using Visual Studio 2010 -goto select-target - -:vc-set-2008 -@rem Look for Visual Studio 2008 -if not defined VS90COMNTOOLS goto vc-set-notfound -if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound -call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% -set GYP_MSVS_VERSION=2008 -echo Using Visual Studio 2008 -goto select-target - -:vc-set-notfound -echo Warning: Visual Studio not found - -:select-target -if not "%config%"=="" goto project-gen -if "%run%"=="run-tests.exe" set config=Debug& goto project-gen -if "%run%"=="run-benchmarks.exe" set config=Release& goto project-gen -set config=Debug - -:project-gen -@rem Skip project generation if requested. -if defined noprojgen goto msbuild - -@rem Generate the VS project. -if exist build\gyp goto have_gyp -echo git clone https://chromium.googlesource.com/external/gyp build/gyp -git clone https://chromium.googlesource.com/external/gyp build/gyp -if errorlevel 1 goto gyp_install_failed -goto have_gyp - -:gyp_install_failed -echo Failed to download gyp. Make sure you have git installed, or -echo manually install gyp into %~dp0build\gyp. -exit /b 1 - -:have_gyp -if not defined PYTHON set PYTHON=python -"%PYTHON%" gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library% -if errorlevel 1 goto create-msvs-files-failed -if not exist uv.sln goto create-msvs-files-failed -echo Project files generated. - -:msbuild -@rem Skip project generation if requested. -if defined nobuild goto run - -@rem Check if VS build env is available -if defined VCINSTALLDIR goto msbuild-found -if defined WindowsSDKDir goto msbuild-found -echo Build skipped. To build, this file needs to run from VS cmd prompt. -goto run - -@rem Build the sln with msbuild. -:msbuild-found -msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo -if errorlevel 1 exit /b 1 -msbuild test\test.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo -if errorlevel 1 exit /b 1 - -:run -@rem Run tests if requested. -if "%run%"=="" goto exit -echo running 'test\%config%\%run%' -test\%config%\%run% -goto exit - -:create-msvs-files-failed -echo Failed to create vc project files. -exit /b 1 - -:help -echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] -echo Examples: -echo vcbuild.bat : builds debug build -echo vcbuild.bat test : builds debug build and runs tests -echo vcbuild.bat release bench: builds release build and runs benchmarks -goto exit - -:exit