Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16d6a0b49d | ||
|
|
436c04048e | ||
|
|
feddddb56b | ||
|
|
f61f9c29d8 | ||
|
|
843b64faf5 | ||
|
|
85b526f56a | ||
|
|
8a94b7b2ec | ||
|
|
b807450e98 | ||
|
|
82cdfb75ff | ||
|
|
dcace2a393 | ||
|
|
378edb28f4 | ||
|
|
7894072528 | ||
|
|
abe59d6319 | ||
|
|
e399e00e78 | ||
|
|
51477bc711 | ||
|
|
23632e9104 | ||
|
|
a6ddf41edf | ||
|
|
82351168b3 | ||
|
|
bc19beadbd | ||
|
|
f15c602bd0 | ||
|
|
0f31978c30 | ||
|
|
a2ba04f83f | ||
|
|
8fb9cb9194 | ||
|
|
be8eec8c5a | ||
|
|
e59e2a9e49 | ||
|
|
ec5a4b54f7 | ||
|
|
beebf02cf6 | ||
|
|
a94f2ad2b7 | ||
|
|
3d78d121f4 | ||
|
|
e8969bff6c | ||
|
|
7b4cf04a91 | ||
|
|
acebb97490 | ||
|
|
88201044ed | ||
|
|
72d9abccd7 | ||
|
|
16e6e84dcc | ||
|
|
7752218db2 | ||
|
|
88baee1a35 | ||
|
|
264bb335af | ||
|
|
6af08fb527 | ||
|
|
2494c088f0 | ||
|
|
467859c2ba | ||
|
|
69bad8201b | ||
|
|
c431bc39c3 | ||
|
|
14644080c8 | ||
|
|
3d0578e6eb | ||
|
|
61c966cf0b | ||
|
|
b7d07d78e9 | ||
|
|
556a0f1f0f | ||
|
|
b1d30f9489 | ||
|
|
c6d43bea09 | ||
|
|
31ea3411cc | ||
|
|
d05744e3ed | ||
|
|
1b084f7bbe | ||
|
|
5dcef22c62 | ||
|
|
15e3f84678 | ||
|
|
2907f6d69e | ||
|
|
c6b67af390 | ||
|
|
7b75935b00 | ||
|
|
2d8371a06e | ||
|
|
d4ab6fbba4 | ||
|
|
e129cd7fda | ||
|
|
a3abfbcb08 | ||
|
|
64f4502b9b | ||
|
|
0caf5bb876 | ||
|
|
94e467ad93 | ||
|
|
078180e13d |
155
.github/workflows/CI-unix.yml
vendored
155
.github/workflows/CI-unix.yml
vendored
@ -29,59 +29,67 @@ jobs:
|
|||||||
|
|
||||||
build-android:
|
build-android:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: reactnativecommunity/react-native-android:2020-5-20
|
|
||||||
# Work around an issue where the node from actions/checkout is too new
|
|
||||||
# to run inside the long-in-the-tooth react-nactive-android container
|
|
||||||
# image.
|
|
||||||
env:
|
env:
|
||||||
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
|
|
||||||
ANDROID_AVD_HOME: /root/.android/avd
|
ANDROID_AVD_HOME: /root/.android/avd
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- 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
|
|
||||||
- name: Install Android ABI arm64-v8a
|
|
||||||
run: |
|
|
||||||
# TODO: This can be in a pre-built docker image
|
|
||||||
sdkmanager "build-tools;24.0.3" "platforms;android-24" "system-images;android-24;google_apis;arm64-v8a"
|
|
||||||
|
|
||||||
- name: Start emulator
|
|
||||||
run: |
|
|
||||||
echo no | avdmanager create avd -n test -k "system-images;android-24;google_apis;arm64-v8a"
|
|
||||||
|
|
||||||
adb start-server
|
|
||||||
|
|
||||||
emulator @test -memory 2048 -no-audio -no-window -gpu off -no-snapshot -no-boot-anim -netdelay none -netspeed full -no-snapshot-save -no-snapshot-load -writable-system &
|
|
||||||
|
|
||||||
adb wait-for-device
|
|
||||||
|
|
||||||
adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc.
|
|
||||||
|
|
||||||
# Push the build and test fixtures to the device
|
|
||||||
adb push build /data/local/tmp
|
|
||||||
adb shell mkdir /data/local/tmp/build/test
|
|
||||||
adb push test/fixtures /data/local/tmp/build/test
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: |
|
|
||||||
adb shell "cd /data/local/tmp/build ; env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a"
|
|
||||||
|
|
||||||
build-macos:
|
|
||||||
runs-on: macos-12
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Envinfo
|
- name: Envinfo
|
||||||
run: npx envinfo
|
run: npx envinfo
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
- name: Build and Test
|
||||||
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
|
with:
|
||||||
|
api-level: 30
|
||||||
|
arch: x86_64
|
||||||
|
target: google_apis
|
||||||
|
ram-size: 2048M
|
||||||
|
emulator-options: -no-audio -no-window -gpu off -no-boot-anim -netdelay none -netspeed full -writable-system -no-snapshot-save -no-snapshot-load -no-snapshot
|
||||||
|
disable-animations: true
|
||||||
|
script: |
|
||||||
|
echo "::group::Configure"
|
||||||
|
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="x86_64" -DANDROID_PLATFORM=android-30
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
echo "::group::Build"
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
|
## Correct some ld bugs that cause problems with libuv tests
|
||||||
|
wget "https://github.com/termux/termux-elf-cleaner/releases/download/v2.2.1/termux-elf-cleaner" -P build
|
||||||
|
chmod a+x build/termux-elf-cleaner
|
||||||
|
build/termux-elf-cleaner --api-level 30 ./build/uv_run_tests
|
||||||
|
build/termux-elf-cleaner --api-level 30 ./build/uv_run_tests_a
|
||||||
|
|
||||||
|
adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc.
|
||||||
|
|
||||||
|
## Push the build and test fixtures to the device
|
||||||
|
adb push build /data/local/tmp
|
||||||
|
adb shell mkdir /data/local/tmp/build/test
|
||||||
|
adb push test/fixtures /data/local/tmp/build/test
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
## Run the tests
|
||||||
|
file build/uv_run_tests_a
|
||||||
|
adb shell "cd /data/local/tmp/build && env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a"
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [macos-13, macos-14]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Envinfo
|
||||||
|
run: npx envinfo
|
||||||
|
- name: Disable Firewall
|
||||||
|
run: |
|
||||||
|
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
|
||||||
|
sudo defaults write /Library/Preferences/com.apple.alf globalstate -int 0
|
||||||
|
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
|
||||||
- name: Setup
|
- name: Setup
|
||||||
run: |
|
run: |
|
||||||
brew install ninja automake libtool
|
brew install ninja automake libtool
|
||||||
@ -112,7 +120,11 @@ jobs:
|
|||||||
make -C build-auto -j4
|
make -C build-auto -j4
|
||||||
|
|
||||||
build-ios:
|
build-ios:
|
||||||
runs-on: macos-12
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [macos-13, macos-14]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Configure
|
- name: Configure
|
||||||
@ -126,45 +138,36 @@ jobs:
|
|||||||
ls -lh build-ios
|
ls -lh build-ios
|
||||||
|
|
||||||
build-cross-qemu:
|
build-cross-qemu:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
name: build-cross-qemu-${{ matrix.config.target }}
|
name: build-cross-qemu-${{ matrix.config.target }}
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
config:
|
config:
|
||||||
- {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static }
|
- {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm }
|
||||||
- {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm-static }
|
- {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm }
|
||||||
- {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static }
|
- {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64 }
|
||||||
- {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64-static }
|
- {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64 }
|
||||||
- {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static }
|
- {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc }
|
||||||
- {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static }
|
- {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64 }
|
||||||
- {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le-static }
|
- {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le }
|
||||||
- {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x-static }
|
- {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x }
|
||||||
- {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips-static }
|
- {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips }
|
||||||
- {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64-static }
|
- {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64 }
|
||||||
- {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel-static }
|
- {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel }
|
||||||
- {target: mips64el,toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el-static }
|
- {target: mips64el, toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el }
|
||||||
- {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static}
|
- {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm }
|
||||||
- {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static}
|
- {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64 }
|
||||||
- {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static}
|
- {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc }
|
||||||
- {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static}
|
- {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64 }
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install QEMU
|
- name: Install qemu and ${{ matrix.config.toolchain }}
|
||||||
# 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_7\\.2+dfsg-.*_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: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install ${{ matrix.config.toolchain }} -y
|
sudo apt install qemu-user qemu-user-binfmt ${{ matrix.config.toolchain }} -y
|
||||||
- name: Configure with ${{ matrix.config.cc }}
|
- name: Configure with ${{ matrix.config.cc }}
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|||||||
2
.github/workflows/sanitizer.yml
vendored
2
.github/workflows/sanitizer.yml
vendored
@ -67,7 +67,7 @@ jobs:
|
|||||||
./build-ubsan/uv_run_tests_a
|
./build-ubsan/uv_run_tests_a
|
||||||
|
|
||||||
sanitizers-macos:
|
sanitizers-macos:
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|||||||
1
.mailmap
1
.mailmap
@ -52,6 +52,7 @@ San-Tai Hsu <vanilla@fatpipi.com>
|
|||||||
Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
|
Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
|
||||||
Saúl Ibarra Corretgé <s@saghul.net>
|
Saúl Ibarra Corretgé <s@saghul.net>
|
||||||
Saúl Ibarra Corretgé <s@saghul.net> <saghul@gmail.com>
|
Saúl Ibarra Corretgé <s@saghul.net> <saghul@gmail.com>
|
||||||
|
Saúl Ibarra Corretgé <saghul@gmail.com> <s@saghul.net>
|
||||||
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
|
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
|
||||||
Shuowang (Wayne) Zhang <shuowang.zhang@ibm.com>
|
Shuowang (Wayne) Zhang <shuowang.zhang@ibm.com>
|
||||||
TK-one <tk5641@naver.com>
|
TK-one <tk5641@naver.com>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ version: 2
|
|||||||
|
|
||||||
sphinx:
|
sphinx:
|
||||||
builder: html
|
builder: html
|
||||||
configuration: null
|
configuration: docs/src/conf.py
|
||||||
fail_on_warning: false
|
fail_on_warning: false
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
|||||||
4
AUTHORS
4
AUTHORS
@ -588,5 +588,7 @@ Raihaan Shouhell <raihaanhimself@gmail.com>
|
|||||||
Rialbat <miha-wead@mail.ru>
|
Rialbat <miha-wead@mail.ru>
|
||||||
Adam <adam@NetBSD.org>
|
Adam <adam@NetBSD.org>
|
||||||
Poul T Lomholt <ptlomholt@users.noreply.github.com>
|
Poul T Lomholt <ptlomholt@users.noreply.github.com>
|
||||||
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
|
||||||
Thad House <ThadHouse@users.noreply.github.com>
|
Thad House <ThadHouse@users.noreply.github.com>
|
||||||
|
Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com>
|
||||||
|
amcgoogan <105525867+amcgoogan@users.noreply.github.com>
|
||||||
|
Rafael Gonzaga <rafael.nunu@hotmail.com>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
if(POLICY CMP0091)
|
if(POLICY CMP0091)
|
||||||
cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting
|
cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting
|
||||||
@ -186,7 +186,7 @@ set(uv_sources
|
|||||||
src/version.c)
|
src/version.c)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 _CRT_DECLARE_NONSTDC_NAMES=0)
|
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 _CRT_DECLARE_NONSTDC_NAMES=0)
|
||||||
list(APPEND uv_libraries
|
list(APPEND uv_libraries
|
||||||
psapi
|
psapi
|
||||||
user32
|
user32
|
||||||
@ -667,6 +667,7 @@ if(LIBUV_BUILD_TESTS)
|
|||||||
test/test-thread-affinity.c
|
test/test-thread-affinity.c
|
||||||
test/test-thread-equal.c
|
test/test-thread-equal.c
|
||||||
test/test-thread.c
|
test/test-thread.c
|
||||||
|
test/test-thread-name.c
|
||||||
test/test-thread-priority.c
|
test/test-thread-priority.c
|
||||||
test/test-threadpool-cancel.c
|
test/test-threadpool-cancel.c
|
||||||
test/test-threadpool.c
|
test/test-threadpool.c
|
||||||
|
|||||||
83
ChangeLog
83
ChangeLog
@ -1,4 +1,85 @@
|
|||||||
2024.10.18, Version 1.49.2 (Stable)
|
2025.01.15, Version 1.50.0 (Stable), 8fb9cb919489a48880680a56efecff6a7dfb4504
|
||||||
|
|
||||||
|
Changes since version 1.49.2:
|
||||||
|
|
||||||
|
* ci: run macOS and iOS tests also on macOS 14 (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* unix,win: map ENOEXEC errno (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* test: skip multicast join test on ENOEXEC (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* ci: make sure the macOS firewall is disabled (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* darwin,test: squelch EBUSY error on multicast join (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* build: update minimum cmake to 3.10 (Ben Noordhuis)
|
||||||
|
|
||||||
|
* kqueue: use EVFILT_USER for async if available (Jameson Nash)
|
||||||
|
|
||||||
|
* unix,win: fix off-by-one in uv_wtf8_to_utf16() (Ben Noordhuis)
|
||||||
|
|
||||||
|
* doc: add scala-native-loop to LINKS.md (Julian A Avar C)
|
||||||
|
|
||||||
|
* unix: fix build breakage on haiku, openbsd, etc (Jeffrey H. Johnson)
|
||||||
|
|
||||||
|
* kqueue: lower overhead in uv__io_check_fd (Andy Pan)
|
||||||
|
|
||||||
|
* doc: move cjihrig back to active maintainers (cjihrig)
|
||||||
|
|
||||||
|
* build(deps): bump actions/checkout from 3 to 4 (dependabot[bot])
|
||||||
|
|
||||||
|
* unix,pipe: fix handling null buffer in uv_pipe_get{sock,peer}name (Saúl
|
||||||
|
Ibarra Corretgé)
|
||||||
|
|
||||||
|
* unix,win: harmonize buffer checking (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* unix,win: add support for detached threads (Juan José Arboleda)
|
||||||
|
|
||||||
|
* src: add uv_thread_set/getname() methods (Santiago Gimeno)
|
||||||
|
|
||||||
|
* build: fix qemu builds (Ben Noordhuis)
|
||||||
|
|
||||||
|
* win: drop support for windows 8 (Ben Noordhuis)
|
||||||
|
|
||||||
|
* linux: fix uv_cpu_info() arm cpu model detection (Ben Noordhuis)
|
||||||
|
|
||||||
|
* linux: always use io_uring for epoll batching (Ben Noordhuis)
|
||||||
|
|
||||||
|
* doc: clarify repeating timer behavior more (Ben Noordhuis)
|
||||||
|
|
||||||
|
* unix,win: handle nbufs=0 in uv_udp_try_send (Ben Noordhuis)
|
||||||
|
|
||||||
|
* win: use GetQueuedCompletionStatusEx directly (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* win: enable uv_thread_{get,set}name on MinGW (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* win: drop support for the legacy MinGW (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* win,fs: get (most) fstat when no permission (Jameson Nash)
|
||||||
|
|
||||||
|
* win: plug uv_fs_event_start memory leak (amcgoogan)
|
||||||
|
|
||||||
|
* test: address FreeBSD kernel bug causing NULL path in fsevents (Juan José
|
||||||
|
Arboleda)
|
||||||
|
|
||||||
|
* unix: refactor udp sendmsg code (Ben Noordhuis)
|
||||||
|
|
||||||
|
* unix,win: add uv_udp_try_send2 (Ben Noordhuis)
|
||||||
|
|
||||||
|
* test: fix flaky flaky udp_mmsg test (Juan José Arboleda)
|
||||||
|
|
||||||
|
* build: enable fdsan in Android (Juan José Arboleda)
|
||||||
|
|
||||||
|
* test: fix udp-multicast-join for FreeBSD (Juan José Arboleda)
|
||||||
|
|
||||||
|
* win: fix leak processing fs event (Saúl Ibarra Corretgé)
|
||||||
|
|
||||||
|
* src: set a default thread name for workers (Rafael Gonzaga)
|
||||||
|
|
||||||
|
* misc: implement uv_getrusage_thread (Juan José Arboleda)
|
||||||
|
|
||||||
|
|
||||||
|
2024.10.18, Version 1.49.2 (Stable), e1095c7a4373ce00cd8874d8e820de5afb25776e
|
||||||
|
|
||||||
Changes since version 1.49.1:
|
Changes since version 1.49.1:
|
||||||
|
|
||||||
|
|||||||
3
LINKS.md
3
LINKS.md
@ -37,6 +37,7 @@
|
|||||||
* [Pixie-io](https://github.com/pixie-io/pixie): Open-source observability tool for Kubernetes applications.
|
* [Pixie-io](https://github.com/pixie-io/pixie): Open-source observability tool for Kubernetes applications.
|
||||||
* [potion](https://github.com/perl11/potion)/[p2](https://github.com/perl11/p2): runtime
|
* [potion](https://github.com/perl11/potion)/[p2](https://github.com/perl11/p2): runtime
|
||||||
* [racer](https://libraries.io/rubygems/racer): Ruby web server written as an C extension
|
* [racer](https://libraries.io/rubygems/racer): Ruby web server written as an C extension
|
||||||
|
* [scala-native-loop](https://github.com/scala-native/scala-native-loop): Extensible event loop and async-oriented IO for Scala Native; powered by libuv
|
||||||
* [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript
|
* [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript
|
||||||
* [spider-gazelle](https://github.com/cotag/spider-gazelle): Ruby web server using libuv bindings
|
* [spider-gazelle](https://github.com/cotag/spider-gazelle): Ruby web server using libuv bindings
|
||||||
* [Suave](http://suave.io/): A simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition
|
* [Suave](http://suave.io/): A simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition
|
||||||
@ -107,3 +108,5 @@
|
|||||||
* [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem
|
* [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem
|
||||||
* Haskell
|
* Haskell
|
||||||
* [Z.Haskell](https://z.haskell.world)
|
* [Z.Haskell](https://z.haskell.world)
|
||||||
|
* C3
|
||||||
|
* [libuv.c3l](https://github.com/velikoss/libuv.c3l)
|
||||||
|
|||||||
@ -4,6 +4,9 @@ libuv is currently managed by the following individuals:
|
|||||||
|
|
||||||
* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
|
* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
|
||||||
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
|
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
|
||||||
|
* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig))
|
||||||
|
- GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig)
|
||||||
|
- GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb)
|
||||||
* **Jameson Nash** ([@vtjnash](https://github.com/vtjnash))
|
* **Jameson Nash** ([@vtjnash](https://github.com/vtjnash))
|
||||||
- GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-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)
|
- GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash)
|
||||||
@ -24,9 +27,6 @@ libuv is currently managed by the following individuals:
|
|||||||
* **Anna Henningsen** ([@addaleax](https://github.com/addaleax))
|
* **Anna Henningsen** ([@addaleax](https://github.com/addaleax))
|
||||||
* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz))
|
* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz))
|
||||||
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
|
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
|
||||||
* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig))
|
|
||||||
- GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig)
|
|
||||||
- GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb)
|
|
||||||
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
|
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
|
||||||
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
|
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
|
||||||
* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq))
|
* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq))
|
||||||
|
|||||||
@ -59,7 +59,7 @@ if WINNT
|
|||||||
uvinclude_HEADERS += include/uv/win.h include/uv/tree.h
|
uvinclude_HEADERS += include/uv/win.h include/uv/tree.h
|
||||||
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
|
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
|
||||||
-DWIN32_LEAN_AND_MEAN \
|
-DWIN32_LEAN_AND_MEAN \
|
||||||
-D_WIN32_WINNT=0x0602
|
-D_WIN32_WINNT=0x0A00
|
||||||
libuv_la_SOURCES += src/win/async.c \
|
libuv_la_SOURCES += src/win/async.c \
|
||||||
src/win/atomicops-inl.h \
|
src/win/atomicops-inl.h \
|
||||||
src/win/core.c \
|
src/win/core.c \
|
||||||
@ -294,6 +294,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||||||
test/test-thread-equal.c \
|
test/test-thread-equal.c \
|
||||||
test/test-thread.c \
|
test/test-thread.c \
|
||||||
test/test-thread-affinity.c \
|
test/test-thread-affinity.c \
|
||||||
|
test/test-thread-name.c \
|
||||||
test/test-thread-priority.c \
|
test/test-thread-priority.c \
|
||||||
test/test-threadpool-cancel.c \
|
test/test-threadpool-cancel.c \
|
||||||
test/test-threadpool.c \
|
test/test-threadpool.c \
|
||||||
|
|||||||
@ -4,14 +4,14 @@
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | |
|
| GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | |
|
||||||
| macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases |
|
| macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases |
|
||||||
| Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported |
|
| Windows | Tier 1 | >= Windows 10 | VS 2015 and later are supported |
|
||||||
| FreeBSD | Tier 2 | >= 12 | |
|
| FreeBSD | Tier 2 | >= 12 | |
|
||||||
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
|
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
|
||||||
| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
|
| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
|
||||||
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
|
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
|
||||||
| Linux with musl | Tier 2 | musl >= 1.0 | |
|
| Linux with musl | Tier 2 | musl >= 1.0 | |
|
||||||
| Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` |
|
| Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` |
|
||||||
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
|
| MinGW | Tier 3 | MinGW-w64 | |
|
||||||
| SunOS | Tier 3 | Solaris 121 and later | |
|
| SunOS | Tier 3 | Solaris 121 and later | |
|
||||||
| Other | Tier 3 | N/A | |
|
| Other | Tier 3 | N/A | |
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
AC_PREREQ(2.57)
|
AC_PREREQ(2.57)
|
||||||
AC_INIT([libuv], [1.49.2], [https://github.com/libuv/libuv/issues])
|
AC_INIT([libuv], [1.50.1-dev], [https://github.com/libuv/libuv/issues])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
m4_include([m4/libuv-extra-automake-flags.m4])
|
m4_include([m4/libuv-extra-automake-flags.m4])
|
||||||
m4_include([m4/as_case.m4])
|
m4_include([m4/as_case.m4])
|
||||||
|
|||||||
@ -430,6 +430,12 @@ API
|
|||||||
|
|
||||||
Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively.
|
Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively.
|
||||||
|
|
||||||
|
Passing `UV_FS_UTIME_NOW` as the atime or mtime sets the timestamp to the
|
||||||
|
current time.
|
||||||
|
|
||||||
|
Passing `UV_FS_UTIME_OMIT` as the atime or mtime leaves the timestamp
|
||||||
|
untouched.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return
|
z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return
|
||||||
``UV_ENOSYS``.
|
``UV_ENOSYS``.
|
||||||
|
|||||||
@ -47,6 +47,11 @@ Data types
|
|||||||
|
|
||||||
The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements.
|
The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
For FreeBSD path could sometimes be `NULL` due to a kernel bug.
|
||||||
|
|
||||||
|
.. _Reference: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695
|
||||||
|
|
||||||
.. c:enum:: uv_fs_event
|
.. c:enum:: uv_fs_event
|
||||||
|
|
||||||
Event types that :c:type:`uv_fs_event_t` handles monitor.
|
Event types that :c:type:`uv_fs_event_t` handles monitor.
|
||||||
|
|||||||
@ -58,5 +58,5 @@ libuv can be downloaded from `here <https://dist.libuv.org/dist/>`_.
|
|||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Installation instructions can be found in `the README <https://github.com/libuv/libuv/blob/master/README.md>`_.
|
Installation instructions can be found in the `README <https://github.com/libuv/libuv/blob/master/README.md>`_.
|
||||||
|
|
||||||
|
|||||||
@ -360,6 +360,17 @@ API
|
|||||||
On Windows not all fields are set, the unsupported fields are filled with zeroes.
|
On Windows not all fields are set, the unsupported fields are filled with zeroes.
|
||||||
See :c:type:`uv_rusage_t` for more details.
|
See :c:type:`uv_rusage_t` for more details.
|
||||||
|
|
||||||
|
.. c:function:: int uv_getrusage_thread(uv_rusage_t* rusage)
|
||||||
|
|
||||||
|
Gets the resource usage measures for the calling thread.
|
||||||
|
|
||||||
|
.. versionadded:: 1.50.0
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Not supported on all platforms. May return `UV_ENOTSUP`.
|
||||||
|
On macOS and Windows not all fields are set, the unsupported fields are filled with zeroes.
|
||||||
|
See :c:type:`uv_rusage_t` for more details.
|
||||||
|
|
||||||
.. c:function:: uv_pid_t uv_os_getpid(void)
|
.. c:function:: uv_pid_t uv_os_getpid(void)
|
||||||
|
|
||||||
Returns the current process ID.
|
Returns the current process ID.
|
||||||
|
|||||||
@ -78,6 +78,14 @@ Threads
|
|||||||
|
|
||||||
.. versionchanged:: 1.4.1 returns a UV_E* error code on failure
|
.. versionchanged:: 1.4.1 returns a UV_E* error code on failure
|
||||||
|
|
||||||
|
.. c:function:: int uv_thread_detach(uv_thread_t* tid)
|
||||||
|
|
||||||
|
Detaches a thread. Detached threads automatically release their
|
||||||
|
resources upon termination, eliminating the need for the application to
|
||||||
|
call `uv_thread_join`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.50.0
|
||||||
|
|
||||||
.. c:function:: int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg)
|
.. c:function:: int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg)
|
||||||
|
|
||||||
Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread.
|
Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread.
|
||||||
@ -132,7 +140,29 @@ Threads
|
|||||||
.. c:function:: int uv_thread_join(uv_thread_t *tid)
|
.. c:function:: int uv_thread_join(uv_thread_t *tid)
|
||||||
.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2)
|
.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2)
|
||||||
|
|
||||||
|
.. c:function:: int uv_thread_setname(const char* name)
|
||||||
|
|
||||||
|
Sets the name of the current thread. Different platforms define different limits on the max number of characters
|
||||||
|
a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()`
|
||||||
|
will truncate it in case `name` is larger than the limit of the platform.
|
||||||
|
|
||||||
|
Not supported on Windows Server 2016, returns `UV_ENOSYS`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.50.0
|
||||||
|
|
||||||
|
.. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size)
|
||||||
|
|
||||||
|
Gets the name of the thread specified by `tid`. The thread name is copied, with the trailing NUL, into the buffer
|
||||||
|
pointed to by `name`. The `size` parameter specifies the size of the buffer pointed to by `name`.
|
||||||
|
The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit
|
||||||
|
with the trailing NUL.
|
||||||
|
|
||||||
|
Not supported on Windows Server 2016, returns `UV_ENOSYS`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.50.0
|
||||||
|
|
||||||
.. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority)
|
.. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority)
|
||||||
|
|
||||||
If the function succeeds, the return value is 0.
|
If the function succeeds, the return value is 0.
|
||||||
If the function fails, the return value is less than zero.
|
If the function fails, the return value is less than zero.
|
||||||
Sets the scheduling priority of the thread specified by tid. It requires elevated
|
Sets the scheduling priority of the thread specified by tid. It requires elevated
|
||||||
@ -140,7 +170,9 @@ Threads
|
|||||||
The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST,
|
The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST,
|
||||||
UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL,
|
UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL,
|
||||||
UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST.
|
UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST.
|
||||||
|
|
||||||
.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority)
|
.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority)
|
||||||
|
|
||||||
If the function succeeds, the return value is 0.
|
If the function succeeds, the return value is 0.
|
||||||
If the function fails, the return value is less than zero.
|
If the function fails, the return value is less than zero.
|
||||||
Retrieves the scheduling priority of the thread specified by tid. The value in the
|
Retrieves the scheduling priority of the thread specified by tid. The value in the
|
||||||
|
|||||||
@ -17,6 +17,8 @@ is 1024).
|
|||||||
.. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the
|
.. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the
|
||||||
(sometimes too low) platform default.
|
(sometimes too low) platform default.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.50.0 threads now have a default name of libuv-worker.
|
||||||
|
|
||||||
The threadpool is global and shared across all event loops. When a particular
|
The threadpool is global and shared across all event loops. When a particular
|
||||||
function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`)
|
function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`)
|
||||||
libuv preallocates and initializes the maximum number of threads allowed by
|
libuv preallocates and initializes the maximum number of threads allowed by
|
||||||
|
|||||||
@ -6,6 +6,15 @@
|
|||||||
|
|
||||||
Timer handles are used to schedule callbacks to be called in the future.
|
Timer handles are used to schedule callbacks to be called in the future.
|
||||||
|
|
||||||
|
Timers are either single-shot or repeating. Repeating timers do not adjust
|
||||||
|
for overhead but are rearmed relative to the event loop's idea of "now".
|
||||||
|
|
||||||
|
Libuv updates its idea of "now" right before executing timer callbacks, and
|
||||||
|
right after waking up from waiting for I/O. See also :c:func:`uv_update_time`.
|
||||||
|
|
||||||
|
Example: a repeating timer with a 50 ms interval whose callback takes 17 ms
|
||||||
|
to complete, runs again 33 ms later. If other tasks take longer than 33 ms,
|
||||||
|
the timer callback runs as soon as possible.
|
||||||
|
|
||||||
Data types
|
Data types
|
||||||
----------
|
----------
|
||||||
@ -64,11 +73,6 @@ API
|
|||||||
duration, and will follow normal timer semantics in the case of a
|
duration, and will follow normal timer semantics in the case of a
|
||||||
time-slice overrun.
|
time-slice overrun.
|
||||||
|
|
||||||
For example, if a 50ms repeating timer first runs for 17ms, it will be
|
|
||||||
scheduled to run again 33ms later. If other tasks consume more than the
|
|
||||||
33ms following the first timer callback, then the callback will run as soon
|
|
||||||
as possible.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If the repeat value is set from a timer callback it does not immediately take effect.
|
If the repeat value is set from a timer callback it does not immediately take effect.
|
||||||
If the timer was non-repeating before, it will have been stopped. If it was repeating,
|
If the timer was non-repeating before, it will have been stopped. If it was repeating,
|
||||||
|
|||||||
@ -27,10 +27,15 @@ Data types
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
/* Initial/normal terminal mode */
|
/* Initial/normal terminal mode */
|
||||||
UV_TTY_MODE_NORMAL,
|
UV_TTY_MODE_NORMAL,
|
||||||
/* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
|
/*
|
||||||
|
* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled).
|
||||||
|
* May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions.
|
||||||
|
*/
|
||||||
UV_TTY_MODE_RAW,
|
UV_TTY_MODE_RAW,
|
||||||
/* Binary-safe I/O mode for IPC (Unix-only) */
|
/* Binary-safe I/O mode for IPC (Unix-only) */
|
||||||
UV_TTY_MODE_IO
|
UV_TTY_MODE_IO,
|
||||||
|
/* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */
|
||||||
|
UV_TTY_MODE_RAW_VT
|
||||||
} uv_tty_mode_t;
|
} uv_tty_mode_t;
|
||||||
|
|
||||||
.. c:enum:: uv_tty_vtermstate_t
|
.. c:enum:: uv_tty_vtermstate_t
|
||||||
|
|||||||
@ -426,6 +426,20 @@ API
|
|||||||
|
|
||||||
.. versionchanged:: 1.27.0 added support for connected sockets
|
.. versionchanged:: 1.27.0 added support for connected sockets
|
||||||
|
|
||||||
|
.. c:function:: int uv_udp_try_send2(uv_udp_t* handle, unsigned int count, uv_buf_t* bufs[/*count*/], unsigned int nbufs[/*count*/], struct sockaddr* addrs[/*count*/], unsigned int flags)
|
||||||
|
|
||||||
|
Like :c:func:`uv_udp_try_send`, but can send multiple datagrams.
|
||||||
|
Lightweight abstraction around :man:`sendmmsg(2)`, with a :man:`sendmsg(2)`
|
||||||
|
fallback loop for platforms that do not support the former. The handle must
|
||||||
|
be fully initialized; call c:func:`uv_udp_bind` first.
|
||||||
|
|
||||||
|
:returns: >= 0: number of datagrams sent. Zero only if `count` was zero.
|
||||||
|
< 0: negative error code. Only if sending the first datagram fails,
|
||||||
|
otherwise returns a positive send count. ``UV_EAGAIN`` when datagrams
|
||||||
|
cannot be sent right now; fall back to :c:func:`uv_udp_send`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.50.0
|
||||||
|
|
||||||
.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
|
.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
|
||||||
|
|
||||||
Prepare for receiving data. If the socket has not previously been bound
|
Prepare for receiving data. If the socket has not previously been bound
|
||||||
|
|||||||
24
include/uv.h
24
include/uv.h
@ -58,6 +58,7 @@ extern "C" {
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/* Internal type, do not use. */
|
/* Internal type, do not use. */
|
||||||
struct uv__queue {
|
struct uv__queue {
|
||||||
@ -157,6 +158,7 @@ struct uv__queue {
|
|||||||
XX(ESOCKTNOSUPPORT, "socket type not supported") \
|
XX(ESOCKTNOSUPPORT, "socket type not supported") \
|
||||||
XX(ENODATA, "no data available") \
|
XX(ENODATA, "no data available") \
|
||||||
XX(EUNATCH, "protocol driver not attached") \
|
XX(EUNATCH, "protocol driver not attached") \
|
||||||
|
XX(ENOEXEC, "exec format error") \
|
||||||
|
|
||||||
#define UV_HANDLE_TYPE_MAP(XX) \
|
#define UV_HANDLE_TYPE_MAP(XX) \
|
||||||
XX(ASYNC, async) \
|
XX(ASYNC, async) \
|
||||||
@ -775,6 +777,12 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
|
|||||||
const uv_buf_t bufs[],
|
const uv_buf_t bufs[],
|
||||||
unsigned int nbufs,
|
unsigned int nbufs,
|
||||||
const struct sockaddr* addr);
|
const struct sockaddr* addr);
|
||||||
|
UV_EXTERN int uv_udp_try_send2(uv_udp_t* handle,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/],
|
||||||
|
unsigned int flags);
|
||||||
UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
|
UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
|
||||||
uv_alloc_cb alloc_cb,
|
uv_alloc_cb alloc_cb,
|
||||||
uv_udp_recv_cb recv_cb);
|
uv_udp_recv_cb recv_cb);
|
||||||
@ -798,10 +806,15 @@ struct uv_tty_s {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
/* Initial/normal terminal mode */
|
/* Initial/normal terminal mode */
|
||||||
UV_TTY_MODE_NORMAL,
|
UV_TTY_MODE_NORMAL,
|
||||||
/* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
|
/*
|
||||||
|
* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled).
|
||||||
|
* May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions.
|
||||||
|
*/
|
||||||
UV_TTY_MODE_RAW,
|
UV_TTY_MODE_RAW,
|
||||||
/* Binary-safe I/O mode for IPC (Unix-only) */
|
/* Binary-safe I/O mode for IPC (Unix-only) */
|
||||||
UV_TTY_MODE_IO
|
UV_TTY_MODE_IO,
|
||||||
|
/* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */
|
||||||
|
UV_TTY_MODE_RAW_VT
|
||||||
} uv_tty_mode_t;
|
} uv_tty_mode_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -1288,6 +1301,7 @@ typedef struct {
|
|||||||
} uv_rusage_t;
|
} uv_rusage_t;
|
||||||
|
|
||||||
UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
|
UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
|
||||||
|
UV_EXTERN int uv_getrusage_thread(uv_rusage_t* rusage);
|
||||||
|
|
||||||
UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
|
UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
|
||||||
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
|
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
|
||||||
@ -1577,6 +1591,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
|
|||||||
const char* path,
|
const char* path,
|
||||||
int mode,
|
int mode,
|
||||||
uv_fs_cb cb);
|
uv_fs_cb cb);
|
||||||
|
#define UV_FS_UTIME_NOW (INFINITY)
|
||||||
|
#define UV_FS_UTIME_OMIT (NAN)
|
||||||
UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
|
UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
|
||||||
uv_fs_t* req,
|
uv_fs_t* req,
|
||||||
const char* path,
|
const char* path,
|
||||||
@ -1869,6 +1885,7 @@ UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv);
|
|||||||
typedef void (*uv_thread_cb)(void* arg);
|
typedef void (*uv_thread_cb)(void* arg);
|
||||||
|
|
||||||
UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
|
UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
|
||||||
|
UV_EXTERN int uv_thread_detach(uv_thread_t* tid);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UV_THREAD_NO_FLAGS = 0x00,
|
UV_THREAD_NO_FLAGS = 0x00,
|
||||||
@ -1898,6 +1915,9 @@ UV_EXTERN int uv_thread_getcpu(void);
|
|||||||
UV_EXTERN uv_thread_t uv_thread_self(void);
|
UV_EXTERN uv_thread_t uv_thread_self(void);
|
||||||
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
|
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
|
||||||
UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
|
UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
|
||||||
|
UV_EXTERN int uv_thread_setname(const char* name);
|
||||||
|
UV_EXTERN int uv_thread_getname(uv_thread_t* tid, char* name, size_t size);
|
||||||
|
|
||||||
|
|
||||||
/* The presence of these unions force similar struct layout. */
|
/* The presence of these unions force similar struct layout. */
|
||||||
#define XX(_, name) uv_ ## name ## _t name;
|
#define XX(_, name) uv_ ## name ## _t name;
|
||||||
|
|||||||
@ -474,4 +474,10 @@
|
|||||||
# define UV__EUNATCH (-4023)
|
# define UV__EUNATCH (-4023)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENOEXEC) && !defined(_WIN32)
|
||||||
|
# define UV__ENOEXEC UV__ERR(ENOEXEC)
|
||||||
|
#else
|
||||||
|
# define UV__ENOEXEC (-4022)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* UV_ERRNO_H_ */
|
#endif /* UV_ERRNO_H_ */
|
||||||
|
|||||||
@ -271,7 +271,10 @@ typedef struct {
|
|||||||
|
|
||||||
#define UV_UDP_SEND_PRIVATE_FIELDS \
|
#define UV_UDP_SEND_PRIVATE_FIELDS \
|
||||||
struct uv__queue queue; \
|
struct uv__queue queue; \
|
||||||
struct sockaddr_storage addr; \
|
union { \
|
||||||
|
struct sockaddr addr; \
|
||||||
|
struct sockaddr_storage storage; \
|
||||||
|
} u; \
|
||||||
unsigned int nbufs; \
|
unsigned int nbufs; \
|
||||||
uv_buf_t* bufs; \
|
uv_buf_t* bufs; \
|
||||||
ssize_t status; \
|
ssize_t status; \
|
||||||
|
|||||||
@ -31,10 +31,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define UV_VERSION_MAJOR 1
|
#define UV_VERSION_MAJOR 1
|
||||||
#define UV_VERSION_MINOR 49
|
#define UV_VERSION_MINOR 50
|
||||||
#define UV_VERSION_PATCH 2
|
#define UV_VERSION_PATCH 1
|
||||||
#define UV_VERSION_IS_RELEASE 1
|
#define UV_VERSION_IS_RELEASE 0
|
||||||
#define UV_VERSION_SUFFIX ""
|
#define UV_VERSION_SUFFIX "dev"
|
||||||
|
|
||||||
#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
|
#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
|
||||||
(UV_VERSION_MINOR << 8) | \
|
(UV_VERSION_MINOR << 8) | \
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32_WINNT
|
#ifndef _WIN32_WINNT
|
||||||
# define _WIN32_WINNT 0x0600
|
# define _WIN32_WINNT 0x0A00
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||||
@ -32,14 +32,6 @@ typedef intptr_t ssize_t;
|
|||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
||||||
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
|
||||||
typedef struct pollfd {
|
|
||||||
SOCKET fd;
|
|
||||||
short events;
|
|
||||||
short revents;
|
|
||||||
} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LOCALE_INVARIANT
|
#ifndef LOCALE_INVARIANT
|
||||||
# define LOCALE_INVARIANT 0x007f
|
# define LOCALE_INVARIANT 0x007f
|
||||||
#endif
|
#endif
|
||||||
@ -507,8 +499,11 @@ typedef struct {
|
|||||||
union { \
|
union { \
|
||||||
struct { \
|
struct { \
|
||||||
/* Used for readable TTY handles */ \
|
/* Used for readable TTY handles */ \
|
||||||
/* TODO: remove me in v2.x. */ \
|
union { \
|
||||||
HANDLE unused_; \
|
/* TODO: remove me in v2.x. */ \
|
||||||
|
HANDLE unused_; \
|
||||||
|
int mode; \
|
||||||
|
} mode; \
|
||||||
uv_buf_t read_line_buffer; \
|
uv_buf_t read_line_buffer; \
|
||||||
HANDLE read_raw_wait; \
|
HANDLE read_raw_wait; \
|
||||||
/* Fields used for translating win keystrokes into vt100 characters */ \
|
/* Fields used for translating win keystrokes into vt100 characters */ \
|
||||||
|
|||||||
@ -139,6 +139,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
|
|||||||
struct poll_ctx* ctx;
|
struct poll_ctx* ctx;
|
||||||
size_t required_len;
|
size_t required_len;
|
||||||
|
|
||||||
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (!uv_is_active((uv_handle_t*)handle)) {
|
if (!uv_is_active((uv_handle_t*)handle)) {
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|||||||
@ -393,7 +393,7 @@ void uv_wtf8_to_utf16(const char* source_ptr,
|
|||||||
code_point = uv__wtf8_decode1(&source_ptr);
|
code_point = uv__wtf8_decode1(&source_ptr);
|
||||||
/* uv_wtf8_length_as_utf16 should have been called and checked first. */
|
/* uv_wtf8_length_as_utf16 should have been called and checked first. */
|
||||||
assert(code_point >= 0);
|
assert(code_point >= 0);
|
||||||
if (code_point > 0x10000) {
|
if (code_point > 0xFFFF) {
|
||||||
assert(code_point < 0x10FFFF);
|
assert(code_point < 0x10FFFF);
|
||||||
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
|
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
|
||||||
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
|
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
|
||||||
|
|||||||
@ -59,6 +59,7 @@ static void worker(void* arg) {
|
|||||||
struct uv__queue* q;
|
struct uv__queue* q;
|
||||||
int is_slow_work;
|
int is_slow_work;
|
||||||
|
|
||||||
|
uv_thread_setname("libuv-worker");
|
||||||
uv_sem_post((uv_sem_t*) arg);
|
uv_sem_post((uv_sem_t*) arg);
|
||||||
arg = NULL;
|
arg = NULL;
|
||||||
|
|
||||||
|
|||||||
@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
struct ifreq *ifr, *p, flg;
|
struct ifreq *ifr, *p, flg;
|
||||||
struct in6_ifreq if6;
|
struct in6_ifreq if6;
|
||||||
struct sockaddr_dl* sa_addr;
|
struct sockaddr_dl* sa_addr;
|
||||||
|
size_t namelen;
|
||||||
|
char* name;
|
||||||
|
|
||||||
ifc.ifc_req = NULL;
|
ifc.ifc_req = NULL;
|
||||||
sock6fd = -1;
|
sock6fd = -1;
|
||||||
@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
|
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
|
||||||
|
|
||||||
/* Count all up and running ipv4/ipv6 addresses */
|
/* Count all up and running ipv4/ipv6 addresses */
|
||||||
|
namelen = 0;
|
||||||
ifr = ifc.ifc_req;
|
ifr = ifc.ifc_req;
|
||||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||||
p = ifr;
|
p = ifr;
|
||||||
@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
namelen += strlen(ent->ifa_name) + 1;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,8 +1186,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Alloc the return interface structs */
|
/* Alloc the return interface structs */
|
||||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||||
if (!(*addresses)) {
|
if (*addresses == NULL) {
|
||||||
r = UV_ENOMEM;
|
r = UV_ENOMEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -1210,7 +1214,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
|
|
||||||
/* All conditions above must match count loop */
|
/* All conditions above must match count loop */
|
||||||
|
|
||||||
address->name = uv__strdup(p->ifr_name);
|
namelen = strlen(p->ifr_name) + 1;
|
||||||
|
address->name = memcpy(name, p->ifr_name, namelen);
|
||||||
|
name += namelen;
|
||||||
|
|
||||||
if (inet6)
|
if (inet6)
|
||||||
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||||
@ -1282,13 +1288,7 @@ cleanup:
|
|||||||
|
|
||||||
|
|
||||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||||
int count) {
|
int count) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
uv__free(addresses[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
uv__free(addresses);
|
uv__free(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,34 @@
|
|||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UV__KQUEUE_EVFILT_USER
|
||||||
|
static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT;
|
||||||
|
static int kqueue_evfilt_user_support = 1;
|
||||||
|
|
||||||
|
|
||||||
|
static void uv__kqueue_runtime_detection(void) {
|
||||||
|
int kq;
|
||||||
|
struct kevent ev[2];
|
||||||
|
struct timespec timeout = {0, 0};
|
||||||
|
|
||||||
|
/* Perform the runtime detection to ensure that kqueue with
|
||||||
|
* EVFILT_USER actually works. */
|
||||||
|
kq = kqueue();
|
||||||
|
EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER,
|
||||||
|
EV_ADD | EV_CLEAR, 0, 0, 0);
|
||||||
|
EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER,
|
||||||
|
0, NOTE_TRIGGER, 0, 0);
|
||||||
|
if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 ||
|
||||||
|
ev[0].filter != EVFILT_USER ||
|
||||||
|
ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT ||
|
||||||
|
ev[0].flags & EV_ERROR)
|
||||||
|
/* If we wind up here, we can assume that EVFILT_USER is defined but
|
||||||
|
* broken on the current system. */
|
||||||
|
kqueue_evfilt_user_support = 0;
|
||||||
|
uv__close(kq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void uv__async_send(uv_loop_t* loop);
|
static void uv__async_send(uv_loop_t* loop);
|
||||||
static int uv__async_start(uv_loop_t* loop);
|
static int uv__async_start(uv_loop_t* loop);
|
||||||
static void uv__cpu_relax(void);
|
static void uv__cpu_relax(void);
|
||||||
@ -139,7 +167,11 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
|||||||
|
|
||||||
assert(w == &loop->async_io_watcher);
|
assert(w == &loop->async_io_watcher);
|
||||||
|
|
||||||
|
#if UV__KQUEUE_EVFILT_USER
|
||||||
|
for (;!kqueue_evfilt_user_support;) {
|
||||||
|
#else
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
#endif
|
||||||
r = read(w->fd, buf, sizeof(buf));
|
r = read(w->fd, buf, sizeof(buf));
|
||||||
|
|
||||||
if (r == sizeof(buf))
|
if (r == sizeof(buf))
|
||||||
@ -195,6 +227,17 @@ static void uv__async_send(uv_loop_t* loop) {
|
|||||||
len = sizeof(val);
|
len = sizeof(val);
|
||||||
fd = loop->async_io_watcher.fd; /* eventfd */
|
fd = loop->async_io_watcher.fd; /* eventfd */
|
||||||
}
|
}
|
||||||
|
#elif UV__KQUEUE_EVFILT_USER
|
||||||
|
struct kevent ev;
|
||||||
|
|
||||||
|
if (kqueue_evfilt_user_support) {
|
||||||
|
fd = loop->async_io_watcher.fd; /* magic number for EVFILT_USER */
|
||||||
|
EV_SET(&ev, fd, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
|
||||||
|
r = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL);
|
||||||
|
if (r == 0)
|
||||||
|
return;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -215,6 +258,9 @@ static void uv__async_send(uv_loop_t* loop) {
|
|||||||
static int uv__async_start(uv_loop_t* loop) {
|
static int uv__async_start(uv_loop_t* loop) {
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
int err;
|
int err;
|
||||||
|
#if UV__KQUEUE_EVFILT_USER
|
||||||
|
struct kevent ev;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (loop->async_io_watcher.fd != -1)
|
if (loop->async_io_watcher.fd != -1)
|
||||||
return 0;
|
return 0;
|
||||||
@ -226,6 +272,36 @@ static int uv__async_start(uv_loop_t* loop) {
|
|||||||
|
|
||||||
pipefd[0] = err;
|
pipefd[0] = err;
|
||||||
pipefd[1] = -1;
|
pipefd[1] = -1;
|
||||||
|
#elif UV__KQUEUE_EVFILT_USER
|
||||||
|
uv_once(&kqueue_runtime_detection_guard, uv__kqueue_runtime_detection);
|
||||||
|
if (kqueue_evfilt_user_support) {
|
||||||
|
/* In order not to break the generic pattern of I/O polling, a valid
|
||||||
|
* file descriptor is required to take up a room in loop->watchers,
|
||||||
|
* thus we create one for that, but this fd will not be actually used,
|
||||||
|
* it's just a placeholder and magic number which is going to be closed
|
||||||
|
* during the cleanup, as other FDs. */
|
||||||
|
err = uv__open_cloexec("/", O_RDONLY);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
pipefd[0] = err;
|
||||||
|
pipefd[1] = -1;
|
||||||
|
|
||||||
|
/* When using EVFILT_USER event to wake up the kqueue, this event must be
|
||||||
|
* registered beforehand. Otherwise, calling kevent() to issue an
|
||||||
|
* unregistered EVFILT_USER event will get an ENOENT.
|
||||||
|
* Since uv__async_send() may happen before uv__io_poll() with multi-threads,
|
||||||
|
* we can't defer this registration of EVFILT_USER event as we did for other
|
||||||
|
* events, but must perform it right away. */
|
||||||
|
EV_SET(&ev, err, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
|
||||||
|
err = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL);
|
||||||
|
if (err < 0)
|
||||||
|
return UV__ERR(errno);
|
||||||
|
} else {
|
||||||
|
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
|
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@ -236,6 +312,13 @@ static int uv__async_start(uv_loop_t* loop) {
|
|||||||
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
|
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
|
||||||
loop->async_wfd = pipefd[1];
|
loop->async_wfd = pipefd[1];
|
||||||
|
|
||||||
|
#if UV__KQUEUE_EVFILT_USER
|
||||||
|
/* Prevent the EVFILT_USER event from being added to kqueue redundantly
|
||||||
|
* and mistakenly later in uv__io_poll(). */
|
||||||
|
if (kqueue_evfilt_user_support)
|
||||||
|
loop->async_io_watcher.events = loop->async_io_watcher.pevents;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO(bnoordhuis) share with linux.c */
|
||||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||||
|
uv_interface_address_t* address;
|
||||||
struct ifaddrs* addrs;
|
struct ifaddrs* addrs;
|
||||||
struct ifaddrs* ent;
|
struct ifaddrs* ent;
|
||||||
uv_interface_address_t* address;
|
size_t namelen;
|
||||||
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
|
char* name;
|
||||||
int i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*count = 0;
|
*count = 0;
|
||||||
*addresses = NULL;
|
*addresses = NULL;
|
||||||
@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
return UV__ERR(errno);
|
return UV__ERR(errno);
|
||||||
|
|
||||||
/* Count the number of interfaces */
|
/* Count the number of interfaces */
|
||||||
|
namelen = 0;
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||||
continue;
|
continue;
|
||||||
|
namelen += strlen(ent->ifa_name) + 1;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the memory is initiallized to zero using calloc() */
|
/* Make sure the memory is initiallized to zero using calloc() */
|
||||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||||
|
|
||||||
if (*addresses == NULL) {
|
if (*addresses == NULL) {
|
||||||
freeifaddrs(addrs);
|
freeifaddrs(addrs);
|
||||||
return UV_ENOMEM;
|
return UV_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = (char*) &(*addresses)[*count];
|
||||||
address = *addresses;
|
address = *addresses;
|
||||||
|
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
address->name = uv__strdup(ent->ifa_name);
|
namelen = strlen(ent->ifa_name) + 1;
|
||||||
|
address->name = memcpy(name, ent->ifa_name, namelen);
|
||||||
|
name += namelen;
|
||||||
|
|
||||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||||
@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
|
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
|
||||||
/* Fill in physical addresses for each interface */
|
/* Fill in physical addresses for each interface */
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
|
int i;
|
||||||
|
|
||||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO(bnoordhuis) share with linux.c */
|
||||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||||
int count) {
|
int count) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
uv__free(addresses[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
uv__free(addresses);
|
uv__free(addresses);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
# include <mach/mach.h>
|
||||||
|
# include <mach/thread_info.h>
|
||||||
# include <sys/filio.h>
|
# include <sys/filio.h>
|
||||||
# include <sys/sysctl.h>
|
# include <sys/sysctl.h>
|
||||||
#endif /* defined(__APPLE__) */
|
#endif /* defined(__APPLE__) */
|
||||||
@ -751,7 +753,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
|||||||
int uv_cwd(char* buffer, size_t* size) {
|
int uv_cwd(char* buffer, size_t* size) {
|
||||||
char scratch[1 + UV__PATH_MAX];
|
char scratch[1 + UV__PATH_MAX];
|
||||||
|
|
||||||
if (buffer == NULL || size == NULL)
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* Try to read directly into the user's buffer first... */
|
/* Try to read directly into the user's buffer first... */
|
||||||
@ -999,10 +1001,10 @@ int uv__fd_exists(uv_loop_t* loop, int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_getrusage(uv_rusage_t* rusage) {
|
static int uv__getrusage(int who, uv_rusage_t* rusage) {
|
||||||
struct rusage usage;
|
struct rusage usage;
|
||||||
|
|
||||||
if (getrusage(RUSAGE_SELF, &usage))
|
if (getrusage(who, &usage))
|
||||||
return UV__ERR(errno);
|
return UV__ERR(errno);
|
||||||
|
|
||||||
rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
|
rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
|
||||||
@ -1041,6 +1043,50 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_getrusage(uv_rusage_t* rusage) {
|
||||||
|
return uv__getrusage(RUSAGE_SELF, rusage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_getrusage_thread(uv_rusage_t* rusage) {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
mach_msg_type_number_t count;
|
||||||
|
thread_basic_info_data_t info;
|
||||||
|
kern_return_t kr;
|
||||||
|
thread_t thread;
|
||||||
|
|
||||||
|
thread = mach_thread_self();
|
||||||
|
count = THREAD_BASIC_INFO_COUNT;
|
||||||
|
kr = thread_info(thread,
|
||||||
|
THREAD_BASIC_INFO,
|
||||||
|
(thread_info_t)&info,
|
||||||
|
&count);
|
||||||
|
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
mach_port_deallocate(mach_task_self(), thread);
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(rusage, 0, sizeof(*rusage));
|
||||||
|
|
||||||
|
rusage->ru_utime.tv_sec = info.user_time.seconds;
|
||||||
|
rusage->ru_utime.tv_usec = info.user_time.microseconds;
|
||||||
|
rusage->ru_stime.tv_sec = info.system_time.seconds;
|
||||||
|
rusage->ru_stime.tv_usec = info.system_time.microseconds;
|
||||||
|
|
||||||
|
mach_port_deallocate(mach_task_self(), thread);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(RUSAGE_LWP)
|
||||||
|
return uv__getrusage(RUSAGE_LWP, rusage);
|
||||||
|
#elif defined(RUSAGE_THREAD)
|
||||||
|
return uv__getrusage(RUSAGE_THREAD, rusage);
|
||||||
|
#endif /* defined(__APPLE__) */
|
||||||
|
return UV_ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv__open_cloexec(const char* path, int flags) {
|
int uv__open_cloexec(const char* path, int flags) {
|
||||||
#if defined(O_CLOEXEC)
|
#if defined(O_CLOEXEC)
|
||||||
int fd;
|
int fd;
|
||||||
|
|||||||
@ -33,25 +33,9 @@
|
|||||||
#include "darwin-stub.h"
|
#include "darwin-stub.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int uv__pthread_setname_np(const char* name) {
|
|
||||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
|
||||||
int err;
|
|
||||||
|
|
||||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
|
||||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
|
||||||
|
|
||||||
err = pthread_setname_np(namebuf);
|
|
||||||
if (err)
|
|
||||||
return UV__ERR(err);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int uv__set_process_title(const char* title) {
|
int uv__set_process_title(const char* title) {
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
return uv__pthread_setname_np(title);
|
return uv__thread_setname(title);
|
||||||
#else
|
#else
|
||||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||||
const char*,
|
const char*,
|
||||||
@ -177,7 +161,7 @@ int uv__set_process_title(const char* title) {
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
uv__thread_setname(title); /* Don't care if it fails. */
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
116
src/unix/fs.c
116
src/unix/fs.c
@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
|
#if defined(__APPLE__) \
|
||||||
|
|| defined(_AIX71) \
|
||||||
|
|| defined(__DragonFly__) \
|
||||||
|
|| defined(__FreeBSD__) \
|
||||||
|
|| defined(__HAIKU__) \
|
||||||
|
|| defined(__NetBSD__) \
|
||||||
|
|| defined(__OpenBSD__) \
|
||||||
|
|| defined(__linux__) \
|
||||||
|
|| defined(__sun)
|
||||||
|
static struct timespec uv__fs_to_timespec(double time) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
|
if (uv__isinf(time))
|
||||||
|
return (struct timespec){UTIME_NOW, UTIME_NOW};
|
||||||
|
if (uv__isnan(time))
|
||||||
|
return (struct timespec){UTIME_OMIT, UTIME_OMIT};
|
||||||
|
|
||||||
ts.tv_sec = time;
|
ts.tv_sec = time;
|
||||||
ts.tv_nsec = (time - ts.tv_sec) * 1e9;
|
ts.tv_nsec = (time - ts.tv_sec) * 1e9;
|
||||||
|
|
||||||
@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
|
|||||||
}
|
}
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = time;
|
|
||||||
tv.tv_usec = (time - tv.tv_sec) * 1e6;
|
|
||||||
if (tv.tv_usec < 0) {
|
|
||||||
tv.tv_usec += 1e6;
|
|
||||||
tv.tv_sec -= 1;
|
|
||||||
}
|
|
||||||
return tv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||||
#if defined(__linux__) \
|
#if defined(__APPLE__) \
|
||||||
|| defined(_AIX71) \
|
|| defined(_AIX71) \
|
||||||
|
|| defined(__DragonFly__) \
|
||||||
|
|| defined(__FreeBSD__) \
|
||||||
|| defined(__HAIKU__) \
|
|| defined(__HAIKU__) \
|
||||||
|| defined(__GNU__)
|
|| defined(__NetBSD__) \
|
||||||
|
|| defined(__OpenBSD__) \
|
||||||
|
|| defined(__linux__) \
|
||||||
|
|| defined(__sun)
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
ts[0] = uv__fs_to_timespec(req->atime);
|
ts[0] = uv__fs_to_timespec(req->atime);
|
||||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||||
return futimens(req->file, ts);
|
return futimens(req->file, ts);
|
||||||
#elif defined(__APPLE__) \
|
|
||||||
|| defined(__DragonFly__) \
|
|
||||||
|| defined(__FreeBSD__) \
|
|
||||||
|| defined(__NetBSD__) \
|
|
||||||
|| defined(__OpenBSD__) \
|
|
||||||
|| defined(__sun)
|
|
||||||
struct timeval tv[2];
|
|
||||||
tv[0] = uv__fs_to_timeval(req->atime);
|
|
||||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
|
||||||
# if defined(__sun)
|
|
||||||
return futimesat(req->file, NULL, tv);
|
|
||||||
# else
|
|
||||||
return futimes(req->file, tv);
|
|
||||||
# endif
|
|
||||||
#elif defined(__MVS__)
|
#elif defined(__MVS__)
|
||||||
attrib_t atr;
|
attrib_t atr;
|
||||||
memset(&atr, 0, sizeof(atr));
|
memset(&atr, 0, sizeof(atr));
|
||||||
@ -461,12 +458,7 @@ static ssize_t uv__pwritev_emul(int fd,
|
|||||||
|
|
||||||
/* The function pointer cache is an uintptr_t because _Atomic void*
|
/* The function pointer cache is an uintptr_t because _Atomic void*
|
||||||
* doesn't work on macos/ios/etc...
|
* doesn't work on macos/ios/etc...
|
||||||
* Disable optimization on armv7 to work around the bug described in
|
|
||||||
* https://github.com/libuv/libuv/issues/4532
|
|
||||||
*/
|
*/
|
||||||
#if defined(__arm__) && (__ARM_ARCH == 7)
|
|
||||||
__attribute__((optimize("O0")))
|
|
||||||
#endif
|
|
||||||
static ssize_t uv__preadv_or_pwritev(int fd,
|
static ssize_t uv__preadv_or_pwritev(int fd,
|
||||||
const struct iovec* bufs,
|
const struct iovec* bufs,
|
||||||
size_t nbufs,
|
size_t nbufs,
|
||||||
@ -479,7 +471,12 @@ static ssize_t uv__preadv_or_pwritev(int fd,
|
|||||||
p = (void*) atomic_load_explicit(cache, memory_order_relaxed);
|
p = (void*) atomic_load_explicit(cache, memory_order_relaxed);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
#ifdef RTLD_DEFAULT
|
#ifdef RTLD_DEFAULT
|
||||||
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev");
|
/* Try _LARGEFILE_SOURCE version of preadv/pwritev first,
|
||||||
|
* then fall back to the plain version, for libcs like musl.
|
||||||
|
*/
|
||||||
|
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv64" : "pwritev64");
|
||||||
|
if (p == NULL)
|
||||||
|
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev");
|
||||||
dlerror(); /* Clear errors. */
|
dlerror(); /* Clear errors. */
|
||||||
#endif /* RTLD_DEFAULT */
|
#endif /* RTLD_DEFAULT */
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
@ -487,10 +484,7 @@ static ssize_t uv__preadv_or_pwritev(int fd,
|
|||||||
atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed);
|
atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use memcpy instead of `f = p` to work around a compiler bug,
|
f = p;
|
||||||
* see https://github.com/libuv/libuv/issues/4532
|
|
||||||
*/
|
|
||||||
memcpy(&f, &p, sizeof(p));
|
|
||||||
return f(fd, bufs, nbufs, off);
|
return f(fd, bufs, nbufs, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
|||||||
|
|
||||||
|
|
||||||
static ssize_t uv__fs_utime(uv_fs_t* req) {
|
static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||||
#if defined(__linux__) \
|
#if defined(__APPLE__) \
|
||||||
|| defined(_AIX71) \
|
|| defined(_AIX71) \
|
||||||
|| defined(__sun) \
|
|| defined(__DragonFly__) \
|
||||||
|| defined(__HAIKU__)
|
|| defined(__FreeBSD__) \
|
||||||
|
|| defined(__HAIKU__) \
|
||||||
|
|| defined(__NetBSD__) \
|
||||||
|
|| defined(__OpenBSD__) \
|
||||||
|
|| defined(__linux__) \
|
||||||
|
|| defined(__sun)
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
ts[0] = uv__fs_to_timespec(req->atime);
|
ts[0] = uv__fs_to_timespec(req->atime);
|
||||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||||
return utimensat(AT_FDCWD, req->path, ts, 0);
|
return utimensat(AT_FDCWD, req->path, ts, 0);
|
||||||
#elif defined(__APPLE__) \
|
#elif defined(_AIX) && !defined(_AIX71)
|
||||||
|| defined(__DragonFly__) \
|
|
||||||
|| defined(__FreeBSD__) \
|
|
||||||
|| defined(__NetBSD__) \
|
|
||||||
|| defined(__OpenBSD__)
|
|
||||||
struct timeval tv[2];
|
|
||||||
tv[0] = uv__fs_to_timeval(req->atime);
|
|
||||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
|
||||||
return utimes(req->path, tv);
|
|
||||||
#elif defined(_AIX) \
|
|
||||||
&& !defined(_AIX71)
|
|
||||||
struct utimbuf buf;
|
struct utimbuf buf;
|
||||||
buf.actime = req->atime;
|
buf.actime = req->atime;
|
||||||
buf.modtime = req->mtime;
|
buf.modtime = req->mtime;
|
||||||
@ -1184,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|
|||||||
|
|
||||||
|
|
||||||
static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
||||||
#if defined(__linux__) || \
|
#if defined(__APPLE__) \
|
||||||
defined(_AIX71) || \
|
|| defined(_AIX71) \
|
||||||
defined(__sun) || \
|
|| defined(__DragonFly__) \
|
||||||
defined(__HAIKU__) || \
|
|| defined(__FreeBSD__) \
|
||||||
defined(__GNU__) || \
|
|| defined(__HAIKU__) \
|
||||||
defined(__OpenBSD__)
|
|| defined(__NetBSD__) \
|
||||||
|
|| defined(__OpenBSD__) \
|
||||||
|
|| defined(__linux__) \
|
||||||
|
|| defined(__sun)
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
ts[0] = uv__fs_to_timespec(req->atime);
|
ts[0] = uv__fs_to_timespec(req->atime);
|
||||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||||
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
|
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
|
||||||
#elif defined(__APPLE__) || \
|
|
||||||
defined(__DragonFly__) || \
|
|
||||||
defined(__FreeBSD__) || \
|
|
||||||
defined(__NetBSD__)
|
|
||||||
struct timeval tv[2];
|
|
||||||
tv[0] = uv__fs_to_timeval(req->atime);
|
|
||||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
|
||||||
return lutimes(req->path, tv);
|
|
||||||
#else
|
#else
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@ -403,6 +403,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
return UV_ENOSYS;
|
return UV_ENOSYS;
|
||||||
|
|
||||||
/* The first loop to get the size of the array to be allocated */
|
/* The first loop to get the size of the array to be allocated */
|
||||||
|
namelen = 0;
|
||||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||||
cur->ifa_addr->sa_family == AF_INET))
|
cur->ifa_addr->sa_family == AF_INET))
|
||||||
@ -411,6 +412,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
namelen += strlen(cur->ifa_name) + 1;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,11 +422,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Alloc the return interface structs */
|
/* Alloc the return interface structs */
|
||||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||||
if (*addresses == NULL) {
|
if (*addresses == NULL) {
|
||||||
Qp2freeifaddrs(ifap);
|
Qp2freeifaddrs(ifap);
|
||||||
return UV_ENOMEM;
|
return UV_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = (char*) &(*addresses)[*count];
|
||||||
address = *addresses;
|
address = *addresses;
|
||||||
|
|
||||||
/* The second loop to fill in the array */
|
/* The second loop to fill in the array */
|
||||||
@ -436,7 +440,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
address->name = uv__strdup(cur->ifa_name);
|
namelen = strlen(cur->ifa_name) + 1;
|
||||||
|
address->name = memcpy(name, cur->ifa_name, namelen);
|
||||||
|
name += namelen;
|
||||||
|
|
||||||
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
|
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
|
||||||
|
|
||||||
@ -497,13 +503,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
|
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||||
int i;
|
int count) {
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
uv__free(addresses[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
uv__free(addresses);
|
uv__free(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,10 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#if defined(__APPLE__) || defined(__DragonFly__) || \
|
||||||
|
defined(__FreeBSD__) || defined(__NetBSD__)
|
||||||
|
#include <sys/event.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define uv__msan_unpoison(p, n) \
|
#define uv__msan_unpoison(p, n) \
|
||||||
do { \
|
do { \
|
||||||
@ -323,6 +327,8 @@ void uv__prepare_close(uv_prepare_t* handle);
|
|||||||
void uv__process_close(uv_process_t* handle);
|
void uv__process_close(uv_process_t* handle);
|
||||||
void uv__stream_close(uv_stream_t* handle);
|
void uv__stream_close(uv_stream_t* handle);
|
||||||
void uv__tcp_close(uv_tcp_t* handle);
|
void uv__tcp_close(uv_tcp_t* handle);
|
||||||
|
int uv__thread_setname(const char* name);
|
||||||
|
int uv__thread_getname(uv_thread_t* tid, char* name, size_t size);
|
||||||
size_t uv__thread_stack_size(void);
|
size_t uv__thread_stack_size(void);
|
||||||
void uv__udp_close(uv_udp_t* handle);
|
void uv__udp_close(uv_udp_t* handle);
|
||||||
void uv__udp_finish_close(uv_udp_t* handle);
|
void uv__udp_finish_close(uv_udp_t* handle);
|
||||||
@ -504,4 +510,22 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
|
||||||
|
/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0,
|
||||||
|
* FreeBSD 8.1, and NetBSD 10.0.
|
||||||
|
*
|
||||||
|
* Note that even though EVFILT_USER is defined on the current system,
|
||||||
|
* it may still fail to work at runtime somehow. In that case, we fall
|
||||||
|
* back to pipe-based signaling.
|
||||||
|
*/
|
||||||
|
#define UV__KQUEUE_EVFILT_USER 1
|
||||||
|
/* Magic number of identifier used for EVFILT_USER during runtime detection.
|
||||||
|
* There are no Google hits for this number when I create it. That way,
|
||||||
|
* people will be directed here if this number gets printed due to some
|
||||||
|
* kqueue error and they google for help. */
|
||||||
|
#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711
|
||||||
|
#else
|
||||||
|
#define UV__KQUEUE_EVFILT_USER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||||
|
|||||||
@ -97,8 +97,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
|||||||
|
|
||||||
|
|
||||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||||
struct kevent ev;
|
struct kevent ev[2];
|
||||||
int rc;
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
@ -133,17 +132,12 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rc = 0;
|
EV_SET(ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||||
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
EV_SET(ev + 1, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
||||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
if (kevent(loop->backend_fd, ev, 2, NULL, 0, NULL))
|
||||||
rc = UV__ERR(errno);
|
return UV__ERR(errno);
|
||||||
|
|
||||||
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
return 0;
|
||||||
if (rc == 0)
|
|
||||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
|
||||||
abort();
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -367,6 +361,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UV__KQUEUE_EVFILT_USER
|
||||||
|
if (ev->filter == EVFILT_USER) {
|
||||||
|
w = &loop->async_io_watcher;
|
||||||
|
assert(fd == w->fd);
|
||||||
|
uv__metrics_update_idle_time(loop);
|
||||||
|
w->cb(loop, w, w->events);
|
||||||
|
nevents++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ev->filter == EVFILT_VNODE) {
|
if (ev->filter == EVFILT_VNODE) {
|
||||||
assert(w->events == POLLIN);
|
assert(w->events == POLLIN);
|
||||||
assert(w->pevents == POLLIN);
|
assert(w->pevents == POLLIN);
|
||||||
|
|||||||
103
src/unix/linux.c
103
src/unix/linux.c
@ -455,7 +455,7 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int uv__use_io_uring(void) {
|
static int uv__use_io_uring(uint32_t flags) {
|
||||||
#if defined(__ANDROID_API__)
|
#if defined(__ANDROID_API__)
|
||||||
return 0; /* Possibly available but blocked by seccomp. */
|
return 0; /* Possibly available but blocked by seccomp. */
|
||||||
#elif defined(__arm__) && __SIZEOF_POINTER__ == 4
|
#elif defined(__arm__) && __SIZEOF_POINTER__ == 4
|
||||||
@ -470,25 +470,27 @@ static int uv__use_io_uring(void) {
|
|||||||
char* val;
|
char* val;
|
||||||
int use;
|
int use;
|
||||||
|
|
||||||
|
#if defined(__hppa__)
|
||||||
|
/* io_uring first supported on parisc in 6.1, functional in .51
|
||||||
|
* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/
|
||||||
|
*/
|
||||||
|
if (uv__kernel_version() < /*6.1.51*/0x060133)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* SQPOLL is all kinds of buggy but epoll batching should work fine. */
|
||||||
|
if (0 == (flags & UV__IORING_SETUP_SQPOLL))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Older kernels have a bug where the sqpoll thread uses 100% CPU. */
|
||||||
|
if (uv__kernel_version() < /*5.10.186*/0x050ABA)
|
||||||
|
return 0;
|
||||||
|
|
||||||
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
|
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
|
||||||
|
|
||||||
if (use == 0) {
|
if (use == 0) {
|
||||||
use = uv__kernel_version() >=
|
|
||||||
#if defined(__hppa__)
|
|
||||||
/* io_uring first supported on parisc in 6.1, functional in .51 */
|
|
||||||
/* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */
|
|
||||||
/* 6.1.51 */ 0x060133
|
|
||||||
#else
|
|
||||||
/* Older kernels have a bug where the sqpoll thread uses 100% CPU. */
|
|
||||||
/* 5.10.186 */ 0x050ABA
|
|
||||||
#endif
|
|
||||||
? 1 : -1;
|
|
||||||
|
|
||||||
/* But users can still enable it if they so desire. */
|
|
||||||
val = getenv("UV_USE_IO_URING");
|
val = getenv("UV_USE_IO_URING");
|
||||||
if (val != NULL)
|
use = val != NULL && atoi(val) > 0 ? 1 : -1;
|
||||||
use = atoi(val) ? 1 : -1;
|
|
||||||
|
|
||||||
atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
|
atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +520,7 @@ static void uv__iou_init(int epollfd,
|
|||||||
sq = MAP_FAILED;
|
sq = MAP_FAILED;
|
||||||
sqe = MAP_FAILED;
|
sqe = MAP_FAILED;
|
||||||
|
|
||||||
if (!uv__use_io_uring())
|
if (!uv__use_io_uring(flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
kernel_version = uv__kernel_version();
|
kernel_version = uv__kernel_version();
|
||||||
@ -766,14 +768,13 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
|||||||
*/
|
*/
|
||||||
if (iou->ringfd == -2) {
|
if (iou->ringfd == -2) {
|
||||||
/* By default, the SQPOLL is not created. Enable only if the loop is
|
/* By default, the SQPOLL is not created. Enable only if the loop is
|
||||||
* configured with UV_LOOP_USE_IO_URING_SQPOLL.
|
* configured with UV_LOOP_USE_IO_URING_SQPOLL and the UV_USE_IO_URING
|
||||||
|
* environment variable is unset or a positive number.
|
||||||
*/
|
*/
|
||||||
if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) {
|
if (loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL)
|
||||||
iou->ringfd = -1;
|
if (uv__use_io_uring(UV__IORING_SETUP_SQPOLL))
|
||||||
return NULL;
|
uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL);
|
||||||
}
|
|
||||||
|
|
||||||
uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL);
|
|
||||||
if (iou->ringfd == -2)
|
if (iou->ringfd == -2)
|
||||||
iou->ringfd = -1; /* "failed" */
|
iou->ringfd = -1; /* "failed" */
|
||||||
}
|
}
|
||||||
@ -1713,16 +1714,22 @@ int uv_uptime(double* uptime) {
|
|||||||
int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
|
int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
|
||||||
#if defined(__PPC__)
|
#if defined(__PPC__)
|
||||||
static const char model_marker[] = "cpu\t\t: ";
|
static const char model_marker[] = "cpu\t\t: ";
|
||||||
|
static const char model_marker2[] = "";
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
static const char model_marker[] = "Processor\t: ";
|
static const char model_marker[] = "model name\t: ";
|
||||||
|
static const char model_marker2[] = "Processor\t: ";
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
static const char model_marker[] = "CPU part\t: ";
|
static const char model_marker[] = "CPU part\t: ";
|
||||||
|
static const char model_marker2[] = "";
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
static const char model_marker[] = "cpu model\t\t: ";
|
static const char model_marker[] = "cpu model\t\t: ";
|
||||||
|
static const char model_marker2[] = "";
|
||||||
#elif defined(__loongarch__)
|
#elif defined(__loongarch__)
|
||||||
static const char model_marker[] = "cpu family\t\t: ";
|
static const char model_marker[] = "cpu family\t\t: ";
|
||||||
|
static const char model_marker2[] = "";
|
||||||
#else
|
#else
|
||||||
static const char model_marker[] = "model name\t: ";
|
static const char model_marker[] = "model name\t: ";
|
||||||
|
static const char model_marker2[] = "";
|
||||||
#endif
|
#endif
|
||||||
static const char parts[] =
|
static const char parts[] =
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
@ -1821,14 +1828,22 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
|
|||||||
if (1 != fscanf(fp, "processor\t: %u\n", &cpu))
|
if (1 != fscanf(fp, "processor\t: %u\n", &cpu))
|
||||||
break; /* Parse error. */
|
break; /* Parse error. */
|
||||||
|
|
||||||
found = 0;
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
while (!found && fgets(buf, sizeof(buf), fp))
|
if (!strncmp(buf, model_marker, sizeof(model_marker) - 1)) {
|
||||||
found = !strncmp(buf, model_marker, sizeof(model_marker) - 1);
|
p = buf + sizeof(model_marker) - 1;
|
||||||
|
goto parts;
|
||||||
|
}
|
||||||
|
if (!*model_marker2)
|
||||||
|
continue;
|
||||||
|
if (!strncmp(buf, model_marker2, sizeof(model_marker2) - 1)) {
|
||||||
|
p = buf + sizeof(model_marker2) - 1;
|
||||||
|
goto parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!found)
|
goto next; /* Not found. */
|
||||||
goto next;
|
|
||||||
|
|
||||||
p = buf + sizeof(model_marker) - 1;
|
parts:
|
||||||
n = (int) strcspn(p, "\n");
|
n = (int) strcspn(p, "\n");
|
||||||
|
|
||||||
/* arm64: translate CPU part code to model name. */
|
/* arm64: translate CPU part code to model name. */
|
||||||
@ -1939,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
|||||||
return !exclude_type;
|
return !exclude_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO(bnoordhuis) share with bsd-ifaddrs.c */
|
||||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||||
struct ifaddrs *addrs, *ent;
|
|
||||||
uv_interface_address_t* address;
|
uv_interface_address_t* address;
|
||||||
|
struct sockaddr_ll* sll;
|
||||||
|
struct ifaddrs* addrs;
|
||||||
|
struct ifaddrs* ent;
|
||||||
|
size_t namelen;
|
||||||
|
char* name;
|
||||||
int i;
|
int i;
|
||||||
struct sockaddr_ll *sll;
|
|
||||||
|
|
||||||
*count = 0;
|
*count = 0;
|
||||||
*addresses = NULL;
|
*addresses = NULL;
|
||||||
@ -1952,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
return UV__ERR(errno);
|
return UV__ERR(errno);
|
||||||
|
|
||||||
/* Count the number of interfaces */
|
/* Count the number of interfaces */
|
||||||
|
namelen = 0;
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
namelen += strlen(ent->ifa_name) + 1;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1965,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the memory is initiallized to zero using calloc() */
|
/* Make sure the memory is initiallized to zero using calloc() */
|
||||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||||
if (!(*addresses)) {
|
if (*addresses == NULL) {
|
||||||
freeifaddrs(addrs);
|
freeifaddrs(addrs);
|
||||||
return UV_ENOMEM;
|
return UV_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = (char*) &(*addresses)[*count];
|
||||||
address = *addresses;
|
address = *addresses;
|
||||||
|
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
address->name = uv__strdup(ent->ifa_name);
|
namelen = strlen(ent->ifa_name) + 1;
|
||||||
|
address->name = memcpy(name, ent->ifa_name, namelen);
|
||||||
|
name += namelen;
|
||||||
|
|
||||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||||
@ -2021,14 +2045,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO(bnoordhuis) share with bsd-ifaddrs.c */
|
||||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||||
int count) {
|
int count) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
uv__free(addresses[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
uv__free(addresses);
|
uv__free(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -360,6 +360,9 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
|||||||
char* p;
|
char* p;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
addrlen = sizeof(sa);
|
addrlen = sizeof(sa);
|
||||||
memset(&sa, 0, addrlen);
|
memset(&sa, 0, addrlen);
|
||||||
err = uv__getsockpeername((const uv_handle_t*) handle,
|
err = uv__getsockpeername((const uv_handle_t*) handle,
|
||||||
@ -444,7 +447,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
|||||||
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||||
unsigned desired_mode;
|
unsigned desired_mode;
|
||||||
struct stat pipe_stat;
|
struct stat pipe_stat;
|
||||||
char* name_buffer;
|
char name_buffer[1 + UV__PATH_MAX];
|
||||||
size_t name_len;
|
size_t name_len;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -457,26 +460,14 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
|||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
|
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
|
||||||
name_len = 0;
|
name_len = sizeof(name_buffer);
|
||||||
r = uv_pipe_getsockname(handle, NULL, &name_len);
|
|
||||||
if (r != UV_ENOBUFS)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
name_buffer = uv__malloc(name_len);
|
|
||||||
if (name_buffer == NULL)
|
|
||||||
return UV_ENOMEM;
|
|
||||||
|
|
||||||
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
||||||
if (r != 0) {
|
if (r != 0)
|
||||||
uv__free(name_buffer);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
/* stat must be used as fstat has a bug on Darwin */
|
/* stat must be used as fstat has a bug on Darwin */
|
||||||
if (uv__stat(name_buffer, &pipe_stat) == -1) {
|
if (uv__stat(name_buffer, &pipe_stat) == -1)
|
||||||
uv__free(name_buffer);
|
return UV__ERR(errno);
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
desired_mode = 0;
|
desired_mode = 0;
|
||||||
if (mode & UV_READABLE)
|
if (mode & UV_READABLE)
|
||||||
@ -485,15 +476,12 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
|||||||
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||||
|
|
||||||
/* Exit early if pipe already has desired mode. */
|
/* Exit early if pipe already has desired mode. */
|
||||||
if ((pipe_stat.st_mode & desired_mode) == desired_mode) {
|
if ((pipe_stat.st_mode & desired_mode) == desired_mode)
|
||||||
uv__free(name_buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
pipe_stat.st_mode |= desired_mode;
|
pipe_stat.st_mode |= desired_mode;
|
||||||
|
|
||||||
r = chmod(name_buffer, pipe_stat.st_mode);
|
r = chmod(name_buffer, pipe_stat.st_mode);
|
||||||
uv__free(name_buffer);
|
|
||||||
|
|
||||||
return r != -1 ? 0 : UV__ERR(errno);
|
return r != -1 ? 0 : UV__ERR(errno);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
|
|
||||||
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||||
|
|||||||
@ -188,8 +188,12 @@ void uv__wait_children(uv_loop_t* loop) {
|
|||||||
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||||
int mask;
|
int mask;
|
||||||
int fd;
|
int fd;
|
||||||
|
int ret;
|
||||||
|
int size;
|
||||||
|
int i;
|
||||||
|
|
||||||
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
|
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
|
||||||
|
size = 64 * 1024;
|
||||||
|
|
||||||
switch (container->flags & mask) {
|
switch (container->flags & mask) {
|
||||||
case UV_IGNORE:
|
case UV_IGNORE:
|
||||||
@ -199,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
|||||||
assert(container->data.stream != NULL);
|
assert(container->data.stream != NULL);
|
||||||
if (container->data.stream->type != UV_NAMED_PIPE)
|
if (container->data.stream->type != UV_NAMED_PIPE)
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
else
|
else {
|
||||||
return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
|
ret = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
setsockopt(fds[i], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||||
|
setsockopt(fds[i], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
case UV_INHERIT_FD:
|
case UV_INHERIT_FD:
|
||||||
case UV_INHERIT_STREAM:
|
case UV_INHERIT_STREAM:
|
||||||
|
|||||||
@ -826,6 +826,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
uv_interface_address_t* address;
|
uv_interface_address_t* address;
|
||||||
struct ifaddrs* addrs;
|
struct ifaddrs* addrs;
|
||||||
struct ifaddrs* ent;
|
struct ifaddrs* ent;
|
||||||
|
size_t namelen;
|
||||||
|
char* name;
|
||||||
|
|
||||||
*count = 0;
|
*count = 0;
|
||||||
*addresses = NULL;
|
*addresses = NULL;
|
||||||
@ -834,9 +836,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
return UV__ERR(errno);
|
return UV__ERR(errno);
|
||||||
|
|
||||||
/* Count the number of interfaces */
|
/* Count the number of interfaces */
|
||||||
|
namelen = 0;
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent))
|
if (uv__ifaddr_exclude(ent))
|
||||||
continue;
|
continue;
|
||||||
|
namelen += strlen(ent->ifa_name) + 1;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,19 +849,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||||
if (!(*addresses)) {
|
if (*addresses == NULL) {
|
||||||
freeifaddrs(addrs);
|
freeifaddrs(addrs);
|
||||||
return UV_ENOMEM;
|
return UV_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = (char*) &(*addresses)[*count];
|
||||||
address = *addresses;
|
address = *addresses;
|
||||||
|
|
||||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||||
if (uv__ifaddr_exclude(ent))
|
if (uv__ifaddr_exclude(ent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
address->name = uv__strdup(ent->ifa_name);
|
namelen = strlen(ent->ifa_name) + 1;
|
||||||
|
address->name = memcpy(name, ent->ifa_name, namelen);
|
||||||
|
name += namelen;
|
||||||
|
|
||||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||||
@ -885,13 +892,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||||||
#endif /* SUNOS_NO_IFADDRS */
|
#endif /* SUNOS_NO_IFADDRS */
|
||||||
|
|
||||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||||
int count) {
|
int count) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
uv__free(addresses[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
uv__free(addresses);
|
uv__free(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,9 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#include <pthread_np.h>
|
||||||
|
#endif
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -126,6 +129,12 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
|||||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_thread_detach(uv_thread_t *tid) {
|
||||||
|
return UV__ERR(pthread_detach(*tid));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_thread_create_ex(uv_thread_t* tid,
|
int uv_thread_create_ex(uv_thread_t* tid,
|
||||||
const uv_thread_options_t* params,
|
const uv_thread_options_t* params,
|
||||||
void (*entry)(void *arg),
|
void (*entry)(void *arg),
|
||||||
@ -205,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid,
|
|||||||
if (cpumask[i])
|
if (cpumask[i])
|
||||||
CPU_SET(i, &cpuset);
|
CPU_SET(i, &cpuset);
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__) || defined(__OHOS__)
|
||||||
if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
||||||
r = errno;
|
r = errno;
|
||||||
else
|
else
|
||||||
@ -233,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid,
|
|||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
CPU_ZERO(&cpuset);
|
CPU_ZERO(&cpuset);
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__) || defined(__OHOS__)
|
||||||
if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
||||||
r = errno;
|
r = errno;
|
||||||
else
|
else
|
||||||
@ -291,6 +300,18 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
|
|||||||
return pthread_equal(*t1, *t2);
|
return pthread_equal(*t1, *t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uv_thread_setname(const char* name) {
|
||||||
|
if (name == NULL)
|
||||||
|
return UV_EINVAL;
|
||||||
|
return uv__thread_setname(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
if (name == NULL || size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
return uv__thread_getname(tid, name, size);
|
||||||
|
}
|
||||||
|
|
||||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||||
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
||||||
@ -875,3 +896,80 @@ void uv_key_set(uv_key_t* key, void* value) {
|
|||||||
if (pthread_setspecific(*key, value))
|
if (pthread_setspecific(*key, value))
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(_AIX) || defined(__MVS__) || defined(__PASE__)
|
||||||
|
int uv__thread_setname(const char* name) {
|
||||||
|
return UV_ENOSYS;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
int uv__thread_setname(const char* name) {
|
||||||
|
char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||||
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
int err = pthread_setname_np(namebuf);
|
||||||
|
if (err)
|
||||||
|
return UV__ERR(errno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
int uv__thread_setname(const char* name) {
|
||||||
|
char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||||
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
return UV__ERR(pthread_setname_np(pthread_self(), "%s", namebuf));
|
||||||
|
}
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
int uv__thread_setname(const char* name) {
|
||||||
|
char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||||
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
pthread_set_name_np(pthread_self(), namebuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int uv__thread_setname(const char* name) {
|
||||||
|
char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||||
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
return UV__ERR(pthread_setname_np(pthread_self(), namebuf));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__ANDROID_API__) && __ANDROID_API__ < 26) || \
|
||||||
|
defined(_AIX) || \
|
||||||
|
defined(__MVS__) || \
|
||||||
|
defined(__PASE__)
|
||||||
|
int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
return UV_ENOSYS;
|
||||||
|
}
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
char thread_name[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
pthread_get_name_np(*tid, thread_name, sizeof(thread_name));
|
||||||
|
strncpy(name, thread_name, size - 1);
|
||||||
|
name[size - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
char thread_name[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
if (pthread_getname_np(*tid, thread_name, sizeof(thread_name)) != 0)
|
||||||
|
return UV__ERR(errno);
|
||||||
|
|
||||||
|
strncpy(name, thread_name, size - 1);
|
||||||
|
name[size - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
int r;
|
||||||
|
char thread_name[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
r = pthread_getname_np(*tid, thread_name, sizeof(thread_name));
|
||||||
|
if (r != 0)
|
||||||
|
return UV__ERR(r);
|
||||||
|
|
||||||
|
strncpy(name, thread_name, size - 1);
|
||||||
|
name[size - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||||||
int fd;
|
int fd;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (uv__is_raw_tty_mode(mode)) {
|
||||||
|
/* There is only a single raw TTY mode on UNIX. */
|
||||||
|
mode = UV_TTY_MODE_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
if (tty->mode == (int) mode)
|
if (tty->mode == (int) mode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||||||
case UV_TTY_MODE_IO:
|
case UV_TTY_MODE_IO:
|
||||||
uv__tty_make_raw(&tmp);
|
uv__tty_make_raw(&tmp);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply changes after draining */
|
/* Apply changes after draining */
|
||||||
|
|||||||
390
src/unix/udp.c
390
src/unix/udp.c
@ -47,6 +47,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle);
|
|||||||
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||||
int domain,
|
int domain,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
static int uv__udp_sendmsg1(int fd,
|
||||||
|
const uv_buf_t* bufs,
|
||||||
|
unsigned int nbufs,
|
||||||
|
const struct sockaddr* addr);
|
||||||
|
|
||||||
|
|
||||||
void uv__udp_close(uv_udp_t* handle) {
|
void uv__udp_close(uv_udp_t* handle) {
|
||||||
@ -282,169 +286,6 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
|||||||
&& handle->recv_cb != NULL);
|
&& handle->recv_cb != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) {
|
|
||||||
struct uv__queue* q;
|
|
||||||
struct msghdr h;
|
|
||||||
ssize_t size;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
memset(&h, 0, sizeof h);
|
|
||||||
if (req->addr.ss_family == AF_UNSPEC) {
|
|
||||||
h.msg_name = NULL;
|
|
||||||
h.msg_namelen = 0;
|
|
||||||
} else {
|
|
||||||
h.msg_name = &req->addr;
|
|
||||||
if (req->addr.ss_family == AF_INET6)
|
|
||||||
h.msg_namelen = sizeof(struct sockaddr_in6);
|
|
||||||
else if (req->addr.ss_family == AF_INET)
|
|
||||||
h.msg_namelen = sizeof(struct sockaddr_in);
|
|
||||||
else if (req->addr.ss_family == AF_UNIX)
|
|
||||||
h.msg_namelen = sizeof(struct sockaddr_un);
|
|
||||||
else {
|
|
||||||
assert(0 && "unsupported address family");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.msg_iov = (struct iovec*) req->bufs;
|
|
||||||
h.msg_iovlen = req->nbufs;
|
|
||||||
|
|
||||||
do
|
|
||||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
|
||||||
while (size == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (size == -1)
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
req->status = (size == -1 ? UV__ERR(errno) : size);
|
|
||||||
|
|
||||||
/* Sending a datagram is an atomic operation: either all data
|
|
||||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
|
||||||
* why we don't handle partial writes. Just pop the request
|
|
||||||
* off the write queue and onto the completed queue, done.
|
|
||||||
*/
|
|
||||||
uv__queue_remove(&req->queue);
|
|
||||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
|
||||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
|
||||||
|
|
||||||
if (uv__queue_empty(&handle->write_queue))
|
|
||||||
return;
|
|
||||||
|
|
||||||
q = uv__queue_head(&handle->write_queue);
|
|
||||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
|
||||||
static void uv__udp_sendmsg_many(uv_udp_t* handle) {
|
|
||||||
uv_udp_send_t* req;
|
|
||||||
struct mmsghdr h[20];
|
|
||||||
struct mmsghdr* p;
|
|
||||||
struct uv__queue* q;
|
|
||||||
ssize_t npkts;
|
|
||||||
size_t pkts;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
write_queue_drain:
|
|
||||||
for (pkts = 0, q = uv__queue_head(&handle->write_queue);
|
|
||||||
pkts < ARRAY_SIZE(h) && q != &handle->write_queue;
|
|
||||||
++pkts, q = uv__queue_head(q)) {
|
|
||||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
|
||||||
|
|
||||||
p = &h[pkts];
|
|
||||||
memset(p, 0, sizeof(*p));
|
|
||||||
if (req->addr.ss_family == AF_UNSPEC) {
|
|
||||||
p->msg_hdr.msg_name = NULL;
|
|
||||||
p->msg_hdr.msg_namelen = 0;
|
|
||||||
} else {
|
|
||||||
p->msg_hdr.msg_name = &req->addr;
|
|
||||||
if (req->addr.ss_family == AF_INET6)
|
|
||||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
|
|
||||||
else if (req->addr.ss_family == AF_INET)
|
|
||||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
|
|
||||||
else if (req->addr.ss_family == AF_UNIX)
|
|
||||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
|
|
||||||
else {
|
|
||||||
assert(0 && "unsupported address family");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
|
|
||||||
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
do
|
|
||||||
npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT);
|
|
||||||
while (npkts == -1 && errno == EINTR);
|
|
||||||
#else
|
|
||||||
do
|
|
||||||
npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0);
|
|
||||||
while (npkts == -1 && errno == EINTR);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (npkts < 1) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
|
||||||
return;
|
|
||||||
for (i = 0, q = uv__queue_head(&handle->write_queue);
|
|
||||||
i < pkts && q != &handle->write_queue;
|
|
||||||
++i, q = uv__queue_head(&handle->write_queue)) {
|
|
||||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
|
||||||
req->status = UV__ERR(errno);
|
|
||||||
uv__queue_remove(&req->queue);
|
|
||||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
|
||||||
}
|
|
||||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safety: npkts known to be >0 below. Hence cast from ssize_t
|
|
||||||
* to size_t safe.
|
|
||||||
*/
|
|
||||||
for (i = 0, q = uv__queue_head(&handle->write_queue);
|
|
||||||
i < (size_t)npkts && q != &handle->write_queue;
|
|
||||||
++i, q = uv__queue_head(&handle->write_queue)) {
|
|
||||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
|
||||||
req->status = req->bufs[0].len;
|
|
||||||
|
|
||||||
/* Sending a datagram is an atomic operation: either all data
|
|
||||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
|
||||||
* why we don't handle partial writes. Just pop the request
|
|
||||||
* off the write queue and onto the completed queue, done.
|
|
||||||
*/
|
|
||||||
uv__queue_remove(&req->queue);
|
|
||||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
|
|
||||||
if (!uv__queue_empty(&handle->write_queue))
|
|
||||||
goto write_queue_drain;
|
|
||||||
|
|
||||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
|
||||||
}
|
|
||||||
#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
|
||||||
|
|
||||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
|
||||||
struct uv__queue* q;
|
|
||||||
uv_udp_send_t* req;
|
|
||||||
|
|
||||||
if (uv__queue_empty(&handle->write_queue))
|
|
||||||
return;
|
|
||||||
|
|
||||||
q = uv__queue_head(&handle->write_queue);
|
|
||||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
|
||||||
/* Use sendmmsg() if this send request contains more than one datagram OR
|
|
||||||
* there is more than one send request (because that automatically implies
|
|
||||||
* there is more than one datagram.)
|
|
||||||
*/
|
|
||||||
if (req->nbufs != 1 || &handle->write_queue != uv__queue_next(&req->queue))
|
|
||||||
return uv__udp_sendmsg_many(handle);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return uv__udp_sendmsg_one(handle, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||||
* refinements for programs that use multicast. Therefore we preferentially
|
* refinements for programs that use multicast. Therefore we preferentially
|
||||||
@ -743,11 +584,11 @@ int uv__udp_send(uv_udp_send_t* req,
|
|||||||
empty_queue = (handle->send_queue_count == 0);
|
empty_queue = (handle->send_queue_count == 0);
|
||||||
|
|
||||||
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
||||||
assert(addrlen <= sizeof(req->addr));
|
assert(addrlen <= sizeof(req->u.storage));
|
||||||
if (addr == NULL)
|
if (addr == NULL)
|
||||||
req->addr.ss_family = AF_UNSPEC;
|
req->u.storage.ss_family = AF_UNSPEC;
|
||||||
else
|
else
|
||||||
memcpy(&req->addr, addr, addrlen);
|
memcpy(&req->u.storage, addr, addrlen);
|
||||||
req->send_cb = send_cb;
|
req->send_cb = send_cb;
|
||||||
req->handle = handle;
|
req->handle = handle;
|
||||||
req->nbufs = nbufs;
|
req->nbufs = nbufs;
|
||||||
@ -790,10 +631,9 @@ int uv__udp_try_send(uv_udp_t* handle,
|
|||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
unsigned int addrlen) {
|
unsigned int addrlen) {
|
||||||
int err;
|
int err;
|
||||||
struct msghdr h;
|
|
||||||
ssize_t size;
|
|
||||||
|
|
||||||
assert(nbufs > 0);
|
if (nbufs < 1)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* already sending a message */
|
/* already sending a message */
|
||||||
if (handle->send_queue_count != 0)
|
if (handle->send_queue_count != 0)
|
||||||
@ -807,24 +647,11 @@ int uv__udp_try_send(uv_udp_t* handle,
|
|||||||
assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
|
assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&h, 0, sizeof h);
|
err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr);
|
||||||
h.msg_name = (struct sockaddr*) addr;
|
if (err > 0)
|
||||||
h.msg_namelen = addrlen;
|
return uv__count_bufs(bufs, nbufs);
|
||||||
h.msg_iov = (struct iovec*) bufs;
|
|
||||||
h.msg_iovlen = nbufs;
|
|
||||||
|
|
||||||
do {
|
return err;
|
||||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
|
||||||
} while (size == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (size == -1) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
|
||||||
return UV_EAGAIN;
|
|
||||||
else
|
|
||||||
return UV__ERR(errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1401,3 +1228,194 @@ int uv__udp_recv_stop(uv_udp_t* handle) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int uv__udp_prep_pkt(struct msghdr* h,
|
||||||
|
const uv_buf_t* bufs,
|
||||||
|
const unsigned int nbufs,
|
||||||
|
const struct sockaddr* addr) {
|
||||||
|
memset(h, 0, sizeof(*h));
|
||||||
|
h->msg_name = (void*) addr;
|
||||||
|
h->msg_iov = (void*) bufs;
|
||||||
|
h->msg_iovlen = nbufs;
|
||||||
|
if (addr == NULL)
|
||||||
|
return 0;
|
||||||
|
switch (addr->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
h->msg_namelen = sizeof(struct sockaddr_in);
|
||||||
|
return 0;
|
||||||
|
case AF_INET6:
|
||||||
|
h->msg_namelen = sizeof(struct sockaddr_in6);
|
||||||
|
return 0;
|
||||||
|
case AF_UNIX:
|
||||||
|
h->msg_namelen = sizeof(struct sockaddr_un);
|
||||||
|
return 0;
|
||||||
|
case AF_UNSPEC:
|
||||||
|
h->msg_name = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int uv__udp_sendmsg1(int fd,
|
||||||
|
const uv_buf_t* bufs,
|
||||||
|
unsigned int nbufs,
|
||||||
|
const struct sockaddr* addr) {
|
||||||
|
struct msghdr h;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((r = uv__udp_prep_pkt(&h, bufs, nbufs, addr)))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
do
|
||||||
|
r = sendmsg(fd, &h, 0);
|
||||||
|
while (r == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
r = UV__ERR(errno);
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||||
|
r = UV_EAGAIN;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UDP sockets don't EOF so we don't have to handle r=0 specially,
|
||||||
|
* that only happens when the input was a zero-sized buffer.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int uv__udp_sendmsgv(int fd,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/]) {
|
||||||
|
unsigned int i;
|
||||||
|
int nsent;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
nsent = 0;
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
|
||||||
|
(defined(__sun__) && defined(MSG_WAITFORONE))
|
||||||
|
if (count > 1) {
|
||||||
|
for (i = 0; i < count; /*empty*/) {
|
||||||
|
struct mmsghdr m[20];
|
||||||
|
unsigned int n;
|
||||||
|
|
||||||
|
for (n = 0; i < count && n < ARRAY_SIZE(m); i++, n++)
|
||||||
|
if ((r = uv__udp_prep_pkt(&m[n].msg_hdr, bufs[i], nbufs[i], addrs[i])))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
do
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
r = sendmsg_x(fd, m, n, MSG_DONTWAIT);
|
||||||
|
#else
|
||||||
|
r = sendmmsg(fd, m, n, 0);
|
||||||
|
#endif
|
||||||
|
while (r == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (r < 1)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
nsent += r;
|
||||||
|
i += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||
|
||||||
|
* (defined(__sun__) && defined(MSG_WAITFORONE))
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++, nsent++)
|
||||||
|
if ((r = uv__udp_sendmsg1(fd, bufs[i], nbufs[i], addrs[i])))
|
||||||
|
goto exit; /* goto to avoid unused label warning. */
|
||||||
|
|
||||||
|
exit:
|
||||||
|
|
||||||
|
if (nsent > 0)
|
||||||
|
return nsent;
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
r = UV__ERR(errno);
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||||
|
r = UV_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||||
|
static const int N = 20;
|
||||||
|
struct sockaddr* addrs[N];
|
||||||
|
unsigned int nbufs[N];
|
||||||
|
uv_buf_t* bufs[N];
|
||||||
|
struct uv__queue* q;
|
||||||
|
uv_udp_send_t* req;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (uv__queue_empty(&handle->write_queue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
again:
|
||||||
|
n = 0;
|
||||||
|
q = uv__queue_head(&handle->write_queue);
|
||||||
|
do {
|
||||||
|
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||||
|
addrs[n] = &req->u.addr;
|
||||||
|
nbufs[n] = req->nbufs;
|
||||||
|
bufs[n] = req->bufs;
|
||||||
|
q = uv__queue_next(q);
|
||||||
|
n++;
|
||||||
|
} while (n < N && q != &handle->write_queue);
|
||||||
|
|
||||||
|
n = uv__udp_sendmsgv(handle->io_watcher.fd, n, bufs, nbufs, addrs);
|
||||||
|
while (n > 0) {
|
||||||
|
q = uv__queue_head(&handle->write_queue);
|
||||||
|
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||||
|
req->status = uv__count_bufs(req->bufs, req->nbufs);
|
||||||
|
uv__queue_remove(&req->queue);
|
||||||
|
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
if (uv__queue_empty(&handle->write_queue))
|
||||||
|
goto feed;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == UV_EAGAIN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Register the error against first request in queue because that
|
||||||
|
* is the request that uv__udp_sendmsgv tried but failed to send,
|
||||||
|
* because if it did send any requests, it won't return an error.
|
||||||
|
*/
|
||||||
|
q = uv__queue_head(&handle->write_queue);
|
||||||
|
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||||
|
req->status = n;
|
||||||
|
uv__queue_remove(&req->queue);
|
||||||
|
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||||
|
feed:
|
||||||
|
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv__udp_try_send2(uv_udp_t* handle,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/]) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = handle->io_watcher.fd;
|
||||||
|
if (fd == -1)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
return uv__udp_sendmsgv(fd, count, bufs, nbufs, addrs);
|
||||||
|
}
|
||||||
|
|||||||
@ -514,6 +514,25 @@ int uv_udp_try_send(uv_udp_t* handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_udp_try_send2(uv_udp_t* handle,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/],
|
||||||
|
unsigned int flags) {
|
||||||
|
if (count < 1)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (flags != 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (handle->send_queue_count > 0)
|
||||||
|
return UV_EAGAIN;
|
||||||
|
|
||||||
|
return uv__udp_try_send2(handle, count, bufs, nbufs, addrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_udp_recv_start(uv_udp_t* handle,
|
int uv_udp_recv_start(uv_udp_t* handle,
|
||||||
uv_alloc_cb alloc_cb,
|
uv_alloc_cb alloc_cb,
|
||||||
uv_udp_recv_cb recv_cb) {
|
uv_udp_recv_cb recv_cb) {
|
||||||
@ -644,6 +663,9 @@ int uv_send_buffer_size(uv_handle_t* handle, int *value) {
|
|||||||
int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
|
int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
|
||||||
size_t required_len;
|
size_t required_len;
|
||||||
|
|
||||||
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (!uv__is_active(handle)) {
|
if (!uv__is_active(handle)) {
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "uv/tree.h"
|
#include "uv/tree.h"
|
||||||
@ -125,7 +126,7 @@ enum {
|
|||||||
|
|
||||||
/* Only used by uv_tty_t handles. */
|
/* Only used by uv_tty_t handles. */
|
||||||
UV_HANDLE_TTY_READABLE = 0x01000000,
|
UV_HANDLE_TTY_READABLE = 0x01000000,
|
||||||
UV_HANDLE_TTY_RAW = 0x02000000,
|
UV_HANDLE_UNUSED0 = 0x02000000,
|
||||||
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
|
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
|
||||||
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
|
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
|
||||||
|
|
||||||
@ -140,6 +141,10 @@ enum {
|
|||||||
UV_HANDLE_REAP = 0x10000000
|
UV_HANDLE_REAP = 0x10000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) {
|
||||||
|
return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT;
|
||||||
|
}
|
||||||
|
|
||||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|
||||||
|
|
||||||
void uv__loop_close(uv_loop_t* loop);
|
void uv__loop_close(uv_loop_t* loop);
|
||||||
@ -191,6 +196,12 @@ int uv__udp_try_send(uv_udp_t* handle,
|
|||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
unsigned int addrlen);
|
unsigned int addrlen);
|
||||||
|
|
||||||
|
int uv__udp_try_send2(uv_udp_t* handle,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/]);
|
||||||
|
|
||||||
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
|
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
|
||||||
uv_udp_recv_cb recv_cb);
|
uv_udp_recv_cb recv_cb);
|
||||||
|
|
||||||
@ -428,4 +439,36 @@ struct uv__loop_internal_fields_s {
|
|||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP 32767
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP 64
|
||||||
|
#elif defined(__NetBSD__) || defined(__illumos__)
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP PTHREAD_MAX_NAMELEN_NP
|
||||||
|
#elif defined (__linux__)
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP 16
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP (MAXCOMLEN + 1)
|
||||||
|
#else
|
||||||
|
# define UV_PTHREAD_MAX_NAMELEN_NP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Open-coded so downstream users don't have to link libm. */
|
||||||
|
static inline int uv__isinf(double d) {
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(v) == sizeof(d));
|
||||||
|
memcpy(&v, &d, sizeof(v));
|
||||||
|
return (v << 1 >> 53) == 2047 && !(v << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open-coded so downstream users don't have to link libm. */
|
||||||
|
static inline int uv__isnan(double d) {
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(v) == sizeof(d));
|
||||||
|
memcpy(&v, &d, sizeof(v));
|
||||||
|
return (v << 1 >> 53) == 2047 && !!(v << 12);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* UV_COMMON_H_ */
|
#endif /* UV_COMMON_H_ */
|
||||||
|
|||||||
110
src/win/core.c
110
src/win/core.c
@ -423,97 +423,6 @@ int uv_backend_timeout(const uv_loop_t* loop) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
|
||||||
uv__loop_internal_fields_t* lfields;
|
|
||||||
DWORD bytes;
|
|
||||||
ULONG_PTR key;
|
|
||||||
OVERLAPPED* overlapped;
|
|
||||||
uv_req_t* req;
|
|
||||||
int repeat;
|
|
||||||
uint64_t timeout_time;
|
|
||||||
uint64_t user_timeout;
|
|
||||||
int reset_timeout;
|
|
||||||
|
|
||||||
lfields = uv__get_internal_fields(loop);
|
|
||||||
timeout_time = loop->time + timeout;
|
|
||||||
|
|
||||||
if (lfields->flags & UV_METRICS_IDLE_TIME) {
|
|
||||||
reset_timeout = 1;
|
|
||||||
user_timeout = timeout;
|
|
||||||
timeout = 0;
|
|
||||||
} else {
|
|
||||||
reset_timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (repeat = 0; ; repeat++) {
|
|
||||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
|
||||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
|
||||||
*/
|
|
||||||
if (timeout != 0)
|
|
||||||
uv__metrics_set_provider_entry_time(loop);
|
|
||||||
|
|
||||||
/* Store the current timeout in a location that's globally accessible so
|
|
||||||
* other locations like uv__work_done() can determine whether the queue
|
|
||||||
* of events in the callback were waiting when poll was called.
|
|
||||||
*/
|
|
||||||
lfields->current_timeout = timeout;
|
|
||||||
|
|
||||||
GetQueuedCompletionStatus(loop->iocp,
|
|
||||||
&bytes,
|
|
||||||
&key,
|
|
||||||
&overlapped,
|
|
||||||
timeout);
|
|
||||||
|
|
||||||
if (reset_timeout != 0) {
|
|
||||||
if (overlapped && timeout == 0)
|
|
||||||
uv__metrics_inc_events_waiting(loop, 1);
|
|
||||||
timeout = user_timeout;
|
|
||||||
reset_timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Placed here because on success the loop will break whether there is an
|
|
||||||
* empty package or not, or if GetQueuedCompletionStatus returned early then
|
|
||||||
* the timeout will be updated and the loop will run again. In either case
|
|
||||||
* the idle time will need to be updated.
|
|
||||||
*/
|
|
||||||
uv__metrics_update_idle_time(loop);
|
|
||||||
|
|
||||||
if (overlapped) {
|
|
||||||
uv__metrics_inc_events(loop, 1);
|
|
||||||
|
|
||||||
/* Package was dequeued */
|
|
||||||
req = uv__overlapped_to_req(overlapped);
|
|
||||||
uv__insert_pending_req(loop, req);
|
|
||||||
|
|
||||||
/* Some time might have passed waiting for I/O,
|
|
||||||
* so update the loop time here.
|
|
||||||
*/
|
|
||||||
uv_update_time(loop);
|
|
||||||
} else if (GetLastError() != WAIT_TIMEOUT) {
|
|
||||||
/* Serious error */
|
|
||||||
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
|
|
||||||
} else if (timeout > 0) {
|
|
||||||
/* GetQueuedCompletionStatus can occasionally return a little early.
|
|
||||||
* Make sure that the desired timeout target time is reached.
|
|
||||||
*/
|
|
||||||
uv_update_time(loop);
|
|
||||||
if (timeout_time > loop->time) {
|
|
||||||
timeout = (DWORD)(timeout_time - loop->time);
|
|
||||||
/* The first call to GetQueuedCompletionStatus should return very
|
|
||||||
* close to the target time and the second should reach it, but
|
|
||||||
* this is not stated in the documentation. To make sure a busy
|
|
||||||
* loop cannot happen, the timeout is increased exponentially
|
|
||||||
* starting on the third round.
|
|
||||||
*/
|
|
||||||
timeout += repeat ? (1 << (repeat - 1)) : 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||||
uv__loop_internal_fields_t* lfields;
|
uv__loop_internal_fields_t* lfields;
|
||||||
BOOL success;
|
BOOL success;
|
||||||
@ -553,12 +462,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
|||||||
*/
|
*/
|
||||||
lfields->current_timeout = timeout;
|
lfields->current_timeout = timeout;
|
||||||
|
|
||||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
success = GetQueuedCompletionStatusEx(loop->iocp,
|
||||||
overlappeds,
|
overlappeds,
|
||||||
ARRAY_SIZE(overlappeds),
|
ARRAY_SIZE(overlappeds),
|
||||||
&count,
|
&count,
|
||||||
timeout,
|
timeout,
|
||||||
FALSE);
|
FALSE);
|
||||||
|
|
||||||
if (reset_timeout != 0) {
|
if (reset_timeout != 0) {
|
||||||
timeout = user_timeout;
|
timeout = user_timeout;
|
||||||
@ -566,7 +475,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Placed here because on success the loop will break whether there is an
|
/* Placed here because on success the loop will break whether there is an
|
||||||
* empty package or not, or if pGetQueuedCompletionStatusEx returned early
|
* empty package or not, or if GetQueuedCompletionStatusEx returned early
|
||||||
* then the timeout will be updated and the loop will run again. In either
|
* then the timeout will be updated and the loop will run again. In either
|
||||||
* case the idle time will need to be updated.
|
* case the idle time will need to be updated.
|
||||||
*/
|
*/
|
||||||
@ -647,10 +556,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
|||||||
|
|
||||||
uv__metrics_inc_loop_count(loop);
|
uv__metrics_inc_loop_count(loop);
|
||||||
|
|
||||||
if (pGetQueuedCompletionStatusEx)
|
uv__poll(loop, timeout);
|
||||||
uv__poll(loop, timeout);
|
|
||||||
else
|
|
||||||
uv__poll_wine(loop, timeout);
|
|
||||||
|
|
||||||
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
||||||
* times to avoid loop starvation.*/
|
* times to avoid loop starvation.*/
|
||||||
|
|||||||
@ -253,6 +253,8 @@ short_path_done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
dir_to_watch = dir;
|
dir_to_watch = dir;
|
||||||
|
uv__free(short_path);
|
||||||
|
short_path = NULL;
|
||||||
uv__free(pathw);
|
uv__free(pathw);
|
||||||
pathw = NULL;
|
pathw = NULL;
|
||||||
}
|
}
|
||||||
@ -577,6 +579,8 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
|||||||
info.DeletePending) {
|
info.DeletePending) {
|
||||||
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
||||||
handle->cb(handle, filename, UV_RENAME, 0);
|
handle->cb(handle, filename, UV_RENAME, 0);
|
||||||
|
uv__free(filename);
|
||||||
|
filename = NULL;
|
||||||
} else {
|
} else {
|
||||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||||
}
|
}
|
||||||
|
|||||||
234
src/win/fs.c
234
src/win/fs.c
@ -58,6 +58,19 @@
|
|||||||
#define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010
|
#define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010
|
||||||
#endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */
|
#endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */
|
||||||
|
|
||||||
|
NTSTATUS uv__RtlUnicodeStringInit(
|
||||||
|
PUNICODE_STRING DestinationString,
|
||||||
|
PWSTR SourceString,
|
||||||
|
size_t SourceStringLen
|
||||||
|
) {
|
||||||
|
if (SourceStringLen > 0x7FFF)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
DestinationString->MaximumLength = DestinationString->Length =
|
||||||
|
SourceStringLen * sizeof(SourceString[0]);
|
||||||
|
DestinationString->Buffer = SourceString;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#define INIT(subtype) \
|
#define INIT(subtype) \
|
||||||
do { \
|
do { \
|
||||||
if (req == NULL) \
|
if (req == NULL) \
|
||||||
@ -1689,12 +1702,12 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path,
|
|||||||
uv_stat_t* statbuf, int do_lstat) {
|
uv_stat_t* statbuf, int do_lstat) {
|
||||||
FILE_STAT_BASIC_INFORMATION stat_info;
|
FILE_STAT_BASIC_INFORMATION stat_info;
|
||||||
|
|
||||||
// Check if the new fast API is available.
|
/* Check if the new fast API is available. */
|
||||||
if (!pGetFileInformationByName) {
|
if (!pGetFileInformationByName) {
|
||||||
return FS__STAT_PATH_TRY_SLOW;
|
return FS__STAT_PATH_TRY_SLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the API call fails.
|
/* Check if the API call fails. */
|
||||||
if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info,
|
if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info,
|
||||||
sizeof(stat_info))) {
|
sizeof(stat_info))) {
|
||||||
switch(GetLastError()) {
|
switch(GetLastError()) {
|
||||||
@ -1708,7 +1721,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path,
|
|||||||
return FS__STAT_PATH_TRY_SLOW;
|
return FS__STAT_PATH_TRY_SLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A file handle is needed to get st_size for links.
|
/* A file handle is needed to get st_size for links. */
|
||||||
if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||||
return FS__STAT_PATH_TRY_SLOW;
|
return FS__STAT_PATH_TRY_SLOW;
|
||||||
}
|
}
|
||||||
@ -1775,7 +1788,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
|||||||
SetLastError(pRtlNtStatusToDosError(nt_status));
|
SetLastError(pRtlNtStatusToDosError(nt_status));
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber;
|
stat_info.VolumeSerialNumber.LowPart = volume_info.VolumeSerialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
stat_info.DeviceType = device_info.DeviceType;
|
stat_info.DeviceType = device_info.DeviceType;
|
||||||
@ -1802,7 +1815,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
|||||||
* detect this failure and retry without do_lstat if appropriate.
|
* detect this failure and retry without do_lstat if appropriate.
|
||||||
*/
|
*/
|
||||||
if (fs__readlink_handle(handle, NULL, &target_length) != 0) {
|
if (fs__readlink_handle(handle, NULL, &target_length) != 0) {
|
||||||
fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
stat_info.EndOfFile.QuadPart = target_length;
|
stat_info.EndOfFile.QuadPart = target_length;
|
||||||
@ -1827,7 +1839,7 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) {
|
|||||||
|
|
||||||
INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf,
|
INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf,
|
||||||
FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) {
|
FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) {
|
||||||
statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart;
|
statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart;
|
||||||
|
|
||||||
/* Todo: st_mode should probably always be 0666 for everyone. We might also
|
/* Todo: st_mode should probably always be 0666 for everyone. We might also
|
||||||
* want to report 0777 if the file is a .exe or a directory.
|
* want to report 0777 if the file is a .exe or a directory.
|
||||||
@ -1941,6 +1953,179 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf,
|
||||||
|
int do_lstat, DWORD ret_error) {
|
||||||
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
FILE_STAT_BASIC_INFORMATION stat_info;
|
||||||
|
FILE_ID_FULL_DIR_INFORMATION dir_info;
|
||||||
|
FILE_FS_VOLUME_INFORMATION volume_info;
|
||||||
|
FILE_FS_DEVICE_INFORMATION device_info;
|
||||||
|
IO_STATUS_BLOCK io_status;
|
||||||
|
NTSTATUS nt_status;
|
||||||
|
WCHAR* path_dirpath = NULL;
|
||||||
|
WCHAR* path_filename = NULL;
|
||||||
|
UNICODE_STRING FileMask;
|
||||||
|
size_t len;
|
||||||
|
size_t split;
|
||||||
|
WCHAR splitchar;
|
||||||
|
int includes_name;
|
||||||
|
|
||||||
|
/* AKA strtok or wcscspn, in reverse. */
|
||||||
|
len = wcslen(path);
|
||||||
|
split = len;
|
||||||
|
|
||||||
|
includes_name = 0;
|
||||||
|
while (split > 0 && path[split - 1] != L'\\' && path[split - 1] != L'/' &&
|
||||||
|
path[split - 1] != L':') {
|
||||||
|
/* check if the path contains a character other than /,\,:,. */
|
||||||
|
if (path[split-1] != '.') {
|
||||||
|
includes_name = 1;
|
||||||
|
}
|
||||||
|
split--;
|
||||||
|
}
|
||||||
|
/* If the path is a relative path with a file name or a folder name */
|
||||||
|
if (split == 0 && includes_name) {
|
||||||
|
path_dirpath = L".";
|
||||||
|
/* If there is a slash or a backslash */
|
||||||
|
} else if (path[split - 1] == L'\\' || path[split - 1] == L'/') {
|
||||||
|
path_dirpath = path;
|
||||||
|
/* If there is no filename, consider it as a relative folder path */
|
||||||
|
if (!includes_name) {
|
||||||
|
split = len;
|
||||||
|
/* Else, split it */
|
||||||
|
} else {
|
||||||
|
splitchar = path[split - 1];
|
||||||
|
path[split - 1] = L'\0';
|
||||||
|
}
|
||||||
|
/* e.g. "..", "c:" */
|
||||||
|
} else {
|
||||||
|
path_dirpath = path;
|
||||||
|
split = len;
|
||||||
|
}
|
||||||
|
path_filename = &path[split];
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
while (1) {
|
||||||
|
if (path_filename[len] == L'\0')
|
||||||
|
break;
|
||||||
|
if (path_filename[len] == L'*' || path_filename[len] == L'?' ||
|
||||||
|
path_filename[len] == L'>' || path_filename[len] == L'<' ||
|
||||||
|
path_filename[len] == L'"') {
|
||||||
|
ret_error = ERROR_INVALID_NAME;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get directory handle */
|
||||||
|
handle = CreateFileW(path_dirpath,
|
||||||
|
FILE_LIST_DIRECTORY,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
|
ret_error = GetLastError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get files in the directory */
|
||||||
|
nt_status = uv__RtlUnicodeStringInit(&FileMask, path_filename, len);
|
||||||
|
if (!NT_SUCCESS(nt_status)) {
|
||||||
|
ret_error = pRtlNtStatusToDosError(nt_status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
nt_status = pNtQueryDirectoryFile(handle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&io_status,
|
||||||
|
&dir_info,
|
||||||
|
sizeof(dir_info),
|
||||||
|
FileIdFullDirectoryInformation,
|
||||||
|
TRUE,
|
||||||
|
&FileMask,
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
/* Buffer overflow (a warning status code) is expected here since there isn't
|
||||||
|
* enough space to store the FileName, and actually indicates success. */
|
||||||
|
if (!NT_SUCCESS(nt_status) && nt_status != STATUS_BUFFER_OVERFLOW) {
|
||||||
|
if (nt_status == STATUS_NO_MORE_FILES)
|
||||||
|
ret_error = ERROR_PATH_NOT_FOUND;
|
||||||
|
else
|
||||||
|
ret_error = pRtlNtStatusToDosError(nt_status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign values to stat_info */
|
||||||
|
memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION));
|
||||||
|
stat_info.FileAttributes = dir_info.FileAttributes;
|
||||||
|
stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart;
|
||||||
|
stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart;
|
||||||
|
stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart;
|
||||||
|
if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
|
/* A file handle is needed to get st_size for the link (from
|
||||||
|
* FSCTL_GET_REPARSE_POINT), which is required by posix, but we are here
|
||||||
|
* because getting the file handle failed. We could get just the
|
||||||
|
* ReparsePointTag by querying FILE_ID_EXTD_DIR_INFORMATION instead to make
|
||||||
|
* sure this really is a link before giving up here on the uv_fs_stat call,
|
||||||
|
* but that doesn't seem essential. */
|
||||||
|
if (!do_lstat)
|
||||||
|
goto cleanup;
|
||||||
|
stat_info.EndOfFile.QuadPart = 0;
|
||||||
|
stat_info.AllocationSize.QuadPart = 0;
|
||||||
|
} else {
|
||||||
|
stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart;
|
||||||
|
stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart;
|
||||||
|
}
|
||||||
|
stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart;
|
||||||
|
stat_info.FileId.QuadPart = dir_info.FileId.QuadPart;
|
||||||
|
|
||||||
|
/* Finish up by getting device info from the directory handle,
|
||||||
|
* since files presumably must live on their device. */
|
||||||
|
nt_status = pNtQueryVolumeInformationFile(handle,
|
||||||
|
&io_status,
|
||||||
|
&volume_info,
|
||||||
|
sizeof volume_info,
|
||||||
|
FileFsVolumeInformation);
|
||||||
|
|
||||||
|
/* Buffer overflow (a warning status code) is expected here. */
|
||||||
|
if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
|
||||||
|
stat_info.VolumeSerialNumber.QuadPart = 0;
|
||||||
|
} else if (NT_ERROR(nt_status)) {
|
||||||
|
ret_error = pRtlNtStatusToDosError(nt_status);
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
nt_status = pNtQueryVolumeInformationFile(handle,
|
||||||
|
&io_status,
|
||||||
|
&device_info,
|
||||||
|
sizeof device_info,
|
||||||
|
FileFsDeviceInformation);
|
||||||
|
|
||||||
|
/* Buffer overflow (a warning status code) is expected here. */
|
||||||
|
if (NT_ERROR(nt_status)) {
|
||||||
|
ret_error = pRtlNtStatusToDosError(nt_status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat_info.DeviceType = device_info.DeviceType;
|
||||||
|
stat_info.NumberOfLinks = 1; /* No way to recover this info. */
|
||||||
|
|
||||||
|
fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);
|
||||||
|
ret_error = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (split != 0)
|
||||||
|
path[split - 1] = splitchar;
|
||||||
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(handle);
|
||||||
|
return ret_error;
|
||||||
|
}
|
||||||
|
|
||||||
INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
||||||
int do_lstat,
|
int do_lstat,
|
||||||
@ -1949,7 +2134,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
|||||||
DWORD flags;
|
DWORD flags;
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
// If new API exists, try to use it.
|
/* If new API exists, try to use it. */
|
||||||
switch (fs__stat_path(path, statbuf, do_lstat)) {
|
switch (fs__stat_path(path, statbuf, do_lstat)) {
|
||||||
case FS__STAT_PATH_SUCCESS:
|
case FS__STAT_PATH_SUCCESS:
|
||||||
return 0;
|
return 0;
|
||||||
@ -1959,7 +2144,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the new API does not exist, use the old API.
|
/* If the new API does not exist, use the old API. */
|
||||||
flags = FILE_FLAG_BACKUP_SEMANTICS;
|
flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||||
if (do_lstat)
|
if (do_lstat)
|
||||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||||
@ -1972,8 +2157,12 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
|||||||
flags,
|
flags,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
return GetLastError();
|
ret = GetLastError();
|
||||||
|
if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION)
|
||||||
|
return ret;
|
||||||
|
return fs__stat_directory(path, statbuf, do_lstat, ret);
|
||||||
|
}
|
||||||
|
|
||||||
if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
|
if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
|
||||||
ret = GetLastError();
|
ret = GetLastError();
|
||||||
@ -2391,14 +2580,29 @@ fchmod_cleanup:
|
|||||||
|
|
||||||
|
|
||||||
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
|
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
|
||||||
FILETIME filetime_a, filetime_m;
|
FILETIME filetime_as, *filetime_a = &filetime_as;
|
||||||
|
FILETIME filetime_ms, *filetime_m = &filetime_ms;
|
||||||
|
FILETIME now;
|
||||||
|
|
||||||
TIME_T_TO_FILETIME(atime, &filetime_a);
|
if (uv__isinf(atime) || uv__isinf(mtime))
|
||||||
TIME_T_TO_FILETIME(mtime, &filetime_m);
|
GetSystemTimeAsFileTime(&now);
|
||||||
|
|
||||||
if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
|
if (uv__isinf(atime))
|
||||||
|
filetime_a = &now;
|
||||||
|
else if (uv__isnan(atime))
|
||||||
|
filetime_a = NULL;
|
||||||
|
else
|
||||||
|
TIME_T_TO_FILETIME(atime, filetime_a);
|
||||||
|
|
||||||
|
if (uv__isinf(mtime))
|
||||||
|
filetime_m = &now;
|
||||||
|
else if (uv__isnan(mtime))
|
||||||
|
filetime_m = NULL;
|
||||||
|
else
|
||||||
|
TIME_T_TO_FILETIME(mtime, filetime_m);
|
||||||
|
|
||||||
|
if (!SetFileTime(handle, NULL, filetime_a, filetime_m))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2602,6 +2602,9 @@ int uv_pipe_pending_count(uv_pipe_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||||
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (handle->flags & UV_HANDLE_BOUND)
|
if (handle->flags & UV_HANDLE_BOUND)
|
||||||
return uv__pipe_getname(handle, buffer, size);
|
return uv__pipe_getname(handle, buffer, size);
|
||||||
|
|
||||||
@ -2616,6 +2619,9 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||||
|
if (buffer == NULL || size == NULL || *size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* emulate unix behaviour */
|
/* emulate unix behaviour */
|
||||||
if (handle->flags & UV_HANDLE_BOUND)
|
if (handle->flags & UV_HANDLE_BOUND)
|
||||||
return UV_ENOTCONN;
|
return UV_ENOTCONN;
|
||||||
|
|||||||
@ -898,7 +898,7 @@ int uv_spawn(uv_loop_t* loop,
|
|||||||
*env = NULL, *cwd = NULL;
|
*env = NULL, *cwd = NULL;
|
||||||
STARTUPINFOW startup;
|
STARTUPINFOW startup;
|
||||||
PROCESS_INFORMATION info;
|
PROCESS_INFORMATION info;
|
||||||
DWORD process_flags;
|
DWORD process_flags, cwd_len;
|
||||||
BYTE* child_stdio_buffer;
|
BYTE* child_stdio_buffer;
|
||||||
|
|
||||||
uv__process_init(loop, process);
|
uv__process_init(loop, process);
|
||||||
@ -947,9 +947,10 @@ int uv_spawn(uv_loop_t* loop,
|
|||||||
if (err)
|
if (err)
|
||||||
goto done_uv;
|
goto done_uv;
|
||||||
|
|
||||||
|
cwd_len = wcslen(cwd);
|
||||||
} else {
|
} else {
|
||||||
/* Inherit cwd */
|
/* Inherit cwd */
|
||||||
DWORD cwd_len, r;
|
DWORD r;
|
||||||
|
|
||||||
cwd_len = GetCurrentDirectoryW(0, NULL);
|
cwd_len = GetCurrentDirectoryW(0, NULL);
|
||||||
if (!cwd_len) {
|
if (!cwd_len) {
|
||||||
@ -970,6 +971,15 @@ int uv_spawn(uv_loop_t* loop,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If cwd is too long, shorten it */
|
||||||
|
if (cwd_len >= MAX_PATH) {
|
||||||
|
cwd_len = GetShortPathNameW(cwd, cwd, cwd_len);
|
||||||
|
if (cwd_len == 0) {
|
||||||
|
err = GetLastError();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get PATH environment variable. */
|
/* Get PATH environment variable. */
|
||||||
path = find_path(env);
|
path = find_path(env);
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
|
|||||||
@ -57,6 +57,9 @@ STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
|
|||||||
|
|
||||||
static uv_key_t uv__current_thread_key;
|
static uv_key_t uv__current_thread_key;
|
||||||
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
|
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
|
||||||
|
static uv_once_t uv__thread_name_once = UV_ONCE_INIT;
|
||||||
|
HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*);
|
||||||
|
HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR);
|
||||||
|
|
||||||
|
|
||||||
static void uv__init_current_thread_key(void) {
|
static void uv__init_current_thread_key(void) {
|
||||||
@ -95,6 +98,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
|||||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_thread_detach(uv_thread_t *tid) {
|
||||||
|
if (CloseHandle(*tid) == 0)
|
||||||
|
return uv_translate_sys_error(GetLastError());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_thread_create_ex(uv_thread_t* tid,
|
int uv_thread_create_ex(uv_thread_t* tid,
|
||||||
const uv_thread_options_t* params,
|
const uv_thread_options_t* params,
|
||||||
void (*entry)(void *arg),
|
void (*entry)(void *arg),
|
||||||
@ -269,6 +281,92 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void uv__thread_name_init_once(void) {
|
||||||
|
HMODULE m;
|
||||||
|
|
||||||
|
m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll");
|
||||||
|
if (m != NULL) {
|
||||||
|
pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription");
|
||||||
|
pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_thread_setname(const char* name) {
|
||||||
|
HRESULT hr;
|
||||||
|
WCHAR* namew;
|
||||||
|
int err;
|
||||||
|
char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
|
||||||
|
uv_once(&uv__thread_name_once, uv__thread_name_init_once);
|
||||||
|
|
||||||
|
if (pSetThreadDescription == NULL)
|
||||||
|
return UV_ENOSYS;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||||
|
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||||
|
|
||||||
|
namew = NULL;
|
||||||
|
err = uv__convert_utf8_to_utf16(namebuf, &namew);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
hr = pSetThreadDescription(GetCurrentThread(), namew);
|
||||||
|
uv__free(namew);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return uv_translate_sys_error(HRESULT_CODE(hr));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||||
|
HRESULT hr;
|
||||||
|
WCHAR* namew;
|
||||||
|
char* thread_name;
|
||||||
|
size_t buf_size;
|
||||||
|
int r;
|
||||||
|
DWORD exit_code;
|
||||||
|
|
||||||
|
uv_once(&uv__thread_name_once, uv__thread_name_init_once);
|
||||||
|
|
||||||
|
if (pGetThreadDescription == NULL)
|
||||||
|
return UV_ENOSYS;
|
||||||
|
|
||||||
|
if (name == NULL || size == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (tid == NULL || *tid == NULL)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
/* Check if the thread handle is valid */
|
||||||
|
if (!GetExitCodeThread(*tid, &exit_code) || exit_code != STILL_ACTIVE)
|
||||||
|
return UV_ENOENT;
|
||||||
|
|
||||||
|
namew = NULL;
|
||||||
|
thread_name = NULL;
|
||||||
|
hr = pGetThreadDescription(*tid, &namew);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return uv_translate_sys_error(HRESULT_CODE(hr));
|
||||||
|
|
||||||
|
buf_size = size;
|
||||||
|
r = uv__copy_utf16_to_utf8(namew, -1, name, &buf_size);
|
||||||
|
if (r == UV_ENOBUFS) {
|
||||||
|
r = uv__convert_utf16_to_utf8(namew, wcslen(namew), &thread_name);
|
||||||
|
if (r == 0) {
|
||||||
|
uv__strscpy(name, thread_name, size);
|
||||||
|
uv__free(thread_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFree(namew);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||||
InitializeCriticalSection(mutex);
|
InitializeCriticalSection(mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -58,6 +58,9 @@
|
|||||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||||
|
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CURSOR_SIZE_SMALL 25
|
#define CURSOR_SIZE_SMALL 25
|
||||||
#define CURSOR_SIZE_LARGE 100
|
#define CURSOR_SIZE_LARGE 100
|
||||||
@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1;
|
|||||||
* handle signalling SIGWINCH
|
* handle signalling SIGWINCH
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
|
static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE;
|
||||||
|
static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE;
|
||||||
|
static DWORD uv__tty_console_in_original_mode = (DWORD)-1;
|
||||||
|
static volatile LONG uv__tty_console_in_need_mode_reset = 0;
|
||||||
static int uv__tty_console_height = -1;
|
static int uv__tty_console_height = -1;
|
||||||
static int uv__tty_console_width = -1;
|
static int uv__tty_console_width = -1;
|
||||||
static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
|
static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
|
||||||
@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
|
|||||||
static void uv__determine_vterm_state(HANDLE handle);
|
static void uv__determine_vterm_state(HANDLE handle);
|
||||||
|
|
||||||
void uv__console_init(void) {
|
void uv__console_init(void) {
|
||||||
|
DWORD dwMode;
|
||||||
|
|
||||||
if (uv_sem_init(&uv_tty_output_lock, 1))
|
if (uv_sem_init(&uv_tty_output_lock, 1))
|
||||||
abort();
|
abort();
|
||||||
uv__tty_console_handle = CreateFileW(L"CONOUT$",
|
uv__tty_console_handle_out = CreateFileW(L"CONOUT$",
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_WRITE,
|
FILE_SHARE_WRITE,
|
||||||
0,
|
0,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) {
|
||||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||||
uv_mutex_init(&uv__tty_console_resize_mutex);
|
uv_mutex_init(&uv__tty_console_resize_mutex);
|
||||||
if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
|
if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) {
|
||||||
uv__tty_console_width = sb_info.dwSize.X;
|
uv__tty_console_width = sb_info.dwSize.X;
|
||||||
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||||
}
|
}
|
||||||
@ -179,6 +187,18 @@ void uv__console_init(void) {
|
|||||||
NULL,
|
NULL,
|
||||||
WT_EXECUTELONGFUNCTION);
|
WT_EXECUTELONGFUNCTION);
|
||||||
}
|
}
|
||||||
|
uv__tty_console_handle_in = CreateFileW(L"CONIN$",
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) {
|
||||||
|
if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) {
|
||||||
|
uv__tty_console_in_original_mode = dwMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
|||||||
/* Initialize TTY input specific fields. */
|
/* Initialize TTY input specific fields. */
|
||||||
tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
|
tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
|
||||||
/* TODO: remove me in v2.x. */
|
/* TODO: remove me in v2.x. */
|
||||||
tty->tty.rd.unused_ = NULL;
|
tty->tty.rd.mode.unused_ = NULL;
|
||||||
|
/* Partially overwrites unused_ again. */
|
||||||
|
tty->tty.rd.mode.mode = 0;
|
||||||
tty->tty.rd.read_line_buffer = uv_null_buf_;
|
tty->tty.rd.read_line_buffer = uv_null_buf_;
|
||||||
tty->tty.rd.read_raw_wait = NULL;
|
tty->tty.rd.read_raw_wait = NULL;
|
||||||
|
|
||||||
@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style(
|
|||||||
|
|
||||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
|
DWORD try_set_flags;
|
||||||
unsigned char was_reading;
|
unsigned char was_reading;
|
||||||
uv_alloc_cb alloc_cb;
|
uv_alloc_cb alloc_cb;
|
||||||
uv_read_cb read_cb;
|
uv_read_cb read_cb;
|
||||||
@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
|
if ((int)mode == tty->tty.rd.mode.mode) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try_set_flags = 0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case UV_TTY_MODE_NORMAL:
|
case UV_TTY_MODE_NORMAL:
|
||||||
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||||||
break;
|
break;
|
||||||
|
case UV_TTY_MODE_RAW_VT:
|
||||||
|
try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1);
|
||||||
|
/* fallthrough */
|
||||||
case UV_TTY_MODE_RAW:
|
case UV_TTY_MODE_RAW:
|
||||||
flags = ENABLE_WINDOW_INPUT;
|
flags = ENABLE_WINDOW_INPUT;
|
||||||
break;
|
break;
|
||||||
@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uv_sem_wait(&uv_tty_output_lock);
|
uv_sem_wait(&uv_tty_output_lock);
|
||||||
if (!SetConsoleMode(tty->handle, flags)) {
|
if (!SetConsoleMode(tty->handle, flags | try_set_flags) &&
|
||||||
|
!SetConsoleMode(tty->handle, flags)) {
|
||||||
err = uv_translate_sys_error(GetLastError());
|
err = uv_translate_sys_error(GetLastError());
|
||||||
uv_sem_post(&uv_tty_output_lock);
|
uv_sem_post(&uv_tty_output_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
uv_sem_post(&uv_tty_output_lock);
|
uv_sem_post(&uv_tty_output_lock);
|
||||||
|
|
||||||
/* Update flag. */
|
/* Update mode. */
|
||||||
tty->flags &= ~UV_HANDLE_TTY_RAW;
|
tty->tty.rd.mode.mode = mode;
|
||||||
tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
|
|
||||||
|
|
||||||
/* If we just stopped reading, restart. */
|
/* If we just stopped reading, restart. */
|
||||||
if (was_reading) {
|
if (was_reading) {
|
||||||
@ -614,7 +642,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
|
static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
|
||||||
if (handle->flags & UV_HANDLE_TTY_RAW) {
|
if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) {
|
||||||
uv__tty_queue_read_raw(loop, handle);
|
uv__tty_queue_read_raw(loop, handle);
|
||||||
} else {
|
} else {
|
||||||
uv__tty_queue_read_line(loop, handle);
|
uv__tty_queue_read_line(loop, handle);
|
||||||
@ -702,7 +730,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
|||||||
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
||||||
|
|
||||||
if (!(handle->flags & UV_HANDLE_READING) ||
|
if (!(handle->flags & UV_HANDLE_READING) ||
|
||||||
!(handle->flags & UV_HANDLE_TTY_RAW)) {
|
!(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1050,7 +1078,7 @@ int uv__tty_read_stop(uv_tty_t* handle) {
|
|||||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (handle->flags & UV_HANDLE_TTY_RAW) {
|
if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) {
|
||||||
/* Cancel raw read. Write some bullshit event to force the console wait to
|
/* Cancel raw read. Write some bullshit event to force the console wait to
|
||||||
* return. */
|
* return. */
|
||||||
memset(&record, 0, sizeof record);
|
memset(&record, 0, sizeof record);
|
||||||
@ -2293,7 +2321,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_tty_reset_mode(void) {
|
int uv_tty_reset_mode(void) {
|
||||||
/* Not necessary to do anything. */
|
/**
|
||||||
|
* Shells on Windows do know to reset output flags after a program exits,
|
||||||
|
* but not necessarily input flags, so we do that for them.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
uv__tty_console_handle_in != INVALID_HANDLE_VALUE &&
|
||||||
|
uv__tty_console_in_original_mode != (DWORD)-1 &&
|
||||||
|
InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0
|
||||||
|
) {
|
||||||
|
SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2390,7 +2428,7 @@ static void uv__tty_console_signal_resize(void) {
|
|||||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
|
if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
width = sb_info.dwSize.X;
|
width = sb_info.dwSize.X;
|
||||||
|
|||||||
@ -1101,7 +1101,8 @@ int uv__udp_try_send(uv_udp_t* handle,
|
|||||||
struct sockaddr_storage converted;
|
struct sockaddr_storage converted;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
assert(nbufs > 0);
|
if (nbufs < 1)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (addr != NULL) {
|
if (addr != NULL) {
|
||||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||||
@ -1141,3 +1142,21 @@ int uv__udp_try_send(uv_udp_t* handle,
|
|||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv__udp_try_send2(uv_udp_t* handle,
|
||||||
|
unsigned int count,
|
||||||
|
uv_buf_t* bufs[/*count*/],
|
||||||
|
unsigned int nbufs[/*count*/],
|
||||||
|
struct sockaddr* addrs[/*count*/]) {
|
||||||
|
unsigned int i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
r = uv_udp_try_send(handle, bufs[i], nbufs[i], addrs[i]);
|
||||||
|
if (r < 0)
|
||||||
|
return i > 0 ? i : r; /* Error if first packet, else send count. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|||||||
@ -191,7 +191,7 @@ int uv_cwd(char* buffer, size_t* size) {
|
|||||||
WCHAR *utf16_buffer;
|
WCHAR *utf16_buffer;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (buffer == NULL || size == NULL) {
|
if (buffer == NULL || size == NULL || *size == 0) {
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,56 +874,100 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
|||||||
|
|
||||||
|
|
||||||
int uv_getrusage(uv_rusage_t *uv_rusage) {
|
int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||||
FILETIME createTime, exitTime, kernelTime, userTime;
|
FILETIME create_time, exit_time, kernel_time, user_time;
|
||||||
SYSTEMTIME kernelSystemTime, userSystemTime;
|
SYSTEMTIME kernel_system_time, user_system_time;
|
||||||
PROCESS_MEMORY_COUNTERS memCounters;
|
PROCESS_MEMORY_COUNTERS mem_counters;
|
||||||
IO_COUNTERS ioCounters;
|
IO_COUNTERS io_counters;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
|
ret = GetProcessTimes(GetCurrentProcess(),
|
||||||
|
&create_time,
|
||||||
|
&exit_time,
|
||||||
|
&kernel_time,
|
||||||
|
&user_time);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return uv_translate_sys_error(GetLastError());
|
return uv_translate_sys_error(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
|
ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return uv_translate_sys_error(GetLastError());
|
return uv_translate_sys_error(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = FileTimeToSystemTime(&userTime, &userSystemTime);
|
ret = FileTimeToSystemTime(&user_time, &user_system_time);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return uv_translate_sys_error(GetLastError());
|
return uv_translate_sys_error(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = GetProcessMemoryInfo(GetCurrentProcess(),
|
ret = GetProcessMemoryInfo(GetCurrentProcess(),
|
||||||
&memCounters,
|
&mem_counters,
|
||||||
sizeof(memCounters));
|
sizeof(mem_counters));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return uv_translate_sys_error(GetLastError());
|
return uv_translate_sys_error(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
|
ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return uv_translate_sys_error(GetLastError());
|
return uv_translate_sys_error(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
||||||
|
|
||||||
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
|
uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
|
||||||
userSystemTime.wMinute * 60 +
|
user_system_time.wMinute * 60 +
|
||||||
userSystemTime.wSecond;
|
user_system_time.wSecond;
|
||||||
uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
|
uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
|
||||||
|
|
||||||
uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
|
uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
|
||||||
kernelSystemTime.wMinute * 60 +
|
kernel_system_time.wMinute * 60 +
|
||||||
kernelSystemTime.wSecond;
|
kernel_system_time.wSecond;
|
||||||
uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
|
uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
|
||||||
|
|
||||||
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
|
uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount;
|
||||||
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
|
uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024;
|
||||||
|
|
||||||
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
|
uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount;
|
||||||
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
|
uv_rusage->ru_inblock = (uint64_t) io_counters.ReadOperationCount;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_getrusage_thread(uv_rusage_t* uv_rusage) {
|
||||||
|
FILETIME create_time, exit_time, kernel_time, user_time;
|
||||||
|
SYSTEMTIME kernel_system_time, user_system_time;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = GetThreadTimes(GetCurrentThread(),
|
||||||
|
&create_time,
|
||||||
|
&exit_time,
|
||||||
|
&kernel_time,
|
||||||
|
&user_time);
|
||||||
|
if (ret == 0) {
|
||||||
|
return uv_translate_sys_error(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
|
||||||
|
if (ret == 0) {
|
||||||
|
return uv_translate_sys_error(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = FileTimeToSystemTime(&user_time, &user_system_time);
|
||||||
|
if (ret == 0) {
|
||||||
|
return uv_translate_sys_error(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
||||||
|
|
||||||
|
uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
|
||||||
|
user_system_time.wMinute * 60 +
|
||||||
|
user_system_time.wSecond;
|
||||||
|
uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
|
||||||
|
|
||||||
|
uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
|
||||||
|
kernel_system_time.wMinute * 60 +
|
||||||
|
kernel_system_time.wSecond;
|
||||||
|
uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -972,6 +1016,7 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_os_tmpdir(char* buffer, size_t* size) {
|
int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||||
|
int r;
|
||||||
wchar_t *path;
|
wchar_t *path;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@ -1010,7 +1055,9 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
|||||||
path[len] = L'\0';
|
path[len] = L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return uv__copy_utf16_to_utf8(path, len, buffer, size);
|
r = uv__copy_utf16_to_utf8(path, len, buffer, size);
|
||||||
|
uv__free(path);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
|||||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||||
sNtQueryInformationProcess pNtQueryInformationProcess;
|
sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||||
|
|
||||||
/* Kernel32 function pointers */
|
|
||||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
|
||||||
|
|
||||||
/* Powrprof.dll function pointer */
|
/* Powrprof.dll function pointer */
|
||||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||||
|
|
||||||
@ -55,7 +52,6 @@ void uv__winapi_init(void) {
|
|||||||
HMODULE ntdll_module;
|
HMODULE ntdll_module;
|
||||||
HMODULE powrprof_module;
|
HMODULE powrprof_module;
|
||||||
HMODULE user32_module;
|
HMODULE user32_module;
|
||||||
HMODULE kernel32_module;
|
|
||||||
HMODULE ws2_32_module;
|
HMODULE ws2_32_module;
|
||||||
HMODULE api_win_core_file_module;
|
HMODULE api_win_core_file_module;
|
||||||
|
|
||||||
@ -121,15 +117,6 @@ void uv__winapi_init(void) {
|
|||||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel32_module = GetModuleHandleA("kernel32.dll");
|
|
||||||
if (kernel32_module == NULL) {
|
|
||||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
|
||||||
}
|
|
||||||
|
|
||||||
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
|
|
||||||
kernel32_module,
|
|
||||||
"GetQueuedCompletionStatusEx");
|
|
||||||
|
|
||||||
powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||||
if (powrprof_module != NULL) {
|
if (powrprof_module != NULL) {
|
||||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||||
|
|||||||
101
src/win/winapi.h
101
src/win/winapi.h
@ -4145,45 +4145,40 @@ typedef struct _FILE_STAT_BASIC_INFORMATION {
|
|||||||
ULONG DeviceType;
|
ULONG DeviceType;
|
||||||
ULONG DeviceCharacteristics;
|
ULONG DeviceCharacteristics;
|
||||||
ULONG Reserved;
|
ULONG Reserved;
|
||||||
FILE_ID_128 FileId128;
|
|
||||||
LARGE_INTEGER VolumeSerialNumber;
|
LARGE_INTEGER VolumeSerialNumber;
|
||||||
|
FILE_ID_128 FileId128;
|
||||||
} FILE_STAT_BASIC_INFORMATION;
|
} FILE_STAT_BASIC_INFORMATION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
|
typedef struct _REPARSE_DATA_BUFFER {
|
||||||
* not.
|
ULONG ReparseTag;
|
||||||
*/
|
USHORT ReparseDataLength;
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
|
USHORT Reserved;
|
||||||
typedef struct _REPARSE_DATA_BUFFER {
|
union {
|
||||||
ULONG ReparseTag;
|
struct {
|
||||||
USHORT ReparseDataLength;
|
USHORT SubstituteNameOffset;
|
||||||
USHORT Reserved;
|
USHORT SubstituteNameLength;
|
||||||
union {
|
USHORT PrintNameOffset;
|
||||||
struct {
|
USHORT PrintNameLength;
|
||||||
USHORT SubstituteNameOffset;
|
ULONG Flags;
|
||||||
USHORT SubstituteNameLength;
|
WCHAR PathBuffer[1];
|
||||||
USHORT PrintNameOffset;
|
} SymbolicLinkReparseBuffer;
|
||||||
USHORT PrintNameLength;
|
struct {
|
||||||
ULONG Flags;
|
USHORT SubstituteNameOffset;
|
||||||
WCHAR PathBuffer[1];
|
USHORT SubstituteNameLength;
|
||||||
} SymbolicLinkReparseBuffer;
|
USHORT PrintNameOffset;
|
||||||
struct {
|
USHORT PrintNameLength;
|
||||||
USHORT SubstituteNameOffset;
|
WCHAR PathBuffer[1];
|
||||||
USHORT SubstituteNameLength;
|
} MountPointReparseBuffer;
|
||||||
USHORT PrintNameOffset;
|
struct {
|
||||||
USHORT PrintNameLength;
|
UCHAR DataBuffer[1];
|
||||||
WCHAR PathBuffer[1];
|
} GenericReparseBuffer;
|
||||||
} MountPointReparseBuffer;
|
struct {
|
||||||
struct {
|
ULONG StringCount;
|
||||||
UCHAR DataBuffer[1];
|
WCHAR StringList[1];
|
||||||
} GenericReparseBuffer;
|
} AppExecLinkReparseBuffer;
|
||||||
struct {
|
};
|
||||||
ULONG StringCount;
|
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||||
WCHAR StringList[1];
|
|
||||||
} AppExecLinkReparseBuffer;
|
|
||||||
};
|
|
||||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _IO_STATUS_BLOCK {
|
typedef struct _IO_STATUS_BLOCK {
|
||||||
union {
|
union {
|
||||||
@ -4292,6 +4287,22 @@ typedef struct _FILE_BOTH_DIR_INFORMATION {
|
|||||||
WCHAR FileName[1];
|
WCHAR FileName[1];
|
||||||
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
|
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _FILE_ID_FULL_DIR_INFORMATION {
|
||||||
|
ULONG NextEntryOffset;
|
||||||
|
ULONG FileIndex;
|
||||||
|
LARGE_INTEGER CreationTime;
|
||||||
|
LARGE_INTEGER LastAccessTime;
|
||||||
|
LARGE_INTEGER LastWriteTime;
|
||||||
|
LARGE_INTEGER ChangeTime;
|
||||||
|
LARGE_INTEGER EndOfFile;
|
||||||
|
LARGE_INTEGER AllocationSize;
|
||||||
|
ULONG FileAttributes;
|
||||||
|
ULONG FileNameLength;
|
||||||
|
ULONG EaSize;
|
||||||
|
LARGE_INTEGER FileId;
|
||||||
|
WCHAR FileName[1];
|
||||||
|
} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
|
||||||
|
|
||||||
typedef struct _FILE_BASIC_INFORMATION {
|
typedef struct _FILE_BASIC_INFORMATION {
|
||||||
LARGE_INTEGER CreationTime;
|
LARGE_INTEGER CreationTime;
|
||||||
LARGE_INTEGER LastAccessTime;
|
LARGE_INTEGER LastAccessTime;
|
||||||
@ -4661,15 +4672,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
|
|||||||
# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
|
# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
|
||||||
typedef struct _OVERLAPPED_ENTRY {
|
|
||||||
ULONG_PTR lpCompletionKey;
|
|
||||||
LPOVERLAPPED lpOverlapped;
|
|
||||||
ULONG_PTR Internal;
|
|
||||||
DWORD dwNumberOfBytesTransferred;
|
|
||||||
} OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* from wincon.h */
|
/* from wincon.h */
|
||||||
#ifndef ENABLE_INSERT_MODE
|
#ifndef ENABLE_INSERT_MODE
|
||||||
# define ENABLE_INSERT_MODE 0x20
|
# define ENABLE_INSERT_MODE 0x20
|
||||||
@ -4716,14 +4718,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
|
|||||||
# define ERROR_MUI_FILE_NOT_LOADED 15105
|
# define ERROR_MUI_FILE_NOT_LOADED 15105
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
|
|
||||||
(HANDLE CompletionPort,
|
|
||||||
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
|
|
||||||
ULONG ulCount,
|
|
||||||
PULONG ulNumEntriesRemoved,
|
|
||||||
DWORD dwMilliseconds,
|
|
||||||
BOOL fAlertable);
|
|
||||||
|
|
||||||
/* from powerbase.h */
|
/* from powerbase.h */
|
||||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||||
# define DEVICE_NOTIFY_CALLBACK 2
|
# define DEVICE_NOTIFY_CALLBACK 2
|
||||||
@ -4818,9 +4812,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
|||||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||||
extern sNtQueryInformationProcess pNtQueryInformationProcess;
|
extern sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||||
|
|
||||||
/* Kernel32 function pointers */
|
|
||||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
|
||||||
|
|
||||||
/* Powrprof.dll function pointer */
|
/* Powrprof.dll function pointer */
|
||||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||||
|
|
||||||
|
|||||||
@ -154,47 +154,6 @@ typedef struct _AFD_RECV_INFO {
|
|||||||
#define IOCTL_AFD_POLL \
|
#define IOCTL_AFD_POLL \
|
||||||
_AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
|
_AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
|
||||||
|
|
||||||
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
|
||||||
typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
|
|
||||||
/* FIXME: __C89_NAMELESS was removed */
|
|
||||||
/* __C89_NAMELESS */ union {
|
|
||||||
ULONGLONG Alignment;
|
|
||||||
/* __C89_NAMELESS */ struct {
|
|
||||||
ULONG Length;
|
|
||||||
DWORD Flags;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
|
|
||||||
SOCKET_ADDRESS Address;
|
|
||||||
IP_PREFIX_ORIGIN PrefixOrigin;
|
|
||||||
IP_SUFFIX_ORIGIN SuffixOrigin;
|
|
||||||
IP_DAD_STATE DadState;
|
|
||||||
ULONG ValidLifetime;
|
|
||||||
ULONG PreferredLifetime;
|
|
||||||
ULONG LeaseLifetime;
|
|
||||||
} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
|
|
||||||
|
|
||||||
typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
|
|
||||||
union {
|
|
||||||
ULONGLONG Alignment;
|
|
||||||
struct {
|
|
||||||
ULONG Length;
|
|
||||||
DWORD Flags;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
|
|
||||||
SOCKET_ADDRESS Address;
|
|
||||||
IP_PREFIX_ORIGIN PrefixOrigin;
|
|
||||||
IP_SUFFIX_ORIGIN SuffixOrigin;
|
|
||||||
IP_DAD_STATE DadState;
|
|
||||||
ULONG ValidLifetime;
|
|
||||||
ULONG PreferredLifetime;
|
|
||||||
ULONG LeaseLifetime;
|
|
||||||
UINT8 OnLinkPrefixLength;
|
|
||||||
} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
|
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
|
||||||
struct sockaddr_storage* storage);
|
struct sockaddr_storage* storage);
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,11 @@
|
|||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
|
|
||||||
|
/* Refs: https://github.com/libuv/libuv/issues/4369 */
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <android/fdsan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
char executable_path[sizeof(executable_path)];
|
char executable_path[sizeof(executable_path)];
|
||||||
|
|
||||||
|
|
||||||
@ -142,6 +147,13 @@ void log_tap_result(int test_count,
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enable_fdsan(void) {
|
||||||
|
/* Refs: https://github.com/libuv/libuv/issues/4369 */
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int run_test(const char* test,
|
int run_test(const char* test,
|
||||||
int benchmark_output,
|
int benchmark_output,
|
||||||
@ -160,6 +172,8 @@ int run_test(const char* test,
|
|||||||
main_proc = NULL;
|
main_proc = NULL;
|
||||||
process_count = 0;
|
process_count = 0;
|
||||||
|
|
||||||
|
enable_fdsan();
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
/* Clean up stale socket from previous run. */
|
/* Clean up stale socket from previous run. */
|
||||||
remove(TEST_PIPENAME);
|
remove(TEST_PIPENAME);
|
||||||
|
|||||||
@ -153,7 +153,14 @@ static void fs_event_cb_del_dir(uv_fs_event_t* handle,
|
|||||||
ASSERT_PTR_EQ(handle, &fs_event);
|
ASSERT_PTR_EQ(handle, &fs_event);
|
||||||
ASSERT_OK(status);
|
ASSERT_OK(status);
|
||||||
ASSERT(events == UV_CHANGE || events == UV_RENAME);
|
ASSERT(events == UV_CHANGE || events == UV_RENAME);
|
||||||
|
/* There is a bug in the FreeBSD kernel where the filename is sometimes NULL.
|
||||||
|
* Refs: https://github.com/libuv/libuv/issues/4606
|
||||||
|
*/
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
ASSERT(filename == NULL || strcmp(filename, "watch_del_dir") == 0);
|
||||||
|
#else
|
||||||
ASSERT_OK(strcmp(filename, "watch_del_dir"));
|
ASSERT_OK(strcmp(filename, "watch_del_dir"));
|
||||||
|
#endif
|
||||||
ASSERT_OK(uv_fs_event_stop(handle));
|
ASSERT_OK(uv_fs_event_stop(handle));
|
||||||
uv_close((uv_handle_t*)handle, close_cb);
|
uv_close((uv_handle_t*)handle, close_cb);
|
||||||
}
|
}
|
||||||
@ -1121,7 +1128,7 @@ TEST_IMPL(fs_event_getpath) {
|
|||||||
ASSERT_EQ(r, UV_EINVAL);
|
ASSERT_EQ(r, UV_EINVAL);
|
||||||
r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0);
|
r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
len = 0;
|
len = 1;
|
||||||
r = uv_fs_event_getpath(&fs_event, buf, &len);
|
r = uv_fs_event_getpath(&fs_event, buf, &len);
|
||||||
ASSERT_EQ(r, UV_ENOBUFS);
|
ASSERT_EQ(r, UV_ENOBUFS);
|
||||||
ASSERT_LT(len, sizeof buf); /* sanity check */
|
ASSERT_LT(len, sizeof buf); /* sanity check */
|
||||||
|
|||||||
325
test/test-fs.c
325
test/test-fs.c
@ -59,6 +59,18 @@
|
|||||||
#define TOO_LONG_NAME_LENGTH 65536
|
#define TOO_LONG_NAME_LENGTH 65536
|
||||||
#define PATHMAX 4096
|
#define PATHMAX 4096
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static const int is_win32 = 1;
|
||||||
|
#else
|
||||||
|
static const int is_win32 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__SUNPRO_C)
|
||||||
|
static const int is_apple_or_sunpro_c = 1;
|
||||||
|
#else
|
||||||
|
static const int is_apple_or_sunpro_c = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* path;
|
const char* path;
|
||||||
double atime;
|
double atime;
|
||||||
@ -827,43 +839,70 @@ static void check_utime(const char* path,
|
|||||||
ASSERT_OK(req.result);
|
ASSERT_OK(req.result);
|
||||||
s = &req.statbuf;
|
s = &req.statbuf;
|
||||||
|
|
||||||
if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) {
|
if (isfinite(atime)) {
|
||||||
/*
|
/* Test sub-second timestamps only when supported (such as Windows with
|
||||||
* Test sub-second timestamps only when supported (such as Windows with
|
|
||||||
* NTFS). Some other platforms support sub-second timestamps, but that
|
* NTFS). Some other platforms support sub-second timestamps, but that
|
||||||
* support is filesystem-dependent. Notably OS X (HFS Plus) does NOT
|
* support is filesystem-dependent. Notably OS X (HFS Plus) does NOT
|
||||||
* support sub-second timestamps. But kernels may round or truncate in
|
* support sub-second timestamps. But kernels may round or truncate in
|
||||||
* either direction, so we may accept either possible answer.
|
* either direction, so we may accept either possible answer.
|
||||||
*/
|
*/
|
||||||
#ifdef _WIN32
|
if (s->st_atim.tv_nsec == 0) {
|
||||||
ASSERT_DOUBLE_EQ(atime, (long) atime);
|
if (is_win32)
|
||||||
ASSERT_DOUBLE_EQ(mtime, (long) atime);
|
ASSERT_DOUBLE_EQ(atime, (long) atime);
|
||||||
#endif
|
if (atime > 0 || (long) atime == atime)
|
||||||
if (atime > 0 || (long) atime == atime)
|
ASSERT_EQ(s->st_atim.tv_sec, (long) atime);
|
||||||
ASSERT_EQ(s->st_atim.tv_sec, (long) atime);
|
ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1);
|
||||||
if (mtime > 0 || (long) mtime == mtime)
|
ASSERT_LE(s->st_atim.tv_sec, (long) atime);
|
||||||
ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime);
|
} else {
|
||||||
ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1);
|
double st_atim;
|
||||||
ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1);
|
/* TODO(vtjnash): would it be better to normalize this? */
|
||||||
ASSERT_LE(s->st_atim.tv_sec, (long) atime);
|
if (!is_apple_or_sunpro_c)
|
||||||
ASSERT_LE(s->st_mtim.tv_sec, (long) mtime);
|
ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0);
|
||||||
} else {
|
st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
|
||||||
double st_atim;
|
/* Linux does not allow reading reliably the atime of a symlink
|
||||||
double st_mtim;
|
* since readlink() can update it
|
||||||
#if !defined(__APPLE__) && !defined(__SUNPRO_C)
|
*/
|
||||||
/* TODO(vtjnash): would it be better to normalize this? */
|
if (!test_lutime)
|
||||||
ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0);
|
ASSERT_DOUBLE_EQ(st_atim, atime);
|
||||||
ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0);
|
}
|
||||||
#endif
|
} else if (isinf(atime)) {
|
||||||
st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
|
/* We test with timestamps that are in the distant past
|
||||||
st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;
|
* (if you're a Gen Z-er) so check it's more recent than that.
|
||||||
/*
|
|
||||||
* Linux does not allow reading reliably the atime of a symlink
|
|
||||||
* since readlink() can update it
|
|
||||||
*/
|
*/
|
||||||
if (!test_lutime)
|
ASSERT_GT(s->st_atim.tv_sec, 1739710000);
|
||||||
ASSERT_DOUBLE_EQ(st_atim, atime);
|
} else {
|
||||||
ASSERT_DOUBLE_EQ(st_mtim, mtime);
|
ASSERT_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isfinite(mtime)) {
|
||||||
|
/* Test sub-second timestamps only when supported (such as Windows with
|
||||||
|
* NTFS). Some other platforms support sub-second timestamps, but that
|
||||||
|
* support is filesystem-dependent. Notably OS X (HFS Plus) does NOT
|
||||||
|
* support sub-second timestamps. But kernels may round or truncate in
|
||||||
|
* either direction, so we may accept either possible answer.
|
||||||
|
*/
|
||||||
|
if (s->st_mtim.tv_nsec == 0) {
|
||||||
|
if (is_win32)
|
||||||
|
ASSERT_DOUBLE_EQ(mtime, (long) atime);
|
||||||
|
if (mtime > 0 || (long) mtime == mtime)
|
||||||
|
ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime);
|
||||||
|
ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1);
|
||||||
|
ASSERT_LE(s->st_mtim.tv_sec, (long) mtime);
|
||||||
|
} else {
|
||||||
|
double st_mtim;
|
||||||
|
/* TODO(vtjnash): would it be better to normalize this? */
|
||||||
|
if (!is_apple_or_sunpro_c)
|
||||||
|
ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0);
|
||||||
|
st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;
|
||||||
|
ASSERT_DOUBLE_EQ(st_mtim, mtime);
|
||||||
|
}
|
||||||
|
} else if (isinf(mtime)) {
|
||||||
|
/* We test with timestamps that are in the distant past
|
||||||
|
* (if you're a Gen Z-er) so check it's more recent than that.
|
||||||
|
*/
|
||||||
|
ASSERT_GT(s->st_mtim.tv_sec, 1739710000);
|
||||||
|
} else {
|
||||||
|
ASSERT_OK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
@ -1607,6 +1646,50 @@ TEST_IMPL(fs_fstat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_IMPL(fs_fstat_st_dev) {
|
||||||
|
uv_fs_t req;
|
||||||
|
uv_fs_t req_link;
|
||||||
|
uv_loop_t* loop = uv_default_loop();
|
||||||
|
char* test_file = "tmp_st_dev";
|
||||||
|
char* symlink_file = "tmp_st_dev_link";
|
||||||
|
|
||||||
|
unlink(test_file);
|
||||||
|
unlink(symlink_file);
|
||||||
|
|
||||||
|
// Create file
|
||||||
|
int r = uv_fs_open(NULL, &req, test_file, UV_FS_O_RDWR | UV_FS_O_CREAT,
|
||||||
|
S_IWUSR | S_IRUSR, NULL);
|
||||||
|
ASSERT_GE(r, 0);
|
||||||
|
ASSERT_GE(req.result, 0);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
|
// Create a symlink
|
||||||
|
r = uv_fs_symlink(loop, &req, test_file, symlink_file, 0, NULL);
|
||||||
|
ASSERT_EQ(r, 0);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
|
// Call uv_fs_fstat for file
|
||||||
|
r = uv_fs_stat(loop, &req, test_file, NULL);
|
||||||
|
ASSERT_EQ(r, 0);
|
||||||
|
|
||||||
|
// Call uv_fs_fstat for symlink
|
||||||
|
r = uv_fs_stat(loop, &req_link, symlink_file, NULL);
|
||||||
|
ASSERT_EQ(r, 0);
|
||||||
|
|
||||||
|
// Compare st_dev
|
||||||
|
ASSERT_EQ(((uv_stat_t*)req.ptr)->st_dev, ((uv_stat_t*)req_link.ptr)->st_dev);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
uv_fs_req_cleanup(&req_link);
|
||||||
|
unlink(test_file);
|
||||||
|
unlink(symlink_file);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_IMPL(fs_fstat_stdio) {
|
TEST_IMPL(fs_fstat_stdio) {
|
||||||
int fd;
|
int fd;
|
||||||
int res;
|
int res;
|
||||||
@ -2684,13 +2767,46 @@ TEST_IMPL(fs_utime) {
|
|||||||
|
|
||||||
atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
|
atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
|
||||||
|
|
||||||
r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
|
ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL));
|
||||||
ASSERT_OK(r);
|
|
||||||
ASSERT_OK(req.result);
|
ASSERT_OK(req.result);
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_utime(NULL,
|
||||||
|
&req,
|
||||||
|
path,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_utime(NULL,
|
||||||
|
&req,
|
||||||
|
path,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_utime(NULL,
|
||||||
|
&req,
|
||||||
|
path,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0);
|
||||||
|
|
||||||
atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */
|
atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */
|
||||||
checkme.path = path;
|
checkme.path = path;
|
||||||
checkme.atime = atime;
|
checkme.atime = atime;
|
||||||
@ -2824,9 +2940,43 @@ TEST_IMPL(fs_futime) {
|
|||||||
ASSERT_OK(req.result);
|
ASSERT_OK(req.result);
|
||||||
#endif
|
#endif
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_futime(NULL,
|
||||||
|
&req,
|
||||||
|
file,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_futime(NULL,
|
||||||
|
&req,
|
||||||
|
file,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_futime(NULL, &req, file, atime, mtime, NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, mtime, /* test_lutime */ 0);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_futime(NULL,
|
||||||
|
&req,
|
||||||
|
file,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0);
|
||||||
|
|
||||||
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
|
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
|
||||||
|
|
||||||
checkme.atime = atime;
|
checkme.atime = atime;
|
||||||
@ -2888,20 +3038,50 @@ TEST_IMPL(fs_lutime) {
|
|||||||
/* Test the synchronous version. */
|
/* Test the synchronous version. */
|
||||||
atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
|
atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
|
||||||
|
|
||||||
checkme.atime = atime;
|
|
||||||
checkme.mtime = mtime;
|
|
||||||
checkme.path = symlink_path;
|
|
||||||
req.data = &checkme;
|
|
||||||
|
|
||||||
r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
|
r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
|
||||||
#if (defined(_AIX) && !defined(_AIX71)) || \
|
#if (defined(_AIX) && !defined(_AIX71)) || defined(__MVS__)
|
||||||
defined(__MVS__)
|
|
||||||
ASSERT_EQ(r, UV_ENOSYS);
|
ASSERT_EQ(r, UV_ENOSYS);
|
||||||
RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
|
RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
|
||||||
#endif
|
#endif
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
lutime_cb(&req);
|
ASSERT_OK(req.result);
|
||||||
ASSERT_EQ(1, lutime_cb_count);
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(symlink_path, atime, mtime, /* test_lutime */ 1);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_lutime(NULL,
|
||||||
|
&req,
|
||||||
|
symlink_path,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(symlink_path, atime, mtime, /* test_lutime */ 1);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_lutime(NULL,
|
||||||
|
&req,
|
||||||
|
symlink_path,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(symlink_path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 1);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(symlink_path, atime, mtime, /* test_lutime */ 1);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_fs_lutime(NULL,
|
||||||
|
&req,
|
||||||
|
symlink_path,
|
||||||
|
UV_FS_UTIME_OMIT,
|
||||||
|
UV_FS_UTIME_NOW,
|
||||||
|
NULL));
|
||||||
|
ASSERT_OK(req.result);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
check_utime(symlink_path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 1);
|
||||||
|
|
||||||
/* Test the asynchronous version. */
|
/* Test the asynchronous version. */
|
||||||
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
|
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
|
||||||
@ -2909,11 +3089,12 @@ TEST_IMPL(fs_lutime) {
|
|||||||
checkme.atime = atime;
|
checkme.atime = atime;
|
||||||
checkme.mtime = mtime;
|
checkme.mtime = mtime;
|
||||||
checkme.path = symlink_path;
|
checkme.path = symlink_path;
|
||||||
|
req.data = &checkme;
|
||||||
|
|
||||||
r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
|
r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
uv_run(loop, UV_RUN_DEFAULT);
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
ASSERT_EQ(2, lutime_cb_count);
|
ASSERT_EQ(1, lutime_cb_count);
|
||||||
|
|
||||||
/* Cleanup. */
|
/* Cleanup. */
|
||||||
unlink(path);
|
unlink(path);
|
||||||
@ -4507,6 +4688,60 @@ TEST_IMPL(fs_open_readonly_acl) {
|
|||||||
MAKE_VALGRIND_HAPPY(loop);
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(fs_stat_no_permission) {
|
||||||
|
uv_passwd_t pwd;
|
||||||
|
uv_fs_t req;
|
||||||
|
int r;
|
||||||
|
char* filename = "test_file_no_permission.txt";
|
||||||
|
|
||||||
|
/* Setup - clear the ACL and remove the file */
|
||||||
|
loop = uv_default_loop();
|
||||||
|
r = uv_os_get_passwd(&pwd);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
call_icacls("icacls %s /remove *S-1-1-0:(F)", filename);
|
||||||
|
unlink(filename);
|
||||||
|
|
||||||
|
/* Create the file */
|
||||||
|
r = uv_fs_open(loop,
|
||||||
|
&open_req1,
|
||||||
|
filename,
|
||||||
|
UV_FS_O_RDONLY | UV_FS_O_CREAT,
|
||||||
|
S_IRUSR,
|
||||||
|
NULL);
|
||||||
|
ASSERT_GE(r, 0);
|
||||||
|
ASSERT_GE(open_req1.result, 0);
|
||||||
|
uv_fs_req_cleanup(&open_req1);
|
||||||
|
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_OK(close_req.result);
|
||||||
|
uv_fs_req_cleanup(&close_req);
|
||||||
|
|
||||||
|
/* Set up ACL */
|
||||||
|
r = call_icacls("icacls %s /deny *S-1-1-0:(F)", filename);
|
||||||
|
if (r != 0) {
|
||||||
|
goto acl_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read file stats */
|
||||||
|
r = uv_fs_stat(NULL, &req, filename, NULL);
|
||||||
|
if (r != 0) {
|
||||||
|
goto acl_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
|
acl_cleanup:
|
||||||
|
/* Cleanup */
|
||||||
|
call_icacls("icacls %s /reset", filename);
|
||||||
|
uv_fs_unlink(NULL, &unlink_req, filename, NULL);
|
||||||
|
uv_fs_req_cleanup(&unlink_req);
|
||||||
|
unlink(filename);
|
||||||
|
uv_os_free_passwd(&pwd);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@ -39,7 +39,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Two-byte sequences. */
|
/* Two-byte sequences. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF");
|
snprintf(b, sizeof(b), "%s", "\xC2\x80\xDF\xBF");
|
||||||
ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 2);
|
ASSERT_PTR_EQ(p, b + 2);
|
||||||
ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -47,7 +47,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Three-byte sequences. */
|
/* Three-byte sequences. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF");
|
snprintf(b, sizeof(b), "%s", "\xE0\xA0\x80\xEF\xBF\xBF");
|
||||||
ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 3);
|
ASSERT_PTR_EQ(p, b + 3);
|
||||||
ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -55,7 +55,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Four-byte sequences. */
|
/* Four-byte sequences. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF");
|
snprintf(b, sizeof(b), "%s", "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF");
|
||||||
ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 4);
|
ASSERT_PTR_EQ(p, b + 4);
|
||||||
ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -63,7 +63,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Four-byte sequences > U+10FFFF; disallowed. */
|
/* Four-byte sequences > U+10FFFF; disallowed. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF");
|
snprintf(b, sizeof(b), "%s", "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF");
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 4);
|
ASSERT_PTR_EQ(p, b + 4);
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -71,7 +71,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Overlong; disallowed. */
|
/* Overlong; disallowed. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xC0\x80\xC1\x80");
|
snprintf(b, sizeof(b), "%s", "\xC0\x80\xC1\x80");
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 2);
|
ASSERT_PTR_EQ(p, b + 2);
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -79,7 +79,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Surrogate pairs; disallowed. */
|
/* Surrogate pairs; disallowed. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF");
|
snprintf(b, sizeof(b), "%s", "\xED\xA0\x80\xED\xA3\xBF");
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
ASSERT_PTR_EQ(p, b + 3);
|
ASSERT_PTR_EQ(p, b + 3);
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -87,7 +87,7 @@ TEST_IMPL(utf8_decode1) {
|
|||||||
|
|
||||||
/* Simply illegal. */
|
/* Simply illegal. */
|
||||||
p = b;
|
p = b;
|
||||||
snprintf(b, sizeof(b), "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF");
|
snprintf(b, sizeof(b), "%s", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF");
|
||||||
|
|
||||||
for (i = 1; i <= 8; i++) {
|
for (i = 1; i <= 8; i++) {
|
||||||
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b)));
|
||||||
@ -218,3 +218,15 @@ TEST_IMPL(idna_toascii) {
|
|||||||
#undef T
|
#undef T
|
||||||
|
|
||||||
#endif /* __MVS__ */
|
#endif /* __MVS__ */
|
||||||
|
|
||||||
|
TEST_IMPL(wtf8) {
|
||||||
|
static const char input[] = "ᜄȺy𐞲:𞢢𘴇𐀀'¥3̞[<i$";
|
||||||
|
uint16_t buf[32];
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
len = uv_wtf8_length_as_utf16(input);
|
||||||
|
ASSERT_GT(len, 0);
|
||||||
|
ASSERT_LT(len, ARRAY_SIZE(buf));
|
||||||
|
uv_wtf8_to_utf16(input, buf, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -53,7 +53,8 @@ TEST_DECLARE (tty_raw)
|
|||||||
TEST_DECLARE (tty_empty_write)
|
TEST_DECLARE (tty_empty_write)
|
||||||
TEST_DECLARE (tty_large_write)
|
TEST_DECLARE (tty_large_write)
|
||||||
TEST_DECLARE (tty_raw_cancel)
|
TEST_DECLARE (tty_raw_cancel)
|
||||||
TEST_DECLARE (tty_duplicate_vt100_fn_key)
|
TEST_DECLARE (tty_duplicate_vt100_fn_key_libuv)
|
||||||
|
TEST_DECLARE (tty_duplicate_vt100_fn_key_winvt)
|
||||||
TEST_DECLARE (tty_duplicate_alt_modifier_key)
|
TEST_DECLARE (tty_duplicate_alt_modifier_key)
|
||||||
TEST_DECLARE (tty_composing_character)
|
TEST_DECLARE (tty_composing_character)
|
||||||
TEST_DECLARE (tty_cursor_up)
|
TEST_DECLARE (tty_cursor_up)
|
||||||
@ -364,6 +365,7 @@ TEST_DECLARE (fs_mkdtemp)
|
|||||||
TEST_DECLARE (fs_mkstemp)
|
TEST_DECLARE (fs_mkstemp)
|
||||||
TEST_DECLARE (fs_fstat)
|
TEST_DECLARE (fs_fstat)
|
||||||
TEST_DECLARE (fs_fstat_stdio)
|
TEST_DECLARE (fs_fstat_stdio)
|
||||||
|
TEST_DECLARE (fs_fstat_st_dev)
|
||||||
TEST_DECLARE (fs_access)
|
TEST_DECLARE (fs_access)
|
||||||
TEST_DECLARE (fs_chmod)
|
TEST_DECLARE (fs_chmod)
|
||||||
TEST_DECLARE (fs_copyfile)
|
TEST_DECLARE (fs_copyfile)
|
||||||
@ -466,6 +468,7 @@ TEST_DECLARE (threadpool_cancel_work)
|
|||||||
TEST_DECLARE (threadpool_cancel_fs)
|
TEST_DECLARE (threadpool_cancel_fs)
|
||||||
TEST_DECLARE (threadpool_cancel_single)
|
TEST_DECLARE (threadpool_cancel_single)
|
||||||
TEST_DECLARE (threadpool_cancel_when_busy)
|
TEST_DECLARE (threadpool_cancel_when_busy)
|
||||||
|
TEST_DECLARE (thread_detach)
|
||||||
TEST_DECLARE (thread_local_storage)
|
TEST_DECLARE (thread_local_storage)
|
||||||
TEST_DECLARE (thread_stack_size)
|
TEST_DECLARE (thread_stack_size)
|
||||||
TEST_DECLARE (thread_stack_size_explicit)
|
TEST_DECLARE (thread_stack_size_explicit)
|
||||||
@ -477,6 +480,8 @@ TEST_DECLARE (thread_create)
|
|||||||
TEST_DECLARE (thread_equal)
|
TEST_DECLARE (thread_equal)
|
||||||
TEST_DECLARE (thread_affinity)
|
TEST_DECLARE (thread_affinity)
|
||||||
TEST_DECLARE (thread_priority)
|
TEST_DECLARE (thread_priority)
|
||||||
|
TEST_DECLARE (thread_name)
|
||||||
|
TEST_DECLARE (thread_name_threadpool)
|
||||||
TEST_DECLARE (dlerror)
|
TEST_DECLARE (dlerror)
|
||||||
#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \
|
#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \
|
||||||
!defined(__sun)
|
!defined(__sun)
|
||||||
@ -512,6 +517,7 @@ TEST_DECLARE (environment_creation)
|
|||||||
TEST_DECLARE (listen_with_simultaneous_accepts)
|
TEST_DECLARE (listen_with_simultaneous_accepts)
|
||||||
TEST_DECLARE (listen_no_simultaneous_accepts)
|
TEST_DECLARE (listen_no_simultaneous_accepts)
|
||||||
TEST_DECLARE (fs_stat_root)
|
TEST_DECLARE (fs_stat_root)
|
||||||
|
TEST_DECLARE (fs_stat_no_permission)
|
||||||
TEST_DECLARE (spawn_with_an_odd_path)
|
TEST_DECLARE (spawn_with_an_odd_path)
|
||||||
TEST_DECLARE (spawn_no_path)
|
TEST_DECLARE (spawn_no_path)
|
||||||
TEST_DECLARE (spawn_no_ext)
|
TEST_DECLARE (spawn_no_ext)
|
||||||
@ -572,6 +578,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple)
|
|||||||
|
|
||||||
TEST_DECLARE (iouring_pollhup)
|
TEST_DECLARE (iouring_pollhup)
|
||||||
|
|
||||||
|
TEST_DECLARE (wtf8)
|
||||||
TEST_DECLARE (idna_toascii)
|
TEST_DECLARE (idna_toascii)
|
||||||
TEST_DECLARE (utf8_decode1)
|
TEST_DECLARE (utf8_decode1)
|
||||||
TEST_DECLARE (utf8_decode1_overrun)
|
TEST_DECLARE (utf8_decode1_overrun)
|
||||||
@ -630,7 +637,8 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (tty_empty_write)
|
TEST_ENTRY (tty_empty_write)
|
||||||
TEST_ENTRY (tty_large_write)
|
TEST_ENTRY (tty_large_write)
|
||||||
TEST_ENTRY (tty_raw_cancel)
|
TEST_ENTRY (tty_raw_cancel)
|
||||||
TEST_ENTRY (tty_duplicate_vt100_fn_key)
|
TEST_ENTRY (tty_duplicate_vt100_fn_key_libuv)
|
||||||
|
TEST_ENTRY (tty_duplicate_vt100_fn_key_winvt)
|
||||||
TEST_ENTRY (tty_duplicate_alt_modifier_key)
|
TEST_ENTRY (tty_duplicate_alt_modifier_key)
|
||||||
TEST_ENTRY (tty_composing_character)
|
TEST_ENTRY (tty_composing_character)
|
||||||
TEST_ENTRY (tty_cursor_up)
|
TEST_ENTRY (tty_cursor_up)
|
||||||
@ -1040,6 +1048,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (listen_with_simultaneous_accepts)
|
TEST_ENTRY (listen_with_simultaneous_accepts)
|
||||||
TEST_ENTRY (listen_no_simultaneous_accepts)
|
TEST_ENTRY (listen_no_simultaneous_accepts)
|
||||||
TEST_ENTRY (fs_stat_root)
|
TEST_ENTRY (fs_stat_root)
|
||||||
|
TEST_ENTRY (fs_stat_no_permission)
|
||||||
TEST_ENTRY (spawn_with_an_odd_path)
|
TEST_ENTRY (spawn_with_an_odd_path)
|
||||||
TEST_ENTRY (spawn_no_path)
|
TEST_ENTRY (spawn_no_path)
|
||||||
TEST_ENTRY (spawn_no_ext)
|
TEST_ENTRY (spawn_no_ext)
|
||||||
@ -1077,6 +1086,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (fs_mkstemp)
|
TEST_ENTRY (fs_mkstemp)
|
||||||
TEST_ENTRY (fs_fstat)
|
TEST_ENTRY (fs_fstat)
|
||||||
TEST_ENTRY (fs_fstat_stdio)
|
TEST_ENTRY (fs_fstat_stdio)
|
||||||
|
TEST_ENTRY (fs_fstat_st_dev)
|
||||||
TEST_ENTRY (fs_access)
|
TEST_ENTRY (fs_access)
|
||||||
TEST_ENTRY (fs_chmod)
|
TEST_ENTRY (fs_chmod)
|
||||||
TEST_ENTRY (fs_copyfile)
|
TEST_ENTRY (fs_copyfile)
|
||||||
@ -1179,6 +1189,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (threadpool_cancel_fs)
|
TEST_ENTRY (threadpool_cancel_fs)
|
||||||
TEST_ENTRY (threadpool_cancel_single)
|
TEST_ENTRY (threadpool_cancel_single)
|
||||||
TEST_ENTRY (threadpool_cancel_when_busy)
|
TEST_ENTRY (threadpool_cancel_when_busy)
|
||||||
|
TEST_ENTRY (thread_detach)
|
||||||
TEST_ENTRY (thread_local_storage)
|
TEST_ENTRY (thread_local_storage)
|
||||||
TEST_ENTRY (thread_stack_size)
|
TEST_ENTRY (thread_stack_size)
|
||||||
TEST_ENTRY (thread_stack_size_explicit)
|
TEST_ENTRY (thread_stack_size_explicit)
|
||||||
@ -1190,6 +1201,8 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (thread_equal)
|
TEST_ENTRY (thread_equal)
|
||||||
TEST_ENTRY (thread_affinity)
|
TEST_ENTRY (thread_affinity)
|
||||||
TEST_ENTRY (thread_priority)
|
TEST_ENTRY (thread_priority)
|
||||||
|
TEST_ENTRY (thread_name)
|
||||||
|
TEST_ENTRY (thread_name_threadpool)
|
||||||
TEST_ENTRY (dlerror)
|
TEST_ENTRY (dlerror)
|
||||||
TEST_ENTRY (ip4_addr)
|
TEST_ENTRY (ip4_addr)
|
||||||
TEST_ENTRY (ip6_addr_link_local)
|
TEST_ENTRY (ip6_addr_link_local)
|
||||||
@ -1223,6 +1236,7 @@ TASK_LIST_START
|
|||||||
|
|
||||||
TEST_ENTRY (iouring_pollhup)
|
TEST_ENTRY (iouring_pollhup)
|
||||||
|
|
||||||
|
TEST_ENTRY (wtf8)
|
||||||
TEST_ENTRY (utf8_decode1)
|
TEST_ENTRY (utf8_decode1)
|
||||||
TEST_ENTRY (utf8_decode1_overrun)
|
TEST_ENTRY (utf8_decode1_overrun)
|
||||||
TEST_ENTRY (uname)
|
TEST_ENTRY (uname)
|
||||||
|
|||||||
@ -154,6 +154,15 @@ TEST_IMPL(pipe_getsockname) {
|
|||||||
ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME);
|
ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
r = uv_pipe_getsockname(&pipe_server, NULL, &len);
|
||||||
|
ASSERT_EQ(r, UV_EINVAL);
|
||||||
|
|
||||||
|
r = uv_pipe_getsockname(&pipe_server, buf, NULL);
|
||||||
|
ASSERT_EQ(r, UV_EINVAL);
|
||||||
|
|
||||||
|
r = uv_pipe_getsockname(&pipe_server, NULL, NULL);
|
||||||
|
ASSERT_EQ(r, UV_EINVAL);
|
||||||
|
|
||||||
len = sizeof(TEST_PIPENAME) - 1;
|
len = sizeof(TEST_PIPENAME) - 1;
|
||||||
ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len));
|
ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len));
|
||||||
|
|
||||||
|
|||||||
@ -236,5 +236,24 @@ TEST_IMPL(platform_output) {
|
|||||||
printf(" version: %s\n", uname.version);
|
printf(" version: %s\n", uname.version);
|
||||||
printf(" machine: %s\n", uname.machine);
|
printf(" machine: %s\n", uname.machine);
|
||||||
|
|
||||||
|
err = uv_getrusage_thread(&rusage);
|
||||||
|
if (err != UV_ENOTSUP) {
|
||||||
|
ASSERT_OK(err);
|
||||||
|
ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0);
|
||||||
|
ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0);
|
||||||
|
ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0);
|
||||||
|
ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0);
|
||||||
|
printf("uv_getrusage_thread:\n");
|
||||||
|
printf(" user: %llu sec %llu microsec\n",
|
||||||
|
(unsigned long long) rusage.ru_utime.tv_sec,
|
||||||
|
(unsigned long long) rusage.ru_utime.tv_usec);
|
||||||
|
printf(" system: %llu sec %llu microsec\n",
|
||||||
|
(unsigned long long) rusage.ru_stime.tv_sec,
|
||||||
|
(unsigned long long) rusage.ru_stime.tv_usec);
|
||||||
|
printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt);
|
||||||
|
printf(" maximum resident set size: %llu\n",
|
||||||
|
(unsigned long long) rusage.ru_maxrss);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1329,9 +1329,7 @@ TEST_IMPL(environment_creation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev) { /* verify sort order */
|
if (prev) { /* verify sort order */
|
||||||
#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)
|
|
||||||
ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE));
|
ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
ASSERT(found); /* verify that we expected this variable */
|
ASSERT(found); /* verify that we expected this variable */
|
||||||
}
|
}
|
||||||
|
|||||||
189
test/test-thread-name.c
Normal file
189
test/test-thread-name.c
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/* 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 "../src/uv-common.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct semaphores {
|
||||||
|
uv_sem_t main;
|
||||||
|
uv_sem_t worker;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void thread_run(void* arg) {
|
||||||
|
int r;
|
||||||
|
char thread_name[16];
|
||||||
|
struct semaphores* sem;
|
||||||
|
uv_thread_t thread;
|
||||||
|
|
||||||
|
sem = arg;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* uv_thread_self isn't defined for the main thread on Windows. */
|
||||||
|
thread = GetCurrentThread();
|
||||||
|
#else
|
||||||
|
thread = uv_thread_self();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
r = uv_thread_setname("worker-thread");
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
uv_sem_post(&sem->worker);
|
||||||
|
|
||||||
|
r = uv_thread_getname(&thread, thread_name, sizeof(thread_name));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
ASSERT_STR_EQ(thread_name, "worker-thread");
|
||||||
|
|
||||||
|
uv_sem_wait(&sem->main);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(thread_name) {
|
||||||
|
int r;
|
||||||
|
uv_thread_t threads[2];
|
||||||
|
char tn[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
char thread_name[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
char long_thread_name[UV_PTHREAD_MAX_NAMELEN_NP + 1];
|
||||||
|
struct semaphores sem;
|
||||||
|
|
||||||
|
#if defined(__ANDROID_API__) && __ANDROID_API__ < 26 || \
|
||||||
|
defined(_AIX) || \
|
||||||
|
defined(__MVS__) || \
|
||||||
|
defined(__PASE__)
|
||||||
|
RETURN_SKIP("API not available on this platform");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSERT_OK(uv_sem_init(&sem.main, 0));
|
||||||
|
ASSERT_OK(uv_sem_init(&sem.worker, 0));
|
||||||
|
|
||||||
|
memset(thread_name, 'a', sizeof(thread_name) - 1);
|
||||||
|
thread_name[sizeof(thread_name) - 1] = '\0';
|
||||||
|
|
||||||
|
memset(long_thread_name, 'a', sizeof(long_thread_name) - 1);
|
||||||
|
long_thread_name[sizeof(long_thread_name) - 1] = '\0';
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* uv_thread_self isn't defined for the main thread on Windows. */
|
||||||
|
threads[0] = GetCurrentThread();
|
||||||
|
#else
|
||||||
|
threads[0] = uv_thread_self();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
r = uv_thread_getname(&threads[0], tn, sizeof(tn));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_thread_setname(long_thread_name);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_thread_getname(&threads[0], tn, sizeof(tn));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_STR_EQ(tn, thread_name);
|
||||||
|
|
||||||
|
r = uv_thread_setname(thread_name);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_thread_getname(&threads[0], tn, sizeof(tn));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_STR_EQ(tn, thread_name);
|
||||||
|
|
||||||
|
r = uv_thread_getname(&threads[0], tn, 3);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_EQ(strlen(tn), 2);
|
||||||
|
ASSERT_OK(memcmp(thread_name, tn, 2));
|
||||||
|
|
||||||
|
/* Illumos doesn't support non-ASCII thread names. */
|
||||||
|
#ifndef __illumos__
|
||||||
|
r = uv_thread_setname("~½¬{½");
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_thread_getname(&threads[0], tn, sizeof(tn));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_STR_EQ(tn, "~½¬{½");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSERT_OK(uv_thread_create(threads + 1, thread_run, &sem));
|
||||||
|
|
||||||
|
uv_sem_wait(&sem.worker);
|
||||||
|
|
||||||
|
r = uv_thread_getname(threads + 1, tn, sizeof(tn));
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
ASSERT_STR_EQ(tn, "worker-thread");
|
||||||
|
|
||||||
|
uv_sem_post(&sem.main);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_thread_join(threads + 1));
|
||||||
|
|
||||||
|
uv_sem_destroy(&sem.main);
|
||||||
|
uv_sem_destroy(&sem.worker);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_THREADS 4
|
||||||
|
|
||||||
|
static void* executedThreads[MAX_THREADS] = { NULL };
|
||||||
|
static int size;
|
||||||
|
static uv_loop_t* loop;
|
||||||
|
|
||||||
|
static unsigned short int key_exists(void* key) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < MAX_THREADS; i++) {
|
||||||
|
if (executedThreads[i] == key) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void work_cb(uv_work_t* req) {
|
||||||
|
uv_thread_t thread = uv_thread_self();
|
||||||
|
req->data = &thread;
|
||||||
|
char tn[UV_PTHREAD_MAX_NAMELEN_NP];
|
||||||
|
ASSERT_OK(uv_thread_getname(&thread, tn, sizeof(tn)));
|
||||||
|
ASSERT_STR_EQ(tn, "libuv-worker");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void after_work_cb(uv_work_t* req, int status) {
|
||||||
|
ASSERT_OK(status);
|
||||||
|
if (!key_exists(req->data)) {
|
||||||
|
executedThreads[size++] = req->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == MAX_THREADS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_queue_work(loop, req, work_cb, after_work_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(thread_name_threadpool) {
|
||||||
|
uv_work_t req;
|
||||||
|
loop = uv_default_loop();
|
||||||
|
// Just to make sure all workers will be executed
|
||||||
|
// with the correct thread name
|
||||||
|
ASSERT_OK(uv_queue_work(loop, &req, work_cb, after_work_cb));
|
||||||
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -294,3 +294,13 @@ TEST_IMPL(thread_stack_size_explicit) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void thread_detach_cb(void* arg) {}
|
||||||
|
|
||||||
|
TEST_IMPL(thread_detach) {
|
||||||
|
uv_thread_t thread;
|
||||||
|
ASSERT_OK(uv_thread_create(&thread, thread_detach_cb, NULL));
|
||||||
|
ASSERT_OK(uv_thread_detach(&thread));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -131,7 +131,7 @@ static void make_key_event_records(WORD virt_key, DWORD ctr_key_state,
|
|||||||
# undef KEV
|
# undef KEV
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_IMPL(tty_duplicate_vt100_fn_key) {
|
TEST_IMPL(tty_duplicate_vt100_fn_key_libuv) {
|
||||||
int r;
|
int r;
|
||||||
int ttyin_fd;
|
int ttyin_fd;
|
||||||
uv_tty_t tty_in;
|
uv_tty_t tty_in;
|
||||||
@ -163,6 +163,10 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) {
|
|||||||
r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
|
r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libuv has chosen to emit ESC[[A, but other terminals, and even
|
||||||
|
* Windows itself use a different escape sequence, see the test below.
|
||||||
|
*/
|
||||||
expect_str = ESC"[[A";
|
expect_str = ESC"[[A";
|
||||||
expect_nread = strlen(expect_str);
|
expect_nread = strlen(expect_str);
|
||||||
|
|
||||||
@ -184,6 +188,62 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(tty_duplicate_vt100_fn_key_winvt) {
|
||||||
|
int r;
|
||||||
|
int ttyin_fd;
|
||||||
|
uv_tty_t tty_in;
|
||||||
|
uv_loop_t* loop;
|
||||||
|
HANDLE handle;
|
||||||
|
INPUT_RECORD records[2];
|
||||||
|
DWORD written;
|
||||||
|
|
||||||
|
loop = uv_default_loop();
|
||||||
|
|
||||||
|
/* Make sure we have an FD that refers to a tty */
|
||||||
|
handle = CreateFileA("conin$",
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE);
|
||||||
|
ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
|
||||||
|
ASSERT_GE(ttyin_fd, 0);
|
||||||
|
ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd));
|
||||||
|
|
||||||
|
r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
|
||||||
|
ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
|
||||||
|
|
||||||
|
r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some keys, like F1, get are assigned a different value by Windows
|
||||||
|
* in ENABLE_VIRTUAL_TERMINAL_INPUT mode vs. libuv in the test above.
|
||||||
|
*/
|
||||||
|
expect_str = ESC"OP";
|
||||||
|
expect_nread = strlen(expect_str);
|
||||||
|
|
||||||
|
/* Turn on raw mode. */
|
||||||
|
r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW_VT);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send F1 keystroke.
|
||||||
|
*/
|
||||||
|
make_key_event_records(VK_F1, 0, TRUE, records);
|
||||||
|
WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written);
|
||||||
|
ASSERT_EQ(written, ARRAY_SIZE(records));
|
||||||
|
|
||||||
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_IMPL(tty_duplicate_alt_modifier_key) {
|
TEST_IMPL(tty_duplicate_alt_modifier_key) {
|
||||||
int r;
|
int r;
|
||||||
int ttyin_fd;
|
int ttyin_fd;
|
||||||
|
|||||||
@ -32,12 +32,12 @@
|
|||||||
#define BUFFER_MULTIPLIER 20
|
#define BUFFER_MULTIPLIER 20
|
||||||
#define MAX_DGRAM_SIZE (64 * 1024)
|
#define MAX_DGRAM_SIZE (64 * 1024)
|
||||||
#define NUM_SENDS 40
|
#define NUM_SENDS 40
|
||||||
#define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER)
|
|
||||||
|
|
||||||
static uv_udp_t recver;
|
static uv_udp_t recver;
|
||||||
static uv_udp_t sender;
|
static uv_udp_t sender;
|
||||||
static int recv_cb_called;
|
static int recv_cb_called;
|
||||||
static int received_datagrams;
|
static int received_datagrams;
|
||||||
|
static int read_bytes;
|
||||||
static int close_cb_called;
|
static int close_cb_called;
|
||||||
static int alloc_cb_called;
|
static int alloc_cb_called;
|
||||||
|
|
||||||
@ -74,6 +74,7 @@ static void recv_cb(uv_udp_t* handle,
|
|||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
ASSERT_GE(nread, 0);
|
ASSERT_GE(nread, 0);
|
||||||
|
read_bytes += nread;
|
||||||
|
|
||||||
/* free and return if this is a mmsg free-only callback invocation */
|
/* free and return if this is a mmsg free-only callback invocation */
|
||||||
if (flags & UV_UDP_MMSG_FREE) {
|
if (flags & UV_UDP_MMSG_FREE) {
|
||||||
@ -140,7 +141,7 @@ TEST_IMPL(udp_mmsg) {
|
|||||||
|
|
||||||
/* On platforms that don't support mmsg, each recv gets its own alloc */
|
/* On platforms that don't support mmsg, each recv gets its own alloc */
|
||||||
if (uv_udp_using_recvmmsg(&recver))
|
if (uv_udp_using_recvmmsg(&recver))
|
||||||
ASSERT_EQ(alloc_cb_called, EXPECTED_MMSG_ALLOCS);
|
ASSERT_EQ(read_bytes, NUM_SENDS * 4); /* we're sending 4 bytes per datagram */
|
||||||
else
|
else
|
||||||
ASSERT_EQ(alloc_cb_called, recv_cb_called);
|
ASSERT_EQ(alloc_cb_called, recv_cb_called);
|
||||||
|
|
||||||
|
|||||||
@ -36,10 +36,9 @@ static uv_udp_t client;
|
|||||||
static uv_udp_send_t req;
|
static uv_udp_send_t req;
|
||||||
static uv_udp_send_t req_ss;
|
static uv_udp_send_t req_ss;
|
||||||
|
|
||||||
|
static int darwin_ebusy_errors;
|
||||||
static int cl_recv_cb_called;
|
static int cl_recv_cb_called;
|
||||||
|
|
||||||
static int sv_send_cb_called;
|
static int sv_send_cb_called;
|
||||||
|
|
||||||
static int close_cb_called;
|
static int close_cb_called;
|
||||||
|
|
||||||
static void alloc_cb(uv_handle_t* handle,
|
static void alloc_cb(uv_handle_t* handle,
|
||||||
@ -128,6 +127,13 @@ static void cl_recv_cb(uv_udp_t* handle,
|
|||||||
|
|
||||||
#if !defined(__NetBSD__)
|
#if !defined(__NetBSD__)
|
||||||
r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP);
|
r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP);
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
if (r == UV_EBUSY) {
|
||||||
|
uv_close((uv_handle_t*) &server, close_cb);
|
||||||
|
darwin_ebusy_errors++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -160,7 +166,13 @@ TEST_IMPL(udp_multicast_join) {
|
|||||||
r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP);
|
r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP);
|
||||||
if (r == UV_ENODEV)
|
if (r == UV_ENODEV)
|
||||||
RETURN_SKIP("No multicast support.");
|
RETURN_SKIP("No multicast support.");
|
||||||
|
if (r == UV_ENOEXEC)
|
||||||
|
RETURN_SKIP("No multicast support (likely a firewall issue).");
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
/* It returns an ENOSYS error */
|
||||||
|
RETURN_SKIP("Test does not currently work in ANDROID");
|
||||||
|
#endif
|
||||||
|
|
||||||
r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb);
|
r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
@ -175,6 +187,9 @@ TEST_IMPL(udp_multicast_join) {
|
|||||||
/* run the loop till all events are processed */
|
/* run the loop till all events are processed */
|
||||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
if (darwin_ebusy_errors > 0)
|
||||||
|
RETURN_SKIP("Unexplained macOS IP_ADD_SOURCE_MEMBERSHIP EBUSY bug");
|
||||||
|
|
||||||
ASSERT_EQ(2, cl_recv_cb_called);
|
ASSERT_EQ(2, cl_recv_cb_called);
|
||||||
ASSERT_EQ(2, sv_send_cb_called);
|
ASSERT_EQ(2, sv_send_cb_called);
|
||||||
ASSERT_EQ(2, close_cb_called);
|
ASSERT_EQ(2, close_cb_called);
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
#if defined(__APPLE__) || \
|
#if defined(__APPLE__) || \
|
||||||
defined(_AIX) || \
|
defined(_AIX) || \
|
||||||
defined(__MVS__) || \
|
defined(__MVS__) || \
|
||||||
|
defined(__FreeBSD__) || \
|
||||||
defined(__NetBSD__) || \
|
defined(__NetBSD__) || \
|
||||||
defined(__OpenBSD__)
|
defined(__OpenBSD__)
|
||||||
#define MULTICAST_ADDR "ff02::1%lo0"
|
#define MULTICAST_ADDR "ff02::1%lo0"
|
||||||
|
|||||||
@ -60,8 +60,6 @@ static void sv_recv_cb(uv_udp_t* handle,
|
|||||||
const uv_buf_t* rcvbuf,
|
const uv_buf_t* rcvbuf,
|
||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
ASSERT_GT(nread, 0);
|
|
||||||
|
|
||||||
if (nread == 0) {
|
if (nread == 0) {
|
||||||
ASSERT_NULL(addr);
|
ASSERT_NULL(addr);
|
||||||
return;
|
return;
|
||||||
@ -70,11 +68,17 @@ static void sv_recv_cb(uv_udp_t* handle,
|
|||||||
ASSERT_EQ(4, nread);
|
ASSERT_EQ(4, nread);
|
||||||
ASSERT_NOT_NULL(addr);
|
ASSERT_NOT_NULL(addr);
|
||||||
|
|
||||||
ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread));
|
if (!memcmp("EXIT", rcvbuf->base, nread)) {
|
||||||
uv_close((uv_handle_t*) handle, close_cb);
|
uv_close((uv_handle_t*) handle, close_cb);
|
||||||
uv_close((uv_handle_t*) &client, close_cb);
|
uv_close((uv_handle_t*) &client, close_cb);
|
||||||
|
} else {
|
||||||
|
ASSERT_MEM_EQ(rcvbuf->base, "HELO", 4);
|
||||||
|
}
|
||||||
|
|
||||||
sv_recv_cb_called++;
|
sv_recv_cb_called++;
|
||||||
|
|
||||||
|
if (sv_recv_cb_called == 2)
|
||||||
|
uv_udp_recv_stop(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,9 +105,33 @@ TEST_IMPL(udp_try_send) {
|
|||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
|
|
||||||
buf = uv_buf_init(buffer, sizeof(buffer));
|
buf = uv_buf_init(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
r = uv_udp_try_send(&client, &buf, 0, (const struct sockaddr*) &addr);
|
||||||
|
ASSERT_EQ(r, UV_EINVAL);
|
||||||
|
|
||||||
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
|
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
|
||||||
ASSERT_EQ(r, UV_EMSGSIZE);
|
ASSERT_EQ(r, UV_EMSGSIZE);
|
||||||
|
|
||||||
|
uv_buf_t* bufs[] = {&buf, &buf};
|
||||||
|
unsigned int nbufs[] = {1, 1};
|
||||||
|
struct sockaddr* addrs[] = {
|
||||||
|
(struct sockaddr*) &addr,
|
||||||
|
(struct sockaddr*) &addr,
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_EQ(0, sv_recv_cb_called);
|
||||||
|
|
||||||
|
buf = uv_buf_init("HELO", 4);
|
||||||
|
r = uv_udp_try_send2(&client, 2, bufs, nbufs, addrs, /*flags*/0);
|
||||||
|
ASSERT_EQ(r, 2);
|
||||||
|
|
||||||
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
ASSERT_EQ(2, sv_recv_cb_called);
|
||||||
|
|
||||||
|
r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
buf = uv_buf_init("EXIT", 4);
|
buf = uv_buf_init("EXIT", 4);
|
||||||
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
|
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
|
||||||
ASSERT_EQ(4, r);
|
ASSERT_EQ(4, r);
|
||||||
@ -111,7 +139,7 @@ TEST_IMPL(udp_try_send) {
|
|||||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
ASSERT_EQ(2, close_cb_called);
|
ASSERT_EQ(2, close_cb_called);
|
||||||
ASSERT_EQ(1, sv_recv_cb_called);
|
ASSERT_EQ(3, sv_recv_cb_called);
|
||||||
|
|
||||||
ASSERT_OK(client.send_queue_size);
|
ASSERT_OK(client.send_queue_size);
|
||||||
ASSERT_OK(server.send_queue_size);
|
ASSERT_OK(server.send_queue_size);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user