libuv 1.44.2

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3934 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-07-24 21:25:38 +00:00
parent 41afc3bdd6
commit f06753b56e
67 changed files with 2148 additions and 764 deletions

View File

@ -0,0 +1,32 @@
name: ci-sample
on:
pull_request:
paths:
- '**'
- '!docs/**'
- '!.**'
- '.github/workflows/CI-sample.yml'
push:
branches:
- v[0-9].*
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: setup
run: cmake -E make_directory ${{runner.workspace}}/libuv/docs/code/build
- name: configure
# you may like use Ninja on unix-like OS, but for windows, the only easy way is to use Visual Studio if you want Ninja
run: cmake ..
working-directory: ${{runner.workspace}}/libuv/docs/code/build
- name: build
run: cmake --build .
working-directory: ${{runner.workspace}}/libuv/docs/code/build

129
deps/libuv/.github/workflows/CI-unix.yml vendored Normal file
View File

@ -0,0 +1,129 @@
name: CI-unix
on:
pull_request:
paths:
- '**'
- '!docs/**'
- '!src/win/**'
- '!.**'
- '.github/workflows/CI-unix.yml'
push:
branches:
- v[0-9].*
- master
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: Configure 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-24 ..
- name: Build android arm64
run: |
$ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build build
ls -lh build
build-macos:
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
- name: Envinfo
run: npx envinfo
- name: Setup
run: |
brew install ninja
- name: Configure
run: |
mkdir build
cd build
cmake .. -DBUILD_TESTING=ON -G Ninja
- name: Build
run: |
cmake --build build
ls -lh
- name: platform_output
run: |
./build/uv_run_tests platform_output
- name: platform_output_a
run: |
./build/uv_run_tests_a platform_output
- name: Test
run: |
cd build && ctest -V
build-ios:
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
- name: Configure
run: |
mkdir build-ios
cd build-ios
cmake .. -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DCMAKE_CONFIGURATION_TYPES:STRING=Release
- name: Build
run: |
cmake --build build-ios
ls -lh build-ios
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: Configure with ${{ matrix.config.cc }}
run: |
mkdir build
cd build
cmake .. -DBUILD_TESTING=ON -DQEMU=ON -DCMAKE_C_COMPILER=${{ matrix.config.cc }}
- name: Build
run: |
cmake --build build
ls -lh build
- name: Test
run: |
${{ matrix.config.qemu }} build/uv_run_tests_a

51
deps/libuv/.github/workflows/CI-win.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: CI-win
on:
pull_request:
paths:
- '**'
- '!docs/**'
- '!src/unix/**'
- '!.**'
- '.github/workflows/CI-win.yml'
push:
branches:
- v[0-9].*
- master
jobs:
build-windows:
runs-on: windows-${{ matrix.config.server }}
name: build-${{ matrix.config.toolchain}}-${{ matrix.config.arch}}
strategy:
fail-fast: false
matrix:
config:
- {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019}
- {toolchain: Visual Studio 16 2019, arch: x64, server: 2019}
- {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022}
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022}
steps:
- uses: actions/checkout@v2
- name: Envinfo
run: npx envinfo
- name: Build
shell: cmd
run: |
mkdir -p build
cd build
cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }}
cmake --build .
- name: platform_output
shell: cmd
run: |
build\\Debug\\uv_run_tests.exe platform_output
- name: platform_output_a
shell: cmd
run: |
build\\Debug\\uv_run_tests_a.exe platform_output
- name: Test
shell: cmd
run: |
cd build
ctest -C Debug -V

View File

@ -1,6 +1,16 @@
name: Sanitizer checks
on: [push, pull_request]
on:
pull_request:
paths:
- '**'
- '!docs/**'
- '!.**'
- '.github/workflows/sanitizer.yml'
push:
branches:
- v[0-9].*
- master
jobs:
sanitizers:
@ -12,15 +22,20 @@ jobs:
sudo apt-get install ninja-build
- name: Envinfo
run: npx envinfo
- name: TSAN
- name: TSAN Build
run: |
mkdir build-tsan
(cd build-tsan && cmake .. -G Ninja -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release)
cmake --build build-tsan
./build-tsan/uv_run_tests_a || true # currently permit failures
- name: ASAN
- name: TSAN Test
continue-on-error: true # currently permit failures
run: |
./build-tsan/uv_run_tests_a
- name: ASAN Build
run: |
mkdir build-asan
(cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug)
cmake --build build-asan
- name: ASAN Test
run: |
./build-asan/uv_run_tests_a

9
deps/libuv/AUTHORS vendored
View File

@ -508,3 +508,12 @@ Paul Evans <leonerd@leonerd.org.uk>
wyckster <wyckster@hotmail.com>
Vittore F. Scolari <vittore.scolari@gmail.com>
roflcopter4 <15476346+roflcopter4@users.noreply.github.com>
V-for-Vasili <vasili.skurydzin@protonmail.com>
Denny C. Dai <dennycd@me.com>
Hannah Shi <hannahshisfb@gmail.com>
tuftedocelot <tuftedocelot@fastmail.fm>
blogdaren <blogdaren@163.com>
chucksilvers <chuq@chuq.com>
Sergey Fedorov <vital.had@gmail.com>
theanarkh <2923878201@qq.com>
Samuel Cabrero <samuelcabrero@gmail.com>

View File

@ -125,6 +125,7 @@ set(uv_sources
src/inet.c
src/random.c
src/strscpy.c
src/strtok.c
src/threadpool.c
src/timer.c
src/uv-common.c
@ -269,6 +270,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "GNU")
src/unix/hurd.c)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD")
list(APPEND uv_defines _GNU_SOURCE)
list(APPEND uv_libraries dl freebsd-glue)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112)
list(APPEND uv_libraries dl rt)
@ -458,7 +464,6 @@ if(LIBUV_BUILD_TESTS)
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
@ -557,10 +562,12 @@ if(LIBUV_BUILD_TESTS)
test/test-spawn.c
test/test-stdio-over-pipes.c
test/test-strscpy.c
test/test-strtok.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-after-read-timeout.c
test/test-tcp-close-while-connecting.c
test/test-tcp-close.c
test/test-tcp-close-reset.c
@ -574,6 +581,7 @@ if(LIBUV_BUILD_TESTS)
test/test-tcp-open.c
test/test-tcp-read-stop.c
test/test-tcp-read-stop-start.c
test/test-tcp-rst.c
test/test-tcp-shutdown-after-write.c
test/test-tcp-try-write.c
test/test-tcp-try-write-error.c

130
deps/libuv/ChangeLog vendored
View File

@ -1,4 +1,132 @@
2022.03.09, Version 1.44.1 (Stable)
2022.07.12, Version 1.44.2 (Stable)
Changes since version 1.44.1:
* Add SHA to ChangeLog (Jameson Nash)
* aix, ibmi: handle server hang when remote sends TCP RST (V-for-Vasili)
* build: make CI a bit noisier (Jameson Nash)
* process: reset the signal mask if the fork fails (Jameson Nash)
* zos: implement cmpxchgi() using assembly (Shuowang (Wayne) Zhang)
* build: AC_SUBST for AM_CFLAGS (Claes Nästén)
* ibmi: Implement UDP disconnect (V-for-Vasili)
* doc: update active maintainers list (Ben Noordhuis)
* build: fix kFreeBSD build (James McCoy)
* build: remove Windows 2016 workflows (Darshan Sen)
* Revert "win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES" (Darshan Sen)
* unix: simplify getpwuid call (Jameson Nash)
* build: filter CI by paths and branches (Jameson Nash)
* build: add iOS to macos CI (Jameson Nash)
* build: re-enable CI for windows changes (Jameson Nash)
* process,iOS: fix build breakage in process.c (Denny C. Dai)
* test: remove unused declarations in tcp_rst test (V-for-Vasili)
* core: add thread-safe strtok implementation (Guilherme Íscaro)
* win: fix incompatible-types warning (twosee)
* test: fix flaky file watcher test (Ben Noordhuis)
* build: fix AIX xlc autotools build (V-for-Vasili)
* unix,win: fix UV_RUN_ONCE + uv_idle_stop loop hang (Ben Noordhuis)
* win: fix unexpected ECONNRESET error on TCP socket (twosee)
* doc: make sample cross-platform build (gengjiawen)
* test: separate some static variables by test cases (Hannah Shi)
* sunos: fs-event callback can be called after uv_close() (Andy Fiddaman)
* uv: re-register interest in a file after change (Shuowang (Wayne) Zhang)
* uv: register UV_RENAME event for _RFIM_UNLINK (Shuowang (Wayne) Zhang)
* uv: register __rfim_event 156 as UV_RENAME (Shuowang (Wayne) Zhang)
* doc: remove smartos from supported platforms (Ben Noordhuis)
* macos: avoid posix_spawnp() cwd bug (Jameson Nash)
* release: check versions of autogen scripts are newer (Jameson Nash)
* test: rewrite embed test (Ben Noordhuis)
* openbsd: use utimensat instead of lutimes (tuftedocelot)
* doc: fix link to uvwget example main() function (blogdaren)
* unix: use MSG_CMSG_CLOEXEC where supported (Ben Noordhuis)
* test: remove disabled callback_order test (Ben Noordhuis)
* win,pipe: fix bugs with pipe resource lifetime management (Jameson Nash)
* loop: better align order-of-events behavior between platforms (Jameson Nash)
* aix,test: uv_backend_fd is not supported by poll (V-for-Vasili)
* kqueue: skip EVFILT_PROC when invalidating fds (chucksilvers)
* darwin: fix atomic-ops.h ppc64 build (Sergey Fedorov)
* zos: don't err when killing a zombie process (Shuowang (Wayne) Zhang)
* zos: avoid fs event callbacks after uv_close() (Shuowang (Wayne) Zhang)
* zos: correctly format interface addresses names (Shuowang (Wayne) Zhang)
* zos: add uv_interface_addresses() netmask support (Shuowang (Wayne) Zhang)
* zos: improve memory management of ip addresses (Shuowang (Wayne) Zhang)
* tcp,pipe: fail `bind` or `listen` after `close` (theanarkh)
* zos: implement uv_available_parallelism() (Shuowang (Wayne) Zhang)
* udp,win: fix UDP compiler warning (Jameson Nash)
* zos: fix early exit of epoll_wait() (Shuowang (Wayne) Zhang)
* unix,tcp: fix errno handling in uv__tcp_bind() (Samuel Cabrero)
* shutdown,unix: reduce code duplication (Jameson Nash)
* unix: fix c99 comments (Ben Noordhuis)
* unix: retry tcgetattr/tcsetattr() on EINTR (Ben Noordhuis)
* docs: update introduction.rst (Ikko Ashimine)
* unix,stream: optimize uv_shutdown() codepath (Jameson Nash)
* zos: delay signal handling until after normal i/o (Shuowang (Wayne) Zhang)
* stream: uv__drain() always needs to stop POLLOUT (Jameson Nash)
* unix,tcp: allow EINVAL errno from setsockopt in uv_tcp_close_reset() (Stacey
Marshall)
* win,shutdown: improve how shutdown is dispatched (Jameson Nash)
2022.03.09, Version 1.44.1 (Stable), e8b7eb6908a847ffbe6ab2eec7428e43a0aa53a2
Changes since version 1.44.0:

View File

@ -1,10 +1,7 @@
# Project Maintainers
libuv is currently managed by the following individuals:
* **Anna Henningsen** ([@addaleax](https://github.com/addaleax))
* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz))
* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
@ -13,13 +10,10 @@ libuv is currently managed by the following individuals:
- GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb)
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq))
- GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere)
* **Jameson Nash** ([@vtjnash](https://github.com/vtjnash))
- GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash)
- GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash)
* **Jiawen Geng** ([@gengjiawen](https://github.com/gengjiawen))
* **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))
@ -29,6 +23,13 @@ libuv is currently managed by the following individuals:
* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
- GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul)
## Project Maintainers emeriti
* **Anna Henningsen** ([@addaleax](https://github.com/addaleax))
* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz))
* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq))
* **John Barboza** ([@jbarz](https://github.com/jbarz))
## Storing a maintainer key in Git
It's quite handy to store a maintainer's signature as a git blob, and have

View File

@ -43,7 +43,9 @@ libuv_la_SOURCES = src/fs-poll.c \
src/uv-data-getter-setters.c \
src/uv-common.c \
src/uv-common.h \
src/version.c
src/version.c \
src/strtok.c \
src/strtok.h
if SUNOS
# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
@ -150,7 +152,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-async.c \
test/test-async-null-cb.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 \
@ -250,11 +251,13 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-spawn.c \
test/test-stdio-over-pipes.c \
test/test-strscpy.c \
test/test-strtok.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-after-read-timeout.c \
test/test-tcp-close.c \
test/test-tcp-close-reset.c \
test/test-tcp-create-socket-early.c \
@ -266,6 +269,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-tcp-open.c \
test/test-tcp-read-stop.c \
test/test-tcp-read-stop-start.c \
test/test-tcp-rst.c \
test/test-tcp-shutdown-after-write.c \
test/test-tcp-unexpected-read.c \
test/test-tcp-oob.c \
@ -463,6 +467,10 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \
src/unix/hurd.c
endif
if KFREEBSD
libuv_la_CFLAGS += -D_GNU_SOURCE
endif
if LINUX
uvinclude_HEADERS += include/uv/linux.h
libuv_la_CFLAGS += -D_GNU_SOURCE

View File

@ -10,7 +10,6 @@
| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
| Linux with musl | Tier 2 | musl >= 1.0 | |
| SmartOS | Tier 3 | >= 14.4 | |
| Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` |
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
| SunOS | Tier 3 | Solaris 121 and later | |

35
deps/libuv/autogen.sh vendored
View File

@ -14,9 +14,16 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
set -eu
cd `dirname "$0"`
if [ "$LIBTOOLIZE" = "" ] && [ "`uname`" = "Darwin" ]; then
if [ "${1:-dev}" == "release" ]; then
export LIBUV_RELEASE=true
else
export LIBUV_RELEASE=false
fi
if [ "${LIBTOOLIZE:-}" = "" ] && [ "`uname`" = "Darwin" ]; then
LIBTOOLIZE=glibtoolize
fi
@ -25,9 +32,17 @@ AUTOCONF=${AUTOCONF:-autoconf}
AUTOMAKE=${AUTOMAKE:-automake}
LIBTOOLIZE=${LIBTOOLIZE:-libtoolize}
aclocal_version=`"$ACLOCAL" --version | head -n 1 | sed 's/[^.0-9]//g'`
autoconf_version=`"$AUTOCONF" --version | head -n 1 | sed 's/[^.0-9]//g'`
automake_version=`"$AUTOMAKE" --version | head -n 1 | sed 's/[^.0-9]//g'`
automake_version_major=`echo "$automake_version" | cut -d. -f1`
automake_version_minor=`echo "$automake_version" | cut -d. -f2`
libtoolize_version=`"$LIBTOOLIZE" --version | head -n 1 | sed 's/[^.0-9]//g'`
if [ $aclocal_version != $automake_version ]; then
echo "FATAL: aclocal version appears not to be from the same as automake"
exit 1
fi
UV_EXTRA_AUTOMAKE_FLAGS=
if test "$automake_version_major" -gt 1 || \
@ -39,8 +54,22 @@ fi
echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \
> m4/libuv-extra-automake-flags.m4
set -ex
"$LIBTOOLIZE" --copy
(set -x
"$LIBTOOLIZE" --copy --force
"$ACLOCAL" -I m4
)
if $LIBUV_RELEASE; then
"$AUTOCONF" -o /dev/null m4/libuv-check-versions.m4
echo "
AC_PREREQ($autoconf_version)
AC_INIT([libuv-release-check], [0.0])
AM_INIT_AUTOMAKE([$automake_version])
LT_PREREQ($libtoolize_version)
AC_OUTPUT
" > m4/libuv-check-versions.m4
fi
(
set -x
"$AUTOCONF"
"$AUTOMAKE" --add-missing --copy
)

View File

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [1.44.1], [https://github.com/libuv/libuv/issues])
AC_INIT([libuv], [1.44.2], [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])
@ -28,7 +28,9 @@ AM_PROG_CC_C_O
CC_ATTRIBUTE_VISIBILITY([default], [
CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"])
])
CC_CHECK_CFLAGS_APPEND([-fno-strict-aliasing])
# Xlc has a flag "-f<filename>". Need to use CC_CHECK_FLAG_SUPPORTED_APPEND so
# we exclude -fno-strict-aliasing for xlc
CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing])
CC_CHECK_CFLAGS_APPEND([-g])
CC_CHECK_CFLAGS_APPEND([-std=gnu89])
CC_CHECK_CFLAGS_APPEND([-Wall])
@ -60,6 +62,7 @@ AM_CONDITIONAL([CYGWIN], [AS_CASE([$host_os],[cygwin*], [true], [false])
AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])])
AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])])
AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])])
AM_CONDITIONAL([KFREEBSD], [AS_CASE([$host_os],[kfreebsd*], [true], [false])])
AM_CONDITIONAL([HAIKU], [AS_CASE([$host_os],[haiku], [true], [false])])
AM_CONDITIONAL([HURD], [AS_CASE([$host_os],[gnu*], [true], [false])])
AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])])

51
deps/libuv/docs/code/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.5)
project(libuv_sample)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_subdirectory("../../" build)
set(SIMPLE_SAMPLES
cgi
helloworld
dns
detach
default-loop
idle-basic
idle-compute
interfaces
locks
onchange
pipe-echo-server
ref-timer
spawn
tcp-echo-server
thread-create
udp-dhcp
uvcat
uvstop
uvtee
)
IF (NOT WIN32)
list(APPEND SIMPLE_SAMPLES
signal
progress
queue-cancel
queue-work
tty
tty-gravity
)
ENDIF()
foreach (X IN LISTS SIMPLE_SAMPLES)
add_executable(${X} ${X}/main.c)
target_link_libraries(${X} uv_a)
endforeach ()
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
add_executable(uvwget uvwget/main.c)
target_link_libraries(uvwget uv_a ${CURL_LIBRARIES})
ENDIF(CURL_FOUND)

View File

@ -15,8 +15,8 @@ void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) {
}
void invoke_cgi_script(uv_tcp_t *client) {
size_t size = 500;
char path[size];
char path[500];
size_t size = sizeof(path);
uv_exepath(path, &size);
strcpy(path + (strlen(path) - strlen("cgi")), "tick");

View File

@ -11,17 +11,17 @@ int main() {
printf("Number of interfaces: %d\n", count);
while (i--) {
uv_interface_address_t interface = info[i];
uv_interface_address_t interface_a = info[i];
printf("Name: %s\n", interface.name);
printf("Internal? %s\n", interface.is_internal ? "Yes" : "No");
printf("Name: %s\n", interface_a.name);
printf("Internal? %s\n", interface_a.is_internal ? "Yes" : "No");
if (interface.address.address4.sin_family == AF_INET) {
uv_ip4_name(&interface.address.address4, buf, sizeof(buf));
if (interface_a.address.address4.sin_family == AF_INET) {
uv_ip4_name(&interface_a.address.address4, buf, sizeof(buf));
printf("IPv4 address: %s\n", buf);
}
else if (interface.address.address4.sin_family == AF_INET6) {
uv_ip6_name(&interface.address.address6, buf, sizeof(buf));
else if (interface_a.address.address4.sin_family == AF_INET6) {
uv_ip6_name(&interface_a.address.address6, buf, sizeof(buf));
printf("IPv6 address: %s\n", buf);
}

View File

@ -1,5 +1,4 @@
#include <stdio.h>
#include <unistd.h>
#include <uv.h>
@ -7,7 +6,7 @@ void hare(void *arg) {
int tracklen = *((int *) arg);
while (tracklen) {
tracklen--;
sleep(1);
uv_sleep(1000);
fprintf(stderr, "Hare ran another step\n");
}
fprintf(stderr, "Hare done running!\n");
@ -18,7 +17,7 @@ void tortoise(void *arg) {
while (tracklen) {
tracklen--;
fprintf(stderr, "Tortoise ran another step\n");
sleep(3);
uv_sleep(3000);
}
fprintf(stderr, "Tortoise done running!\n");
}

View File

@ -53,7 +53,8 @@ uv_buf_t make_discover_msg() {
// HOPS
buffer.base[3] = 0x0;
// XID 4 bytes
buffer.base[4] = (unsigned int) random();
if (uv_random(NULL, NULL, &buffer.base[4], 4, 0, NULL))
abort();
// SECS
buffer.base[8] = 0x0;
// FLAGS

View File

@ -1,7 +1,6 @@
#include <assert.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <uv.h>
void on_read(uv_fs_t *req);

View File

@ -1,6 +1,5 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

View File

@ -53,7 +53,7 @@ Code
----
All the example code and the source of the book is included as part of
the libuv_ project on Github.
the libuv_ project on GitHub.
Clone or Download libuv_, then build it::
sh autogen.sh

View File

@ -220,7 +220,7 @@ progress with the download whenever libuv notifies of I/O readiness.
.. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos:
:lines: 1-9,140-
:lines: 1-9,142-
:emphasize-lines: 7,21,24-25
The way each library is integrated with libuv will vary. In the case of

View File

@ -32,7 +32,7 @@
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 44
#define UV_VERSION_PATCH 1
#define UV_VERSION_PATCH 2
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

View File

@ -377,6 +377,12 @@ typedef struct {
OVERLAPPED overlapped; \
size_t queued_bytes; \
} io; \
/* in v2, we can move these to the UV_CONNECT_PRIVATE_FIELDS */ \
struct { \
ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\
HANDLE pipeHandle; \
DWORD duplex_flags; \
} connect; \
} u; \
struct uv_req_s* next_req;

View File

@ -73,6 +73,8 @@ AC_DEFUN([CC_CHECK_CFLAG_APPEND], [
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[AM_CFLAGS="$AM_CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3])
AC_SUBST([AM_CFLAGS])
])
dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not])
@ -102,6 +104,20 @@ AC_DEFUN([CC_CHECK_LDFLAGS], [
[$2], [$3])
])
dnl Check if flag is supported by both compiler and linker
dnl If so, append it to AM_CFLAGS
dnl CC_CHECK_FLAG_SUPPORTED_APPEND([FLAG])
AC_DEFUN([CC_CHECK_FLAG_SUPPORTED_APPEND], [
CC_CHECK_CFLAGS([$1],
[CC_CHECK_LDFLAGS([$1],
[AM_CFLAGS="$AM_CFLAGS $1";
DEBUG_CFLAGS="$DEBUG_CFLAGS $1";
AC_SUBST([AM_CFLAGS])
])
])
])
dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
dnl the current linker to avoid undefined references in a shared object.
AC_DEFUN([CC_NOUNDEFINED], [

7
deps/libuv/m4/libuv-check-versions.m4 vendored Normal file
View File

@ -0,0 +1,7 @@
AC_PREREQ(2.71)
AC_INIT([libuv-release-check], [0.0])
AM_INIT_AUTOMAKE([1.16.5])
LT_PREREQ(2.4.7)
AC_OUTPUT

52
deps/libuv/src/strtok.c vendored Normal file
View File

@ -0,0 +1,52 @@
/* 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 <stdlib.h>
#include "strtok.h"
char* uv__strtok(char* str, const char* sep, char** itr) {
const char* sep_itr;
char* tmp;
char* start;
if (str == NULL)
start = tmp = *itr;
else
start = tmp = str;
if (tmp == NULL)
return NULL;
while (*tmp != '\0') {
sep_itr = sep;
while (*sep_itr != '\0') {
if (*tmp == *sep_itr) {
*itr = tmp + 1;
*tmp = '\0';
return start;
}
sep_itr++;
}
tmp++;
}
*itr = NULL;
return start;
}

27
deps/libuv/src/strtok.h vendored Normal file
View File

@ -0,0 +1,27 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_STRTOK_H_
#define UV_STRTOK_H_
char* uv__strtok(char* str, const char* sep, char** itr);
#endif /* UV_STRTOK_H_ */

View File

@ -37,12 +37,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
: "memory");
return out;
#elif defined(__MVS__)
unsigned int op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
return oldval;
else
return op4;
/* Use hand-rolled assembly because codegen from builtin __plo_CSST results in
* a runtime bug.
*/
__asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :);
return oldval;
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
#else
@ -55,7 +54,9 @@ UV_UNUSED(static void cpu_relax(void)) {
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ __volatile__ ("yield" ::: "memory");
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
__asm volatile ("" : : : "memory");
#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
#endif
}

View File

@ -20,6 +20,7 @@
#include "uv.h"
#include "internal.h"
#include "strtok.h"
#include <stddef.h> /* NULL */
#include <stdio.h> /* printf */
@ -80,7 +81,8 @@ extern char** environ;
#endif
#if defined(__MVS__)
#include <sys/ioctl.h>
# include <sys/ioctl.h>
# include "zos-sys-info.h"
#endif
#if defined(__linux__)
@ -93,7 +95,7 @@ extern char** environ;
# include <sanitizer/linux_syscall_hooks.h>
#endif
static int uv__run_pending(uv_loop_t* loop);
static void uv__run_pending(uv_loop_t* loop);
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
@ -159,6 +161,15 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
case UV_FS_EVENT:
uv__fs_event_close((uv_fs_event_t*)handle);
#if defined(__sun) || defined(__MVS__)
/*
* On Solaris, illumos, and z/OS we will not be able to dissociate the
* watcher for an event which is pending delivery, so we cannot always call
* uv__make_close_pending() straight away. The backend will call the
* function once the event has cleared.
*/
return;
#endif
break;
case UV_POLL:
@ -371,7 +382,7 @@ int uv_loop_alive(const uv_loop_t* loop) {
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
int timeout;
int r;
int ran_pending;
int can_sleep;
r = uv__loop_alive(loop);
if (!r)
@ -380,16 +391,25 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
while (r != 0 && loop->stop_flag == 0) {
uv__update_time(loop);
uv__run_timers(loop);
ran_pending = uv__run_pending(loop);
can_sleep =
QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
timeout = uv__backend_timeout(loop);
uv__io_poll(loop, timeout);
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
* times to avoid loop starvation.*/
for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
uv__run_pending(loop);
/* 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
@ -653,28 +673,23 @@ int uv__cloexec(int fd, int set) {
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
struct cmsghdr* cmsg;
#if defined(__ANDROID__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__) || \
defined(__linux__)
ssize_t rc;
rc = recvmsg(fd, msg, flags | MSG_CMSG_CLOEXEC);
if (rc == -1)
return UV__ERR(errno);
return rc;
#else
struct cmsghdr* cmsg;
int* pfd;
int* end;
#if defined(__linux__)
static int no_msg_cmsg_cloexec;
if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) {
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
if (rc != -1)
return rc;
if (errno != EINVAL)
return UV__ERR(errno);
rc = recvmsg(fd, msg, flags);
if (rc == -1)
return UV__ERR(errno);
uv__store_relaxed(&no_msg_cmsg_cloexec, 1);
} else {
rc = recvmsg(fd, msg, flags);
}
#else
ssize_t rc;
rc = recvmsg(fd, msg, flags);
#endif
if (rc == -1)
return UV__ERR(errno);
if (msg->msg_controllen == 0)
@ -687,6 +702,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
pfd += 1)
uv__cloexec(*pfd, 1);
return rc;
#endif
}
@ -779,14 +795,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
}
static int uv__run_pending(uv_loop_t* loop) {
static void uv__run_pending(uv_loop_t* loop) {
QUEUE* q;
QUEUE pq;
uv__io_t* w;
if (QUEUE_EMPTY(&loop->pending_queue))
return 0;
QUEUE_MOVE(&loop->pending_queue, &pq);
while (!QUEUE_EMPTY(&pq)) {
@ -796,8 +809,6 @@ static int uv__run_pending(uv_loop_t* loop) {
w = QUEUE_DATA(q, uv__io_t, pending_queue);
w->cb(loop, w, POLLOUT);
}
return 1;
}
@ -1162,24 +1173,17 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
size_t name_size;
size_t homedir_size;
size_t shell_size;
long initsize;
int r;
if (pwd == NULL)
return UV_EINVAL;
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (initsize <= 0)
bufsize = 4096;
else
bufsize = (size_t) initsize;
uid = geteuid();
buf = NULL;
for (;;) {
uv__free(buf);
/* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
* is frequently 1024 or 4096, so we can just use that directly. The pwent
* will not usually be large. */
for (bufsize = 2000;; bufsize *= 2) {
buf = uv__malloc(bufsize);
if (buf == NULL)
@ -1189,21 +1193,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
r = getpwuid_r(uid, &pw, buf, bufsize, &result);
while (r == EINTR);
if (r != 0 || result == NULL)
uv__free(buf);
if (r != ERANGE)
break;
bufsize *= 2;
}
if (r != 0) {
uv__free(buf);
if (r != 0)
return UV__ERR(r);
}
if (result == NULL) {
uv__free(buf);
if (result == NULL)
return UV_ENOENT;
}
/* Allocate memory for the username, shell, and home directory */
name_size = strlen(pw.pw_name) + 1;
@ -1556,6 +1557,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
char* cloned_path;
char* path_env;
char* token;
char* itr;
if (buf == NULL || buflen == NULL || *buflen == 0)
return UV_EINVAL;
@ -1597,7 +1599,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
if (cloned_path == NULL)
return UV_ENOMEM;
token = strtok(cloned_path, ":");
token = uv__strtok(cloned_path, ":", &itr);
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
if (realpath(trypath, abspath) == abspath) {
@ -1616,7 +1618,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
return 0;
}
}
token = strtok(NULL, ":");
token = uv__strtok(NULL, ":", &itr);
}
uv__free(cloned_path);
@ -1646,7 +1648,13 @@ unsigned int uv_available_parallelism(void) {
return (unsigned) rc;
#elif defined(__MVS__)
return 1; /* TODO(bnoordhuis) Read from CSD_NUMBER_ONLINE_CPUS? */
int rc;
rc = __get_num_online_cpus();
if (rc < 1)
rc = 1;
return (unsigned) rc;
#else /* __linux__ */
long rc;

View File

@ -1181,7 +1181,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
defined(_AIX71) || \
defined(__sun) || \
defined(__HAIKU__) || \
defined(__GNU__)
defined(__GNU__) || \
defined(__OpenBSD__)
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);

View File

@ -277,7 +277,6 @@ void uv__tcp_close(uv_tcp_t* handle);
size_t uv__thread_stack_size(void);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
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);

View File

@ -456,7 +456,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].ident == fd)
if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC)
events[i].ident = -1;
}

View File

@ -284,6 +284,8 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
nmsgsfds_t size;
struct pollfd* pfds;
int pollret;
int pollfdret;
int pollmsgret;
int reventcount;
int nevents;
struct pollfd msg_fd;
@ -304,24 +306,24 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
return -1;
}
if (lst->size > 0)
_SET_FDS_MSGS(size, 1, lst->size - 1);
else
_SET_FDS_MSGS(size, 0, 0);
assert(lst->size > 0);
_SET_FDS_MSGS(size, 1, lst->size - 1);
pfds = lst->items;
pollret = poll(pfds, size, timeout);
if (pollret <= 0)
return pollret;
assert(lst->size > 0);
pollret = _NFDS(pollret) + _NMSGS(pollret);
pollfdret = _NFDS(pollret);
pollmsgret = _NMSGS(pollret);
reventcount = 0;
nevents = 0;
msg_fd = pfds[lst->size - 1];
msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */
maxevents = maxevents - pollmsgret; /* allow spot for message queue */
for (i = 0;
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
i < lst->size - 1 &&
nevents < maxevents &&
reventcount < pollfdret; ++i) {
struct epoll_event ev;
struct pollfd* pfd;
@ -332,18 +334,18 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
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))
++reventcount;
pfd->revents = 0;
reventcount++;
events[nevents++] = ev;
}
if (msg_fd.revents != 0 && msg_fd.fd != -1)
if (i == lst->size)
events[nevents - 1].is_msg = 1;
if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
struct epoll_event ev;
ev.fd = msg_fd.fd;
ev.events = msg_fd.revents;
ev.is_msg = 1;
events[nevents++] = ev;
}
return nevents;
}

View File

@ -278,7 +278,9 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
__net_ifconf6header_t ifc;
__net_ifconf6entry_t* ifr;
__net_ifconf6entry_t* p;
__net_ifconf6entry_t flg;
unsigned int i;
int count_names;
unsigned char netmask[16] = {0};
*count = 0;
/* Assume maximum buffer size allowable */
@ -287,24 +289,33 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
return UV__ERR(errno);
ifc.__nif6h_version = 1;
ifc.__nif6h_buflen = maxsize;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
if (ifc.__nif6h_buffer == NULL) {
uv__close(sockfd);
return UV__ERR(errno);
return UV_ENOMEM;
}
ifc.__nif6h_version = 1;
ifc.__nif6h_buflen = maxsize;
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
/* This will error on a system that does not support IPv6. However, we want
* to treat this as there being 0 interfaces so we can continue to get IPv4
* interfaces in uv_interface_addresses(). So return 0 instead of the error.
*/
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
errno = 0;
return 0;
}
*count = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
if (!(p->__nif6e_addr.sin6_family == AF_INET6))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
@ -313,21 +324,28 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
++(*count);
}
if ((*count) == 0) {
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
return 0;
}
/* Alloc the return interface structs */
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
*addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
return UV_ENOMEM;
}
address = *addresses;
count_names = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
if (!(p->__nif6e_addr.sin6_family == AF_INET6))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
@ -335,20 +353,41 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
/* All conditions above must match count loop */
address->name = uv__strdup(p->__nif6e_name);
i = 0;
/* Ignore EBCDIC space (0x40) padding in name */
while (i < ARRAY_SIZE(p->__nif6e_name) &&
p->__nif6e_name[i] != 0x40 &&
p->__nif6e_name[i] != 0)
++i;
address->name = uv__malloc(i + 1);
if (address->name == NULL) {
uv_free_interface_addresses(*addresses, count_names);
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
return UV_ENOMEM;
}
memcpy(address->name, p->__nif6e_name, i);
address->name[i] = '\0';
__e2a_s(address->name);
count_names++;
if (p->__nif6e_addr.sin6_family == AF_INET6)
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
else
address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
for (i = 0; i < (p->__nif6e_prefixlen / 8); i++)
netmask[i] = 0xFF;
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
if (p->__nif6e_prefixlen % 8)
netmask[i] = 0xFF << (8 - (p->__nif6e_prefixlen % 8));
address->netmask.netmask6.sin6_len = p->__nif6e_prefixlen;
memcpy(&(address->netmask.netmask6.sin6_addr), netmask, 16);
address->netmask.netmask6.sin6_family = AF_INET6;
address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
address++;
}
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
return 0;
}
@ -362,14 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifreq flg;
struct ifreq* ifr;
struct ifreq* p;
uv_interface_address_t* addresses_v6;
int count_v6;
unsigned int i;
int rc;
int count_names;
*count = 0;
*addresses = NULL;
/* get the ipv6 addresses first */
uv_interface_address_t* addresses_v6;
uv__interface_addresses_v6(&addresses_v6, &count_v6);
if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
return rc;
/* now get the ipv4 addresses */
@ -377,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
maxsize = 16384;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (0 > sockfd)
if (0 > sockfd) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
return UV__ERR(errno);
}
ifc.ifc_req = uv__calloc(1, maxsize);
if (ifc.ifc_req == NULL) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
uv__close(sockfd);
return UV_ENOMEM;
}
ifc.ifc_len = maxsize;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV__ERR(errno);
}
@ -403,6 +461,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV__ERR(errno);
}
@ -413,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
(*count)++;
}
if (*count == 0) {
if (*count == 0 && count_v6 == 0) {
uv__free(ifc.ifc_req);
uv__close(sockfd);
return 0;
}
/* Alloc the return interface structs */
*addresses = uv__malloc((*count + count_v6) *
*addresses = uv__calloc(1, (*count + count_v6) *
sizeof(uv_interface_address_t));
if (!(*addresses)) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV_ENOMEM;
}
address = *addresses;
/* copy over the ipv6 addresses */
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
address += count_v6;
*count += count_v6;
uv__free(addresses_v6);
/* copy over the ipv6 addresses if any are found */
if (count_v6) {
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
address += count_v6;
*count += count_v6;
/* free ipv6 addresses, but keep address names */
uv__free(addresses_v6);
}
count_names = *count;
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
@ -446,6 +515,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv_free_interface_addresses(*addresses, count_names);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV_ENOSYS;
}
@ -455,22 +526,43 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* All conditions above must match count loop */
address->name = uv__strdup(p->ifr_name);
i = 0;
/* Ignore EBCDIC space (0x40) padding in name */
while (i < ARRAY_SIZE(p->ifr_name) &&
p->ifr_name[i] != 0x40 &&
p->ifr_name[i] != 0)
++i;
address->name = uv__malloc(i + 1);
if (address->name == NULL) {
uv_free_interface_addresses(*addresses, count_names);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV_ENOMEM;
}
memcpy(address->name, p->ifr_name, i);
address->name[i] = '\0';
__e2a_s(address->name);
count_names++;
if (p->ifr_addr.sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
uv_free_interface_addresses(*addresses, count_names);
uv__free(ifc.ifc_req);
uv__close(sockfd);
return UV__ERR(errno);
}
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
address->netmask.netmask4.sin_family = AF_INET;
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++;
}
#undef ADDR_SIZE
#undef MAX
uv__free(ifc.ifc_req);
uv__close(sockfd);
return 0;
}
@ -529,27 +621,17 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
static int os390_regfileint(uv_fs_event_t* handle, char* path) {
uv__os390_epoll* ep;
_RFIS reg_struct;
char* path;
int rc;
if (uv__is_active(handle))
return UV_EINVAL;
ep = handle->loop->ep;
assert(ep->msg_queue != -1);
@ -558,17 +640,10 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
reg_struct.__rfis_type = 1;
memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
path = uv__strdup(filename);
if (path == NULL)
return UV_ENOMEM;
rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
if (rc != 0)
return UV__ERR(errno);
uv__handle_start(handle);
handle->path = path;
handle->cb = cb;
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
sizeof(handle->rfis_rftok));
@ -576,7 +651,33 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
char* path;
int rc;
if (uv__is_active(handle))
return UV_EINVAL;
path = uv__strdup(filename);
if (path == NULL)
return UV_ENOMEM;
rc = os390_regfileint(handle, path);
if (rc != 0) {
uv__free(path);
return rc;
}
uv__handle_start(handle);
handle->path = path;
handle->cb = cb;
return 0;
}
int uv__fs_event_stop(uv_fs_event_t* handle) {
uv__os390_epoll* ep;
_RFIS reg_struct;
int rc;
@ -602,12 +703,40 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
if (rc != 0 && errno != EALREADY && errno != ENOENT)
abort();
if (handle->path != NULL) {
uv__free(handle->path);
handle->path = NULL;
}
if (rc != 0 && errno == EALREADY)
return -1;
uv__handle_stop(handle);
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__fs_event_stop(handle);
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
/*
* If we were unable to unregister file interest here, then it is most likely
* that there is a pending queued change notification. When this happens, we
* don't want to complete the close as it will free the underlying memory for
* the handle, causing a use-after-free problem when the event is processed.
* We defer the final cleanup until after the event is consumed in
* os390_message_queue_handler().
*/
if (uv__fs_event_stop(handle) == 0)
uv__make_close_pending((uv_handle_t*) handle);
}
static int os390_message_queue_handler(uv__os390_epoll* ep) {
uv_fs_event_t* handle;
int msglen;
@ -628,7 +757,15 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
events = 0;
if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
events = UV_CHANGE;
else if (msg.__rfim_event == _RFIM_RENAME)
else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK)
events = UV_RENAME;
else if (msg.__rfim_event == 156)
/* TODO(gabylb): zos - this event should not happen, need to investigate.
*
* This event seems to occur when the watched file is [re]moved, or an
* editor (like vim) renames then creates the file on save (for vim, that's
* when backupcopy=no|auto).
*/
events = UV_RENAME;
else
/* Some event that we are not interested in. */
@ -639,6 +776,26 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
*/
__a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
handle = *(uv_fs_event_t**)(msg.__rfim_utok);
assert(handle != NULL);
assert((handle->flags & UV_HANDLE_CLOSED) == 0);
if (uv__is_closing(handle)) {
uv__handle_stop(handle);
uv__make_close_pending((uv_handle_t*) handle);
return 0;
} else if (handle->path == NULL) {
/* _RFIS_UNREG returned EALREADY. */
uv__handle_stop(handle);
return 0;
}
/* The file is implicitly unregistered when the change notification is
* sent, only one notification is sent per registration. So we need to
* re-register interest in a file after each change notification we
* receive.
*/
assert(handle->path != NULL);
os390_regfileint(handle, handle->path);
handle->cb(handle, uv__basename_r(handle->path), events, 0);
return 1;
}
@ -650,6 +807,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
struct epoll_event* pe;
struct epoll_event e;
uv__os390_epoll* ep;
int have_signals;
int real_timeout;
QUEUE* q;
uv__io_t* w;
@ -712,6 +870,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
int nevents = 0;
have_signals = 0;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
@ -796,6 +955,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
ep = loop->ep;
if (pe->is_msg) {
os390_message_queue_handler(ep);
nevents++;
continue;
}
@ -825,19 +985,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
/* 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) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
}
nevents++;
}
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
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;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
@ -872,6 +1048,5 @@ int uv__io_fork(uv_loop_t* loop) {
*/
loop->ep = NULL;
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}

View File

@ -51,7 +51,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
/* Already bound? */
if (uv__stream_fd(handle) >= 0)
return UV_EINVAL;
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
/* Make a copy of the file name, it outlives this function's scope. */
pipe_fname = uv__strdup(name);
if (pipe_fname == NULL)
@ -319,7 +321,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (handle->accepted_fd == -1)
return UV_UNKNOWN_HANDLE;
else
return uv__handle_type(handle->accepted_fd);
return uv_guess_handle(handle->accepted_fd);
}

View File

@ -35,7 +35,7 @@
#include <fcntl.h>
#include <poll.h>
#if defined(__APPLE__) && !TARGET_OS_IPHONE
#if defined(__APPLE__)
# include <spawn.h>
# include <paths.h>
# include <sys/kauth.h>
@ -671,27 +671,25 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
if (options->env != NULL)
env = options->env;
/* If options->file contains a slash, posix_spawn/posix_spawnp behave
* the same, and don't involve PATH resolution at all. Otherwise, if
* options->file does not include a slash, but no custom environment is
* to be used, the environment used for path resolution as well for the
* child process is that of the parent process, so posix_spawnp is the
* way to go. */
if (strchr(options->file, '/') != NULL || options->env == NULL) {
/* If options->file contains a slash, posix_spawn/posix_spawnp should behave
* the same, and do not involve PATH resolution at all. The libc
* `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it
* here, per https://github.com/libuv/libuv/pull/3583. */
if (strchr(options->file, '/') != NULL) {
do
err = posix_spawnp(pid, options->file, actions, attrs, options->args, env);
err = posix_spawn(pid, options->file, actions, attrs, options->args, env);
while (err == EINTR);
return err;
}
/* Look for the definition of PATH in the provided env */
path = uv__spawn_find_path_in_env(options->env);
path = uv__spawn_find_path_in_env(env);
/* The following resolution logic (execvpe emulation) is copied from
* https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
* and adapted to work for our specific usage */
/* If no path was provided in options->env, use the default value
/* If no path was provided in env, use the default value
* to look for the executable */
if (path == NULL)
path = _PATH_DEFPATH;
@ -812,11 +810,6 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
*pid = fork();
if (*pid == -1) {
/* Failed to fork */
return UV__ERR(errno);
}
if (*pid == 0) {
/* Fork succeeded, in the child process */
uv__process_child_init(options, stdio_count, pipes, error_fd);
@ -826,6 +819,10 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
abort();
if (*pid == -1)
/* Failed to fork */
return UV__ERR(errno);
/* Fork succeeded, in the parent process */
return 0;
}
@ -1066,9 +1063,16 @@ int uv_process_kill(uv_process_t* process, int signum) {
int uv_kill(int pid, int signum) {
if (kill(pid, signum))
if (kill(pid, signum)) {
#if defined(__MVS__)
/* EPERM is returned if the process is a zombie. */
siginfo_t infop;
if (errno == EPERM &&
waitid(P_PID, pid, &infop, WNOHANG | WNOWAIT | WEXITED) == 0)
return 0;
#endif
return UV__ERR(errno);
else
} else
return 0;
}

View File

@ -66,6 +66,7 @@ static void uv__read(uv_stream_t* stream);
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
static void uv__write_callbacks(uv_stream_t* stream);
static size_t uv__write_req_size(uv_write_t* req);
static void uv__drain(uv_stream_t* stream);
void uv__stream_init(uv_loop_t* loop,
@ -453,17 +454,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
uv__stream_flush_write_queue(stream, UV_ECANCELED);
uv__write_callbacks(stream);
if (stream->shutdown_req) {
/* The ECANCELED error code is a lie, the shutdown(2) syscall is a
* fait accompli at this point. Maybe we should revisit this in v0.11.
* A possible reason for leaving it unchanged is that it informs the
* callee that the handle has been destroyed.
*/
uv__req_unregister(stream->loop, stream->shutdown_req);
stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED);
stream->shutdown_req = NULL;
}
uv__drain(stream);
assert(stream->write_queue_size == 0);
}
@ -641,7 +632,9 @@ done:
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;
if (uv__is_closing(stream)) {
return UV_EINVAL;
}
switch (stream->type) {
case UV_TCP:
err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
@ -667,25 +660,30 @@ static void uv__drain(uv_stream_t* stream) {
int err;
assert(QUEUE_EMPTY(&stream->write_queue));
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
if (!(stream->flags & UV_HANDLE_CLOSING)) {
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
}
/* Shutdown? */
if ((stream->flags & UV_HANDLE_SHUTTING) &&
!(stream->flags & UV_HANDLE_CLOSING) &&
if (!(stream->flags & UV_HANDLE_SHUTTING))
return;
req = stream->shutdown_req;
assert(req);
if ((stream->flags & UV_HANDLE_CLOSING) ||
!(stream->flags & UV_HANDLE_SHUT)) {
assert(stream->shutdown_req);
req = stream->shutdown_req;
stream->shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING;
uv__req_unregister(stream->loop, req);
err = 0;
if (shutdown(uv__stream_fd(stream), SHUT_WR))
if (stream->flags & UV_HANDLE_CLOSING)
/* The user destroyed the stream before we got to do the shutdown. */
err = UV_ECANCELED;
else if (shutdown(uv__stream_fd(stream), SHUT_WR))
err = UV__ERR(errno);
if (err == 0)
else /* Success. */
stream->flags |= UV_HANDLE_SHUT;
if (req->cb != NULL)
@ -926,7 +924,6 @@ static void uv__write(uv_stream_t* stream) {
}
req->error = n;
// XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events
uv__write_req_finish(req);
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
@ -964,49 +961,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
}
uv_handle_type uv__handle_type(int fd) {
struct sockaddr_storage ss;
socklen_t sslen;
socklen_t len;
int type;
memset(&ss, 0, sizeof(ss));
sslen = sizeof(ss);
if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
return UV_UNKNOWN_HANDLE;
len = sizeof type;
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
return UV_UNKNOWN_HANDLE;
if (type == SOCK_STREAM) {
#if defined(_AIX) || defined(__DragonFly__)
/* on AIX/DragonFly the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/
if (sslen == 0)
return UV_NAMED_PIPE;
#endif
switch (ss.ss_family) {
case AF_UNIX:
return UV_NAMED_PIPE;
case AF_INET:
case AF_INET6:
return UV_TCP;
}
}
if (type == SOCK_DGRAM &&
(ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
return UV_UDP;
return UV_UNKNOWN_HANDLE;
}
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
stream->flags |= UV_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING;
@ -1278,7 +1232,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
assert(uv__stream_fd(stream) >= 0);
/* Initialize request */
/* Initialize request. The `shutdown(2)` call will always be deferred until
* `uv__drain`, just before the callback is run. */
uv__req_init(stream->loop, req, UV_SHUTDOWN);
req->handle = stream;
req->cb = cb;
@ -1286,8 +1241,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
stream->flags |= UV_HANDLE_SHUTTING;
stream->flags &= ~UV_HANDLE_WRITABLE;
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
if (QUEUE_EMPTY(&stream->write_queue))
uv__io_feed(stream->loop, &stream->io_watcher);
return 0;
}

View File

@ -154,7 +154,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t set;
uint64_t base;
uint64_t diff;
uint64_t idle_poll;
unsigned int nfds;
unsigned int i;
int saved_errno;
@ -424,7 +423,7 @@ void uv_loadavg(double avg[3]) {
#if defined(PORT_SOURCE_FILE)
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
if (handle->fd == -1)
if (handle->fd == PORT_DELETED)
return UV_EBADF;
if (port_associate(handle->loop->fs_fd,
@ -475,6 +474,12 @@ static void uv__fs_event_read(uv_loop_t* loop,
handle = (uv_fs_event_t*) pe.portev_user;
assert((r == 0) && "unexpected port_get() error");
if (uv__is_closing(handle)) {
uv__handle_stop(handle);
uv__make_close_pending((uv_handle_t*) handle);
break;
}
events = 0;
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
events |= UV_CHANGE;
@ -542,12 +547,14 @@ int uv_fs_event_start(uv_fs_event_t* handle,
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
static int uv__fs_event_stop(uv_fs_event_t* handle) {
int ret = 0;
if (!uv__is_active(handle))
return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd,
if (handle->fd == PORT_LOADED) {
ret = port_dissociate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo);
}
@ -556,13 +563,28 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__free(handle->path);
handle->path = NULL;
handle->fo.fo_name = NULL;
uv__handle_stop(handle);
if (ret == 0)
uv__handle_stop(handle);
return ret;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
(void) uv__fs_event_stop(handle);
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
/*
* If we were unable to dissociate the port here, then it is most likely
* that there is a pending queued event. When this happens, we don't want
* to complete the close as it will free the underlying memory for the
* handle, causing a use-after-free problem when the event is processed.
* We defer the final cleanup until after the event is consumed in
* uv__fs_event_read().
*/
if (uv__fs_event_stop(handle) == 0)
uv__make_close_pending((uv_handle_t*) handle);
}
#else /* !defined(PORT_SOURCE_FILE) */

View File

@ -184,14 +184,15 @@ int uv__tcp_bind(uv_tcp_t* tcp,
#endif
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
err = bind(tcp->io_watcher.fd, addr, addrlen);
if (err == -1 && errno != EADDRINUSE) {
if (errno == EAFNOSUPPORT)
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
* socket created with AF_INET to an AF_INET6 address or vice versa. */
return UV_EINVAL;
return UV__ERR(errno);
}
tcp->delayed_error = UV__ERR(errno);
tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
tcp->flags |= UV_HANDLE_BOUND;
if (addr->sa_family == AF_INET6)
@ -320,8 +321,16 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
return UV_EINVAL;
fd = uv__stream_fd(handle);
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
return UV__ERR(errno);
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
if (errno == EINVAL) {
/* Open Group Specifications Issue 7, 2018 edition states that
* EINVAL may mean the socket has been shut down already.
* Behavior observed on Solaris, illumos and macOS. */
errno = 0;
} else {
return UV__ERR(errno);
}
}
uv_close((uv_handle_t*) handle, close_cb);
return 0;

View File

@ -66,6 +66,19 @@ static int orig_termios_fd = -1;
static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
int uv__tcsetattr(int fd, int how, const struct termios *term) {
int rc;
do
rc = tcsetattr(fd, how, term);
while (rc == -1 && errno == EINTR);
if (rc == -1)
return UV__ERR(errno);
return 0;
}
static int uv__tty_is_slave(const int fd) {
int result;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@ -268,13 +281,18 @@ static void uv__tty_make_raw(struct termios* tio) {
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
struct termios tmp;
int fd;
int rc;
if (tty->mode == (int) mode)
return 0;
fd = uv__stream_fd(tty);
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
if (tcgetattr(fd, &tty->orig_termios))
do
rc = tcgetattr(fd, &tty->orig_termios);
while (rc == -1 && errno == EINTR);
if (rc == -1)
return UV__ERR(errno);
/* This is used for uv_tty_reset_mode() */
@ -304,11 +322,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
}
/* Apply changes after draining */
if (tcsetattr(fd, TCSADRAIN, &tmp))
return UV__ERR(errno);
rc = uv__tcsetattr(fd, TCSADRAIN, &tmp);
if (rc == 0)
tty->mode = mode;
tty->mode = mode;
return 0;
return rc;
}
@ -331,7 +349,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
uv_handle_type uv_guess_handle(uv_file file) {
struct sockaddr sa;
struct sockaddr_storage ss;
struct stat s;
socklen_t len;
int type;
@ -342,8 +360,24 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (isatty(file))
return UV_TTY;
if (fstat(file, &s))
if (fstat(file, &s)) {
#if defined(__PASE__)
/* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
* an error state. fstat will return EINVAL, getsockname will also return
* EINVAL, even if sockaddr_storage is valid. (If file does not refer to a
* socket, ENOTSOCK is returned instead.)
* In such cases, we will permit the user to open the connection as uv_tcp
* still, so that the user can get immediately notified of the error in
* their read callback and close this fd.
*/
len = sizeof(ss);
if (getsockname(file, (struct sockaddr*) &ss, &len)) {
if (errno == EINVAL)
return UV_TCP;
}
#endif
return UV_UNKNOWN_HANDLE;
}
if (S_ISREG(s.st_mode))
return UV_FILE;
@ -357,16 +391,29 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (!S_ISSOCK(s.st_mode))
return UV_UNKNOWN_HANDLE;
len = sizeof(ss);
if (getsockname(file, (struct sockaddr*) &ss, &len)) {
#if defined(_AIX)
/* On aix receiving RST from TCP instead of FIN immediately puts fd into
* an error state. In such case getsockname will return EINVAL, even if
* sockaddr_storage is valid.
* In such cases, we will permit the user to open the connection as uv_tcp
* still, so that the user can get immediately notified of the error in
* their read callback and close this fd.
*/
if (errno == EINVAL) {
return UV_TCP;
}
#endif
return UV_UNKNOWN_HANDLE;
}
len = sizeof(type);
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
return UV_UNKNOWN_HANDLE;
len = sizeof(sa);
if (getsockname(file, &sa, &len))
return UV_UNKNOWN_HANDLE;
if (type == SOCK_DGRAM)
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
return UV_UDP;
if (type == SOCK_STREAM) {
@ -379,9 +426,9 @@ uv_handle_type uv_guess_handle(uv_file file) {
return UV_NAMED_PIPE;
#endif /* defined(_AIX) || defined(__DragonFly__) */
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
return UV_TCP;
if (sa.sa_family == AF_UNIX)
if (ss.ss_family == AF_UNIX)
return UV_NAMED_PIPE;
}
@ -403,8 +450,7 @@ int uv_tty_reset_mode(void) {
err = 0;
if (orig_termios_fd != -1)
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
err = UV__ERR(errno);
err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
uv_spinlock_unlock(&termios_spinlock);
errno = saved_errno;

View File

@ -704,7 +704,16 @@ int uv__udp_disconnect(uv_udp_t* handle) {
do {
errno = 0;
#ifdef __PASE__
/* On IBMi a connectionless transport socket can be disconnected by
* either setting the addr parameter to NULL or setting the
* addr_length parameter to zero, and issuing another connect().
* https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm
*/
r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0);
#else
r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
#endif
} while (r == -1 && errno == EINTR);
if (r == -1) {

View File

@ -295,7 +295,9 @@ int uv_tcp_bind(uv_tcp_t* handle,
if (handle->type != UV_TCP)
return UV_EINVAL;
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)

View File

@ -592,7 +592,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r;
int ran_pending;
int can_sleep;
r = uv__loop_alive(loop);
if (!r)
@ -602,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv_update_time(loop);
uv__run_timers(loop);
ran_pending = uv__process_reqs(loop);
can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
uv__process_reqs(loop);
uv__idle_invoke(loop);
uv__prepare_invoke(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx)
@ -615,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
else
uv__poll_wine(loop, timeout);
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
* times to avoid loop starvation.*/
for (r = 0; r < 8 && loop->pending_reqs_tail != NULL; r++)
uv__process_reqs(loop);
/* 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

View File

@ -73,7 +73,6 @@ int uv_translate_sys_error(int sys_errno) {
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
case ERROR_ACCESS_DENIED: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
@ -155,6 +154,7 @@ int uv_translate_sys_error(int sys_errno) {
case WSAENOTSOCK: return UV_ENOTSOCK;
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
case ERROR_BROKEN_PIPE: return UV_EOF;
case ERROR_ACCESS_DENIED: return UV_EPERM;
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
case ERROR_BAD_PIPE: return UV_EPIPE;
case ERROR_NO_DATA: return UV_EPIPE;

View File

@ -88,6 +88,9 @@ void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req);
void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_connect_t* req);
void uv__process_tcp_shutdown_req(uv_loop_t* loop,
uv_tcp_t* stream,
uv_shutdown_t* req);
void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
@ -130,6 +133,7 @@ int uv__pipe_write(uv_loop_t* loop,
size_t nbufs,
uv_stream_t* send_handle,
uv_write_cb cb);
void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req);
void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* req);
@ -143,7 +147,6 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req);
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
@ -177,7 +180,9 @@ void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
*/
void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
uv_connect_t* req);
void uv__process_tty_shutdown_req(uv_loop_t* loop,
uv_tty_t* stream,
uv_shutdown_t* req);
void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle);

View File

@ -121,14 +121,10 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
static void uv__pipe_connection_init(uv_pipe_t* handle) {
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
uv__connection_init((uv_stream_t*) handle);
handle->read_req.data = handle;
handle->pipe.conn.eof_timer = NULL;
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
handle->pipe.conn.readfile_thread_handle = NULL;
InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock);
}
}
@ -393,6 +389,8 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
unsigned int client_flags;
int err;
uv__pipe_connection_init(parent_pipe);
server_pipe = INVALID_HANDLE_VALUE;
client_pipe = INVALID_HANDLE_VALUE;
@ -427,7 +425,6 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
goto error;
}
uv__pipe_connection_init(parent_pipe);
parent_pipe->handle = server_pipe;
*child_pipe_ptr = client_pipe;
@ -462,7 +459,9 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
DWORD current_mode = 0;
DWORD err = 0;
if (handle->flags & UV_HANDLE_PIPESERVER)
assert(handle->flags & UV_HANDLE_CONNECTION);
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
if (handle->flags & UV_HANDLE_CLOSING)
return UV_EINVAL;
if (handle->handle != INVALID_HANDLE_VALUE)
return UV_EBUSY;
@ -478,18 +477,17 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
*/
if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
NULL, NULL, 0)) {
return -1;
return uv_translate_sys_error(GetLastError());
} else if (current_mode & PIPE_NOWAIT) {
SetLastError(ERROR_ACCESS_DENIED);
return -1;
return UV_EACCES;
}
} else {
/* If this returns ERROR_INVALID_PARAMETER we probably opened
* something that is not a pipe. */
if (err == ERROR_INVALID_PARAMETER) {
SetLastError(WSAENOTSOCK);
return UV_ENOTSOCK;
}
return -1;
return uv_translate_sys_error(err);
}
}
@ -500,13 +498,15 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
sizeof(mode_info),
FileModeInformation);
if (nt_status != STATUS_SUCCESS) {
return -1;
return uv_translate_sys_error(err);
}
if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
/* Non-overlapped pipe. */
handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
handle->pipe.conn.readfile_thread_handle = NULL;
InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock);
} else {
/* Overlapped pipe. Try to associate with IOCP. */
if (CreateIoCompletionPort(pipeHandle,
@ -578,135 +578,109 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
}
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
int err;
void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t *req) {
DWORD result;
uv_shutdown_t* req;
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_PIPE_LOCAL_INFORMATION pipe_info;
assert(handle->flags & UV_HANDLE_CONNECTION);
assert(req != NULL);
assert(handle->stream.conn.write_reqs_pending == 0);
SET_REQ_SUCCESS(req);
if (handle->flags & UV_HANDLE_CLOSING) {
uv__insert_pending_req(loop, (uv_req_t*) req);
return;
}
/* Try to avoid flushing the pipe buffer in the thread pool. */
nt_status = pNtQueryInformationFile(handle->handle,
&io_status,
&pipe_info,
sizeof pipe_info,
FilePipeLocalInformation);
if (nt_status != STATUS_SUCCESS) {
SET_REQ_ERROR(req, pRtlNtStatusToDosError(nt_status));
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */
uv__insert_pending_req(loop, (uv_req_t*) req);
return;
}
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
/* Short-circuit, no need to call FlushFileBuffers:
* all writes have been read. */
uv__insert_pending_req(loop, (uv_req_t*) req);
return;
}
/* Run FlushFileBuffers in the thread pool. */
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
req,
WT_EXECUTELONGFUNCTION);
if (!result) {
SET_REQ_ERROR(req, GetLastError());
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */
uv__insert_pending_req(loop, (uv_req_t*) req);
return;
}
}
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
uv__ipc_xfer_queue_item_t* xfer_queue_item;
if ((handle->flags & UV_HANDLE_CONNECTION) &&
handle->stream.conn.shutdown_req != NULL &&
handle->stream.conn.write_reqs_pending == 0) {
req = handle->stream.conn.shutdown_req;
assert(handle->reqs_pending == 0);
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
/* Clear the shutdown_req field so we don't go here again. */
handle->stream.conn.shutdown_req = NULL;
if (handle->flags & UV_HANDLE_CONNECTION) {
/* Free pending sockets */
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
QUEUE* q;
SOCKET socket;
if (handle->flags & UV_HANDLE_CLOSING) {
UNREGISTER_HANDLE_REQ(loop, handle, req);
q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
QUEUE_REMOVE(q);
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
/* Already closing. Cancel the shutdown. */
if (req->cb) {
req->cb(req, UV_ECANCELED);
/* Materialize socket and close it */
socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&xfer_queue_item->xfer_info.socket_info,
0,
WSA_FLAG_OVERLAPPED);
uv__free(xfer_queue_item);
if (socket != INVALID_SOCKET)
closesocket(socket);
}
handle->pipe.conn.ipc_xfer_queue_length = 0;
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
/* Try to avoid flushing the pipe buffer in the thread pool. */
nt_status = pNtQueryInformationFile(handle->handle,
&io_status,
&pipe_info,
sizeof pipe_info,
FilePipeLocalInformation);
if (nt_status != STATUS_SUCCESS) {
/* Failure */
UNREGISTER_HANDLE_REQ(loop, handle, req);
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
if (req->cb) {
err = pRtlNtStatusToDosError(nt_status);
req->cb(req, uv_translate_sys_error(err));
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
/* Short-circuit, no need to call FlushFileBuffers. */
uv__insert_pending_req(loop, (uv_req_t*) req);
return;
}
/* Run FlushFileBuffers in the thread pool. */
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
req,
WT_EXECUTELONGFUNCTION);
if (result) {
return;
} else {
/* Failure. */
UNREGISTER_HANDLE_REQ(loop, handle, req);
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
if (req->cb) {
err = GetLastError();
req->cb(req, uv_translate_sys_error(err));
}
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
}
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
if (handle->flags & UV_HANDLE_CONNECTION) {
/* Free pending sockets */
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
QUEUE* q;
SOCKET socket;
q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
QUEUE_REMOVE(q);
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
/* Materialize socket and close it */
socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&xfer_queue_item->xfer_info.socket_info,
0,
WSA_FLAG_OVERLAPPED);
uv__free(xfer_queue_item);
if (socket != INVALID_SOCKET)
closesocket(socket);
}
handle->pipe.conn.ipc_xfer_queue_length = 0;
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
}
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
}
if (handle->flags & UV_HANDLE_PIPESERVER) {
assert(handle->pipe.serv.accept_reqs);
uv__free(handle->pipe.serv.accept_reqs);
handle->pipe.serv.accept_reqs = NULL;
}
uv__handle_close(handle);
if (handle->flags & UV_HANDLE_PIPESERVER) {
assert(handle->pipe.serv.accept_reqs);
uv__free(handle->pipe.serv.accept_reqs);
handle->pipe.serv.accept_reqs = NULL;
}
uv__handle_close(handle);
}
@ -731,7 +705,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
if (!name) {
return UV_EINVAL;
}
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
handle->pipe.serv.pending_instances = default_pending_pipe_instances;
}
@ -815,7 +791,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
assert(loop);
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait
* for the pipe to become available with WaitNamedPipe. */
* up to 30 seconds for the pipe to become available with WaitNamedPipe. */
while (WaitNamedPipeW(handle->name, 30000)) {
/* The pipe is now available, try to connect. */
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
@ -825,9 +801,10 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
SwitchToThread();
}
if (pipeHandle != INVALID_HANDLE_VALUE &&
!uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
if (pipeHandle != INVALID_HANDLE_VALUE) {
SET_REQ_SUCCESS(req);
req->u.connect.pipeHandle = pipeHandle;
req->u.connect.duplex_flags = duplex_flags;
} else {
SET_REQ_ERROR(req, GetLastError());
}
@ -849,6 +826,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
req->u.connect.pipeHandle = INVALID_HANDLE_VALUE;
req->u.connect.duplex_flags = 0;
if (handle->flags & UV_HANDLE_PIPESERVER) {
err = ERROR_INVALID_PARAMETER;
goto error;
}
if (handle->flags & UV_HANDLE_CONNECTION) {
err = ERROR_PIPE_BUSY;
goto error;
}
uv__pipe_connection_init(handle);
/* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
@ -888,17 +877,8 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
goto error;
}
assert(pipeHandle != INVALID_HANDLE_VALUE);
if (uv__set_pipe_handle(loop,
(uv_pipe_t*) req->handle,
pipeHandle,
-1,
duplex_flags)) {
err = GetLastError();
goto error;
}
req->u.connect.pipeHandle = pipeHandle;
req->u.connect.duplex_flags = duplex_flags;
SET_REQ_SUCCESS(req);
uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
@ -937,7 +917,7 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
/* Cancel asynchronous read. */
r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped);
assert(r || GetLastError() == ERROR_NOT_FOUND);
(void) r;
} else {
/* Cancel synchronous read (which is happening in the thread pool). */
HANDLE thread;
@ -973,17 +953,30 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
void uv__pipe_read_stop(uv_pipe_t* handle) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(handle->loop, handle);
uv__pipe_interrupt_read(handle);
}
/* Cleans up uv_pipe_t (server or connection) and all resources associated with
* it. */
void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
int i;
HANDLE pipeHandle;
if (handle->flags & UV_HANDLE_READING) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags &= ~UV_HANDLE_LISTENING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
uv__pipe_interrupt_read(handle);
if (handle->name) {
@ -1003,35 +996,17 @@ void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
}
if (handle->flags & UV_HANDLE_CONNECTION) {
handle->flags &= ~UV_HANDLE_WRITABLE;
eof_timer_destroy(handle);
}
if ((handle->flags & UV_HANDLE_CONNECTION)
&& handle->handle != INVALID_HANDLE_VALUE)
&& handle->handle != INVALID_HANDLE_VALUE) {
/* This will eventually destroy the write queue for us too. */
close_pipe(handle);
}
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
if (handle->flags & UV_HANDLE_READING) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags &= ~UV_HANDLE_LISTENING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
uv__pipe_cleanup(loop, handle);
if (handle->reqs_pending == 0) {
if (handle->reqs_pending == 0)
uv__want_endgame(loop, (uv_handle_t*) handle);
}
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
}
@ -1099,6 +1074,7 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
} else {
pipe_client = (uv_pipe_t*) client;
uv__pipe_connection_init(pipe_client);
/* Find a connection instance that has been connected, but not yet
* accepted. */
@ -1110,7 +1086,6 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
}
/* Initialize the client handle and copy the pipeHandle to the client */
uv__pipe_connection_init(pipe_client);
pipe_client->handle = req->pipeHandle;
pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
@ -2094,10 +2069,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv__queue_non_overlapped_write(handle);
}
if (handle->stream.conn.shutdown_req != NULL &&
handle->stream.conn.write_reqs_pending == 0) {
uv__want_endgame(loop, (uv_handle_t*)handle);
}
if (handle->stream.conn.write_reqs_pending == 0)
if (handle->flags & UV_HANDLE_SHUTTING)
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
DECREASE_PENDING_REQ_COUNT(handle);
}
@ -2110,7 +2084,7 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
assert(handle->type == UV_NAMED_PIPE);
if (handle->flags & UV_HANDLE_CLOSING) {
/* The req->pipeHandle should be freed already in uv__pipe_cleanup(). */
/* The req->pipeHandle should be freed already in uv__pipe_close(). */
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
DECREASE_PENDING_REQ_COUNT(handle);
return;
@ -2140,52 +2114,72 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_connect_t* req) {
HANDLE pipeHandle;
DWORD duplex_flags;
int err;
assert(handle->type == UV_NAMED_PIPE);
UNREGISTER_HANDLE_REQ(loop, handle, req);
if (req->cb) {
err = 0;
if (REQ_SUCCESS(req)) {
uv__pipe_connection_init(handle);
} else {
err = GET_REQ_ERROR(req);
}
req->cb(req, uv_translate_sys_error(err));
err = 0;
if (REQ_SUCCESS(req)) {
pipeHandle = req->u.connect.pipeHandle;
duplex_flags = req->u.connect.duplex_flags;
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
if (err)
CloseHandle(pipeHandle);
} else {
err = uv_translate_sys_error(GET_REQ_ERROR(req));
}
if (req->cb)
req->cb(req, err);
DECREASE_PENDING_REQ_COUNT(handle);
}
void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req) {
int err;
assert(handle->type == UV_NAMED_PIPE);
/* Clear the shutdown_req field so we don't go here again. */
handle->stream.conn.shutdown_req = NULL;
handle->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, handle, req);
if (handle->flags & UV_HANDLE_READABLE) {
/* Initialize and optionally start the eof timer. Only do this if the pipe
* is readable and we haven't seen EOF come in ourselves. */
eof_timer_init(handle);
/* If reading start the timer right now. Otherwise uv__pipe_queue_read will
* start it. */
if (handle->flags & UV_HANDLE_READ_PENDING) {
eof_timer_start(handle);
}
if (handle->flags & UV_HANDLE_CLOSING) {
/* Already closing. Cancel the shutdown. */
err = UV_ECANCELED;
} else if (!REQ_SUCCESS(req)) {
/* An error occurred in trying to shutdown gracefully. */
err = uv_translate_sys_error(GET_REQ_ERROR(req));
} else {
/* This pipe is not readable. We can just close it to let the other end
* know that we're done writing. */
close_pipe(handle);
if (handle->flags & UV_HANDLE_READABLE) {
/* Initialize and optionally start the eof timer. Only do this if the pipe
* is readable and we haven't seen EOF come in ourselves. */
eof_timer_init(handle);
/* If reading start the timer right now. Otherwise uv__pipe_queue_read will
* start it. */
if (handle->flags & UV_HANDLE_READ_PENDING) {
eof_timer_start(handle);
}
} else {
/* This pipe is not readable. We can just close it to let the other end
* know that we're done writing. */
close_pipe(handle);
}
err = 0;
}
if (req->cb) {
req->cb(req, 0);
}
if (req->cb)
req->cb(req, err);
DECREASE_PENDING_REQ_COUNT(handle);
}
@ -2200,7 +2194,8 @@ static void eof_timer_init(uv_pipe_t* pipe) {
pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
assert(r == 0); /* timers can't fail */
assert(r == 0); /* timers can't fail */
(void) r;
pipe->pipe.conn.eof_timer->data = pipe;
uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
}
@ -2280,10 +2275,16 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
IO_STATUS_BLOCK io_status;
FILE_ACCESS_INFORMATION access;
DWORD duplex_flags = 0;
int err;
if (os_handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
if (pipe->flags & UV_HANDLE_PIPESERVER)
return UV_EINVAL;
if (pipe->flags & UV_HANDLE_CONNECTION)
return UV_EBUSY;
uv__pipe_connection_init(pipe);
uv__once_init();
/* In order to avoid closing a stdio file descriptor 0-2, duplicate the
* underlying OS handle and forget about the original fd.
@ -2300,6 +2301,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
FALSE,
DUPLICATE_SAME_ACCESS))
return uv_translate_sys_error(GetLastError());
assert(os_handle != INVALID_HANDLE_VALUE);
file = -1;
}
@ -2327,17 +2329,17 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (access.AccessFlags & FILE_READ_DATA)
duplex_flags |= UV_HANDLE_READABLE;
if (os_handle == INVALID_HANDLE_VALUE ||
uv__set_pipe_handle(pipe->loop,
pipe,
os_handle,
file,
duplex_flags) == -1) {
return UV_EINVAL;
err = uv__set_pipe_handle(pipe->loop,
pipe,
os_handle,
file,
duplex_flags);
if (err) {
if (file == -1)
CloseHandle(os_handle);
return err;
}
uv__pipe_connection_init(pipe);
if (pipe->ipc) {
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
@ -2361,6 +2363,51 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
uv__once_init();
name_info = NULL;
if (handle->name != NULL) {
/* The user might try to query the name before we are connected,
* and this is just easier to return the cached value if we have it. */
name_buf = handle->name;
name_len = wcslen(name_buf);
/* check how much space we need */
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
NULL,
0,
NULL,
NULL);
if (!addrlen) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
return err;
} else if (addrlen >= *size) {
*size = addrlen + 1;
err = UV_ENOBUFS;
goto error;
}
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
buffer,
addrlen,
NULL,
NULL);
if (!addrlen) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
return err;
}
*size = addrlen;
buffer[addrlen] = '\0';
return 0;
}
if (handle->handle == INVALID_HANDLE_VALUE) {
*size = 0;
return UV_EINVAL;
@ -2498,6 +2545,11 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
if (handle->handle != INVALID_HANDLE_VALUE)
return uv__pipe_getname(handle, buffer, size);
if (handle->flags & UV_HANDLE_CONNECTION) {
if (handle->name != NULL)
return uv__pipe_getname(handle, buffer, size);
}
return UV_EBADF;
}

View File

@ -138,13 +138,13 @@ INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
} while (0)
INLINE static int uv__process_reqs(uv_loop_t* loop) {
INLINE static void uv__process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;
if (loop->pending_reqs_tail == NULL)
return 0;
return;
first = loop->pending_reqs_tail->next_req;
next = first;
@ -172,12 +172,7 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) {
break;
case UV_SHUTDOWN:
/* Tcp shutdown requests don't come here. */
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
uv__process_pipe_shutdown_req(
loop,
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
(uv_shutdown_t*) req);
DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle);
break;
case UV_UDP_RECV:
@ -214,8 +209,6 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) {
assert(0);
}
}
return 1;
}
#endif /* UV_WIN_REQ_INL_H_ */

View File

@ -29,7 +29,9 @@
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;
if (uv__is_closing(stream)) {
return UV_EINVAL;
}
err = ERROR_INVALID_PARAMETER;
switch (stream->type) {
case UV_TCP:
@ -217,7 +219,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
uv__want_endgame(loop, (uv_handle_t*)handle);
if (handle->stream.conn.write_reqs_pending == 0) {
if (handle->type == UV_NAMED_PIPE)
uv__pipe_shutdown(loop, (uv_pipe_t*) handle, req);
else
uv__insert_pending_req(loop, (uv_req_t*) req);
}
return 0;
}

View File

@ -205,73 +205,76 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
}
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown_t *req) {
int err;
assert(req);
assert(stream->stream.conn.write_reqs_pending == 0);
assert(!(stream->flags & UV_HANDLE_SHUT));
assert(stream->flags & UV_HANDLE_CONNECTION);
stream->stream.conn.shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, stream, req);
err = 0;
if (stream->flags & UV_HANDLE_CLOSING)
/* The user destroyed the stream before we got to do the shutdown. */
err = UV_ECANCELED;
else if (shutdown(stream->socket, SD_SEND) == SOCKET_ERROR)
err = uv_translate_sys_error(WSAGetLastError());
else /* Success. */
stream->flags |= UV_HANDLE_SHUT;
if (req->cb)
req->cb(req, err);
DECREASE_PENDING_REQ_COUNT(stream);
}
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
unsigned int i;
uv_tcp_accept_t* req;
if (handle->flags & UV_HANDLE_CONNECTION &&
handle->stream.conn.shutdown_req != NULL &&
handle->stream.conn.write_reqs_pending == 0) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(handle->reqs_pending == 0);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->socket == INVALID_SOCKET);
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
err = 0;
if (handle->flags & UV_HANDLE_CLOSING) {
err = ERROR_OPERATION_ABORTED;
} else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
err = WSAGetLastError();
}
if (handle->stream.conn.shutdown_req->cb) {
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
uv_translate_sys_error(err));
}
handle->stream.conn.shutdown_req = NULL;
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->socket == INVALID_SOCKET);
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
req = &handle->tcp.serv.accept_reqs[i];
if (req->wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(req->wait_handle);
req->wait_handle = INVALID_HANDLE_VALUE;
}
if (req->event_handle != NULL) {
CloseHandle(req->event_handle);
req->event_handle = NULL;
}
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
req = &handle->tcp.serv.accept_reqs[i];
if (req->wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(req->wait_handle);
req->wait_handle = INVALID_HANDLE_VALUE;
}
if (req->event_handle != NULL) {
CloseHandle(req->event_handle);
req->event_handle = NULL;
}
}
uv__free(handle->tcp.serv.accept_reqs);
handle->tcp.serv.accept_reqs = NULL;
}
if (handle->flags & UV_HANDLE_CONNECTION &&
handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
}
uv__handle_close(handle);
loop->active_tcp_streams--;
uv__free(handle->tcp.serv.accept_reqs);
handle->tcp.serv.accept_reqs = NULL;
}
if (handle->flags & UV_HANDLE_CONNECTION &&
handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
}
uv__handle_close(handle);
loop->active_tcp_streams--;
}
@ -1160,9 +1163,10 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
closesocket(handle->socket);
handle->socket = INVALID_SOCKET;
}
if (handle->stream.conn.shutdown_req != NULL) {
uv__want_endgame(loop, (uv_handle_t*)handle);
}
if (handle->flags & UV_HANDLE_SHUTTING)
uv__process_tcp_shutdown_req(loop,
handle,
handle->stream.conn.shutdown_req);
}
DECREASE_PENDING_REQ_COUNT(handle);
@ -1411,7 +1415,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
int writing;
socket = tcp->socket;
reading = tcp->flags & UV_HANDLE_READING;
reading = tcp->flags & UV_HANDLE_READ_PENDING;
writing = tcp->stream.conn.write_reqs_pending > 0;
if (!reading && !writing)
return;
@ -1458,10 +1462,10 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
if (tcp->flags & UV_HANDLE_CONNECTION) {
uv__tcp_try_cancel_reqs(tcp);
if (tcp->flags & UV_HANDLE_READING) {
uv_read_stop((uv_stream_t*) tcp);
}
uv__tcp_try_cancel_reqs(tcp);
} else {
if (tcp->tcp.serv.accept_reqs != NULL) {
/* First close the incoming sockets to cancel the accept operations before
@ -1483,6 +1487,9 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
DECREASE_ACTIVE_COUNT(loop, tcp);
}
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(tcp);
/* If any overlapped req failed to cancel, calling `closesocket` now would
* cause Win32 to send an RST packet. Try to avoid that for writes, if
* possibly applicable, by waiting to process the completion notifications
@ -1494,12 +1501,8 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
tcp->socket = INVALID_SOCKET;
}
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(tcp);
if (tcp->reqs_pending == 0) {
uv__want_endgame(tcp->loop, (uv_handle_t*)tcp);
}
if (tcp->reqs_pending == 0)
uv__want_endgame(loop, (uv_handle_t*) tcp);
}

View File

@ -2237,11 +2237,13 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
req->cb(req, uv_translate_sys_error(err));
}
handle->stream.conn.write_reqs_pending--;
if (handle->stream.conn.shutdown_req != NULL &&
handle->stream.conn.write_reqs_pending == 0) {
uv__want_endgame(loop, (uv_handle_t*)handle);
}
if (handle->stream.conn.write_reqs_pending == 0)
if (handle->flags & UV_HANDLE_SHUTTING)
uv__process_tty_shutdown_req(loop,
handle,
handle->stream.conn.shutdown_req);
DECREASE_PENDING_REQ_COUNT(handle);
}
@ -2262,43 +2264,43 @@ void uv__tty_close(uv_tty_t* handle) {
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
if (handle->reqs_pending == 0) {
if (handle->reqs_pending == 0)
uv__want_endgame(handle->loop, (uv_handle_t*) handle);
}
void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) {
assert(stream->stream.conn.write_reqs_pending == 0);
assert(req);
stream->stream.conn.shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, stream, req);
/* TTY shutdown is really just a no-op */
if (req->cb) {
if (stream->flags & UV_HANDLE_CLOSING) {
req->cb(req, UV_ECANCELED);
} else {
req->cb(req, 0);
}
}
DECREASE_PENDING_REQ_COUNT(stream);
}
void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
handle->stream.conn.shutdown_req != NULL &&
handle->stream.conn.write_reqs_pending == 0) {
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
assert(handle->flags & UV_HANDLE_CLOSING);
assert(handle->reqs_pending == 0);
/* TTY shutdown is really just a no-op */
if (handle->stream.conn.shutdown_req->cb) {
if (handle->flags & UV_HANDLE_CLOSING) {
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
} else {
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
}
}
/* The wait handle used for raw reading should be unregistered when the
* wait callback runs. */
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
handle->tty.rd.read_raw_wait == NULL);
handle->stream.conn.shutdown_req = NULL;
DECREASE_PENDING_REQ_COUNT(handle);
return;
}
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
/* The wait handle used for raw reading should be unregistered when the
* wait callback runs. */
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
handle->tty.rd.read_raw_wait == NULL);
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_close(handle);
}
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_close(handle);
}

View File

@ -1087,7 +1087,7 @@ int uv__udp_disconnect(uv_udp_t* handle) {
memset(&addr, 0, sizeof(addr));
err = connect(handle->socket, &addr, sizeof(addr));
err = connect(handle->socket, (struct sockaddr*) &addr, sizeof(addr));
if (err)
return uv_translate_sys_error(WSAGetLastError());
@ -1146,6 +1146,7 @@ int uv__udp_try_send(uv_udp_t* handle,
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
if (err)
return err;
addr = (const struct sockaddr*) &converted;
}
/* Already sending a message.*/
@ -1169,7 +1170,7 @@ int uv__udp_try_send(uv_udp_t* handle,
nbufs,
&bytes,
0,
(const struct sockaddr*) &converted,
addr,
addrlen,
NULL,
NULL);

View File

@ -1,4 +1,4 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
/* 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
@ -25,115 +25,55 @@
#include <stdlib.h>
#include <errno.h>
#ifndef HAVE_KQUEUE
# if defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# define HAVE_KQUEUE 1
# endif
#if !defined(_WIN32) && !defined(_AIX)
#include <poll.h>
#endif
#ifndef HAVE_EPOLL
# if defined(__linux__)
# define HAVE_EPOLL 1
# endif
#endif
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
#if defined(HAVE_KQUEUE)
# include <sys/types.h>
# include <sys/event.h>
# include <sys/time.h>
#endif
#if defined(HAVE_EPOLL)
# include <sys/epoll.h>
#endif
static uv_thread_t embed_thread;
static uv_sem_t embed_sem;
static uv_timer_t embed_timer;
static uv_async_t embed_async;
static volatile int embed_closed;
static int embed_timer_called;
static uv_async_t async;
static uv_barrier_t barrier;
static void embed_thread_runner(void* arg) {
int r;
int fd;
int timeout;
while (!embed_closed) {
fd = uv_backend_fd(uv_default_loop());
timeout = uv_backend_timeout(uv_default_loop());
do {
#if defined(HAVE_KQUEUE)
struct timespec ts;
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
r = kevent(fd, NULL, 0, NULL, 0, &ts);
#elif defined(HAVE_EPOLL)
{
struct epoll_event ev;
r = epoll_wait(fd, &ev, 1, timeout);
}
#endif
} while (r == -1 && errno == EINTR);
uv_async_send(&embed_async);
uv_sem_wait(&embed_sem);
}
static void thread_main(void* arg) {
ASSERT_LE(0, uv_barrier_wait(&barrier));
uv_sleep(250);
ASSERT_EQ(0, uv_async_send(&async));
}
static void embed_cb(uv_async_t* async) {
uv_run(uv_default_loop(), UV_RUN_ONCE);
uv_sem_post(&embed_sem);
static void async_cb(uv_async_t* handle) {
uv_close((uv_handle_t*) handle, NULL);
}
static void embed_timer_cb(uv_timer_t* timer) {
embed_timer_called++;
embed_closed = 1;
uv_close((uv_handle_t*) &embed_async, NULL);
}
#endif
TEST_IMPL(embed) {
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
uv_loop_t external;
uv_thread_t thread;
uv_loop_t* loop;
ASSERT(0 == uv_loop_init(&external));
loop = uv_default_loop();
ASSERT_EQ(0, uv_async_init(loop, &async, async_cb));
ASSERT_EQ(0, uv_barrier_init(&barrier, 2));
ASSERT_EQ(0, uv_thread_create(&thread, thread_main, NULL));
ASSERT_LE(0, uv_barrier_wait(&barrier));
embed_timer_called = 0;
embed_closed = 0;
uv_async_init(&external, &embed_async, embed_cb);
/* Start timer in default loop */
uv_timer_init(uv_default_loop(), &embed_timer);
uv_timer_start(&embed_timer, embed_timer_cb, 250, 0);
/* Start worker that will interrupt external loop */
uv_sem_init(&embed_sem, 0);
uv_thread_create(&embed_thread, embed_thread_runner, NULL);
/* But run external loop */
uv_run(&external, UV_RUN_DEFAULT);
uv_thread_join(&embed_thread);
uv_loop_close(&external);
ASSERT(embed_timer_called == 1);
while (uv_loop_alive(loop)) {
#if defined(_WIN32) || defined(_AIX)
ASSERT_LE(0, uv_run(loop, UV_RUN_ONCE));
#else
int rc;
do {
struct pollfd p;
p.fd = uv_backend_fd(loop);
p.events = POLLIN;
p.revents = 0;
rc = poll(&p, 1, uv_backend_timeout(loop));
} while (rc == -1 && errno == EINTR);
ASSERT_LE(0, uv_run(loop, UV_RUN_NOWAIT));
#endif
}
ASSERT_EQ(0, uv_thread_join(&thread));
uv_barrier_destroy(&barrier);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -334,19 +334,8 @@ static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
uv_close((uv_handle_t*)handle, close_cb);
}
static void timer_cb_close_handle(uv_timer_t* timer) {
uv_handle_t* handle;
ASSERT_NOT_NULL(timer);
handle = timer->data;
uv_close((uv_handle_t*)timer, NULL);
uv_close((uv_handle_t*)handle, close_cb);
}
static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
const char* filename, int events, int status) {
ASSERT(fs_event_cb_called == 0);
++fs_event_cb_called;
ASSERT(handle == &fs_event);
@ -358,13 +347,7 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
#endif
/* Regression test for SunOS: touch should generate just one event. */
{
static uv_timer_t timer;
uv_timer_init(handle->loop, &timer);
timer.data = handle;
uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
}
uv_close((uv_handle_t*)handle, close_cb);
}
static void timer_cb_file(uv_timer_t* handle) {
@ -738,7 +721,8 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(timer_cb_touch_called == 1);
ASSERT(fs_event_cb_called == 1);
/* FSEvents on macOS sometimes sends one change event, sometimes two. */
ASSERT_NE(0, fs_event_cb_called);
ASSERT(close_cb_called == 1);
/* Cleanup */
@ -923,6 +907,44 @@ TEST_IMPL(fs_event_close_with_pending_event) {
return 0;
}
TEST_IMPL(fs_event_close_with_pending_delete_event) {
#if defined(NO_FS_EVENTS)
RETURN_SKIP(NO_FS_EVENTS);
#endif
uv_loop_t* loop;
int r;
loop = uv_default_loop();
create_dir("watch_dir");
create_file("watch_dir/file");
r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0);
ASSERT(r == 0);
/* Generate an fs event. */
remove("watch_dir/file");
/* Allow time for the remove event to propagate to the pending list. */
/* XXX - perhaps just for __sun? */
uv_sleep(1100);
uv_update_time(loop);
uv_close((uv_handle_t*)&fs_event, close_cb);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(close_cb_called == 1);
/* Clean up */
remove("watch_dir/");
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(fs_event_close_in_callback) {
#if defined(NO_FS_EVENTS)
RETURN_SKIP(NO_FS_EVENTS);

View File

@ -30,8 +30,9 @@ static const int server_port = TEST_PORT;
/* Will be updated right after making the uv_connect_call */
static int connect_port = -1;
static int getsocknamecount = 0;
static int getsocknamecount_tcp = 0;
static int getpeernamecount = 0;
static int getsocknamecount_udp = 0;
static uv_loop_t* loop;
static uv_tcp_t tcp;
@ -131,7 +132,7 @@ static void on_connection(uv_stream_t* server, int status) {
r = uv_tcp_getsockname(handle, &sockname, &namelen);
ASSERT(r == 0);
check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket");
getsocknamecount++;
getsocknamecount_tcp++;
namelen = sizeof peername;
r = uv_tcp_getpeername(handle, &peername, &namelen);
@ -154,7 +155,7 @@ static void on_connect(uv_connect_t* req, int status) {
r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen);
ASSERT(r == 0);
check_sockname(&sockname, "127.0.0.1", 0, "connected socket");
getsocknamecount++;
getsocknamecount_tcp++;
namelen = sizeof peername;
r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen);
@ -197,7 +198,7 @@ static int tcp_listener(void) {
r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen);
ASSERT(r == 0);
check_sockname(&sockname, "0.0.0.0", server_port, "server socket");
getsocknamecount++;
getsocknamecount_tcp++;
namelen = sizeof sockname;
r = uv_tcp_getpeername(&tcpServer, &peername, &namelen);
@ -256,7 +257,7 @@ static void udp_recv(uv_udp_t* handle,
r = uv_udp_getsockname(&udp, &sockname, &namelen);
ASSERT(r == 0);
check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket");
getsocknamecount++;
getsocknamecount_udp++;
uv_close((uv_handle_t*) &udp, NULL);
uv_close((uv_handle_t*) handle, NULL);
@ -293,7 +294,7 @@ static int udp_listener(void) {
r = uv_udp_getsockname(&udpServer, &sockname, &namelen);
ASSERT(r == 0);
check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket");
getsocknamecount++;
getsocknamecount_udp++;
r = uv_udp_recv_start(&udpServer, alloc, udp_recv);
ASSERT(r == 0);
@ -333,7 +334,7 @@ TEST_IMPL(getsockname_tcp) {
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(getsocknamecount == 3);
ASSERT(getsocknamecount_tcp == 3);
ASSERT(getpeernamecount == 3);
MAKE_VALGRIND_HAPPY();
@ -351,7 +352,7 @@ TEST_IMPL(getsockname_udp) {
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(getsocknamecount == 2);
ASSERT(getsocknamecount_udp == 2);
ASSERT(udp.send_queue_size == 0);
ASSERT(udpServer.send_queue_size == 0);

View File

@ -97,3 +97,29 @@ TEST_IMPL(idle_starvation) {
MAKE_VALGRIND_HAPPY();
return 0;
}
static void idle_stop(uv_idle_t* handle) {
uv_idle_stop(handle);
}
TEST_IMPL(idle_check) {
ASSERT_EQ(0, uv_idle_init(uv_default_loop(), &idle_handle));
ASSERT_EQ(0, uv_idle_start(&idle_handle, idle_stop));
ASSERT_EQ(0, uv_check_init(uv_default_loop(), &check_handle));
ASSERT_EQ(0, uv_check_start(&check_handle, check_cb));
ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_ONCE));
ASSERT_EQ(1, check_cb_called);
ASSERT_EQ(0, close_cb_called);
uv_close((uv_handle_t*) &idle_handle, close_cb);
uv_close((uv_handle_t*) &check_handle, close_cb);
ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_ONCE));
ASSERT_EQ(2, close_cb_called);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -22,7 +22,6 @@
#include "uv.h"
TEST_DECLARE (platform_output)
TEST_DECLARE (callback_order)
TEST_DECLARE (close_order)
TEST_DECLARE (run_once)
TEST_DECLARE (run_nowait)
@ -123,15 +122,18 @@ TEST_DECLARE (tcp_bind_error_inval)
TEST_DECLARE (tcp_bind_localhost_ok)
TEST_DECLARE (tcp_bind_invalid_flags)
TEST_DECLARE (tcp_bind_writable_flags)
TEST_DECLARE (tcp_bind_or_listen_error_after_close)
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_after_read_timeout)
TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_close_reset_accepted)
TEST_DECLARE (tcp_close_reset_accepted_after_shutdown)
TEST_DECLARE (tcp_close_reset_accepted_after_socket_shutdown)
TEST_DECLARE (tcp_close_reset_client)
TEST_DECLARE (tcp_close_reset_client_after_shutdown)
TEST_DECLARE (tcp_create_early)
@ -147,6 +149,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_rst)
TEST_DECLARE (tcp_bind6_error_addrinuse)
TEST_DECLARE (tcp_bind6_error_addrnotavail)
TEST_DECLARE (tcp_bind6_error_fault)
@ -191,6 +194,7 @@ TEST_DECLARE (pipe_bind_error_addrnotavail)
TEST_DECLARE (pipe_bind_error_inval)
TEST_DECLARE (pipe_connect_multiple)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_bind_or_listen_error_after_close)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (pipe_connect_to_file)
TEST_DECLARE (pipe_connect_on_prepare)
@ -224,6 +228,7 @@ TEST_DECLARE (timer_is_closing)
TEST_DECLARE (timer_null_callback)
TEST_DECLARE (timer_early_check)
TEST_DECLARE (idle_starvation)
TEST_DECLARE (idle_check)
TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg)
TEST_DECLARE (walk_handles)
@ -318,6 +323,7 @@ TEST_DECLARE (spawn_inherit_streams)
TEST_DECLARE (spawn_quoted_path)
TEST_DECLARE (spawn_tcp_server)
TEST_DECLARE (spawn_exercise_sigchld_issue)
TEST_DECLARE (spawn_relative_path)
TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (fs_poll_close_request)
@ -386,6 +392,7 @@ TEST_DECLARE (fs_event_no_callback_after_close)
TEST_DECLARE (fs_event_no_callback_on_close)
TEST_DECLARE (fs_event_immediate_close)
TEST_DECLARE (fs_event_close_with_pending_event)
TEST_DECLARE (fs_event_close_with_pending_delete_event)
TEST_DECLARE (fs_event_close_in_callback)
TEST_DECLARE (fs_event_start_and_close)
TEST_DECLARE (fs_event_error_reporting)
@ -422,6 +429,7 @@ TEST_DECLARE (fs_invalid_mkdir_name)
#endif
TEST_DECLARE (fs_get_system_error)
TEST_DECLARE (strscpy)
TEST_DECLARE (strtok)
TEST_DECLARE (threadpool_queue_work_simple)
TEST_DECLARE (threadpool_queue_work_einval)
TEST_DECLARE (threadpool_multiple_event_loops)
@ -541,9 +549,6 @@ 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)
@ -695,15 +700,18 @@ TASK_LIST_START
TEST_ENTRY (tcp_bind_localhost_ok)
TEST_ENTRY (tcp_bind_invalid_flags)
TEST_ENTRY (tcp_bind_writable_flags)
TEST_ENTRY (tcp_bind_or_listen_error_after_close)
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_after_read_timeout)
TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_close_reset_accepted)
TEST_ENTRY (tcp_close_reset_accepted_after_shutdown)
TEST_ENTRY (tcp_close_reset_accepted_after_socket_shutdown)
TEST_ENTRY (tcp_close_reset_client)
TEST_ENTRY (tcp_close_reset_client_after_shutdown)
TEST_ENTRY (tcp_create_early)
@ -723,6 +731,9 @@ TASK_LIST_START
TEST_ENTRY (tcp_read_stop_start)
TEST_ENTRY (tcp_rst)
TEST_HELPER (tcp_rst, tcp4_echo_server)
TEST_ENTRY (tcp_bind6_error_addrinuse)
TEST_ENTRY (tcp_bind6_error_addrnotavail)
TEST_ENTRY (tcp_bind6_error_fault)
@ -769,6 +780,7 @@ TASK_LIST_START
TEST_ENTRY (pipe_bind_error_inval)
TEST_ENTRY (pipe_connect_multiple)
TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (pipe_bind_or_listen_error_after_close)
TEST_ENTRY (pipe_getsockname)
TEST_ENTRY (pipe_getsockname_abstract)
TEST_ENTRY (pipe_getsockname_blocking)
@ -814,6 +826,7 @@ TASK_LIST_START
TEST_ENTRY (timer_early_check)
TEST_ENTRY (idle_starvation)
TEST_ENTRY (idle_check)
TEST_ENTRY (ref)
TEST_ENTRY (idle_ref)
@ -946,6 +959,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_quoted_path)
TEST_ENTRY (spawn_tcp_server)
TEST_ENTRY (spawn_exercise_sigchld_issue)
TEST_ENTRY (spawn_relative_path)
TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (fs_poll_close_request)
@ -1048,6 +1062,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_no_callback_on_close)
TEST_ENTRY (fs_event_immediate_close)
TEST_ENTRY (fs_event_close_with_pending_event)
TEST_ENTRY (fs_event_close_with_pending_delete_event)
TEST_ENTRY (fs_event_close_in_callback)
TEST_ENTRY (fs_event_start_and_close)
TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000)
@ -1084,6 +1099,7 @@ TASK_LIST_START
TEST_ENTRY (get_osfhandle_valid_handle)
TEST_ENTRY (open_osfhandle_valid_handle)
TEST_ENTRY (strscpy)
TEST_ENTRY (strtok)
TEST_ENTRY (threadpool_queue_work_simple)
TEST_ENTRY (threadpool_queue_work_einval)
TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 60000)

View File

@ -137,3 +137,19 @@ TEST_IMPL(pipe_listen_without_bind) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(pipe_bind_or_listen_error_after_close) {
uv_pipe_t server;
ASSERT_EQ(uv_pipe_init(uv_default_loop(), &server, 0), 0);
uv_close((uv_handle_t*) &server, NULL);
ASSERT_EQ(uv_pipe_bind(&server, TEST_PIPENAME), UV_EINVAL);
ASSERT_EQ(uv_listen((uv_stream_t*) &server, SOMAXCONN, NULL), UV_EINVAL);
ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -102,8 +102,7 @@ TEST_IMPL(pipe_set_non_blocking) {
ASSERT(n == UV_EAGAIN); /* E_NOTIMPL */
ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &pipe_handle, &buf, 1, write_cb));
ASSERT_NOT_NULL(write_req.handle);
ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* queue write_cb */
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* process write_cb */
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
ASSERT_NULL(write_req.handle); /* check for signaled completion of write_cb */
n = buf.len;
#endif

View File

@ -1675,9 +1675,6 @@ TEST_IMPL(closed_fd_events) {
ASSERT(req.result == 1);
uv_fs_req_cleanup(&req);
#ifdef _WIN32
ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE));
#endif
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
/* should have received just one byte */
@ -1981,3 +1978,37 @@ void spawn_stdin_stdout(void) {
}
}
#endif /* !_WIN32 */
TEST_IMPL(spawn_relative_path) {
char* sep;
init_process_options("spawn_helper1", exit_cb);
exepath_size = sizeof(exepath) - 2;
ASSERT_EQ(0, uv_exepath(exepath, &exepath_size));
exepath[exepath_size] = '\0';
/* Poor man's basename(3). */
sep = strrchr(exepath, '/');
if (sep == NULL)
sep = strrchr(exepath, '\\');
ASSERT_NOT_NULL(sep);
/* Split into dirname and basename and make basename relative. */
memmove(sep + 2, sep, 1 + strlen(sep));
sep[0] = '\0';
sep[1] = '.';
sep[2] = '/';
options.cwd = exepath;
options.file = options.args[0] = sep + 1;
ASSERT_EQ(0, uv_spawn(uv_default_loop(), &process, &options));
ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_EQ(1, exit_cb_called);
ASSERT_EQ(1, close_cb_called);
MAKE_VALGRIND_HAPPY();
return 0;
}

90
deps/libuv/test/test-strtok.c vendored Normal file
View File

@ -0,0 +1,90 @@
/* 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 <string.h>
#include "../src/strtok.h"
#include "../src/strtok.c"
struct strtok_test_case {
const char* str;
const char* sep;
};
const char* tokens[] = {
"abc",
NULL,
"abc",
"abf",
NULL,
"This",
"is.a",
"test",
"of",
"the",
"string",
"tokenizer",
"function.",
NULL,
"Hello",
"This-is-a-nice",
"-string",
NULL
};
#define ASSERT_STRCMP(x, y) \
ASSERT((x != NULL && y != NULL && strcmp(x, y) == 0) || (x == y && x == NULL))
TEST_IMPL(strtok) {
struct strtok_test_case tests[] = {
{ "abc", "" },
{ "abc.abf", "." },
{ "This;is.a:test:of=the/string\\tokenizer-function.", "\\/:;=-" },
{ "Hello This-is-a-nice.-string", " ." },
};
size_t tokens_len = ARRAY_SIZE(tokens);
size_t tests_len = ARRAY_SIZE(tests);
size_t i;
size_t j;
char* itr;
char* tok_r;
char current_test[2048];
for (i = 0, j = 0; i < tests_len; i += 1) {
ASSERT(j < tokens_len);
snprintf(current_test, sizeof(current_test), "%s", tests[i].str);
tok_r = uv__strtok(current_test, tests[i].sep, &itr);
ASSERT_STRCMP(tok_r, tokens[j]);
j++;
while (tok_r) {
ASSERT(j < tokens_len);
tok_r = uv__strtok(NULL, tests[i].sep, &itr);
ASSERT_STRCMP(tok_r, tokens[j]);
j++;
}
}
return 0;
}

View File

@ -297,3 +297,21 @@ TEST_IMPL(tcp_bind_writable_flags) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tcp_bind_or_listen_error_after_close) {
uv_tcp_t tcp;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(9999);
addr.sin_family = AF_INET;
ASSERT_EQ(uv_tcp_init(uv_default_loop(), &tcp), 0);
uv_close((uv_handle_t*) &tcp, NULL);
ASSERT_EQ(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0), UV_EINVAL);
ASSERT_EQ(uv_listen((uv_stream_t*) &tcp, 5, NULL), UV_EINVAL);
ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -0,0 +1,183 @@
/* 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"
static uv_tcp_t client;
static uv_tcp_t connection;
static uv_connect_t connect_req;
static uv_timer_t timer;
static int read_cb_called;
static int on_close_called;
static void on_connection(uv_stream_t* server, int status);
static void on_client_connect(uv_connect_t* req, int status);
static void on_client_alloc(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf);
static void on_client_read(uv_stream_t* stream,
ssize_t nread,
const uv_buf_t* buf);
static void on_client_timeout(uv_timer_t* handle);
static void on_close(uv_handle_t* handle);
static void on_client_connect(uv_connect_t* conn_req, int status) {
int r;
r = uv_read_start((uv_stream_t*) &client, on_client_alloc, on_client_read);
ASSERT_EQ(r, 0);
r = uv_timer_start(&timer, on_client_timeout, 1000, 0);
ASSERT_EQ(r, 0);
}
static void on_client_alloc(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
static char slab[8];
buf->base = slab;
buf->len = sizeof(slab);
}
static void on_client_read(uv_stream_t* stream, ssize_t nread,
const uv_buf_t* buf) {
ASSERT_LT(nread, 0);
read_cb_called++;
}
static void on_client_timeout(uv_timer_t* handle) {
ASSERT_EQ(handle, &timer);
ASSERT_EQ(read_cb_called, 0);
uv_read_stop((uv_stream_t*) &client);
uv_close((uv_handle_t*) &client, on_close);
uv_close((uv_handle_t*) &timer, on_close);
}
static void on_connection_alloc(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
static char slab[8];
buf->base = slab;
buf->len = sizeof(slab);
}
static void on_connection_read(uv_stream_t* stream,
ssize_t nread,
const uv_buf_t* buf) {
ASSERT_EQ(nread, UV_EOF);
read_cb_called++;
uv_close((uv_handle_t*) stream, on_close);
}
static void on_connection(uv_stream_t* server, int status) {
int r;
ASSERT_EQ(status, 0);
ASSERT_EQ(uv_accept(server, (uv_stream_t*) &connection), 0);
r = uv_read_start((uv_stream_t*) &connection,
on_connection_alloc,
on_connection_read);
ASSERT_EQ(r, 0);
}
static void on_close(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &client ||
handle == (uv_handle_t*) &connection ||
handle == (uv_handle_t*) &timer);
on_close_called++;
}
static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
struct sockaddr_in addr;
int r;
ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0);
r = uv_tcp_init(loop, handle);
ASSERT_EQ(r, 0);
r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
ASSERT_EQ(r, 0);
r = uv_listen((uv_stream_t*) handle, 128, on_connection);
ASSERT_EQ(r, 0);
uv_unref((uv_handle_t*) handle);
}
/* Check that pending write requests have their callbacks
* invoked when the handle is closed.
*/
TEST_IMPL(tcp_close_after_read_timeout) {
struct sockaddr_in addr;
uv_tcp_t tcp_server;
uv_loop_t* loop;
int r;
ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0);
loop = uv_default_loop();
/* We can't use the echo server, it doesn't handle ECONNRESET. */
start_server(loop, &tcp_server);
r = uv_tcp_init(loop, &client);
ASSERT_EQ(r, 0);
r = uv_tcp_connect(&connect_req,
&client,
(const struct sockaddr*) &addr,
on_client_connect);
ASSERT_EQ(r, 0);
r = uv_tcp_init(loop, &connection);
ASSERT_EQ(r, 0);
r = uv_timer_init(loop, &timer);
ASSERT_EQ(r, 0);
ASSERT_EQ(read_cb_called, 0);
ASSERT_EQ(on_close_called, 0);
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT_EQ(r, 0);
ASSERT_EQ(read_cb_called, 1);
ASSERT_EQ(on_close_called, 3);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -25,6 +25,12 @@
#include <errno.h>
#include <string.h> /* memset */
#ifdef _WIN32
# define INVALID_FD (INVALID_HANDLE_VALUE)
#else
# define INVALID_FD (-1)
#endif
static uv_loop_t* loop;
static uv_tcp_t tcp_server;
static uv_tcp_t tcp_client;
@ -62,9 +68,22 @@ static void do_write(uv_tcp_t* handle) {
static void do_close(uv_tcp_t* handle) {
uv_os_fd_t fd;
int r;
if (shutdown_before_close == 1) {
ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb));
ASSERT(UV_EINVAL == uv_tcp_close_reset(handle, close_cb));
} else if (shutdown_before_close == 2) {
r = uv_fileno((const uv_handle_t*) handle, &fd);
ASSERT_EQ(r, 0);
ASSERT_NE(fd, INVALID_FD);
#ifdef _WIN32
ASSERT_EQ(0, shutdown(fd, SD_BOTH));
#else
ASSERT_EQ(0, shutdown(fd, SHUT_RDWR));
#endif
ASSERT_EQ(0, uv_tcp_close_reset(handle, close_cb));
} else {
ASSERT(0 == uv_tcp_close_reset(handle, close_cb));
ASSERT(UV_ENOTCONN == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb));
@ -288,3 +307,30 @@ TEST_IMPL(tcp_close_reset_accepted_after_shutdown) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tcp_close_reset_accepted_after_socket_shutdown) {
int r;
loop = uv_default_loop();
start_server(loop, &tcp_server);
client_close = 0;
shutdown_before_close = 2;
do_connect(loop, &tcp_client);
ASSERT_EQ(write_cb_called, 0);
ASSERT_EQ(close_cb_called, 0);
ASSERT_EQ(shutdown_cb_called, 0);
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT_EQ(r, 0);
ASSERT_EQ(write_cb_called, 4);
ASSERT_EQ(close_cb_called, 1);
ASSERT_EQ(shutdown_cb_called, 0);
MAKE_VALGRIND_HAPPY();
return 0;
}

107
deps/libuv/test/test-tcp-rst.c vendored Normal file
View File

@ -0,0 +1,107 @@
/* 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"
static uv_tcp_t tcp;
static uv_connect_t connect_req;
static uv_buf_t qbuf;
static int called_alloc_cb;
static int called_connect_cb;
static int called_close_cb;
static void close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &tcp);
called_close_cb++;
}
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
buf->base = malloc(size);
buf->len = size;
called_alloc_cb++;
}
static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) {
ASSERT_PTR_EQ((uv_tcp_t*) t, &tcp);
ASSERT_EQ(nread, UV_ECONNRESET);
int fd;
ASSERT_EQ(0, uv_fileno((uv_handle_t*) t, &fd));
uv_handle_type type = uv_guess_handle(fd);
ASSERT_EQ(type, UV_TCP);
uv_close((uv_handle_t *) t, close_cb);
free(buf->base);
}
static void connect_cb(uv_connect_t *req, int status) {
ASSERT_EQ(status, 0);
ASSERT_PTR_EQ(req, &connect_req);
/* Start reading from the connection so we receive the RST in uv__read. */
ASSERT_EQ(0, uv_read_start((uv_stream_t*) &tcp, alloc_cb, read_cb));
/* Write 'QSH' to receive RST from the echo server. */
ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1));
called_connect_cb++;
}
/*
* This test has a client which connects to the echo_server and receives TCP
* RST. Test checks that uv_guess_handle still works on a reset TCP handle.
*/
TEST_IMPL(tcp_rst) {
#ifndef _WIN32
struct sockaddr_in server_addr;
int r;
qbuf.base = "QSH";
qbuf.len = 3;
ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
r = uv_tcp_init(uv_default_loop(), &tcp);
ASSERT_EQ(r, 0);
r = uv_tcp_connect(&connect_req,
&tcp,
(const struct sockaddr*) &server_addr,
connect_cb);
ASSERT_EQ(r, 0);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT_EQ(called_alloc_cb, 1);
ASSERT_EQ(called_connect_cb, 1);
ASSERT_EQ(called_close_cb, 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
RETURN_SKIP("Unix only test");
#endif
}

View File

@ -25,6 +25,8 @@
static int once_cb_called = 0;
static int once_close_cb_called = 0;
static int twice_cb_called = 0;
static int twice_close_cb_called = 0;
static int repeat_cb_called = 0;
static int repeat_close_cb_called = 0;
static int order_cb_called = 0;
@ -58,6 +60,27 @@ static void once_cb(uv_timer_t* handle) {
uv_update_time(uv_default_loop());
}
static void twice_close_cb(uv_handle_t* handle) {
printf("TWICE_CLOSE_CB\n");
ASSERT_NOT_NULL(handle);
ASSERT(0 == uv_is_active(handle));
twice_close_cb_called++;
}
static void twice_cb(uv_timer_t* handle) {
printf("TWICE_CB %d\n", twice_cb_called);
ASSERT_NOT_NULL(handle);
ASSERT(0 == uv_is_active((uv_handle_t*) handle));
twice_cb_called++;
uv_close((uv_handle_t*)handle, twice_close_cb);
}
static void repeat_close_cb(uv_handle_t* handle) {
printf("REPEAT_CLOSE_CB\n");
@ -144,12 +167,12 @@ TEST_IMPL(timer_start_twice) {
ASSERT(r == 0);
r = uv_timer_start(&once, never_cb, 86400 * 1000, 0);
ASSERT(r == 0);
r = uv_timer_start(&once, once_cb, 10, 0);
r = uv_timer_start(&once, twice_cb, 10, 0);
ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(once_cb_called == 1);
ASSERT(twice_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;

View File

@ -98,10 +98,6 @@ static void sv_recv_cb(uv_udp_t* handle,
TEST_IMPL(udp_connect) {
#if defined(__PASE__)
RETURN_SKIP(
"IBMi PASE's UDP connection can not be disconnected with AF_UNSPEC.");
#endif
uv_udp_send_t req;
struct sockaddr_in ext_addr;
struct sockaddr_in tmp_addr;

View File

@ -98,10 +98,6 @@ static void sv_recv_cb(uv_udp_t* handle,
TEST_IMPL(udp_connect6) {
#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_in6 ext_addr;
struct sockaddr_in6 tmp_addr;