mirror of
https://github.com/libuv/libuv
synced 2025-03-28 21:13:16 +00:00
Compare commits
334 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1a9f01f22 | ||
![]() |
bb706f5fe7 | ||
![]() |
2b96e47f12 | ||
![]() |
ea1cf034be | ||
![]() |
4681d5d570 | ||
![]() |
c727be4df9 | ||
![]() |
98a4bab92a | ||
![]() |
352d992916 | ||
![]() |
92eacd19a1 | ||
![]() |
545ecf515f | ||
![]() |
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 | ||
![]() |
e1095c7a43 | ||
![]() |
058c49b7ba | ||
![]() |
7e6590f31d | ||
![]() |
9cf0710d71 | ||
![]() |
52a9243317 | ||
![]() |
18d48bc13c | ||
![]() |
fbe2d85bd5 | ||
![]() |
be0b00a80d | ||
![]() |
bfbd6db0d6 | ||
![]() |
8be336f4ee | ||
![]() |
7c3abfbf1e | ||
![]() |
1f36b01ed0 | ||
![]() |
8d957c56b3 | ||
![]() |
0be52c8251 | ||
![]() |
1cbffcbd5d | ||
![]() |
670e75ee7e | ||
![]() |
f55efb2f38 | ||
![]() |
88b874e63c | ||
![]() |
473dafc593 | ||
![]() |
65e3735320 | ||
![]() |
f806be87d3 | ||
![]() |
bcc6d1c1fc | ||
![]() |
675a5a5396 | ||
![]() |
5467ec969a | ||
![]() |
511e202e13 | ||
![]() |
d2e56a5e8d | ||
![]() |
cc2e0aa3cf | ||
![]() |
e1a5465255 | ||
![]() |
32603fd5ff | ||
![]() |
1c778bd001 | ||
![]() |
5bb19f35ea | ||
![]() |
88af4a87d2 | ||
![]() |
9dddebab0d | ||
![]() |
a49f264dff | ||
![]() |
44e61dab7e | ||
![]() |
0a00e80c36 | ||
![]() |
5ff1fc724f | ||
![]() |
f00d4b6775 | ||
![]() |
5cbc82e369 | ||
![]() |
58dfb6c89b | ||
![]() |
b5eb41d882 | ||
![]() |
c869cd1d8a | ||
![]() |
5cc7175514 | ||
![]() |
3e1733a053 | ||
![]() |
8809d1df8d | ||
![]() |
1790abb3b2 | ||
![]() |
31d9165999 | ||
![]() |
27134547ff | ||
![]() |
1eac3310ad | ||
![]() |
a53e7877e4 | ||
![]() |
c84a2dbe03 | ||
![]() |
88ab6e78da | ||
![]() |
5537d6a689 | ||
![]() |
e78e29c231 | ||
![]() |
9b3b61f606 | ||
![]() |
a6a987c0de | ||
![]() |
727ee7237e | ||
![]() |
4e310d0f90 | ||
![]() |
f23037fe21 | ||
![]() |
e5cb1d3d3d | ||
![]() |
63b22be083 | ||
![]() |
badecdca14 | ||
![]() |
83306585ff | ||
![]() |
18266a6969 | ||
![]() |
0c36b16d1b | ||
![]() |
e4d47c5357 | ||
![]() |
593aa3b2f6 | ||
![]() |
47c833675b | ||
![]() |
372e4c645e | ||
![]() |
6ab153cf8e | ||
![]() |
9678211c24 | ||
![]() |
5d1ccc12c4 | ||
![]() |
f56f21d7da | ||
![]() |
ecc11611d3 | ||
![]() |
f279d9e6c6 | ||
![]() |
ae6e146775 | ||
![]() |
90648ea3e5 | ||
![]() |
2780b87d56 | ||
![]() |
e37539a46c | ||
![]() |
7c491bde32 | ||
![]() |
6621fe045a | ||
![]() |
36f0789d83 | ||
![]() |
fedfa9893e | ||
![]() |
ba24986f8d | ||
![]() |
eb5af8e3c0 | ||
![]() |
1ee1063402 | ||
![]() |
541329d51f | ||
![]() |
d2d92b74a8 | ||
![]() |
c8d4a87f49 | ||
![]() |
ab3ecf6565 | ||
![]() |
287987b37c | ||
![]() |
10ccd08471 | ||
![]() |
bf61390769 | ||
![]() |
520eb622f0 | ||
![]() |
497f3168d1 | ||
![]() |
8083ab26e0 | ||
![]() |
c0a61c3bb3 | ||
![]() |
f50ae53c42 | ||
![]() |
17219b8f39 | ||
![]() |
46c0e1769b | ||
![]() |
4fce06ec96 | ||
![]() |
77e4cd5b18 | ||
![]() |
d05ed869bb | ||
![]() |
abc9767034 | ||
![]() |
6adeeacee7 | ||
![]() |
f55628eed0 | ||
![]() |
3ecce91410 | ||
![]() |
cc23e204d7 | ||
![]() |
e0c5fc8714 | ||
![]() |
91ba13054a | ||
![]() |
b0816180e3 | ||
![]() |
fa6745b4f2 | ||
![]() |
6912038d72 | ||
![]() |
2c15345016 | ||
![]() |
ff9587991f | ||
![]() |
625d3d275a | ||
![]() |
a7c44d6748 | ||
![]() |
e8458b2402 | ||
![]() |
6b56200cc8 | ||
![]() |
cc9e96147f | ||
![]() |
507f3046d1 | ||
![]() |
7b9e37c7da | ||
![]() |
009d7414bc | ||
![]() |
08a1e7fd23 | ||
![]() |
99e576612d | ||
![]() |
e9f29cb984 | ||
![]() |
c858a14764 | ||
![]() |
e0327e1d50 | ||
![]() |
3530bcc303 | ||
![]() |
0f2d7e784a | ||
![]() |
bb6fbcf6e7 | ||
![]() |
10f313631c | ||
![]() |
129362f356 | ||
![]() |
3f7191e5c2 | ||
![]() |
535efdf319 | ||
![]() |
f98516ddd5 | ||
![]() |
3b6a1a14ca | ||
![]() |
a7cbda92b6 | ||
![]() |
a407b232f0 | ||
![]() |
160cd5629e | ||
![]() |
7d092913b3 | ||
![]() |
a9381cdb03 | ||
![]() |
e72a91e063 | ||
![]() |
64bd28f5ba | ||
![]() |
1dd0ab1315 | ||
![]() |
8861a97efa | ||
![]() |
51a22f60d6 | ||
![]() |
8a499e1331 | ||
![]() |
34db4c21b1 | ||
![]() |
1479b76310 | ||
![]() |
a7d5255122 | ||
![]() |
12bd89bbc3 | ||
![]() |
5e302730cd | ||
![]() |
a5c01d4de3 | ||
![]() |
de43f42735 | ||
![]() |
fc70430b09 | ||
![]() |
7ba94d3909 | ||
![]() |
bfbe4e38d7 | ||
![]() |
4785ad6337 | ||
![]() |
6be130e1b8 | ||
![]() |
f144429365 | ||
![]() |
35da5ded3b | ||
![]() |
b9421d7066 | ||
![]() |
54d8364c24 | ||
![]() |
d843b7cf7f | ||
![]() |
e135dfe183 | ||
![]() |
31e4b90c3c | ||
![]() |
874363f652 | ||
![]() |
f01219dfb7 | ||
![]() |
f067f50ae4 | ||
![]() |
4107b8d4db | ||
![]() |
815693f715 | ||
![]() |
97b7873cba | ||
![]() |
be6b81a352 | ||
![]() |
66160d6973 | ||
![]() |
93efccf4ee | ||
![]() |
77991a0761 | ||
![]() |
f388908593 | ||
![]() |
56fca44a4b | ||
![]() |
a389393ffa | ||
![]() |
7b34154cf2 | ||
![]() |
da527d8d2a | ||
![]() |
b8368a1441 | ||
![]() |
c5f027d6be | ||
![]() |
9956da1567 | ||
![]() |
8ac649e2aa | ||
![]() |
8d69f256d1 | ||
![]() |
815dd8a25c | ||
![]() |
dc1bb0088e | ||
![]() |
197f453b76 | ||
![]() |
d8669609d8 | ||
![]() |
004dfd2d4b | ||
![]() |
13148457a9 | ||
![]() |
75f7de4010 | ||
![]() |
fc4840ebc9 | ||
![]() |
011a1ac1a3 | ||
![]() |
56fada47f2 | ||
![]() |
737f4f953f | ||
![]() |
fef619608b | ||
![]() |
663d88b677 | ||
![]() |
c03569f0df | ||
![]() |
2a4cab70ef | ||
![]() |
d83fadaf09 | ||
![]() |
d277f71333 | ||
![]() |
c811169f91 | ||
![]() |
4e416266f6 | ||
![]() |
0d78f3c758 | ||
![]() |
e2c8fed7b3 | ||
![]() |
0a02887e62 | ||
![]() |
65dc822d6c | ||
![]() |
b3759772d2 | ||
![]() |
65541f772f | ||
![]() |
1b4bd9209e | ||
![]() |
c97017dd1d | ||
![]() |
2f82750098 | ||
![]() |
e893cd6826 | ||
![]() |
124d55c970 | ||
![]() |
30c3ef9f6f | ||
![]() |
55376b044b | ||
![]() |
9c1de6e93f | ||
![]() |
49d83c0301 | ||
![]() |
d09441ca03 | ||
![]() |
50b53cbd0d | ||
![]() |
1230fad8f4 | ||
![]() |
a939d643dd | ||
![]() |
2f87d5c114 | ||
![]() |
c5644368b5 | ||
![]() |
ad523c20c7 | ||
![]() |
f0bb7e40f0 | ||
![]() |
7b43d70be4 | ||
![]() |
c8fad2ac09 | ||
![]() |
ca544ed6fc | ||
![]() |
6df5a72151 | ||
![]() |
3e0b846bdb | ||
![]() |
4b0fe81758 | ||
![]() |
1752791c9e | ||
![]() |
2bf97f123f | ||
![]() |
9179888c2b | ||
![]() |
dde50f0e22 | ||
![]() |
24d1d0802d | ||
![]() |
6a9e4293d8 | ||
![]() |
4002231bd9 | ||
![]() |
7ada448d18 | ||
![]() |
2f1614b128 | ||
![]() |
b9b6db052b | ||
![]() |
e8ec610f28 | ||
![]() |
65c1402ee6 | ||
![]() |
e7b9633170 | ||
![]() |
1b01b786c0 | ||
![]() |
8f32a14afa | ||
![]() |
6d0d4a3e4d | ||
![]() |
962b8e626c | ||
![]() |
281e6185cc | ||
![]() |
5bf18a6e88 | ||
![]() |
4e766761d0 | ||
![]() |
a4649f5078 | ||
![]() |
d4f8a4ab5d | ||
![]() |
b9789a452f |
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
23
.github/stale.yml
vendored
23
.github/stale.yml
vendored
@ -1,23 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 28
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
# Set to false to disable. If disabled, issues still need to be closed
|
||||
# manually, but will remain marked as stale.
|
||||
daysUntilClose: false
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- v2
|
||||
- enhancement
|
||||
- good first issue
|
||||
- feature-request
|
||||
- doc
|
||||
- bug
|
||||
- not-stale
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. Thank you for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
4
.github/workflows/CI-docs.yml
vendored
4
.github/workflows/CI-docs.yml
vendored
@ -11,8 +11,8 @@ jobs:
|
||||
docs-src:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.9'
|
||||
cache: 'pip' # caching pip dependencies
|
||||
|
3
.github/workflows/CI-sample.yml
vendored
3
.github/workflows/CI-sample.yml
vendored
@ -6,6 +6,7 @@ on:
|
||||
- '**'
|
||||
- '!docs/**'
|
||||
- '!.**'
|
||||
- 'docs/code/**'
|
||||
- '.github/workflows/CI-sample.yml'
|
||||
push:
|
||||
branches:
|
||||
@ -20,7 +21,7 @@ jobs:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup
|
||||
run: cmake -E make_directory ${{runner.workspace}}/libuv/docs/code/build
|
||||
- name: configure
|
||||
|
124
.github/workflows/CI-unix.yml
vendored
124
.github/workflows/CI-unix.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
@ -29,28 +29,67 @@ jobs:
|
||||
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
container: reactnativecommunity/react-native-android:2020-5-20
|
||||
env:
|
||||
ANDROID_AVD_HOME: /root/.android/avd
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Envinfo
|
||||
run: npx envinfo
|
||||
- name: Configure android arm64
|
||||
# see build options you can use in https://developer.android.com/ndk/guides/cmake
|
||||
- name: Enable KVM
|
||||
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
|
||||
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: macos-11
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-13, macos-14]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
run: |
|
||||
brew install ninja automake libtool
|
||||
@ -81,9 +120,13 @@ jobs:
|
||||
make -C build-auto -j4
|
||||
|
||||
build-ios:
|
||||
runs-on: macos-11
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-13, macos-14]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build-ios
|
||||
@ -95,45 +138,36 @@ jobs:
|
||||
ls -lh build-ios
|
||||
|
||||
build-cross-qemu:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
name: build-cross-qemu-${{ matrix.config.target }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static }
|
||||
- {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm-static }
|
||||
- {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static }
|
||||
- {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64-static }
|
||||
- {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static }
|
||||
- {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static }
|
||||
- {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le-static }
|
||||
- {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x-static }
|
||||
- {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips-static }
|
||||
- {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64-static }
|
||||
- {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel-static }
|
||||
- {target: mips64el,toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el-static }
|
||||
- {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static}
|
||||
- {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static}
|
||||
- {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static}
|
||||
- {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static}
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
- {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 }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install QEMU
|
||||
# this ensure install latest qemu on ubuntu, apt get version is old
|
||||
env:
|
||||
QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu"
|
||||
QEMU_VER: "qemu-user-static_7\\.0+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 }}
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install qemu and ${{ matrix.config.toolchain }}
|
||||
run: |
|
||||
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 }}
|
||||
run: |
|
||||
mkdir build
|
||||
|
38
.github/workflows/CI-win.yml
vendored
38
.github/workflows/CI-win.yml
vendored
@ -21,17 +21,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019}
|
||||
- {toolchain: Visual Studio 16 2019, arch: x64, server: 2019}
|
||||
- {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022}
|
||||
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022}
|
||||
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN}
|
||||
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN}
|
||||
- {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022}
|
||||
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2025}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Envinfo
|
||||
run: npx envinfo
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run:
|
||||
cmake -S . -B build -DBUILD_TESTING=ON
|
||||
-G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }}
|
||||
@ -39,26 +37,34 @@ jobs:
|
||||
|
||||
cmake --build build --config RelWithDebInfo
|
||||
|
||||
${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.exe" -Destination "build\\RelWithDebInfo\\"' || '' }}
|
||||
|
||||
${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.dll" -Destination "build\\RelWithDebInfo\\"' || '' }}
|
||||
|
||||
ls -l build
|
||||
- name: platform_output
|
||||
shell: cmd
|
||||
run:
|
||||
build\\RelWithDebInfo\\uv_run_tests.exe platform_output
|
||||
|
||||
ls -l build\\RelWithDebInfo
|
||||
- name: platform_output_a
|
||||
if: ${{ matrix.config.arch != 'arm64' }}
|
||||
shell: cmd
|
||||
run:
|
||||
build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output
|
||||
- name: platform_output
|
||||
if: ${{ matrix.config.arch != 'arm64' }}
|
||||
shell: cmd
|
||||
run:
|
||||
build\\RelWithDebInfo\\uv_run_tests.exe platform_output
|
||||
- name: Test
|
||||
# only valid with libuv-master with the fix for
|
||||
# https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md
|
||||
if: ${{ matrix.config.config != 'ASAN' }}
|
||||
if: ${{ matrix.config.config != 'ASAN' && matrix.config.arch != 'arm64' }}
|
||||
shell: cmd
|
||||
run:
|
||||
cd build
|
||||
|
||||
ctest -C RelWithDebInfo -V
|
||||
- name: Test only static
|
||||
if: ${{ matrix.config.config == 'ASAN' }}
|
||||
if: ${{ matrix.config.config == 'ASAN' && matrix.config.arch != 'arm64' }}
|
||||
shell: cmd
|
||||
run:
|
||||
build\\RelWithDebInfo\\uv_run_tests_a.exe
|
||||
@ -73,7 +79,7 @@ jobs:
|
||||
- {arch: i686, server: 2022, libgcc: dw2 }
|
||||
- {arch: x86_64, server: 2022, libgcc: seh }
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install mingw32 environment
|
||||
run: |
|
||||
sudo apt update
|
||||
@ -85,13 +91,13 @@ jobs:
|
||||
cmake --install build --prefix "`pwd`/build/usr"
|
||||
mkdir -p build/usr/test build/usr/bin
|
||||
cp -av test/fixtures build/usr/test
|
||||
cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe \
|
||||
cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe build/uv_run_tests_a_no_ext build/uv_run_tests_no_ext \
|
||||
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libgcc_s_${{ matrix.config.libgcc }}-1.dll` \
|
||||
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libwinpthread-1.dll` \
|
||||
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \
|
||||
build/usr/bin
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mingw-${{ matrix.config.arch }}
|
||||
path: build/usr/**/*
|
||||
@ -109,7 +115,7 @@ jobs:
|
||||
- {arch: x86_64, server: 2022}
|
||||
steps:
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mingw-${{ matrix.config.arch }}
|
||||
- name: Test
|
||||
|
70
.github/workflows/sanitizer.yml
vendored
70
.github/workflows/sanitizer.yml
vendored
@ -13,16 +13,21 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
sanitizers:
|
||||
sanitizers-linux:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup
|
||||
run: |
|
||||
sudo apt-get install ninja-build
|
||||
- name: Envinfo
|
||||
run: npx envinfo
|
||||
|
||||
# [AM]SAN fail on newer kernels due to a bigger PIE slide
|
||||
- name: Disable ASLR
|
||||
run: |
|
||||
sudo sysctl -w kernel.randomize_va_space=0
|
||||
|
||||
- name: ASAN Build
|
||||
run: |
|
||||
mkdir build-asan
|
||||
@ -60,3 +65,64 @@ jobs:
|
||||
- name: UBSAN Test
|
||||
run: |
|
||||
./build-ubsan/uv_run_tests_a
|
||||
|
||||
sanitizers-macos:
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Envinfo
|
||||
run: npx envinfo
|
||||
|
||||
- name: ASAN Build
|
||||
run: |
|
||||
mkdir build-asan
|
||||
(cd build-asan && cmake .. -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug)
|
||||
cmake --build build-asan
|
||||
- name: ASAN Test
|
||||
run: |
|
||||
./build-asan/uv_run_tests_a
|
||||
|
||||
- name: TSAN Build
|
||||
run: |
|
||||
mkdir build-tsan
|
||||
(cd build-tsan && cmake .. -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release)
|
||||
cmake --build build-tsan
|
||||
- name: TSAN Test
|
||||
run: |
|
||||
./build-tsan/uv_run_tests_a
|
||||
|
||||
- name: UBSAN Build
|
||||
run: |
|
||||
mkdir build-ubsan
|
||||
(cd build-ubsan && cmake .. -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug)
|
||||
cmake --build build-ubsan
|
||||
- name: UBSAN Test
|
||||
run: |
|
||||
./build-ubsan/uv_run_tests_a
|
||||
|
||||
sanitizers-windows:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup
|
||||
run: |
|
||||
choco install ninja
|
||||
|
||||
# Note: clang shipped with VS2022 has an issue where the UBSAN runtime doesn't link.
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v2
|
||||
with:
|
||||
version: "17"
|
||||
|
||||
- name: Envinfo
|
||||
run: npx envinfo
|
||||
|
||||
- name: UBSAN Build
|
||||
run: |
|
||||
mkdir build-ubsan
|
||||
cmake -B build-ubsan -G Ninja -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang
|
||||
cmake --build build-ubsan
|
||||
- name: UBSAN Test
|
||||
run: |
|
||||
./build-ubsan/uv_run_tests_a
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -7,9 +7,11 @@
|
||||
*.sdf
|
||||
*.suo
|
||||
.vs/
|
||||
.vscode/
|
||||
*.VC.db
|
||||
*.VC.opendb
|
||||
core
|
||||
.cache
|
||||
vgcore.*
|
||||
.buildstamp
|
||||
.dirstamp
|
||||
@ -74,3 +76,5 @@ cmake-build-debug/
|
||||
|
||||
# make dist output
|
||||
libuv-*.tar.*
|
||||
/dist.libuv.org/
|
||||
/libuv-release-tool/
|
||||
|
9
.mailmap
9
.mailmap
@ -4,6 +4,7 @@ Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
|
||||
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
|
||||
Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
|
||||
Andy Fiddaman <andy@omniosce.org> <omnios@citrus-it.co.uk>
|
||||
Andy Pan <panjf2000@gmail.com> <i@andypan.me>
|
||||
Bert Belder <bertbelder@gmail.com> <i@bertbelder.com>
|
||||
Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
|
||||
Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
|
||||
@ -18,6 +19,7 @@ David Carlier <devnexen@gmail.com>
|
||||
Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
|
||||
Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
|
||||
Frank Denis <github@pureftpd.org>
|
||||
Hüseyin Açacak <110401522+huseyinacacak-janea@users.noreply.github.com> <huseyin@janeasystems.com>
|
||||
Imran Iqbal <imrani@ca.ibm.com> <imran@imraniqbal.org>
|
||||
Isaac Z. Schlueter <i@izs.me>
|
||||
Jason Williams <necmon@yahoo.com>
|
||||
@ -29,6 +31,7 @@ Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu>
|
||||
Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu>
|
||||
Leith Bade <leith@leithalweapon.geek.nz> <leith@mapbox.com>
|
||||
Leonard Hecker <leonard.hecker91@gmail.com> <leonard@hecker.io>
|
||||
Lewis Russell <me@lewisr.dev> <lewis6991@gmail.com>
|
||||
Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
|
||||
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
|
||||
Michael <michael_dawson@ca.ibm.com>
|
||||
@ -36,6 +39,7 @@ Michael Neumann <mneumann@think.localnet> <mneumann@ntecs.de>
|
||||
Michael Penick <michael.penick@datastax.com> <mpenick@users.noreply.github.com>
|
||||
Nicholas Vavilov <vvnicholas@gmail.com>
|
||||
Nick Logan <ugexe@cpan.org> <nlogan@gmail.com>
|
||||
Olivier Valentin <ovalenti@redhat.com> <valentio@free.fr>
|
||||
Rasmus Christian Pedersen <zerhacken@yahoo.com>
|
||||
Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
|
||||
Richard Lau <rlau@redhat.com> <riclau@uk.ibm.com>
|
||||
@ -46,7 +50,8 @@ Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
|
||||
Sam Roberts <vieuxtech@gmail.com> <sam@strongloop.com>
|
||||
San-Tai Hsu <vanilla@fatpipi.com>
|
||||
Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
|
||||
Saúl Ibarra Corretgé <saghul@gmail.com>
|
||||
Saúl Ibarra Corretgé <s@saghul.net>
|
||||
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>
|
||||
Shuowang (Wayne) Zhang <shuowang.zhang@ibm.com>
|
||||
@ -60,5 +65,7 @@ gengjiawen <technicalcute@gmail.com>
|
||||
jBarz <jBarz@users.noreply.github.com> <jbarboza@ca.ibm.com>
|
||||
jBarz <jBarz@users.noreply.github.com> <jbarz@users.noreply.github.com>
|
||||
ptlomholt <pt@lomholt.com>
|
||||
theanarkh <2923878201@qq.com> <theratliter@gmail.com>
|
||||
tjarlama <59913901+tjarlama@users.noreply.github.com> <tjarlama@gmail.com>
|
||||
ywave620 <rogertyang@tencent.com> <60539365+ywave620@users.noreply.github.com>
|
||||
zlargon <zlargon1988@gmail.com>
|
||||
|
@ -2,10 +2,11 @@ version: 2
|
||||
|
||||
sphinx:
|
||||
builder: html
|
||||
configuration: null
|
||||
configuration: docs/src/conf.py
|
||||
fail_on_warning: false
|
||||
|
||||
build:
|
||||
os: "ubuntu-22.04"
|
||||
tools:
|
||||
python: "3.9"
|
||||
|
||||
|
75
AUTHORS
75
AUTHORS
@ -517,3 +517,78 @@ chucksilvers <chuq@chuq.com>
|
||||
Sergey Fedorov <vital.had@gmail.com>
|
||||
theanarkh <2923878201@qq.com>
|
||||
Samuel Cabrero <samuelcabrero@gmail.com>
|
||||
自发对称破缺 <429839446@qq.com>
|
||||
Luan Devecchi <luan@engineer.com>
|
||||
Steven Schveighoffer <schveiguy@gmail.com>
|
||||
number201724 <number201724@me.com>
|
||||
Daniel <reymond315qq@gmail.com>
|
||||
Christian Clason <christian.clason@uni-due.de>
|
||||
ywave620 <rogertyang@tencent.com>
|
||||
jensbjorgensen <jbj1@ultraemail.net>
|
||||
daomingq <daoming.qiu@intel.com>
|
||||
Qix <Qix-@users.noreply.github.com>
|
||||
Edward Humes <29870961+aurxenon@users.noreply.github.com>
|
||||
Tim Besard <tim.besard@gmail.com>
|
||||
Sergey Rubanov <chi187@gmail.com>
|
||||
Stefan Stojanovic <StefanStojanovic@users.noreply.github.com>
|
||||
Zvicii <zvicii@qq.com>
|
||||
dundargoc <33953936+dundargoc@users.noreply.github.com>
|
||||
Jack·Boos·Yu <47264268+JackBoosY@users.noreply.github.com>
|
||||
panran <310762957@qq.com>
|
||||
Tamás Bálint Misius <lbphacker@gmail.com>
|
||||
Bruno Passeri <Varstahl@users.noreply.github.com>
|
||||
Jason Zhang <xzha4350@gmail.com>
|
||||
Lewis Russell <me@lewisr.dev>
|
||||
sivadeilra <arlie.davis@gmail.com>
|
||||
cui fliter <imcusg@gmail.com>
|
||||
Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
|
||||
Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
|
||||
Stefan Karpinski <stefan@karpinski.org>
|
||||
liuxiang88 <94350585+liuxiang88@users.noreply.github.com>
|
||||
Jeffrey H. Johnson <trnsz@pobox.com>
|
||||
Abdirahim Musse <33973272+abmusse@users.noreply.github.com>
|
||||
小明 <7737673+caobug@users.noreply.github.com>
|
||||
Shuduo Sang <sangshuduo@gmail.com>
|
||||
Keith Winstein <keithw@cs.stanford.edu>
|
||||
michalbiesek <michalbiesek@gmail.com>
|
||||
Alois Klink <alois@aloisklink.com>
|
||||
SmorkalovG <smorkalov.g@gmail.com>
|
||||
Pleuvens <pleuvens.fervil@gmail.com>
|
||||
jolai <58589285+laijonathan@users.noreply.github.com>
|
||||
Julien Roncaglia <fox@vbfox.net>
|
||||
prubel <paul@rubels.net>
|
||||
Per Allansson <65364157+per-allansson@users.noreply.github.com>
|
||||
Matheus Izvekov <mizvekov@gmail.com>
|
||||
Christian Heimlich <chris@pcserenity.com>
|
||||
Hao Hu <33607772+hhu8@users.noreply.github.com>
|
||||
matoro <12038583+matoro@users.noreply.github.com>
|
||||
Bo Anderson <mail@boanderson.me>
|
||||
Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com>
|
||||
Anton Bachin <antonbachin@yahoo.com>
|
||||
Trevor Flynn <trevorflynn@liquidcrystalstudios.com>
|
||||
Andy Pan <panjf2000@gmail.com>
|
||||
Viacheslav Muravyev <slavamuravey@mail.ru>
|
||||
Anthony Alayo <anthony.alayo@gmail.com>
|
||||
Thomas Walter <31201229+waltoss@users.noreply.github.com>
|
||||
hiiizxf <385122613@qq.com>
|
||||
Geddy <guandichao@163.com>
|
||||
Farzin Monsef <monseffarzin@gmail.com>
|
||||
tgolang <154592711+tgolang@users.noreply.github.com>
|
||||
josedelinux <josedelinux@hotmail.com>
|
||||
Hüseyin Açacak <110401522+huseyinacacak-janea@users.noreply.github.com>
|
||||
Uilian Ries <uilianries@gmail.com>
|
||||
Olivier Valentin <ovalenti@redhat.com>
|
||||
郑苏波 (Super Zheng) <superzheng@tencent.com>
|
||||
zeertzjq <zeertzjq@outlook.com>
|
||||
Ian Butterworth <i.r.butterworth@gmail.com>
|
||||
握猫猫 <164346864@qq.com>
|
||||
Zuohui Yang <274048862@qq.com>
|
||||
Edigleysson Silva (Edy) <edigleyssonsilva@gmail.com>
|
||||
Raihaan Shouhell <raihaanhimself@gmail.com>
|
||||
Rialbat <miha-wead@mail.ru>
|
||||
Adam <adam@NetBSD.org>
|
||||
Poul T Lomholt <ptlomholt@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.4)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
if(POLICY CMP0091)
|
||||
cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting
|
||||
@ -20,7 +20,7 @@ include(CTest)
|
||||
set(CMAKE_C_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS ON)
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
@ -81,15 +81,20 @@ if(TSAN)
|
||||
endif()
|
||||
|
||||
if(UBSAN)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
list(APPEND uv_defines __UBSAN__=1)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined")
|
||||
elseif(MSVC)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=undefined")
|
||||
add_compile_options("-fsanitize=undefined" "-fno-sanitize-recover=undefined")
|
||||
if (NOT WIN32)
|
||||
add_link_options("-fsanitize=undefined")
|
||||
endif()
|
||||
if(MSVC)
|
||||
add_compile_options("/Oy-")
|
||||
else()
|
||||
add_compile_options("-fno-omit-frame-pointer")
|
||||
endif()
|
||||
else()
|
||||
message(SEND_ERROR "UndefinedBehaviorSanitizer support requires clang, gcc, or msvc. Try again with -DCMAKE_C_COMPILER.")
|
||||
message(SEND_ERROR "UndefinedBehaviorSanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -161,6 +166,11 @@ list(APPEND uv_cflags ${lint-utf8-msvc} )
|
||||
check_c_compiler_flag(-fno-strict-aliasing UV_F_STRICT_ALIASING)
|
||||
list(APPEND uv_cflags $<$<BOOL:${UV_F_STRICT_ALIASING}>:-fno-strict-aliasing>)
|
||||
|
||||
if (MSVC)
|
||||
# Error on calling undeclared functions.
|
||||
list(APPEND uv_cflags "/we4013")
|
||||
endif()
|
||||
|
||||
set(uv_sources
|
||||
src/fs-poll.c
|
||||
src/idna.c
|
||||
@ -176,7 +186,7 @@ set(uv_sources
|
||||
src/version.c)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602)
|
||||
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 _CRT_DECLARE_NONSTDC_NAMES=0)
|
||||
list(APPEND uv_libraries
|
||||
psapi
|
||||
user32
|
||||
@ -186,7 +196,7 @@ if(WIN32)
|
||||
ws2_32
|
||||
dbghelp
|
||||
ole32
|
||||
uuid)
|
||||
shell32)
|
||||
list(APPEND uv_sources
|
||||
src/win/async.c
|
||||
src/win/core.c
|
||||
@ -302,6 +312,7 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "GNU")
|
||||
list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112 _XOPEN_SOURCE=500)
|
||||
list(APPEND uv_libraries dl)
|
||||
list(APPEND uv_sources
|
||||
src/unix/bsd-ifaddrs.c
|
||||
@ -423,6 +434,7 @@ endif()
|
||||
|
||||
if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD")
|
||||
list(APPEND uv_test_libraries util)
|
||||
list(APPEND uv_libraries m)
|
||||
endif()
|
||||
|
||||
if(CYGWIN OR MSYS)
|
||||
@ -477,7 +489,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
|
||||
endif()
|
||||
target_link_libraries(uv_a ${uv_libraries})
|
||||
set_target_properties(uv_a PROPERTIES OUTPUT_NAME "uv")
|
||||
if(MSVC)
|
||||
if(WIN32)
|
||||
set_target_properties(uv_a PROPERTIES PREFIX "lib")
|
||||
endif()
|
||||
|
||||
@ -561,6 +573,7 @@ if(LIBUV_BUILD_TESTS)
|
||||
test/test-hrtime.c
|
||||
test/test-idle.c
|
||||
test/test-idna.c
|
||||
test/test-iouring-pollhup.c
|
||||
test/test-ip4-addr.c
|
||||
test/test-ip6-addr.c
|
||||
test/test-ip-name.c
|
||||
@ -638,6 +651,7 @@ if(LIBUV_BUILD_TESTS)
|
||||
test/test-tcp-oob.c
|
||||
test/test-tcp-open.c
|
||||
test/test-tcp-read-stop.c
|
||||
test/test-tcp-reuseport.c
|
||||
test/test-tcp-read-stop-start.c
|
||||
test/test-tcp-rst.c
|
||||
test/test-tcp-shutdown-after-write.c
|
||||
@ -654,6 +668,8 @@ if(LIBUV_BUILD_TESTS)
|
||||
test/test-thread-affinity.c
|
||||
test/test-thread-equal.c
|
||||
test/test-thread.c
|
||||
test/test-thread-name.c
|
||||
test/test-thread-priority.c
|
||||
test/test-threadpool-cancel.c
|
||||
test/test-threadpool.c
|
||||
test/test-timer-again.c
|
||||
@ -685,6 +701,7 @@ if(LIBUV_BUILD_TESTS)
|
||||
test/test-udp-send-unreachable.c
|
||||
test/test-udp-try-send.c
|
||||
test/test-udp-recv-in-a-row.c
|
||||
test/test-udp-reuseport.c
|
||||
test/test-uname.c
|
||||
test/test-walk-handles.c
|
||||
test/test-watcher-cross-stop.c)
|
||||
@ -701,6 +718,12 @@ if(LIBUV_BUILD_TESTS)
|
||||
set_tests_properties(uv_test PROPERTIES ENVIRONMENT
|
||||
"LIBPATH=${CMAKE_BINARY_DIR}:$ENV{LIBPATH}")
|
||||
endif()
|
||||
if(WIN32)
|
||||
add_custom_command(TARGET uv_run_tests POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:uv_run_tests>"
|
||||
"$<TARGET_FILE_DIR:uv_run_tests>/uv_run_tests_no_ext")
|
||||
endif()
|
||||
add_executable(uv_run_tests_a ${uv_test_sources} uv_win_longpath.manifest)
|
||||
target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines})
|
||||
target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags})
|
||||
@ -717,6 +740,12 @@ if(LIBUV_BUILD_TESTS)
|
||||
set_target_properties(uv_run_tests PROPERTIES LINKER_LANGUAGE CXX)
|
||||
set_target_properties(uv_run_tests_a PROPERTIES LINKER_LANGUAGE CXX)
|
||||
endif()
|
||||
if(WIN32)
|
||||
add_custom_command(TARGET uv_run_tests_a POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:uv_run_tests_a>"
|
||||
"$<TARGET_FILE_DIR:uv_run_tests_a>/uv_run_tests_a_no_ext")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Now for some gibbering horrors from beyond the stars...
|
||||
@ -761,8 +790,22 @@ endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
get_filename_component(CMAKE_C_COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY)
|
||||
if(ASAN)
|
||||
file(INSTALL "${CMAKE_C_COMPILER_DIR}/llvm-symbolizer.exe" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dbg_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(LIB_SELECTED uv)
|
||||
else()
|
||||
set(LIB_SELECTED uv_a)
|
||||
endif()
|
||||
|
||||
add_library(libuv::libuv ALIAS ${LIB_SELECTED})
|
||||
|
||||
message(STATUS "summary of build options:
|
||||
Install prefix: ${CMAKE_INSTALL_PREFIX}
|
||||
Target system: ${CMAKE_SYSTEM_NAME}
|
||||
|
890
ChangeLog
890
ChangeLog
@ -1,3 +1,887 @@
|
||||
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:
|
||||
|
||||
* win,fs: remove trailing slash in junctions (Hüseyin Açacak)
|
||||
|
||||
* Revert "linux: eliminate a read on eventfd per wakeup" (Ben Noordhuis)
|
||||
|
||||
* win: Fix linked list logic in getaddrinfo (Thad House)
|
||||
|
||||
* win: fix compilation against Windows 24H2 SDK (Thad House)
|
||||
|
||||
* win: remap ERROR_NOACCESS and ERROR_BUFFER_OVERFLOW (Jameson Nash)
|
||||
|
||||
* win,fs: match trailing slash presence in junctions to user input (Jameson
|
||||
Nash)
|
||||
|
||||
|
||||
2024.10.11, Version 1.49.1 (Stable), 8be336f4ee296d20e1c071a44d6adf279e202236
|
||||
|
||||
Changes since version 1.49.0:
|
||||
|
||||
* build: add darwin-syscalls.h to release tarball (Ben Noordhuis)
|
||||
|
||||
* linux: use IORING_SETUP_NO_SQARRAY when available (Ben Noordhuis)
|
||||
|
||||
* linux: use IORING_OP_FTRUNCATE when available (Ben Noordhuis)
|
||||
|
||||
* win: fix pNtQueryDirectoryFile check (Rialbat)
|
||||
|
||||
* win: fix WriteFile() error translation (Santiago Gimeno)
|
||||
|
||||
* win,fs: uv_fs_rmdir() to return ENOENT on file (Santiago Gimeno)
|
||||
|
||||
* win,pipe: ipc code does not support async read (Jameson Nash)
|
||||
|
||||
* netbsd: fix build (Adam)
|
||||
|
||||
* win,fs: fix bug in fs__readdir (Hüseyin Açacak)
|
||||
|
||||
* unix: workaround gcc bug on armv7 (Santiago Gimeno)
|
||||
|
||||
* unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis)
|
||||
|
||||
* unix: fix uv_tcp_keepalive in smartOS (Santiago Gimeno)
|
||||
|
||||
* unix: fix uv_getrusage ru_maxrss on solaris (Poul T Lomholt)
|
||||
|
||||
|
||||
2024.09.25, Version 1.49.0 (Stable), d2e56a5e8d3e39947b78405ca6e4727c70f5568a
|
||||
|
||||
Changes since version 1.48.0:
|
||||
|
||||
* test: fix -Wpointer-to-int-cast on 32 bits systems (Ben Noordhuis)
|
||||
|
||||
* build: add alias for libuv to CMakeLists.txt (Anthony Alayo)
|
||||
|
||||
* linux: create io_uring sqpoll ring lazily (Ben Noordhuis)
|
||||
|
||||
* misc: run sample CI when code changes (Jameson Nash)
|
||||
|
||||
* linux: fix uv_available_parallelism using cgroup (Thomas Walter)
|
||||
|
||||
* doc: fix tty example segfault (hiiizxf)
|
||||
|
||||
* udp,unix: fix sendmsg use-after-free (Geddy)
|
||||
|
||||
* cygwin: implement uv_resident_set_memory (Farzin Monsef)
|
||||
|
||||
* win: almost fix race detecting ESRCH in uv_kill (Santiago Gimeno)
|
||||
|
||||
* test: disable env var test under win32+asan (Ben Noordhuis)
|
||||
|
||||
* unix,fs: fix realpath calls that use the system allocator (Saúl Ibarra
|
||||
Corretgé)
|
||||
|
||||
* sunos: sync tcp keep-alive with other unices (Andy Pan)
|
||||
|
||||
* linux: fix /proc/self/stat executable name parsing (Farzin Monsef)
|
||||
|
||||
* test,ci: fix [AM]San, disable ASLR (Ben Noordhuis)
|
||||
|
||||
* win: remove _alloca usage (Ben Noordhuis)
|
||||
|
||||
* unix: reinstate preadv/pwritev fallback code (Ben Noordhuis)
|
||||
|
||||
* linux: don't delay EPOLL_CTL_DEL operations (Ben Noordhuis)
|
||||
|
||||
* doc: fix typos in ChangeLog (tgolang)
|
||||
|
||||
* unix,win: error on zero delay tcp keepalive (Saúl Ibarra Corretgé)
|
||||
|
||||
* win: simplify uv_once implementation (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: correct udp socket options documentation (Ben Noordhuis)
|
||||
|
||||
* linux: don't use sendmmsg() for single datagrams (Ben Noordhuis)
|
||||
|
||||
* unix: fix fd leaks in SCM_RIGHTS error path (Ben Noordhuis)
|
||||
|
||||
* win: robustify uv_os_getenv() error checking (Ben Noordhuis)
|
||||
|
||||
* test: use newer ASSERT_MEM_EQ macro (Ben Noordhuis)
|
||||
|
||||
* unix: de-duplicate conditions for using kqueue (Brad King)
|
||||
|
||||
* darwin: simplify uv_hrtime (Saúl Ibarra Corretgé)
|
||||
|
||||
* mailmap: update saghul's main email address (Saúl Ibarra Corretgé)
|
||||
|
||||
* win: remove no longer needed define (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: fix some typos (josedelinux)
|
||||
|
||||
* linux,darwin: make `uv_fs_copyfile` behaves like `cp -r` (Juan José Arboleda)
|
||||
|
||||
* dragonfly: disable SO_REUSEPORT for UDP socket bindings (Andy Pan)
|
||||
|
||||
* test: remove the obsolete HAVE_KQUEUE macro (Andy Pan)
|
||||
|
||||
* unix: use the presence of SOCK_* instead of OS macros for socketpair (Andy
|
||||
Pan)
|
||||
|
||||
* bsd: support pipe2() on *BSD (Andy Pan)
|
||||
|
||||
* unix: support SO_REUSEPORT with load balancing for TCP (Andy Pan)
|
||||
|
||||
* doc: add entries for extended getpw (Juan José Arboleda)
|
||||
|
||||
* test: fix the flaky test-tcp-reuseport (Andy Pan)
|
||||
|
||||
* aix,ibmi: fix compilation errors in fs_copyfile (Jeffrey H. Johnson)
|
||||
|
||||
* unix: support SO_REUSEPORT with load balancing for UDP (Andy Pan)
|
||||
|
||||
* tcpkeepalive: distinguish OS versions and use proper time units (Andy Pan)
|
||||
|
||||
* win: map ERROR_BAD_EXE_FORMAT to UV_EFTYPE (Hüseyin Açacak)
|
||||
|
||||
* doc: add instruction how to install with Conan (Uilian Ries)
|
||||
|
||||
* unix,win: remove unused req parameter from macros (Viacheslav Muravyev)
|
||||
|
||||
* build: fix android ci build (Ben Noordhuis)
|
||||
|
||||
* unix,win: export wtf8 functions properly (Ben Noordhuis)
|
||||
|
||||
* hurd: add includes and macro prerequisites (Olivier Valentin)
|
||||
|
||||
* hurd: stub uv_thread_setpriority() (Olivier Valentin)
|
||||
|
||||
* ci: use macOS 12 for macOS and iOS builds (Saúl Ibarra Corretgé)
|
||||
|
||||
* darwin: fix crash on iOS(arm64) (郑苏波 (Super Zheng))
|
||||
|
||||
* Create dependabot.yml for updating github-actions (Jameson Nash)
|
||||
|
||||
* doc: correct names of Win32 APIs in fs.rst (zeertzjq)
|
||||
|
||||
* ci: bump upload and download-artifact versions (dependabot[bot])
|
||||
|
||||
* ci: bump actions/setup-python from 4 to 5 (dependabot[bot])
|
||||
|
||||
* ci: bump KyleMayes/install-llvm-action from 1 to 2 (dependabot[bot])
|
||||
|
||||
* win,error: remap ERROR_NO_DATA to EAGAIN (Jameson Nash)
|
||||
|
||||
* test: handle zero-length udp datagram (Ben Noordhuis)
|
||||
|
||||
* misc: remove splay trees macros (Viacheslav Muravyev)
|
||||
|
||||
* test,openbsd: remove superfluous ifdef guard (Ben Noordhuis)
|
||||
|
||||
* win,fs: use posix delete semantics, if supported (Ian Butterworth)
|
||||
|
||||
* win: fix env var in uv_os_homedir and uv_os_tmpdir (Hüseyin Açacak)
|
||||
|
||||
* fsevents: detect watched directory removal (Santiago Gimeno)
|
||||
|
||||
* ci: bump actions/checkout to 4 (dependabot[bot])
|
||||
|
||||
* linux: eliminate a read on eventfd per wakeup (Andy Pan)
|
||||
|
||||
* test: pipe_overlong_path handle ENAMETOOLONG (Abdirahim Musse)
|
||||
|
||||
* win,fs: use the new Windows fast stat API (Hüseyin Açacak)
|
||||
|
||||
* win,pipe: fix race with concurrent readers (Jameson Nash)
|
||||
|
||||
* win,signal: fix data race dispatching SIGWINCH (Jameson Nash)
|
||||
|
||||
* build: ubsan fixes (Matheus Izvekov)
|
||||
|
||||
* linux: disable SQPOLL io_uring by default (Santiago Gimeno)
|
||||
|
||||
* win: fix fs.c ubsan failure (Matheus Izvekov)
|
||||
|
||||
* test: rmdir can return `EEXIST` or `ENOTEMPTY` (Richard Lau)
|
||||
|
||||
* test: check for `UV_CHANGE` or `UV_RENAME` event (Richard Lau)
|
||||
|
||||
* unix,fs: silence -Wunused-result warning (Santiago Gimeno)
|
||||
|
||||
* linux: support abstract unix socket autobinding (Ben Noordhuis)
|
||||
|
||||
* kqueue: use EVFILT_USER for async if available (Andy Pan)
|
||||
|
||||
* win: remove deprecated GetVersionExW call (Shelley Vohr)
|
||||
|
||||
* doc: document uv_loop_option (握猫猫)
|
||||
|
||||
* doc: fix the `uv_*_set_data` series of functions (握猫猫)
|
||||
|
||||
* doc: properly label enumerations and types (握猫猫)
|
||||
|
||||
* doc: document specific macOS fs_event behavior (Santiago Gimeno)
|
||||
|
||||
* win,pipe: restore fallback handling for blocking pipes (Jameson Nash)
|
||||
|
||||
* unix,win: remove unused rb-tree macro parameters (Viacheslav Muravyev)
|
||||
|
||||
* win: compute parallelism from process cpu affinity (Ben Noordhuis)
|
||||
|
||||
* win: use NtQueryInformationProcess in uv_os_getppid (Zuohui Yang)
|
||||
|
||||
* win,pipe: fix missing assignment to success (Jameson Nash)
|
||||
|
||||
* win: fix uv_available_parallelism on win32 (Ben Noordhuis)
|
||||
|
||||
* win,pipe: fix another missing assignment to success (Jameson Nash)
|
||||
|
||||
* kqueue: disallow ill-suited file descriptor kinds (Andy Pan)
|
||||
|
||||
* unix: restore tty attributes on handle close (Ben Noordhuis)
|
||||
|
||||
* test: delete test with invalid assumption (Ben Noordhuis)
|
||||
|
||||
* dragonflybsd: fix compilation failure (Jeffrey H. Johnson)
|
||||
|
||||
* test: run android tests on ci (Edigleysson Silva (Edy))
|
||||
|
||||
* darwin: add udp mmsg support (Raihaan Shouhell)
|
||||
|
||||
* unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis)
|
||||
|
||||
* unix: expand uv_available_parallelism() to support more platforms (Ondřej
|
||||
Surý)
|
||||
|
||||
* doc: add known issue in armv7 (Santiago Gimeno)
|
||||
|
||||
|
||||
2024.02.07, Version 1.48.0 (Stable), e9f29cb984231524e3931aa0ae2c5dae1a32884e
|
||||
|
||||
Changes since version 1.47.0:
|
||||
|
||||
* misc: remove deprecated stalebot file (Jameson Nash)
|
||||
|
||||
* build: disable windows asan buildbot (Ben Noordhuis)
|
||||
|
||||
* test: don't run tcp_writealot under msan (Ben Noordhuis)
|
||||
|
||||
* build,win: remove extraneous -lshell32 (Ben Noordhuis)
|
||||
|
||||
* unix: ignore ifaddrs with NULL ifa_addr (Stephen Gallagher)
|
||||
|
||||
* unix,win: utility for setting priority for thread (Hao Hu)
|
||||
|
||||
* pipe: add back error handling to connect / bind (Jameson Nash)
|
||||
|
||||
* test: check if ipv6 link-local traffic is routable (Ben Noordhuis)
|
||||
|
||||
* win: remove check for UV_PIPE_NO_TRUNCATE (Jameson Nash)
|
||||
|
||||
* linux: disable io_uring on hppa below kernel 6.1.51 (matoro)
|
||||
|
||||
* unix,win: fix read past end of pipe name buffer (Ben Noordhuis)
|
||||
|
||||
* unix: unbreak macOS < 10.14 (Sergey Fedorov)
|
||||
|
||||
* aix: disable ipv6 link local (Abdirahim Musse)
|
||||
|
||||
* doc: move cjihrig to emeriti (cjihrig)
|
||||
|
||||
* unix: correct pwritev conditional (Bo Anderson)
|
||||
|
||||
* test_fs.c: Fix issue on 32-bit systems using btrfs (Stephen Gallagher)
|
||||
|
||||
* misc: ignore libuv-release-tool files (Jameson Nash)
|
||||
|
||||
* win: honor NoDefaultCurrentDirectoryInExePath env var (Ardi Nugraha)
|
||||
|
||||
* idna: fix compilation warning (Saúl Ibarra Corretgé)
|
||||
|
||||
* linux: remove HAVE_IFADDRS_H macro (Ben Noordhuis)
|
||||
|
||||
* test: skip tcp-write-in-a-row on IBM i (Abdirahim Musse)
|
||||
|
||||
* build,win: work around missing uuid.dll on MinGW (Anton Bachin)
|
||||
|
||||
* win: stop using deprecated names (Matheus Izvekov)
|
||||
|
||||
* unix,win: fix busy loop with zero timeout timers (Matheus Izvekov)
|
||||
|
||||
* aix,ibmi: use uv_interface_addresses instead of getifaddrs (Abdirahim Musse)
|
||||
|
||||
* linux: fix bind/connect for abstract sockets (Santiago Gimeno)
|
||||
|
||||
* win: replace c99 comments with c89 comments (Trevor Flynn)
|
||||
|
||||
* build: add .cache clangd folder to .gitignore (Juan José Arboleda)
|
||||
|
||||
* unix: support full TCP keep-alive on Solaris (Andy Pan)
|
||||
|
||||
* freebsd: fix F_KINFO file path handling (David Carlier)
|
||||
|
||||
* linux: retry fs op if unsupported by io_uring (Santiago Gimeno)
|
||||
|
||||
* freebsd: fix build on non-intel archs (David Carlier)
|
||||
|
||||
* unix: optimize uv__tcp_keepalive cpp directives (Andy Pan)
|
||||
|
||||
* linux: disable io_uring on ppc64 and ppc64le (Brad King)
|
||||
|
||||
* doc: add very basic Security Policy document (Santiago Gimeno)
|
||||
|
||||
* build: re-enable msvc-asan job on CI (Jameson Nash)
|
||||
|
||||
* win/spawn: optionally run executable paths with no file extension (Brad King)
|
||||
|
||||
* win: fix ESRCH implementation (Jameson Nash)
|
||||
|
||||
* unix,win: reset the timer queue on stop (Santiago Gimeno)
|
||||
|
||||
* fix: always zero-terminate idna output (Ben Noordhuis)
|
||||
|
||||
* fix: reject zero-length idna inputs (Ben Noordhuis)
|
||||
|
||||
* test: empty strings are not valid IDNA (Santiago Gimeno)
|
||||
|
||||
* Merge pull request from GHSA-f74f-cvh7-c6q6 (Ben Noordhuis)
|
||||
|
||||
|
||||
2023.11.06, Version 1.47.0 (Stable), be6b81a352d17513c95be153afcb3148f1a451cd
|
||||
|
||||
Changes since version 1.46.0:
|
||||
|
||||
* test: fix license blurb (Ben Noordhuis)
|
||||
|
||||
* linux: fix harmless warn_unused_result warning (Shuduo Sang)
|
||||
|
||||
* darwin: fix build warnings (小明)
|
||||
|
||||
* linux: don't use io_uring on pre-5.10.186 kernels (Ben Noordhuis)
|
||||
|
||||
* fs: fix WTF-8 decoding issue (Jameson Nash)
|
||||
|
||||
* test: enable disabled tcp_connect6_error_fault (Ben Noordhuis)
|
||||
|
||||
* test: enable disabled fs_link (Ben Noordhuis)
|
||||
|
||||
* test: enable disabled spawn_same_stdout_stderr (Ben Noordhuis)
|
||||
|
||||
* linux: handle UNAME26 personality (Ben Noordhuis)
|
||||
|
||||
* build: move cmake_minimum_required version to 3.9 (Keith Winstein)
|
||||
|
||||
* unix: set ipv6 scope id for link-local addresses (Ben Noordhuis)
|
||||
|
||||
* unix: match kqueue and epoll code (Trevor Norris)
|
||||
|
||||
* win,spawn: allow `%PATH%` to be unset (Kyle Edwards)
|
||||
|
||||
* doc: switch to Furo, a more modern Sphinx theme (Saúl Ibarra Corretgé)
|
||||
|
||||
* darwin: make TCP_KEEPINTVL and TCP_KEEPCNT available (小明)
|
||||
|
||||
* win,fs: avoid winapi macro redefinition (Brad King)
|
||||
|
||||
* linux: add missing riscv syscall numbers (michalbiesek)
|
||||
|
||||
* doc: fix broken "Shared library" Wikipedia link (Alois Klink)
|
||||
|
||||
* unix: get mainline kernel version in Ubuntu (Santiago Gimeno)
|
||||
|
||||
* unix: get mainline kernel version in Debian (Ben Noordhuis)
|
||||
|
||||
* build: fix qemu install in CI-unix workflow (Santiago Gimeno)
|
||||
|
||||
* unix: disable io_uring close on selected kernels (Santiago Gimeno)
|
||||
|
||||
* test: skip tests when ipv6 is not available (Santiago Gimeno)
|
||||
|
||||
* ibmi: implement ifaddrs, getifaddrs, freeifaddrs (Abdirahim Musse)
|
||||
|
||||
* unix: reset signal counters after fork (SmorkalovG)
|
||||
|
||||
* win,process: avoid assert after spawning Store app (Jameson Nash)
|
||||
|
||||
* unix: remove pread/preadv conditionals (Ben Noordhuis)
|
||||
|
||||
* unix: remove pwrite/pwritev conditionals (Ben Noordhuis)
|
||||
|
||||
* darwin: remove workaround for data corruption bug (Ben Noordhuis)
|
||||
|
||||
* src: default to stream=stderr in handle printer (Ben Noordhuis)
|
||||
|
||||
* test: switch to new-style ASSERT_EQ macros (Pleuvens)
|
||||
|
||||
* zos: correctly get cpu model in uv_cpu_info() (jolai)
|
||||
|
||||
* test: fix get_passwd2 on IBM i (Abdirahim Musse)
|
||||
|
||||
* unix: don't malloc on sync uv_fs_read (Ben Noordhuis)
|
||||
|
||||
* freebsd: get fs event path with fcntl(F_KINFO) (David Carlier)
|
||||
|
||||
* test: switch from ASSERT_* to ASSERT_PTR_* (Pleuvens)
|
||||
|
||||
* darwin: workaround apple pthread_cond_wait bug (Julien Roncaglia)
|
||||
|
||||
* doc: uv_close should be called after exit callback (Pleuvens)
|
||||
|
||||
* test: 192.0.2.0/24 is the actual -TEST-NET-1 (prubel)
|
||||
|
||||
* unix: add back preadv/pwritev fallback (Ben Noordhuis)
|
||||
|
||||
* unix: rename variable for consistency (Ben Noordhuis)
|
||||
|
||||
* unix: merge read/write code into single functions (Ben Noordhuis)
|
||||
|
||||
* doc: filename arg to uv_fs_event_cb can be NULL (Ben Noordhuis)
|
||||
|
||||
* build,win: we need to link against shell32.lib (Per Allansson)
|
||||
|
||||
* unix: no preadv/pwritev workaround if not needed (Jeffrey H. Johnson)
|
||||
|
||||
* build: add CI for Windows ARM64 (build only) (Per Allansson)
|
||||
|
||||
* linux: disable io_uring on 32 bits arm systems (Ben Noordhuis)
|
||||
|
||||
* build: run sanitizers on macos ci (Ben Noordhuis)
|
||||
|
||||
* misc: export WTF8 conversion utilities (Jameson Nash)
|
||||
|
||||
* build: fix libuv.a file name for cmake (Jameson Nash)
|
||||
|
||||
* build: add windows ubsan and clang ci (Matheus Izvekov)
|
||||
|
||||
* win: improve accuracy of ProductName between arch (Christian Heimlich)
|
||||
|
||||
|
||||
2023.06.30, Version 1.46.0 (Stable), f0bb7e40f0508bedf6fad33769b3f87bb8aedfa6
|
||||
|
||||
Changes since version 1.45.0:
|
||||
|
||||
* Add SHA to ChangeLog (Santiago Gimeno)
|
||||
|
||||
* misc: update readthedocs config (Jameson Nash)
|
||||
|
||||
* test: remove erroneous RETURN_SKIP (Ben Noordhuis)
|
||||
|
||||
* android: disable io_uring support (Ben Noordhuis)
|
||||
|
||||
* linux: add some more iouring backed fs ops (Santiago Gimeno)
|
||||
|
||||
* build: add autoconf option for disable-maintainer-mode (Jameson Nash)
|
||||
|
||||
* fs: use WTF-8 on Windows (Stefan Karpinski)
|
||||
|
||||
* unix,win: replace QUEUE with struct uv__queue (Ben Noordhuis)
|
||||
|
||||
* linux: fs_read to use io_uring if iovcnt > IOV_MAX (Santiago Gimeno)
|
||||
|
||||
* ios: fix uv_getrusage() ru_maxrss calculation (Ben Noordhuis)
|
||||
|
||||
* include: update outdated code comment (Ben Noordhuis)
|
||||
|
||||
* linux: support abstract unix sockets (Ben Noordhuis)
|
||||
|
||||
* unix,win: add UV_PIPE_NO_TRUNCATE flag (Ben Noordhuis)
|
||||
|
||||
* unix: add loongarch support (liuxiang88)
|
||||
|
||||
* doc: add DPS8M to LINKS.md (Jeffrey H. Johnson)
|
||||
|
||||
* include: add EUNATCH errno mapping (Abdirahim Musse)
|
||||
|
||||
* src: don't run timers if loop is stopped/unref'd (Trevor Norris)
|
||||
|
||||
* win: fix -Wpointer-to-int-cast warning (Ben Noordhuis)
|
||||
|
||||
* test,win: fix -Wunused-variable warning (Ben Noordhuis)
|
||||
|
||||
* test,win: fix -Wformat warning (Ben Noordhuis)
|
||||
|
||||
* linux: work around io_uring IORING_OP_CLOSE bug (Ben Noordhuis)
|
||||
|
||||
* win: remove unused functions (Ben Noordhuis)
|
||||
|
||||
* bench: add bench to check uv_loop_alive (Trevor Norris)
|
||||
|
||||
* test: add uv_cancel test for threadpool (Trevor Norris)
|
||||
|
||||
* unix: skip prohibited syscalls on tvOS and watchOS (小明)
|
||||
|
||||
* unix,fs: make no_pwritev access thread-safe (Santiago Gimeno)
|
||||
|
||||
* unix: fix build for lower versions of Android (小明)
|
||||
|
||||
|
||||
2023.05.19, Version 1.45.0 (Stable), 96e05543f53b19d9642b4b0dd73b86ad3cea313e
|
||||
|
||||
Changes since version 1.44.2:
|
||||
|
||||
* win: remove stdint-msvc2008.h (Ben Noordhuis)
|
||||
|
||||
* android: remove pthread-fixes.c (Ben Noordhuis)
|
||||
|
||||
* build: enable MSVC_RUNTIME_LIBRARY setting (自发对称破缺)
|
||||
|
||||
* unix: switch to c11 atomics (Ben Noordhuis)
|
||||
|
||||
* unix: don't accept() connections in a loop (Ben Noordhuis)
|
||||
|
||||
* win: fix off-by-1 buffer overrun in uv_exepath() (Ben Noordhuis)
|
||||
|
||||
* build: switch ci from macos-10.15 to macos-11 (Ben Noordhuis)
|
||||
|
||||
* win: fix thread race in uv_cwd() and uv_chdir() (Ben Noordhuis)
|
||||
|
||||
* unix,win: remove UV_HANDLE_SHUTTING flag (Santiago Gimeno)
|
||||
|
||||
* win: support Windows 11 in uv_os_uname() (Luan Devecchi)
|
||||
|
||||
* unix: fix uv_getrusage() ru_maxrss reporting (Ben Noordhuis)
|
||||
|
||||
* doc: add note about offset -1 in uv_fs_read/write (Steven Schveighoffer)
|
||||
|
||||
* test: fix musl libc.a dlerror() test expectation (Ben Noordhuis)
|
||||
|
||||
* kqueue: DRY file descriptor deletion logic (Ben Noordhuis)
|
||||
|
||||
* linux: teach uv_get_constrained_memory() cgroupsv2 (Ben Noordhuis)
|
||||
|
||||
* build: upgrade qemu-user-static package (Ben Noordhuis)
|
||||
|
||||
* linux: move epoll.c back into linux-core.c (Ben Noordhuis)
|
||||
|
||||
* unix: remove pre-macos 10.8 compatibility hack (Ben Noordhuis)
|
||||
|
||||
* unix,win: fix memory leak in uv_fs_scandir() (Ben Noordhuis)
|
||||
|
||||
* build: restore qemu download logic (Ben Noordhuis)
|
||||
|
||||
* win: fix uv__pipe_accept memory leak (number201724)
|
||||
|
||||
* doc: update LINKS.md (Daniel)
|
||||
|
||||
* unix: simplify atomic op in uv_tty_reset_mode() (Ben Noordhuis)
|
||||
|
||||
* build: add LIBUV_BUILD_SHARED cmake option (Christian Clason)
|
||||
|
||||
* linux: remove unused or obsolete syscall wrappers (Ben Noordhuis)
|
||||
|
||||
* linux: merge files back into single file (Ben Noordhuis)
|
||||
|
||||
* stream: process more than one write req per loop tick (ywave620)
|
||||
|
||||
* unix,win: give thread pool threads an 8 MB stack (Ben Noordhuis)
|
||||
|
||||
* build: add MemorySanitizer (MSAN) support (Ben Noordhuis)
|
||||
|
||||
* doc: add uv_poll_cb status==UV_EBADF note (jensbjorgensen)
|
||||
|
||||
* build: support AddressSanitizer on MSVC (Jameson Nash)
|
||||
|
||||
* win,pipe: improve method of obtaining pid for ipc (number201724)
|
||||
|
||||
* thread: add support for affinity (daomingq)
|
||||
|
||||
* include: map ENODATA error code (Ben Noordhuis)
|
||||
|
||||
* build: remove bashism from autogen.sh (Santiago Gimeno)
|
||||
|
||||
* win,tcp,udp: remove "active streams" optimization (Saúl Ibarra Corretgé)
|
||||
|
||||
* win: drop code checking for Windows XP / Server 2k3 (Saúl Ibarra Corretgé)
|
||||
|
||||
* unix,win: fix 'sprintf' is deprecated warning (twosee)
|
||||
|
||||
* doc: mention close_cb can be NULL (Qix)
|
||||
|
||||
* win: optimize udp receive performance (ywave620)
|
||||
|
||||
* win: fix an incompatible types warning (twosee)
|
||||
|
||||
* doc: document 0 return value for free/total memory (Ben Noordhuis)
|
||||
|
||||
* darwin: use hw.cpufrequency again for frequency info (Jameson Nash)
|
||||
|
||||
* win,test: change format of TEST_PIPENAME's (Santiago Gimeno)
|
||||
|
||||
* win,pipe: fixes in uv_pipe_connect() (Santiago Gimeno)
|
||||
|
||||
* misc: fix return value of memory functions (theanarkh)
|
||||
|
||||
* src: add new metrics APIs (Trevor Norris)
|
||||
|
||||
* thread: add uv_thread_getcpu() (daomingq)
|
||||
|
||||
* build: don't use ifaddrs.h on solaris 10 (Edward Humes)
|
||||
|
||||
* unix,win: add uv_get_available_memory() (Tim Besard)
|
||||
|
||||
* test: fix -Wunused-but-set-variable warnings (Ben Noordhuis)
|
||||
|
||||
* doc: bump min supported linux and freebsd versions (Ben Noordhuis)
|
||||
|
||||
* Add Socket Runtime to the LINKS.md (Sergey Rubanov)
|
||||
|
||||
* unix: drop kfreebsd support (Ben Noordhuis)
|
||||
|
||||
* win: fix fstat for pipes and character files (Stefan Stojanovic)
|
||||
|
||||
* win: fix -Wunused-variable warning (Ben Noordhuis)
|
||||
|
||||
* win: fix -Wunused-function warning (Ben Noordhuis)
|
||||
|
||||
* build: drop qemu-alpha from ci matrix (Ben Noordhuis)
|
||||
|
||||
* win: move child_stdio_buffer out of uv_process_t (Santiago Gimeno)
|
||||
|
||||
* test: fix some unreachable code warnings (Santiago Gimeno)
|
||||
|
||||
* linux: simplify uv_uptime() (Ben Noordhuis)
|
||||
|
||||
* test: unflake fs_event_watch_dir test (Ben Noordhuis)
|
||||
|
||||
* darwin: remove unused fsevents symbol lookups (Ben Noordhuis)
|
||||
|
||||
* build: add define guard around UV_EXTERN (Zvicii)
|
||||
|
||||
* build: add UndefinedBehaviorSanitizer support (Ben Noordhuis)
|
||||
|
||||
* build: enable platform_output test on qemu (Ben Noordhuis)
|
||||
|
||||
* linux: handle cpu hotplugging in uv_cpu_info() (Ben Noordhuis)
|
||||
|
||||
* build: remove unnecessary policy setting (dundargoc)
|
||||
|
||||
* docs: add vcpkg instruction step (Jack·Boos·Yu)
|
||||
|
||||
* win,fs: fix readlink errno for a non-symlink file (Darshan Sen)
|
||||
|
||||
* misc: extend getpw to take uid as an argument (Jameson Nash)
|
||||
|
||||
* unix,win: use static_assert when available (Ben Noordhuis)
|
||||
|
||||
* docs: delete code Makefile (Jameson Nash)
|
||||
|
||||
* docs: add CI for docs PRs (Jameson Nash)
|
||||
|
||||
* docs: update Sphinx version on RTD (Jameson Nash)
|
||||
|
||||
* doc: clean up license file (Ben Noordhuis)
|
||||
|
||||
* test: fix some warnings when compiling tests (panran)
|
||||
|
||||
* build,win: add mingw-w64 CI configuration (Jameson Nash)
|
||||
|
||||
* build: add CI for distcheck (Jameson Nash)
|
||||
|
||||
* unix: remove busy loop from uv_async_send (Jameson Nash)
|
||||
|
||||
* doc: document uv_fs_cb type (Tamás Bálint Misius)
|
||||
|
||||
* build: Improve build by cmake for Cygwin (erw7)
|
||||
|
||||
* build: add libuv:: namespace to libuvConfig.cmake (AJ Heller)
|
||||
|
||||
* test: fix ThreadSanitizer thread leak warning (Ben Noordhuis)
|
||||
|
||||
* test: fix ThreadSanitizer data race warning (Ben Noordhuis)
|
||||
|
||||
* test: fix ThreadSanitizer data race warning (Ben Noordhuis)
|
||||
|
||||
* test: fix ThreadSanitizer data race warning (Ben Noordhuis)
|
||||
|
||||
* test: cond-skip fork_threadpool_queue_work_simple (Ben Noordhuis)
|
||||
|
||||
* test: cond-skip signal_multiple_loops (Ben Noordhuis)
|
||||
|
||||
* test: cond-skip tcp_writealot (Ben Noordhuis)
|
||||
|
||||
* build: promote tsan ci to must-pass (Ben Noordhuis)
|
||||
|
||||
* build: add CI for OpenBSD and FreeBSD (James McCoy)
|
||||
|
||||
* build,test: fix distcheck errors (Jameson Nash)
|
||||
|
||||
* test: remove bad tty window size assumption (Ben Noordhuis)
|
||||
|
||||
* darwin,process: feed kevent the signal to reap children (Jameson Nash)
|
||||
|
||||
* unix: abort on clock_gettime() error (Ben Noordhuis)
|
||||
|
||||
* test: remove timing-sensitive check (Ben Noordhuis)
|
||||
|
||||
* unix: DRY and fix tcp bind error path (Jameson Nash)
|
||||
|
||||
* macos: fix fsevents thread race conditions (Ben Noordhuis)
|
||||
|
||||
* win: fix leak in uv_chdir (Trevor Norris)
|
||||
|
||||
* test: make valgrind happy (Trevor Norris)
|
||||
|
||||
* barrier: wait for prior out before next in (Jameson Nash)
|
||||
|
||||
* test: fix visual studio 2015 build error (Ben Noordhuis)
|
||||
|
||||
* linux: fix ceph copy error truncating readonly files (Bruno Passeri)
|
||||
|
||||
* test: silence more valgrind warnings (Trevor Norris)
|
||||
|
||||
* doc: add entries to LINKS.md (Trevor Norris)
|
||||
|
||||
* win,unix: change execution order of timers (Trevor Norris)
|
||||
|
||||
* doc: add trevnorris to maintainers (Trevor Norris)
|
||||
|
||||
* linux: remove epoll_pwait() emulation code path (Ben Noordhuis)
|
||||
|
||||
* linux: replace unsafe macro with inline function (Ben Noordhuis)
|
||||
|
||||
* linux: remove arm oabi support (Ben Noordhuis)
|
||||
|
||||
* unix,sunos: SO_REUSEPORT not valid on all sockets (Stacey Marshall)
|
||||
|
||||
* doc: consistent single backquote in misc.rst (Jason Zhang)
|
||||
|
||||
* src: switch to use C11 atomics where available (Trevor Norris)
|
||||
|
||||
* test: don't use static buffer for formatting (Ben Noordhuis)
|
||||
|
||||
* linux: introduce io_uring support (Ben Noordhuis)
|
||||
|
||||
* linux: fix academic valgrind warning (Ben Noordhuis)
|
||||
|
||||
* test: disable signal test under ASan and MSan (Ben Noordhuis)
|
||||
|
||||
* linux: add IORING_OP_OPENAT support (Ben Noordhuis)
|
||||
|
||||
* linux: add IORING_OP_CLOSE support (Ben Noordhuis)
|
||||
|
||||
* linux: remove bug workaround for obsolete kernels (Ben Noordhuis)
|
||||
|
||||
* doc: update active maintainers list (Ben Noordhuis)
|
||||
|
||||
* test: add ASSERT_OK (Trevor Norris)
|
||||
|
||||
* src: fix events/events_waiting metrics counter (Trevor Norris)
|
||||
|
||||
* unix,win: add uv_clock_gettime() (Ben Noordhuis)
|
||||
|
||||
* build: remove freebsd and openbsd buildbots (Ben Noordhuis)
|
||||
|
||||
* win: fix race condition in uv__init_console() (sivadeilra)
|
||||
|
||||
* linux: fix logic bug in sqe ring space check (Ben Noordhuis)
|
||||
|
||||
* linux: use io_uring to batch epoll_ctl calls (Ben Noordhuis)
|
||||
|
||||
* macos: update minimum supported version (Santiago Gimeno)
|
||||
|
||||
* docs: fix some typos (cui fliter)
|
||||
|
||||
* unix: use memcpy() instead of type punning (Ben Noordhuis)
|
||||
|
||||
* test: add additional assert (Mohammed Keyvanzadeh)
|
||||
|
||||
* build: export compile_commands.json (Lewis Russell)
|
||||
|
||||
* win,process: write minidumps when sending SIGQUIT (Elliot Saba)
|
||||
|
||||
* unix: constrained_memory should return UINT64_MAX (Tim Besard)
|
||||
|
||||
* unix: handle CQ overflow in iou ring (Santiago Gimeno)
|
||||
|
||||
* unix: remove clang compiler warning pragmas (Ben Noordhuis)
|
||||
|
||||
* win: fix mingw build (gengjiawen)
|
||||
|
||||
* test: fix -Wbool-compare compiler warning (Ben Noordhuis)
|
||||
|
||||
* win: define MiniDumpWithAvxXStateContext always (Santiago Gimeno)
|
||||
|
||||
* freebsd: hard-code UV_ENODATA definition (Santiago Gimeno)
|
||||
|
||||
* linux: work around EOWNERDEAD io_uring kernel bug (Ben Noordhuis)
|
||||
|
||||
* linux: fix WRITEV with lots of bufs using io_uring (Santiago Gimeno)
|
||||
|
||||
|
||||
2022.07.12, Version 1.44.2 (Stable), 0c1fa696aa502eb749c2c4735005f41ba00a27b8
|
||||
|
||||
Changes since version 1.44.1:
|
||||
@ -359,7 +1243,7 @@ Changes since version 1.41.0:
|
||||
|
||||
* zos: treat __rfim_utok as binary (Shuowang (Wayne) Zhang)
|
||||
|
||||
* zos: use execvpe() to set environ explictly (Shuowang (Wayne) Zhang)
|
||||
* zos: use execvpe() to set environ explicitly (Shuowang (Wayne) Zhang)
|
||||
|
||||
* zos: use custom proctitle implementation (Shuowang (Wayne) Zhang)
|
||||
|
||||
@ -2865,7 +3749,7 @@ Changes since version 1.9.1:
|
||||
|
||||
* zos: implement uv__io_check_fd (John Barboza)
|
||||
|
||||
* unix: unneccessary use const qualifier in container_of (John Barboza)
|
||||
* unix: unnecessary use const qualifier in container_of (John Barboza)
|
||||
|
||||
* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal)
|
||||
|
||||
@ -4968,7 +5852,7 @@ Changes since version 0.11.8:
|
||||
is an int64_t, and no longer an int. (Bert Belder)
|
||||
|
||||
* process: make uv_spawn() return some types of errors immediately on windows,
|
||||
instead of passing the error code the the exit callback. This brings it on
|
||||
instead of passing the error code the exit callback. This brings it on
|
||||
par with libuv's behavior on unix. (Bert Belder)
|
||||
|
||||
|
||||
|
6
LINKS.md
6
LINKS.md
@ -6,7 +6,8 @@
|
||||
* [clearskies_core](https://github.com/larroy/clearskies_core): Clearskies file synchronization program. (C++11)
|
||||
* [CMake](https://cmake.org) open-source, cross-platform family of tools designed to build, test and package software
|
||||
* [Cocos-Engine](https://github.com/cocos/cocos-engine): The runtime framework for Cocos Creator editor.
|
||||
* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps.
|
||||
* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps.
|
||||
* [DPS8M](https://dps8m.gitlab.io): GE ∕ Honeywell ∕ Bull DPS‑8/M and 6180/L68 mainframe simulator.
|
||||
* [DPS-For-IoT](https://github.com/intel/dps-for-iot/wiki): Fully distributed publish/subscribe protocol.
|
||||
* [HashLink](https://github.com/HaxeFoundation/hashlink): Haxe run-time with libuv support included.
|
||||
* [Haywire](https://github.com/kellabyte/Haywire): Asynchronous HTTP server.
|
||||
@ -36,6 +37,7 @@
|
||||
* [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
|
||||
* [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
|
||||
* [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
|
||||
@ -106,3 +108,5 @@
|
||||
* [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem
|
||||
* Haskell
|
||||
* [Z.Haskell](https://z.haskell.world)
|
||||
* C3
|
||||
* [libuv.c3l](https://github.com/velikoss/libuv.c3l)
|
||||
|
14
Makefile.am
14
Makefile.am
@ -59,7 +59,7 @@ if WINNT
|
||||
uvinclude_HEADERS += include/uv/win.h include/uv/tree.h
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
|
||||
-DWIN32_LEAN_AND_MEAN \
|
||||
-D_WIN32_WINNT=0x0602
|
||||
-D_WIN32_WINNT=0x0A00
|
||||
libuv_la_SOURCES += src/win/async.c \
|
||||
src/win/atomicops-inl.h \
|
||||
src/win/core.c \
|
||||
@ -136,6 +136,12 @@ TESTS = test/run-tests
|
||||
check_PROGRAMS = test/run-tests
|
||||
test_run_tests_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
if WINNT
|
||||
check-am: test/run-tests_no_ext
|
||||
test/run-tests_no_ext: test/run-tests$(EXEEXT)
|
||||
cp test/run-tests$(EXEEXT) test/run-tests_no_ext
|
||||
endif
|
||||
|
||||
if SUNOS
|
||||
# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
|
||||
# on other platforms complain that the argument is unused during compilation.
|
||||
@ -192,6 +198,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-hrtime.c \
|
||||
test/test-idle.c \
|
||||
test/test-idna.c \
|
||||
test/test-iouring-pollhup.c \
|
||||
test/test-ip4-addr.c \
|
||||
test/test-ip6-addr.c \
|
||||
test/test-ip-name.c \
|
||||
@ -269,6 +276,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-tcp-flags.c \
|
||||
test/test-tcp-open.c \
|
||||
test/test-tcp-read-stop.c \
|
||||
test/test-tcp-reuseport.c \
|
||||
test/test-tcp-read-stop-start.c \
|
||||
test/test-tcp-rst.c \
|
||||
test/test-tcp-shutdown-after-write.c \
|
||||
@ -286,6 +294,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-thread-equal.c \
|
||||
test/test-thread.c \
|
||||
test/test-thread-affinity.c \
|
||||
test/test-thread-name.c \
|
||||
test/test-thread-priority.c \
|
||||
test/test-threadpool-cancel.c \
|
||||
test/test-threadpool.c \
|
||||
test/test-timer-again.c \
|
||||
@ -317,6 +327,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-udp-send-unreachable.c \
|
||||
test/test-udp-try-send.c \
|
||||
test/test-udp-recv-in-a-row.c \
|
||||
test/test-udp-reuseport.c \
|
||||
test/test-uname.c \
|
||||
test/test-walk-handles.c \
|
||||
test/test-watcher-cross-stop.c
|
||||
@ -420,6 +431,7 @@ libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
|
||||
libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \
|
||||
src/unix/darwin-proctitle.c \
|
||||
src/unix/darwin-stub.h \
|
||||
src/unix/darwin-syscalls.h \
|
||||
src/unix/darwin.c \
|
||||
src/unix/fsevents.c \
|
||||
src/unix/kqueue.c \
|
||||
|
12
README.md
12
README.md
@ -232,6 +232,18 @@ $ ./bootstrap-vcpkg.sh # for bash
|
||||
$ ./vcpkg install libuv
|
||||
```
|
||||
|
||||
### Install with Conan
|
||||
|
||||
You can install pre-built binaries for libuv or build it from source using [Conan](https://conan.io/). Use the following command:
|
||||
|
||||
```bash
|
||||
conan install --requires="libuv/[*]" --build=missing
|
||||
```
|
||||
|
||||
The libuv Conan recipe is kept up to date by Conan maintainers and community contributors.
|
||||
If the version is out of date, please [create an issue or pull request](https://github.com/conan-io/conan-center-index) on the ConanCenterIndex repository.
|
||||
|
||||
|
||||
### Running tests
|
||||
|
||||
Some tests are timing sensitive. Relaxing test timeouts may be necessary
|
||||
|
27
SECURITY.md
Normal file
27
SECURITY.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Currently, we are providing security updates for the latest release in the v1.x series:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| Latest v1.x | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you believe you have found a security vulnerability in `libuv`, please use the [GitHub's private vulnerability reporting feature](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) in the [libuv repository](https://github.com/libuv/libuv) to report it to us.
|
||||
|
||||
This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository.
|
||||
|
||||
Please do:
|
||||
|
||||
* Provide as much information as you can about the vulnerability.
|
||||
* Provide details about your configuration and environment, if applicable.
|
||||
|
||||
Please do not:
|
||||
|
||||
* Post any information about the vulnerability in public places.
|
||||
* Attempt to exploit the vulnerability yourself.
|
||||
|
||||
We take all security bugs seriously. Thank you for improving the security of `libuv`. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
@ -4,14 +4,14 @@
|
||||
|---|---|---|---|
|
||||
| GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | |
|
||||
| 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 2017 and later are supported |
|
||||
| FreeBSD | Tier 2 | >= 12 | |
|
||||
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
|
||||
| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
|
||||
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
|
||||
| Linux with musl | Tier 2 | musl >= 1.0 | |
|
||||
| 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 | |
|
||||
| Other | Tier 3 | N/A | |
|
||||
|
||||
|
@ -13,12 +13,13 @@
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
AC_INIT([libuv], [1.44.3-dev], [https://github.com/libuv/libuv/issues])
|
||||
AC_INIT([libuv], [1.50.1-dev], [https://github.com/libuv/libuv/issues])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
m4_include([m4/libuv-extra-automake-flags.m4])
|
||||
m4_include([m4/as_case.m4])
|
||||
m4_include([m4/libuv-check-flags.m4])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
|
||||
AM_MAINTAINER_MODE([enable]) # pass --disable-maintainer-mode if autotools may be unavailable
|
||||
AC_CANONICAL_HOST
|
||||
AC_ENABLE_SHARED
|
||||
AC_ENABLE_STATIC
|
||||
@ -32,7 +33,7 @@ CC_ATTRIBUTE_VISIBILITY([default], [
|
||||
# we exclude -fno-strict-aliasing for xlc
|
||||
CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing])
|
||||
CC_CHECK_CFLAGS_APPEND([-g])
|
||||
CC_CHECK_CFLAGS_APPEND([-std=gnu89])
|
||||
CC_CHECK_CFLAGS_APPEND([-std=gnu11])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wall])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wextra])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wno-long-long])
|
||||
@ -73,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false])
|
||||
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
|
||||
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
|
||||
AS_CASE([$host_os],[mingw*], [
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid"
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -lshell32"
|
||||
])
|
||||
AS_CASE([$host_os], [solaris2.10], [
|
||||
CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS"
|
||||
|
@ -18,22 +18,21 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t));
|
||||
uv_lib_t lib;
|
||||
while (--argc) {
|
||||
fprintf(stderr, "Loading %s\n", argv[argc]);
|
||||
if (uv_dlopen(argv[argc], lib)) {
|
||||
fprintf(stderr, "Error: %s\n", uv_dlerror(lib));
|
||||
if (uv_dlopen(argv[argc], &lib)) {
|
||||
fprintf(stderr, "Error: %s\n", uv_dlerror(&lib));
|
||||
continue;
|
||||
}
|
||||
|
||||
init_plugin_function init_plugin;
|
||||
if (uv_dlsym(lib, "initialize", (void **) &init_plugin)) {
|
||||
fprintf(stderr, "dlsym error: %s\n", uv_dlerror(lib));
|
||||
if (uv_dlsym(&lib, "initialize", (void **) &init_plugin)) {
|
||||
fprintf(stderr, "dlsym error: %s\n", uv_dlerror(&lib));
|
||||
continue;
|
||||
}
|
||||
|
||||
init_plugin();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,25 +5,27 @@
|
||||
|
||||
uv_loop_t *loop;
|
||||
uv_tty_t tty;
|
||||
int main() {
|
||||
loop = uv_default_loop();
|
||||
|
||||
int main() {
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
uv_write_t req1;
|
||||
uv_buf_t buf1;
|
||||
|
||||
loop = uv_default_loop();
|
||||
uv_tty_init(loop, &tty, STDOUT_FILENO, 0);
|
||||
uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);
|
||||
|
||||
if (uv_guess_handle(1) == UV_TTY) {
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
buf.base = "\033[41;37m";
|
||||
buf.len = strlen(buf.base);
|
||||
uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL);
|
||||
buf1.base = "\033[41;37m";
|
||||
buf1.len = strlen(buf1.base);
|
||||
uv_write(&req1, (uv_stream_t*) &tty, &buf1, 1, NULL);
|
||||
}
|
||||
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
buf.base = "Hello TTY\n";
|
||||
buf.len = strlen(buf.base);
|
||||
uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL);
|
||||
|
||||
uv_tty_reset_mode();
|
||||
return uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
@ -1,27 +1,36 @@
|
||||
# primary
|
||||
sphinx==6.1.3
|
||||
furo==2023.5.20
|
||||
Sphinx==6.1.3
|
||||
|
||||
# dependencies
|
||||
alabaster==0.7.13
|
||||
Babel==2.11.0
|
||||
beautifulsoup4==4.12.2
|
||||
certifi==2022.12.7
|
||||
charset-normalizer==3.0.1
|
||||
colorama==0.4.6
|
||||
docutils==0.19
|
||||
idna==3.4
|
||||
imagesize==1.4.1
|
||||
importlib-metadata==6.0.0
|
||||
Jinja2==3.1.2
|
||||
livereload==2.6.3
|
||||
MarkupSafe==2.1.2
|
||||
packaging==23.0
|
||||
Pygments==2.14.0
|
||||
pytz==2022.7.1
|
||||
requests==2.28.2
|
||||
six==1.16.0
|
||||
snowballstemmer==2.2.0
|
||||
sphinxcontrib-applehelp==1.0.3
|
||||
soupsieve==2.4.1
|
||||
sphinx-autobuild==2021.3.14
|
||||
sphinx-basic-ng==1.0.0b2
|
||||
sphinxcontrib-devhelp==1.0.2
|
||||
sphinxcontrib-htmlhelp==2.0.0
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==1.0.3
|
||||
sphinxcontrib-serializinghtml==1.1.5
|
||||
sphinxcontrib.applehelp==1.0.3
|
||||
tornado==6.3.2
|
||||
urllib3==1.26.14
|
||||
zipp==3.11.0
|
||||
|
@ -118,7 +118,7 @@ pygments_style = 'sphinx'
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'nature'
|
||||
html_theme = 'furo'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
|
@ -339,6 +339,9 @@ Error constants
|
||||
|
||||
socket type not supported
|
||||
|
||||
.. c:macro:: UV_EUNATCH
|
||||
|
||||
protocol driver not attached
|
||||
|
||||
API
|
||||
---
|
||||
|
@ -16,7 +16,10 @@ Starting with libuv v1.45.0, some file operations on Linux are handed off to
|
||||
`io_uring <https://en.wikipedia.org/wiki/Io_uring>` when possible. Apart from
|
||||
a (sometimes significant) increase in throughput there should be no change in
|
||||
observable behavior. Libuv reverts to using its threadpool when the necessary
|
||||
kernel features are unavailable or unsuitable.
|
||||
kernel features are unavailable or unsuitable. Starting with libuv v1.49.0 this
|
||||
behavior was reverted and Libuv on Linux by default will be using the threadpool
|
||||
again. In order to enable io_uring the :c:type:`uv_loop_t` instance must be
|
||||
configured with the :c:type:`UV_LOOP_ENABLE_IO_URING_SQPOLL` option.
|
||||
|
||||
.. note::
|
||||
On Windows `uv_fs_*` functions use utf-8 encoding.
|
||||
@ -129,10 +132,9 @@ Data types
|
||||
uint64_t f_spare[4];
|
||||
} uv_statfs_t;
|
||||
|
||||
.. c:enum:: uv_dirent_t
|
||||
.. c:enum:: uv_dirent_type_t
|
||||
|
||||
Cross platform (reduced) equivalent of ``struct dirent``.
|
||||
Used in :c:func:`uv_fs_scandir_next`.
|
||||
Type of dirent.
|
||||
|
||||
::
|
||||
|
||||
@ -147,6 +149,14 @@ Data types
|
||||
UV_DIRENT_BLOCK
|
||||
} uv_dirent_type_t;
|
||||
|
||||
|
||||
.. c:type:: uv_dirent_t
|
||||
|
||||
Cross platform (reduced) equivalent of ``struct dirent``.
|
||||
Used in :c:func:`uv_fs_scandir_next`.
|
||||
|
||||
::
|
||||
|
||||
typedef struct uv_dirent_s {
|
||||
const char* name;
|
||||
uv_dirent_type_t type;
|
||||
@ -420,6 +430,12 @@ API
|
||||
|
||||
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::
|
||||
z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return
|
||||
``UV_ENOSYS``.
|
||||
@ -454,7 +470,7 @@ API
|
||||
|
||||
.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
|
||||
|
||||
Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea>`_.
|
||||
Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandleW <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew>`_.
|
||||
The resulting string is stored in `req->ptr`.
|
||||
|
||||
.. warning::
|
||||
@ -653,7 +669,7 @@ File open constants
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_RANDOM` is only supported on Windows via
|
||||
`FILE_FLAG_RANDOM_ACCESS <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea>`_.
|
||||
`FILE_FLAG_RANDOM_ACCESS <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_RDONLY
|
||||
|
||||
@ -670,7 +686,7 @@ File open constants
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_SEQUENTIAL` is only supported on Windows via
|
||||
`FILE_FLAG_SEQUENTIAL_SCAN <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea>`_.
|
||||
`FILE_FLAG_SEQUENTIAL_SCAN <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_SHORT_LIVED
|
||||
|
||||
@ -678,7 +694,7 @@ File open constants
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_SHORT_LIVED` is only supported on Windows via
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea>`_.
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_SYMLINK
|
||||
|
||||
@ -699,7 +715,7 @@ File open constants
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_TEMPORARY` is only supported on Windows via
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea>`_.
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_TRUNC
|
||||
|
||||
|
@ -39,11 +39,20 @@ Data types
|
||||
.. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status)
|
||||
|
||||
Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly
|
||||
after the handle is started. If the handle was started with a directory the
|
||||
`filename` parameter will be a relative path to a file contained in the directory.
|
||||
The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements.
|
||||
after the handle is started.
|
||||
|
||||
.. c:type:: uv_fs_event
|
||||
If the handle was started with a directory the `filename` parameter will
|
||||
be a relative path to a file contained in the directory, or `NULL` if the
|
||||
file name cannot be determined.
|
||||
|
||||
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
|
||||
|
||||
Event types that :c:type:`uv_fs_event_t` handles monitor.
|
||||
|
||||
@ -54,7 +63,7 @@ Data types
|
||||
UV_CHANGE = 2
|
||||
};
|
||||
|
||||
.. c:type:: uv_fs_event_flags
|
||||
.. c:enum:: uv_fs_event_flags
|
||||
|
||||
Flags that can be passed to :c:func:`uv_fs_event_start` to control its
|
||||
behavior.
|
||||
@ -105,10 +114,13 @@ API
|
||||
.. c:function:: int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags)
|
||||
|
||||
Start the handle with the given callback, which will watch the specified
|
||||
`path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`.
|
||||
`path` for changes. `flags` can be an ORed mask of :c:enum:`uv_fs_event_flags`.
|
||||
|
||||
.. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and
|
||||
only on OSX and Windows.
|
||||
.. note:: On macOS, events collected by the OS immediately before calling
|
||||
``uv_fs_event_start`` might be reported to the `uv_fs_event_cb`
|
||||
callback.
|
||||
|
||||
.. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle)
|
||||
|
||||
|
@ -53,6 +53,8 @@ ID of the child process.
|
||||
The exit callback will be invoked with the *exit status* and the type of *signal*
|
||||
which caused the exit.
|
||||
|
||||
Note that it is important **not** to call ``uv_close`` before the exit callback.
|
||||
|
||||
.. rubric:: spawn/main.c
|
||||
.. literalinclude:: ../../code/spawn/main.c
|
||||
:language: c
|
||||
@ -126,7 +128,8 @@ of ``uv_kill`` is::
|
||||
|
||||
For processes started using libuv, you may use ``uv_process_kill`` instead,
|
||||
which accepts the ``uv_process_t`` watcher as the first argument, rather than
|
||||
the pid. In this case, **remember to call** ``uv_close`` on the watcher.
|
||||
the pid. In this case, **remember to call** ``uv_close`` on the watcher _after_
|
||||
the exit callback has been called.
|
||||
|
||||
Signals
|
||||
-------
|
||||
@ -330,7 +333,7 @@ to hand off their I/O to other processes. Applications include load-balancing
|
||||
servers, worker processes and other ways to make optimum use of CPU. libuv only
|
||||
supports sending **TCP sockets or other pipes** over pipes for now.
|
||||
|
||||
To demonstrate, we will look at a echo server implementation that hands of
|
||||
To demonstrate, we will look at an echo server implementation that hands off
|
||||
clients to worker processes in a round-robin fashion. This program is a bit
|
||||
involved, and while only snippets are included in the book, it is recommended
|
||||
to read the full code to really understand it.
|
||||
|
@ -363,7 +363,7 @@ to get the error message.
|
||||
argument. ``init_plugin_function`` is a function pointer to the sort of
|
||||
function we are looking for in the application's plugins.
|
||||
|
||||
.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library#Shared_libraries
|
||||
.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library
|
||||
|
||||
TTY
|
||||
---
|
||||
|
@ -94,7 +94,7 @@ Public members
|
||||
|
||||
.. c:member:: uv_handle_type uv_handle_t.type
|
||||
|
||||
The :c:type:`uv_handle_type`, indicating the type of the underlying handle. Readonly.
|
||||
The :c:enum:`uv_handle_type`, indicating the type of the underlying handle. Readonly.
|
||||
|
||||
.. c:member:: void* uv_handle_t.data
|
||||
|
||||
@ -248,7 +248,7 @@ just for some handle types.
|
||||
|
||||
.. versionadded:: 1.19.0
|
||||
|
||||
.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data)
|
||||
.. c:function:: void uv_handle_set_data(uv_handle_t* handle, void* data)
|
||||
|
||||
Sets `handle->data` to `data`.
|
||||
|
||||
|
@ -58,5 +58,5 @@ libuv can be downloaded from `here <https://dist.libuv.org/dist/>`_.
|
||||
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>`_.
|
||||
|
||||
|
@ -16,6 +16,19 @@ Data types
|
||||
|
||||
Loop data type.
|
||||
|
||||
.. c:enum:: uv_loop_option
|
||||
|
||||
Additional loop options.
|
||||
See :c:func:`uv_loop_configure`.
|
||||
|
||||
::
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL = 0,
|
||||
UV_METRICS_IDLE_TIME,
|
||||
UV_LOOP_USE_IO_URING_SQPOLL
|
||||
} uv_loop_option;
|
||||
|
||||
.. c:enum:: uv_run_mode
|
||||
|
||||
Mode used to run the loop with :c:func:`uv_run`.
|
||||
@ -73,8 +86,13 @@ API
|
||||
|
||||
This option is necessary to use :c:func:`uv_metrics_idle_time`.
|
||||
|
||||
- UV_LOOP_ENABLE_IO_URING_SQPOLL: Enable SQPOLL io_uring instance to handle
|
||||
asynchronous file system operations.
|
||||
|
||||
.. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option.
|
||||
|
||||
.. versionchanged:: 1.49.0 added the UV_LOOP_ENABLE_IO_URING_SQPOLL option.
|
||||
|
||||
.. c:function:: int uv_loop_close(uv_loop_t* loop)
|
||||
|
||||
Releases all internal loop resources. Call this function only when the loop
|
||||
@ -238,7 +256,7 @@ API
|
||||
|
||||
.. versionadded:: 1.19.0
|
||||
|
||||
.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data)
|
||||
.. c:function:: void uv_loop_set_data(uv_loop_t* loop, void* data)
|
||||
|
||||
Sets `loop->data` to `data`.
|
||||
|
||||
|
@ -199,6 +199,18 @@ Data types
|
||||
char* homedir;
|
||||
} uv_passwd_t;
|
||||
|
||||
.. c:type:: uv_group_t
|
||||
|
||||
Data type for group file information.
|
||||
|
||||
::
|
||||
|
||||
typedef struct uv_group_s {
|
||||
char* groupname;
|
||||
unsigned long gid;
|
||||
char** members;
|
||||
} uv_group_t;
|
||||
|
||||
.. c:type:: uv_utsname_t
|
||||
|
||||
Data type for operating system name and version information.
|
||||
@ -348,6 +360,17 @@ API
|
||||
On Windows not all fields are set, the unsupported fields are filled with zeroes.
|
||||
See :c:type:`uv_rusage_t` for more details.
|
||||
|
||||
.. c:function:: int uv_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)
|
||||
|
||||
Returns the current process ID.
|
||||
@ -566,6 +589,35 @@ API
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
.. c:function:: int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid)
|
||||
|
||||
Gets a subset of the password file entry for the provided uid.
|
||||
The populated data includes the username, euid, gid, shell,
|
||||
and home directory. On non-Windows systems, all data comes from
|
||||
:man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no
|
||||
meaning, and shell is `NULL`. After successfully calling this function, the
|
||||
memory allocated to `pwd` needs to be freed with
|
||||
:c:func:`uv_os_free_passwd`.
|
||||
|
||||
.. versionadded:: 1.45.0
|
||||
|
||||
.. c:function:: int uv_os_get_group(uv_group_t* group, uv_uid_t gid)
|
||||
|
||||
Gets a subset of the group file entry for the provided uid.
|
||||
The populated data includes the group name, gid, and members. On non-Windows
|
||||
systems, all data comes from :man:`getgrgid_r(3)`. On Windows, uid and gid
|
||||
are set to -1 and have no meaning. After successfully calling this function,
|
||||
the memory allocated to `group` needs to be freed with
|
||||
:c:func:`uv_os_free_group`.
|
||||
|
||||
.. versionadded:: 1.45.0
|
||||
|
||||
.. c:function:: void uv_os_free_group(uv_passwd_t* pwd)
|
||||
|
||||
Frees the memory previously allocated with :c:func:`uv_os_get_group`.
|
||||
|
||||
.. versionadded:: 1.45.0
|
||||
|
||||
.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd)
|
||||
|
||||
Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`.
|
||||
@ -839,3 +891,50 @@ API
|
||||
Causes the calling thread to sleep for `msec` milliseconds.
|
||||
|
||||
.. versionadded:: 1.34.0
|
||||
|
||||
String manipulation functions
|
||||
-----------------------------
|
||||
|
||||
These string utilities are needed internally for dealing with Windows, and are
|
||||
exported to allow clients to work uniformly with this data when the libuv API
|
||||
is not complete.
|
||||
|
||||
.. c:function:: size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, ssize_t utf16_len)
|
||||
|
||||
Get the length of a UTF-16 (or UCS-2) `utf16` value after converting it to
|
||||
WTF-8. If `utf16` is NUL terminated, `utf16_len` can be set to -1,
|
||||
otherwise it must be specified.
|
||||
|
||||
.. versionadded:: 1.47.0
|
||||
|
||||
.. c:function:: int uv_utf16_to_wtf8(const uint16_t* utf16, ssize_t utf16_len, char** wtf8_ptr, size_t* wtf8_len_ptr)
|
||||
|
||||
Convert UTF-16 (or UCS-2) data in `utf16` to WTF-8 data in `*wtf8_ptr`. The
|
||||
`utf16_len` count (in characters) gives the length of `utf16`. If `utf16`
|
||||
is NUL terminated, `utf16_len` can be set to -1, otherwise it must be
|
||||
specified. If `wtf8_ptr` is `NULL`, no result will be computed, but the
|
||||
length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_ptr`.
|
||||
If `*wtf8_ptr` is `NULL`, space for the conversion will be allocated and
|
||||
returned in `wtf8_ptr` and the length will be returned in `wtf8_len_ptr`.
|
||||
Otherwise, the length of `*wtf8_ptr` must be passed in `wtf8_len_ptr`. The
|
||||
`wtf8_ptr` must contain an extra space for an extra NUL after the result.
|
||||
If the result is truncated, `UV_ENOBUFS` will be returned and
|
||||
`wtf8_len_ptr` will be the length of the required `wtf8_ptr` to contain the
|
||||
whole result.
|
||||
|
||||
.. versionadded:: 1.47.0
|
||||
|
||||
.. c:function:: ssize_t uv_wtf8_length_as_utf16(const char* wtf8)
|
||||
|
||||
Get the length in characters of a NUL-terminated WTF-8 `wtf8` value
|
||||
after converting it to UTF-16 (or UCS-2), including NUL terminator.
|
||||
|
||||
.. versionadded:: 1.47.0
|
||||
|
||||
.. c:function:: void uv_wtf8_to_utf16(const char* utf8, uint16_t* utf16, size_t utf16_len)
|
||||
|
||||
Convert NUL-terminated WTF-8 data in `wtf8` to UTF-16 (or UCS-2) data
|
||||
in `utf16`. The `utf16_len` count (in characters) must include space
|
||||
for the NUL terminator.
|
||||
|
||||
.. versionadded:: 1.47.0
|
||||
|
@ -55,17 +55,61 @@ API
|
||||
|
||||
Bind the pipe to a file path (Unix) or a name (Windows).
|
||||
|
||||
Does not support Linux abstract namespace sockets,
|
||||
unlike :c:func:`uv_pipe_bind2`.
|
||||
|
||||
Alias for ``uv_pipe_bind2(handle, name, strlen(name), 0)``.
|
||||
|
||||
.. note::
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
|
||||
92 and 108 bytes.
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||
typically between 92 and 108 bytes.
|
||||
|
||||
.. c:function:: int uv_pipe_bind2(uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags)
|
||||
|
||||
Bind the pipe to a file path (Unix) or a name (Windows).
|
||||
|
||||
``flags`` must be zero or ``UV_PIPE_NO_TRUNCATE``. Returns ``UV_EINVAL``
|
||||
for unsupported flags without performing the bind operation.
|
||||
|
||||
Supports Linux abstract namespace sockets. ``namelen`` must include
|
||||
the leading nul byte but not the trailing nul byte.
|
||||
|
||||
.. versionadded:: 1.46.0
|
||||
|
||||
.. note::
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||
typically between 92 and 108 bytes, unless the ``UV_PIPE_NO_TRUNCATE``
|
||||
flag is specified, in which case an ``UV_EINVAL`` error is returned.
|
||||
|
||||
.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
|
||||
|
||||
Connect to the Unix domain socket or the named pipe.
|
||||
Connect to the Unix domain socket or the Windows named pipe.
|
||||
|
||||
Does not support Linux abstract namespace sockets,
|
||||
unlike :c:func:`uv_pipe_connect2`.
|
||||
|
||||
Alias for ``uv_pipe_connect2(req, handle, name, strlen(name), 0, cb)``.
|
||||
|
||||
.. note::
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
|
||||
92 and 108 bytes.
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||
typically between 92 and 108 bytes.
|
||||
|
||||
.. c:function:: void uv_pipe_connect2(uv_connect_t* req, uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags, uv_connect_cb cb)
|
||||
|
||||
Connect to the Unix domain socket or the Windows named pipe.
|
||||
|
||||
``flags`` must be zero or ``UV_PIPE_NO_TRUNCATE``. Returns ``UV_EINVAL``
|
||||
for unsupported flags without performing the connect operation.
|
||||
|
||||
Supports Linux abstract namespace sockets. ``namelen`` must include
|
||||
the leading nul byte but not the trailing nul byte.
|
||||
|
||||
.. versionadded:: 1.46.0
|
||||
|
||||
.. note::
|
||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||
typically between 92 and 108 bytes, unless the ``UV_PIPE_NO_TRUNCATE``
|
||||
flag is specified, in which case an ``UV_EINVAL`` error is returned.
|
||||
|
||||
.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)
|
||||
|
||||
|
@ -45,7 +45,7 @@ Data types
|
||||
|
||||
Type definition for callback passed to :c:func:`uv_poll_start`.
|
||||
|
||||
.. c:type:: uv_poll_event
|
||||
.. c:enum:: uv_poll_event
|
||||
|
||||
Poll event types
|
||||
|
||||
|
@ -40,7 +40,7 @@ Data types
|
||||
will indicate the exit status and the signal that caused the process to
|
||||
terminate, if any.
|
||||
|
||||
.. c:type:: uv_process_flags
|
||||
.. c:enum:: uv_process_flags
|
||||
|
||||
Flags to be set on the flags field of :c:type:`uv_process_options_t`.
|
||||
|
||||
@ -85,7 +85,14 @@ Data types
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6),
|
||||
/*
|
||||
* On Windows, if the path to the program to execute, specified in
|
||||
* uv_process_options_t's file field, has a directory component,
|
||||
* search for the exact file name before trying variants with
|
||||
* extensions like '.exe' or '.cmd'.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7)
|
||||
};
|
||||
|
||||
.. c:type:: uv_stdio_container_t
|
||||
@ -183,7 +190,7 @@ Public members
|
||||
Command line arguments. args[0] should be the path to the program. On
|
||||
Windows this uses `CreateProcess` which concatenates the arguments into a
|
||||
string this can cause some strange errors. See the
|
||||
``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`.
|
||||
``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:enum:`uv_process_flags`.
|
||||
|
||||
.. c:member:: char** uv_process_options_t.env
|
||||
|
||||
@ -196,7 +203,7 @@ Public members
|
||||
.. c:member:: unsigned int uv_process_options_t.flags
|
||||
|
||||
Various flags that control how :c:func:`uv_spawn` behaves. See
|
||||
:c:type:`uv_process_flags`.
|
||||
:c:enum:`uv_process_flags`.
|
||||
|
||||
.. c:member:: int uv_process_options_t.stdio_count
|
||||
.. c:member:: uv_stdio_container_t* uv_process_options_t.stdio
|
||||
@ -262,6 +269,9 @@ API
|
||||
.. versionchanged:: 1.24.0 Added `UV_PROCESS_WINDOWS_HIDE_CONSOLE` and
|
||||
`UV_PROCESS_WINDOWS_HIDE_GUI` flags.
|
||||
|
||||
.. versionchanged:: 1.48.0 Added the
|
||||
`UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME` flag.
|
||||
|
||||
.. c:function:: int uv_process_kill(uv_process_t* handle, int signum)
|
||||
|
||||
Sends the specified signal to the given process handle. Check the documentation
|
||||
|
@ -21,17 +21,9 @@ Data types
|
||||
|
||||
Union of all request types.
|
||||
|
||||
.. c:enum:: uv_req_type
|
||||
|
||||
Public members
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. c:member:: void* uv_req_t.data
|
||||
|
||||
Space for user-defined arbitrary data. libuv does not use this field.
|
||||
|
||||
.. c:member:: uv_req_type uv_req_t.type
|
||||
|
||||
Indicated the type of request. Readonly.
|
||||
The kind of the libuv request.
|
||||
|
||||
::
|
||||
|
||||
@ -50,6 +42,18 @@ Public members
|
||||
} uv_req_type;
|
||||
|
||||
|
||||
Public members
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. c:member:: void* uv_req_t.data
|
||||
|
||||
Space for user-defined arbitrary data. libuv does not use this field.
|
||||
|
||||
.. c:member:: uv_req_type uv_req_t.type
|
||||
|
||||
The :c:enum:`uv_req_type`, indicating the type of the request. Readonly.
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
@ -95,7 +99,7 @@ API
|
||||
|
||||
.. versionadded:: 1.19.0
|
||||
|
||||
.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data)
|
||||
.. c:function:: void uv_req_set_data(uv_req_t* req, void* data)
|
||||
|
||||
Sets `req->data` to `data`.
|
||||
|
||||
|
@ -16,6 +16,28 @@ Data types
|
||||
|
||||
TCP handle type.
|
||||
|
||||
.. c:enum:: uv_tcp_flags
|
||||
|
||||
Flags used in :c:func:`uv_tcp_bind`.
|
||||
|
||||
::
|
||||
|
||||
enum uv_tcp_flags {
|
||||
/* Used with uv_tcp_bind, when an IPv6 address is used. */
|
||||
UV_TCP_IPV6ONLY = 1,
|
||||
|
||||
/* Enable SO_REUSEPORT socket option when binding the handle.
|
||||
* This allows completely duplicate bindings by multiple processes
|
||||
* or threads if they all set SO_REUSEPORT before binding the port.
|
||||
* Incoming connections are distributed across the participating
|
||||
* listener sockets.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_TCP_REUSEPORT = 2,
|
||||
};
|
||||
|
||||
|
||||
Public members
|
||||
^^^^^^^^^^^^^^
|
||||
@ -65,6 +87,10 @@ API
|
||||
at the end of this procedure, then the handle is destroyed with a
|
||||
``UV_ETIMEDOUT`` error passed to the corresponding callback.
|
||||
|
||||
If `delay` is less than 1 then ``UV_EINVAL`` is returned.
|
||||
|
||||
.. versionchanged:: 1.49.0 If `delay` is less than 1 then ``UV_EINVAL``` is returned.
|
||||
|
||||
.. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable)
|
||||
|
||||
Enable / disable simultaneous asynchronous accept requests that are
|
||||
@ -77,16 +103,34 @@ API
|
||||
|
||||
.. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags)
|
||||
|
||||
Bind the handle to an address and port. `addr` should point to an
|
||||
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
|
||||
Bind the handle to an address and port.
|
||||
|
||||
When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
|
||||
error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect`. That is,
|
||||
a successful call to this function does not guarantee that the call
|
||||
to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` will succeed as well.
|
||||
error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect` unless you specify
|
||||
``UV_TCP_REUSEPORT`` in `flags` for all the binding sockets. That is, a successful
|
||||
call to this function does not guarantee that the call to :c:func:`uv_listen` or
|
||||
:c:func:`uv_tcp_connect` will succeed as well.
|
||||
|
||||
`flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
|
||||
is disabled and only IPv6 is used.
|
||||
:param handle: TCP handle. It should have been initialized with :c:func:`uv_tcp_init`.
|
||||
|
||||
:param addr: Address to bind to. It should point to an initialized ``struct sockaddr_in``
|
||||
or ``struct sockaddr_in6``.
|
||||
|
||||
:param flags: Flags that control the behavior of binding the socket.
|
||||
``UV_TCP_IPV6ONLY`` can be contained in `flags` to disable dual-stack
|
||||
support and only use IPv6.
|
||||
``UV_TCP_REUSEPORT`` can be contained in `flags` to enable the socket option
|
||||
`SO_REUSEPORT` with the capability of load balancing that distribute incoming
|
||||
connections across all listening sockets in multiple processes or threads.
|
||||
|
||||
:returns: 0 on success, or an error code < 0 on failure.
|
||||
|
||||
.. versionchanged:: 1.49.0 added the ``UV_TCP_REUSEPORT`` flag.
|
||||
|
||||
.. note::
|
||||
``UV_TCP_REUSEPORT`` flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. On other platforms
|
||||
this function will return an UV_ENOTSUP error.
|
||||
|
||||
.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
|
||||
|
||||
|
@ -78,6 +78,14 @@ Threads
|
||||
|
||||
.. 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)
|
||||
|
||||
Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread.
|
||||
@ -132,6 +140,45 @@ Threads
|
||||
.. 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_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)
|
||||
|
||||
If the function succeeds, the return value is 0.
|
||||
If the function fails, the return value is less than zero.
|
||||
Sets the scheduling priority of the thread specified by tid. It requires elevated
|
||||
privilege to set specific priorities on some platforms.
|
||||
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_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST.
|
||||
|
||||
.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority)
|
||||
|
||||
If the function succeeds, the return value is 0.
|
||||
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
|
||||
output parameter priority is platform dependent.
|
||||
For Linux, when schedule policy is SCHED_OTHER (default), priority is 0.
|
||||
|
||||
Thread-local storage
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -17,6 +17,8 @@ is 1024).
|
||||
.. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the
|
||||
(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
|
||||
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
|
||||
|
@ -6,6 +6,15 @@
|
||||
|
||||
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
|
||||
----------
|
||||
@ -64,11 +73,6 @@ API
|
||||
duration, and will follow normal timer semantics in the case of a
|
||||
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::
|
||||
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,
|
||||
|
@ -27,10 +27,15 @@ Data types
|
||||
typedef enum {
|
||||
/* Initial/normal terminal mode */
|
||||
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,
|
||||
/* 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;
|
||||
|
||||
.. c:enum:: uv_tty_vtermstate_t
|
||||
@ -98,7 +103,7 @@ API
|
||||
.. c:function:: int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode)
|
||||
|
||||
.. versionchanged:: 1.2.0: the mode is specified as a
|
||||
:c:type:`uv_tty_mode_t` value.
|
||||
:c:enum:`uv_tty_mode_t` value.
|
||||
|
||||
Set the TTY using the specified terminal mode.
|
||||
|
||||
|
@ -18,7 +18,7 @@ Data types
|
||||
|
||||
UDP send request type.
|
||||
|
||||
.. c:type:: uv_udp_flags
|
||||
.. c:enum:: uv_udp_flags
|
||||
|
||||
Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`..
|
||||
|
||||
@ -28,19 +28,21 @@ Data types
|
||||
/* Disables dual stack mode. */
|
||||
UV_UDP_IPV6ONLY = 1,
|
||||
/*
|
||||
* Indicates message was truncated because read buffer was too small. The
|
||||
* remainder was discarded by the OS. Used in uv_udp_recv_cb.
|
||||
*/
|
||||
* Indicates message was truncated because read buffer was too small. The
|
||||
* remainder was discarded by the OS. Used in uv_udp_recv_cb.
|
||||
*/
|
||||
UV_UDP_PARTIAL = 2,
|
||||
/*
|
||||
* Indicates if SO_REUSEADDR will be set when binding the handle in
|
||||
* uv_udp_bind.
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
|
||||
* Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
|
||||
* multiple threads or processes can bind to the same address without error
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
* Indicates if SO_REUSEADDR will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs (except for
|
||||
* DragonFlyBSD), OS X, and other platforms where SO_REUSEPORTs don't
|
||||
* have the capability of load balancing, as the opposite of what
|
||||
* UV_UDP_REUSEPORT would do. On other Unix platforms, it sets the
|
||||
* SO_REUSEADDR flag. What that means is that multiple threads or
|
||||
* processes can bind to the same address without error (provided
|
||||
* they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
UV_UDP_REUSEADDR = 4,
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||
@ -62,8 +64,20 @@ Data types
|
||||
*/
|
||||
UV_UDP_LINUX_RECVERR = 32,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
* Indicates if SO_REUSEPORT will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket option on supported platforms.
|
||||
* Unlike UV_UDP_REUSEADDR, this flag will make multiple threads or
|
||||
* processes that are binding to the same address and port "share"
|
||||
* the port, which means incoming datagrams are distributed across
|
||||
* the receiving sockets among threads or processes.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_UDP_REUSEPORT = 64,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
UV_UDP_RECVMMSG = 256
|
||||
};
|
||||
|
||||
@ -186,11 +200,24 @@ API
|
||||
with the address and port to bind to.
|
||||
|
||||
:param flags: Indicate how the socket will be bound,
|
||||
``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, and ``UV_UDP_RECVERR``
|
||||
are supported.
|
||||
``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, ``UV_UDP_REUSEPORT``,
|
||||
and ``UV_UDP_RECVERR`` are supported.
|
||||
|
||||
:returns: 0 on success, or an error code < 0 on failure.
|
||||
|
||||
.. versionchanged:: 1.49.0 added the ``UV_UDP_REUSEPORT`` flag.
|
||||
|
||||
.. note::
|
||||
``UV_UDP_REUSEPORT`` flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. On other platforms
|
||||
this function will return an UV_ENOTSUP error.
|
||||
For platforms where `SO_REUSEPORT`s have the capability of load balancing,
|
||||
specifying both ``UV_UDP_REUSEADDR`` and ``UV_UDP_REUSEPORT`` in flags is allowed
|
||||
and `SO_REUSEPORT` will always override the behavior of `SO_REUSEADDR`.
|
||||
For platforms where `SO_REUSEPORT`s don't have the capability of load balancing,
|
||||
specifying both ``UV_UDP_REUSEADDR`` and ``UV_UDP_REUSEPORT`` in flags will fail,
|
||||
returning an UV_ENOTSUP error.
|
||||
|
||||
.. c:function:: int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr)
|
||||
|
||||
Associate the UDP handle to a remote address and port, so every
|
||||
@ -285,7 +312,9 @@ API
|
||||
local sockets.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
:c:func:`uv_udp_init`.
|
||||
:c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have
|
||||
been bound to an address explicitly with :c:func:`uv_udp_bind`, or
|
||||
implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`.
|
||||
|
||||
:param on: 1 for on, 0 for off.
|
||||
|
||||
@ -296,7 +325,9 @@ API
|
||||
Set the multicast ttl.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
:c:func:`uv_udp_init`.
|
||||
:c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have
|
||||
been bound to an address explicitly with :c:func:`uv_udp_bind`, or
|
||||
implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`.
|
||||
|
||||
:param ttl: 1 through 255.
|
||||
|
||||
@ -307,7 +338,9 @@ API
|
||||
Set the multicast interface to send or receive data on.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
:c:func:`uv_udp_init`.
|
||||
:c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have
|
||||
been bound to an address explicitly with :c:func:`uv_udp_bind`, or
|
||||
implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`.
|
||||
|
||||
:param interface_addr: interface address.
|
||||
|
||||
@ -318,7 +351,9 @@ API
|
||||
Set broadcast on or off.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
:c:func:`uv_udp_init`.
|
||||
:c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have
|
||||
been bound to an address explicitly with :c:func:`uv_udp_bind`, or
|
||||
implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`.
|
||||
|
||||
:param on: 1 for on, 0 for off.
|
||||
|
||||
@ -329,7 +364,9 @@ API
|
||||
Set the time to live.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
:c:func:`uv_udp_init`.
|
||||
:c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have
|
||||
been bound to an address explicitly with :c:func:`uv_udp_bind`, or
|
||||
implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`.
|
||||
|
||||
:param ttl: 1 through 255.
|
||||
|
||||
@ -389,6 +426,20 @@ API
|
||||
|
||||
.. 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)
|
||||
|
||||
Prepare for receiving data. If the socket has not previously been bound
|
||||
|
125
include/uv.h
125
include/uv.h
@ -58,6 +58,13 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Internal type, do not use. */
|
||||
struct uv__queue {
|
||||
struct uv__queue* next;
|
||||
struct uv__queue* prev;
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include "uv/win.h"
|
||||
@ -150,6 +157,8 @@ extern "C" {
|
||||
XX(EILSEQ, "illegal byte sequence") \
|
||||
XX(ESOCKTNOSUPPORT, "socket type not supported") \
|
||||
XX(ENODATA, "no data available") \
|
||||
XX(EUNATCH, "protocol driver not attached") \
|
||||
XX(ENOEXEC, "exec format error") \
|
||||
|
||||
#define UV_HANDLE_TYPE_MAP(XX) \
|
||||
XX(ASYNC, async) \
|
||||
@ -253,7 +262,9 @@ typedef struct uv_metrics_s uv_metrics_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL = 0,
|
||||
UV_METRICS_IDLE_TIME
|
||||
UV_METRICS_IDLE_TIME,
|
||||
UV_LOOP_USE_IO_URING_SQPOLL
|
||||
#define UV_LOOP_USE_IO_URING_SQPOLL UV_LOOP_USE_IO_URING_SQPOLL
|
||||
} uv_loop_option;
|
||||
|
||||
typedef enum {
|
||||
@ -283,13 +294,13 @@ UV_EXTERN int uv_loop_init(uv_loop_t* loop);
|
||||
UV_EXTERN int uv_loop_close(uv_loop_t* loop);
|
||||
/*
|
||||
* NOTE:
|
||||
* This function is DEPRECATED (to be removed after 0.12), users should
|
||||
* This function is DEPRECATED, users should
|
||||
* allocate the loop manually and use uv_loop_init instead.
|
||||
*/
|
||||
UV_EXTERN uv_loop_t* uv_loop_new(void);
|
||||
/*
|
||||
* NOTE:
|
||||
* This function is DEPRECATED (to be removed after 0.12). Users should use
|
||||
* This function is DEPRECATED. Users should use
|
||||
* uv_loop_close and free the memory manually instead.
|
||||
*/
|
||||
UV_EXTERN void uv_loop_delete(uv_loop_t*);
|
||||
@ -459,7 +470,7 @@ struct uv_shutdown_s {
|
||||
uv_handle_type type; \
|
||||
/* private */ \
|
||||
uv_close_cb close_cb; \
|
||||
void* handle_queue[2]; \
|
||||
struct uv__queue handle_queue; \
|
||||
union { \
|
||||
int fd; \
|
||||
void* reserved[4]; \
|
||||
@ -597,7 +608,18 @@ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
|
||||
|
||||
enum uv_tcp_flags {
|
||||
/* Used with uv_tcp_bind, when an IPv6 address is used. */
|
||||
UV_TCP_IPV6ONLY = 1
|
||||
UV_TCP_IPV6ONLY = 1,
|
||||
|
||||
/* Enable SO_REUSEPORT socket option when binding the handle.
|
||||
* This allows completely duplicate bindings by multiple processes
|
||||
* or threads if they all set SO_REUSEPORT before binding the port.
|
||||
* Incoming connections are distributed across the participating
|
||||
* listener sockets.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_TCP_REUSEPORT = 2,
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
|
||||
@ -638,10 +660,13 @@ enum uv_udp_flags {
|
||||
UV_UDP_PARTIAL = 2,
|
||||
/*
|
||||
* Indicates if SO_REUSEADDR will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
|
||||
* Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
|
||||
* multiple threads or processes can bind to the same address without error
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs (except for
|
||||
* DragonFlyBSD), OS X, and other platforms where SO_REUSEPORTs don't
|
||||
* have the capability of load balancing, as the opposite of what
|
||||
* UV_UDP_REUSEPORT would do. On other Unix platforms, it sets the
|
||||
* SO_REUSEADDR flag. What that means is that multiple threads or
|
||||
* processes can bind to the same address without error (provided
|
||||
* they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
UV_UDP_REUSEADDR = 4,
|
||||
@ -664,6 +689,18 @@ enum uv_udp_flags {
|
||||
* This flag is no-op on platforms other than Linux.
|
||||
*/
|
||||
UV_UDP_LINUX_RECVERR = 32,
|
||||
/*
|
||||
* Indicates if SO_REUSEPORT will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket option on supported platforms.
|
||||
* Unlike UV_UDP_REUSEADDR, this flag will make multiple threads or
|
||||
* processes that are binding to the same address and port "share"
|
||||
* the port, which means incoming datagrams are distributed across
|
||||
* the receiving sockets among threads or processes.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_UDP_REUSEPORT = 64,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
@ -740,6 +777,12 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
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_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb);
|
||||
@ -763,10 +806,15 @@ struct uv_tty_s {
|
||||
typedef enum {
|
||||
/* Initial/normal terminal mode */
|
||||
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,
|
||||
/* 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;
|
||||
|
||||
typedef enum {
|
||||
@ -801,6 +849,10 @@ inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
|
||||
|
||||
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
|
||||
|
||||
enum {
|
||||
UV_PIPE_NO_TRUNCATE = 1u << 0
|
||||
};
|
||||
|
||||
/*
|
||||
* uv_pipe_t is a subclass of uv_stream_t.
|
||||
*
|
||||
@ -817,10 +869,20 @@ struct uv_pipe_s {
|
||||
UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
|
||||
UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
|
||||
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
|
||||
UV_EXTERN int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
const char* name,
|
||||
size_t namelen,
|
||||
unsigned int flags);
|
||||
UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
uv_connect_cb cb);
|
||||
UV_EXTERN int uv_pipe_connect2(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
size_t namelen,
|
||||
unsigned int flags,
|
||||
uv_connect_cb cb);
|
||||
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
|
||||
char* buffer,
|
||||
size_t* size);
|
||||
@ -1085,7 +1147,14 @@ enum uv_process_flags {
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6),
|
||||
/*
|
||||
* On Windows, if the path to the program to execute, specified in
|
||||
* uv_process_options_t's file field, has a directory component,
|
||||
* search for the exact file name before trying variants with
|
||||
* extensions like '.exe' or '.cmd'.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7)
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1232,6 +1301,7 @@ typedef struct {
|
||||
} uv_rusage_t;
|
||||
|
||||
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_tmpdir(char* buffer, size_t* size);
|
||||
@ -1263,6 +1333,17 @@ UV_EXTERN uv_pid_t uv_os_getppid(void);
|
||||
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
|
||||
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
|
||||
|
||||
enum {
|
||||
UV_THREAD_PRIORITY_HIGHEST = 2,
|
||||
UV_THREAD_PRIORITY_ABOVE_NORMAL = 1,
|
||||
UV_THREAD_PRIORITY_NORMAL = 0,
|
||||
UV_THREAD_PRIORITY_BELOW_NORMAL = -1,
|
||||
UV_THREAD_PRIORITY_LOWEST = -2,
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_thread_getpriority(uv_thread_t tid, int* priority);
|
||||
UV_EXTERN int uv_thread_setpriority(uv_thread_t tid, int priority);
|
||||
|
||||
UV_EXTERN unsigned int uv_available_parallelism(void);
|
||||
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
|
||||
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
|
||||
@ -1510,6 +1591,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
|
||||
const char* path,
|
||||
int mode,
|
||||
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_fs_t* req,
|
||||
const char* path,
|
||||
@ -1802,6 +1885,7 @@ UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv);
|
||||
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_detach(uv_thread_t* tid);
|
||||
|
||||
typedef enum {
|
||||
UV_THREAD_NO_FLAGS = 0x00,
|
||||
@ -1831,6 +1915,9 @@ UV_EXTERN int uv_thread_getcpu(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_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. */
|
||||
#define XX(_, name) uv_ ## name ## _t name;
|
||||
@ -1849,7 +1936,7 @@ struct uv_loop_s {
|
||||
void* data;
|
||||
/* Loop reference counting. */
|
||||
unsigned int active_handles;
|
||||
void* handle_queue[2];
|
||||
struct uv__queue handle_queue;
|
||||
union {
|
||||
void* unused;
|
||||
unsigned int count;
|
||||
@ -1864,6 +1951,18 @@ struct uv_loop_s {
|
||||
UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
|
||||
UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
|
||||
|
||||
/* Unicode utilities needed for dealing with Windows. */
|
||||
UV_EXTERN size_t uv_utf16_length_as_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len);
|
||||
UV_EXTERN int uv_utf16_to_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len,
|
||||
char** wtf8_ptr,
|
||||
size_t* wtf8_len_ptr);
|
||||
UV_EXTERN ssize_t uv_wtf8_length_as_utf16(const char* wtf8);
|
||||
UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8,
|
||||
uint16_t* utf16,
|
||||
size_t utf16_len);
|
||||
|
||||
/* Don't export the private CPP symbols. */
|
||||
#undef UV_HANDLE_TYPE_PRIVATE
|
||||
#undef UV_REQ_TYPE_PRIVATE
|
||||
|
@ -40,7 +40,7 @@
|
||||
void* cf_state; \
|
||||
uv_mutex_t cf_mutex; \
|
||||
uv_sem_t cf_sem; \
|
||||
void* cf_signals[2]; \
|
||||
struct uv__queue cf_signals; \
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
uv__io_t event_watcher; \
|
||||
@ -48,8 +48,8 @@
|
||||
int realpath_len; \
|
||||
int cf_flags; \
|
||||
uv_async_t* cf_cb; \
|
||||
void* cf_events[2]; \
|
||||
void* cf_member[2]; \
|
||||
struct uv__queue cf_events; \
|
||||
struct uv__queue cf_member; \
|
||||
int cf_error; \
|
||||
uv_mutex_t cf_mutex; \
|
||||
|
||||
|
@ -468,4 +468,16 @@
|
||||
# define UV__ENODATA (-4024)
|
||||
#endif
|
||||
|
||||
#if defined(EUNATCH) && !defined(_WIN32)
|
||||
# define UV__EUNATCH UV__ERR(EUNATCH)
|
||||
#else
|
||||
# define UV__EUNATCH (-4023)
|
||||
#endif
|
||||
|
||||
#if defined(ENOEXEC) && !defined(_WIN32)
|
||||
# define UV__ENOEXEC UV__ERR(ENOEXEC)
|
||||
#else
|
||||
# define UV__ENOEXEC (-4022)
|
||||
#endif
|
||||
|
||||
#endif /* UV_ERRNO_H_ */
|
||||
|
@ -28,7 +28,7 @@
|
||||
int inotify_fd; \
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
void* watchers[2]; \
|
||||
struct uv__queue watchers; \
|
||||
int wd; \
|
||||
|
||||
#endif /* UV_LINUX_H */
|
||||
|
@ -31,7 +31,7 @@ struct uv__work {
|
||||
void (*work)(struct uv__work *w);
|
||||
void (*done)(struct uv__work *w, int status);
|
||||
struct uv_loop_s* loop;
|
||||
void* wq[2];
|
||||
struct uv__queue wq;
|
||||
};
|
||||
|
||||
#endif /* UV_THREADPOOL_H_ */
|
||||
|
@ -35,21 +35,7 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file defines data structures for different types of trees:
|
||||
* splay trees and red-black trees.
|
||||
*
|
||||
* A splay tree is a self-organizing data structure. Every operation
|
||||
* on the tree causes a splay to happen. The splay moves the requested
|
||||
* node to the root of the tree and partly rebalances it.
|
||||
*
|
||||
* This has the benefit that request locality causes faster lookups as
|
||||
* the requested nodes move to the top of the tree. On the other hand,
|
||||
* every lookup causes memory writes.
|
||||
*
|
||||
* The Balance Theorem bounds the total access time for m operations
|
||||
* and n inserts on an initially empty tree as O((m + n)lg n). The
|
||||
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
|
||||
*
|
||||
* This file defines data structures for red-black trees.
|
||||
* A red-black tree is a binary search tree with the node color as an
|
||||
* extra attribute. It fulfills a set of conditions:
|
||||
* - every search path from the root to a leaf consists of the
|
||||
@ -61,239 +47,6 @@
|
||||
* The maximum height of a red-black tree is 2lg (n+1).
|
||||
*/
|
||||
|
||||
#define SPLAY_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sph_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define SPLAY_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define SPLAY_INIT(root) do { \
|
||||
(root)->sph_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *spe_left; /* left element */ \
|
||||
struct type *spe_right; /* right element */ \
|
||||
}
|
||||
|
||||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||
#define SPLAY_ROOT(head) (head)->sph_root
|
||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||
|
||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
|
||||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||
void name##_SPLAY(struct name *, struct type *); \
|
||||
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return(NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||
return (head->sph_root); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
name##_SPLAY(head, elm); \
|
||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||
elm = SPLAY_RIGHT(elm, field); \
|
||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||
elm = SPLAY_LEFT(elm, field); \
|
||||
} \
|
||||
} else \
|
||||
elm = NULL; \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
||||
{ \
|
||||
name##_SPLAY_MINMAX(head, val); \
|
||||
return (SPLAY_ROOT(head)); \
|
||||
}
|
||||
|
||||
/* Main splay operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||
struct type * \
|
||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||
} else { \
|
||||
int __comp; \
|
||||
name##_SPLAY(head, elm); \
|
||||
__comp = (cmp)(elm, (head)->sph_root); \
|
||||
if(__comp < 0) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||
} else if (__comp > 0) { \
|
||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||
} else \
|
||||
return ((head)->sph_root); \
|
||||
} \
|
||||
(head)->sph_root = (elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
struct type * \
|
||||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *__tmp; \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return (NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} else { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
name##_SPLAY(head, elm); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
name##_SPLAY(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
int __comp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) > 0){ \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
} \
|
||||
\
|
||||
/* Splay with either the minimum or the maximum element \
|
||||
* Used to find minimum or maximum element in tree. \
|
||||
*/ \
|
||||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
for (;;) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp > 0) { \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
}
|
||||
|
||||
#define SPLAY_NEGINF -1
|
||||
#define SPLAY_INF 1
|
||||
|
||||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||
|
||||
#define SPLAY_FOREACH(x, name, head) \
|
||||
for ((x) = SPLAY_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = SPLAY_NEXT(name, head, x))
|
||||
|
||||
/* Macros that define a red-black tree */
|
||||
#define RB_HEAD(name, type) \
|
||||
struct name { \
|
||||
@ -730,8 +483,8 @@ name##_RB_MINMAX(struct name *head, int val) \
|
||||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||
#define RB_NEXT(name, x) name##_RB_NEXT(x)
|
||||
#define RB_PREV(name, x) name##_RB_PREV(x)
|
||||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||
|
||||
|
@ -92,8 +92,8 @@ typedef struct uv__io_s uv__io_t;
|
||||
|
||||
struct uv__io_s {
|
||||
uv__io_cb cb;
|
||||
void* pending_queue[2];
|
||||
void* watcher_queue[2];
|
||||
struct uv__queue pending_queue;
|
||||
struct uv__queue watcher_queue;
|
||||
unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
|
||||
unsigned int events; /* Current event mask. */
|
||||
int fd;
|
||||
@ -220,21 +220,21 @@ typedef struct {
|
||||
#define UV_LOOP_PRIVATE_FIELDS \
|
||||
unsigned long flags; \
|
||||
int backend_fd; \
|
||||
void* pending_queue[2]; \
|
||||
void* watcher_queue[2]; \
|
||||
struct uv__queue pending_queue; \
|
||||
struct uv__queue watcher_queue; \
|
||||
uv__io_t** watchers; \
|
||||
unsigned int nwatchers; \
|
||||
unsigned int nfds; \
|
||||
void* wq[2]; \
|
||||
struct uv__queue wq; \
|
||||
uv_mutex_t wq_mutex; \
|
||||
uv_async_t wq_async; \
|
||||
uv_rwlock_t cloexec_lock; \
|
||||
uv_handle_t* closing_handles; \
|
||||
void* process_handles[2]; \
|
||||
void* prepare_handles[2]; \
|
||||
void* check_handles[2]; \
|
||||
void* idle_handles[2]; \
|
||||
void* async_handles[2]; \
|
||||
struct uv__queue process_handles; \
|
||||
struct uv__queue prepare_handles; \
|
||||
struct uv__queue check_handles; \
|
||||
struct uv__queue idle_handles; \
|
||||
struct uv__queue async_handles; \
|
||||
void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
|
||||
uv__io_t async_io_watcher; \
|
||||
int async_wfd; \
|
||||
@ -257,7 +257,7 @@ typedef struct {
|
||||
#define UV_PRIVATE_REQ_TYPES /* empty */
|
||||
|
||||
#define UV_WRITE_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
unsigned int write_index; \
|
||||
uv_buf_t* bufs; \
|
||||
unsigned int nbufs; \
|
||||
@ -265,13 +265,16 @@ typedef struct {
|
||||
uv_buf_t bufsml[4]; \
|
||||
|
||||
#define UV_CONNECT_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
|
||||
#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
|
||||
|
||||
#define UV_UDP_SEND_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
struct sockaddr_storage addr; \
|
||||
struct uv__queue queue; \
|
||||
union { \
|
||||
struct sockaddr addr; \
|
||||
struct sockaddr_storage storage; \
|
||||
} u; \
|
||||
unsigned int nbufs; \
|
||||
uv_buf_t* bufs; \
|
||||
ssize_t status; \
|
||||
@ -286,8 +289,8 @@ typedef struct {
|
||||
uv_connect_t *connect_req; \
|
||||
uv_shutdown_t *shutdown_req; \
|
||||
uv__io_t io_watcher; \
|
||||
void* write_queue[2]; \
|
||||
void* write_completed_queue[2]; \
|
||||
struct uv__queue write_queue; \
|
||||
struct uv__queue write_completed_queue; \
|
||||
uv_connection_cb connection_cb; \
|
||||
int delayed_error; \
|
||||
int accepted_fd; \
|
||||
@ -300,35 +303,38 @@ typedef struct {
|
||||
uv_alloc_cb alloc_cb; \
|
||||
uv_udp_recv_cb recv_cb; \
|
||||
uv__io_t io_watcher; \
|
||||
void* write_queue[2]; \
|
||||
void* write_completed_queue[2]; \
|
||||
struct uv__queue write_queue; \
|
||||
struct uv__queue write_completed_queue; \
|
||||
|
||||
#define UV_PIPE_PRIVATE_FIELDS \
|
||||
const char* pipe_fname; /* strdup'ed */
|
||||
const char* pipe_fname; /* NULL or strdup'ed */
|
||||
|
||||
#define UV_POLL_PRIVATE_FIELDS \
|
||||
uv__io_t io_watcher;
|
||||
|
||||
#define UV_PREPARE_PRIVATE_FIELDS \
|
||||
uv_prepare_cb prepare_cb; \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
|
||||
#define UV_CHECK_PRIVATE_FIELDS \
|
||||
uv_check_cb check_cb; \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
|
||||
#define UV_IDLE_PRIVATE_FIELDS \
|
||||
uv_idle_cb idle_cb; \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
|
||||
#define UV_ASYNC_PRIVATE_FIELDS \
|
||||
uv_async_cb async_cb; \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
int pending; \
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
uv_timer_cb timer_cb; \
|
||||
void* heap_node[3]; \
|
||||
union { \
|
||||
void* heap[3]; \
|
||||
struct uv__queue queue; \
|
||||
} node; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id;
|
||||
@ -352,7 +358,7 @@ typedef struct {
|
||||
int retcode;
|
||||
|
||||
#define UV_PROCESS_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
struct uv__queue queue; \
|
||||
int status; \
|
||||
|
||||
#define UV_FS_PRIVATE_FIELDS \
|
||||
@ -417,6 +423,8 @@ typedef struct {
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(__linux__) && defined(__x86_64__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(__linux__) && defined(__loongarch__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(O_DIRECT)
|
||||
# define UV_FS_O_DIRECT O_DIRECT
|
||||
#else
|
||||
|
@ -31,8 +31,8 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 44
|
||||
#define UV_VERSION_PATCH 3
|
||||
#define UV_VERSION_MINOR 50
|
||||
#define UV_VERSION_PATCH 1
|
||||
#define UV_VERSION_IS_RELEASE 0
|
||||
#define UV_VERSION_SUFFIX "dev"
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# define _WIN32_WINNT 0x0A00
|
||||
#endif
|
||||
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
@ -32,20 +32,12 @@ typedef intptr_t ssize_t;
|
||||
|
||||
#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
|
||||
# define LOCALE_INVARIANT 0x007f
|
||||
#endif
|
||||
|
||||
#include <mswsock.h>
|
||||
// Disable the typedef in mstcpip.h of MinGW.
|
||||
/* Disable the typedef in mstcpip.h of MinGW. */
|
||||
#define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
#define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
#define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
@ -70,7 +62,7 @@ typedef struct pollfd {
|
||||
# define S_IFLNK 0xA000
|
||||
#endif
|
||||
|
||||
// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h
|
||||
/* Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h */
|
||||
#if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO)
|
||||
# define S_IFIFO _S_IFIFO
|
||||
#endif
|
||||
@ -290,8 +282,8 @@ typedef struct {
|
||||
#define UV_ONCE_INIT { 0, NULL }
|
||||
|
||||
typedef struct uv_once_s {
|
||||
unsigned char ran;
|
||||
HANDLE event;
|
||||
unsigned char unused;
|
||||
INIT_ONCE init_once;
|
||||
} uv_once_t;
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
@ -357,7 +349,7 @@ typedef struct {
|
||||
/* Counter to started timer */ \
|
||||
uint64_t timer_counter; \
|
||||
/* Threadpool */ \
|
||||
void* wq[2]; \
|
||||
struct uv__queue wq; \
|
||||
uv_mutex_t wq_mutex; \
|
||||
uv_async_t wq_async;
|
||||
|
||||
@ -486,7 +478,7 @@ typedef struct {
|
||||
uint32_t payload_remaining; \
|
||||
uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
|
||||
} ipc_data_frame; \
|
||||
void* ipc_xfer_queue[2]; \
|
||||
struct uv__queue ipc_xfer_queue; \
|
||||
int ipc_xfer_queue_length; \
|
||||
uv_write_t* non_overlapped_writes_tail; \
|
||||
CRITICAL_SECTION readfile_thread_lock; \
|
||||
@ -507,8 +499,11 @@ typedef struct {
|
||||
union { \
|
||||
struct { \
|
||||
/* Used for readable TTY handles */ \
|
||||
/* TODO: remove me in v2.x. */ \
|
||||
HANDLE unused_; \
|
||||
union { \
|
||||
/* TODO: remove me in v2.x. */ \
|
||||
HANDLE unused_; \
|
||||
int mode; \
|
||||
} mode; \
|
||||
uv_buf_t read_line_buffer; \
|
||||
HANDLE read_raw_wait; \
|
||||
/* Fields used for translating win keystrokes into vt100 characters */ \
|
||||
@ -550,7 +545,10 @@ typedef struct {
|
||||
unsigned char events;
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
void* heap_node[3]; \
|
||||
union { \
|
||||
void* heap[3]; \
|
||||
struct uv__queue queue; \
|
||||
} node; \
|
||||
int unused; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat; \
|
||||
|
@ -51,7 +51,7 @@ struct poll_ctx {
|
||||
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
|
||||
static void poll_cb(uv_fs_t* req);
|
||||
static void timer_cb(uv_timer_t* timer);
|
||||
static void timer_close_cb(uv_handle_t* handle);
|
||||
static void timer_close_cb(uv_handle_t* timer);
|
||||
|
||||
static uv_stat_t zero_statbuf;
|
||||
|
||||
@ -139,6 +139,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
|
||||
struct poll_ctx* ctx;
|
||||
size_t required_len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!uv_is_active((uv_handle_t*)handle)) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
|
253
src/idna.c
253
src/idna.c
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
/* Copyright libuv contributors. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -18,11 +18,56 @@
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "uv-common.h"
|
||||
#include "idna.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> /* UINT_MAX */
|
||||
|
||||
|
||||
static int32_t uv__wtf8_decode1(const char** input) {
|
||||
uint32_t code_point;
|
||||
uint8_t b1;
|
||||
uint8_t b2;
|
||||
uint8_t b3;
|
||||
uint8_t b4;
|
||||
|
||||
b1 = **input;
|
||||
if (b1 <= 0x7F)
|
||||
return b1; /* ASCII code point */
|
||||
if (b1 < 0xC2)
|
||||
return -1; /* invalid: continuation byte */
|
||||
code_point = b1;
|
||||
|
||||
b2 = *++*input;
|
||||
if ((b2 & 0xC0) != 0x80)
|
||||
return -1; /* invalid: not a continuation byte */
|
||||
code_point = (code_point << 6) | (b2 & 0x3F);
|
||||
if (b1 <= 0xDF)
|
||||
return 0x7FF & code_point; /* two-byte character */
|
||||
|
||||
b3 = *++*input;
|
||||
if ((b3 & 0xC0) != 0x80)
|
||||
return -1; /* invalid: not a continuation byte */
|
||||
code_point = (code_point << 6) | (b3 & 0x3F);
|
||||
if (b1 <= 0xEF)
|
||||
return 0xFFFF & code_point; /* three-byte character */
|
||||
|
||||
b4 = *++*input;
|
||||
if ((b4 & 0xC0) != 0x80)
|
||||
return -1; /* invalid: not a continuation byte */
|
||||
code_point = (code_point << 6) | (b4 & 0x3F);
|
||||
if (b1 <= 0xF4) {
|
||||
code_point &= 0x1FFFFF;
|
||||
if (code_point <= 0x10FFFF)
|
||||
return code_point; /* four-byte character */
|
||||
}
|
||||
|
||||
/* code point too large */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
const char* pe,
|
||||
unsigned a) {
|
||||
@ -89,6 +134,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
unsigned a;
|
||||
|
||||
@ -102,6 +148,7 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
return uv__utf8_decode1_slow(p, pe, a);
|
||||
}
|
||||
|
||||
|
||||
static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
char** d, char* de) {
|
||||
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
@ -267,13 +314,17 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
return 0;
|
||||
}
|
||||
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
|
||||
ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
const char* si;
|
||||
const char* st;
|
||||
unsigned c;
|
||||
char* ds;
|
||||
int rc;
|
||||
|
||||
if (s == se)
|
||||
return UV_EINVAL;
|
||||
|
||||
ds = d;
|
||||
|
||||
si = s;
|
||||
@ -308,8 +359,202 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (d < de)
|
||||
*d++ = '\0';
|
||||
if (d >= de)
|
||||
return UV_EINVAL;
|
||||
|
||||
*d++ = '\0';
|
||||
return d - ds; /* Number of bytes written. */
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv_wtf8_length_as_utf16(const char* source_ptr) {
|
||||
size_t w_target_len = 0;
|
||||
int32_t code_point;
|
||||
|
||||
do {
|
||||
code_point = uv__wtf8_decode1(&source_ptr);
|
||||
if (code_point < 0)
|
||||
return -1;
|
||||
if (code_point > 0xFFFF)
|
||||
w_target_len++;
|
||||
w_target_len++;
|
||||
} while (*source_ptr++);
|
||||
|
||||
return w_target_len;
|
||||
}
|
||||
|
||||
|
||||
void uv_wtf8_to_utf16(const char* source_ptr,
|
||||
uint16_t* w_target,
|
||||
size_t w_target_len) {
|
||||
int32_t code_point;
|
||||
|
||||
do {
|
||||
code_point = uv__wtf8_decode1(&source_ptr);
|
||||
/* uv_wtf8_length_as_utf16 should have been called and checked first. */
|
||||
assert(code_point >= 0);
|
||||
if (code_point > 0xFFFF) {
|
||||
assert(code_point < 0x10FFFF);
|
||||
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
|
||||
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
|
||||
w_target_len -= 2;
|
||||
} else {
|
||||
*w_target++ = code_point;
|
||||
w_target_len -= 1;
|
||||
}
|
||||
} while (*source_ptr++);
|
||||
|
||||
(void)w_target_len;
|
||||
assert(w_target_len == 0);
|
||||
}
|
||||
|
||||
|
||||
static int32_t uv__get_surrogate_value(const uint16_t* w_source_ptr,
|
||||
ssize_t w_source_len) {
|
||||
uint16_t u;
|
||||
uint16_t next;
|
||||
|
||||
u = w_source_ptr[0];
|
||||
if (u >= 0xD800 && u <= 0xDBFF && w_source_len != 1) {
|
||||
next = w_source_ptr[1];
|
||||
if (next >= 0xDC00 && next <= 0xDFFF)
|
||||
return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
size_t uv_utf16_length_as_wtf8(const uint16_t* w_source_ptr,
|
||||
ssize_t w_source_len) {
|
||||
size_t target_len;
|
||||
int32_t code_point;
|
||||
|
||||
target_len = 0;
|
||||
while (w_source_len) {
|
||||
code_point = uv__get_surrogate_value(w_source_ptr, w_source_len);
|
||||
/* Can be invalid UTF-8 but must be valid WTF-8. */
|
||||
assert(code_point >= 0);
|
||||
if (w_source_len < 0 && code_point == 0)
|
||||
break;
|
||||
if (code_point < 0x80)
|
||||
target_len += 1;
|
||||
else if (code_point < 0x800)
|
||||
target_len += 2;
|
||||
else if (code_point < 0x10000)
|
||||
target_len += 3;
|
||||
else {
|
||||
target_len += 4;
|
||||
w_source_ptr++;
|
||||
if (w_source_len > 0)
|
||||
w_source_len--;
|
||||
}
|
||||
w_source_ptr++;
|
||||
if (w_source_len > 0)
|
||||
w_source_len--;
|
||||
}
|
||||
|
||||
return target_len;
|
||||
}
|
||||
|
||||
|
||||
int uv_utf16_to_wtf8(const uint16_t* w_source_ptr,
|
||||
ssize_t w_source_len,
|
||||
char** target_ptr,
|
||||
size_t* target_len_ptr) {
|
||||
size_t target_len;
|
||||
char* target;
|
||||
char* target_end;
|
||||
int32_t code_point;
|
||||
|
||||
/* If *target_ptr is provided, then *target_len_ptr must be its length
|
||||
* (excluding space for NUL), otherwise we will compute the target_len_ptr
|
||||
* length and may return a new allocation in *target_ptr if target_ptr is
|
||||
* provided. */
|
||||
if (target_ptr == NULL || *target_ptr == NULL) {
|
||||
target_len = uv_utf16_length_as_wtf8(w_source_ptr, w_source_len);
|
||||
if (target_len_ptr != NULL)
|
||||
*target_len_ptr = target_len;
|
||||
} else {
|
||||
target_len = *target_len_ptr;
|
||||
}
|
||||
|
||||
if (target_ptr == NULL)
|
||||
return 0;
|
||||
|
||||
if (*target_ptr == NULL) {
|
||||
target = uv__malloc(target_len + 1);
|
||||
if (target == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
*target_ptr = target;
|
||||
} else {
|
||||
target = *target_ptr;
|
||||
}
|
||||
|
||||
target_end = target + target_len;
|
||||
|
||||
while (target != target_end && w_source_len) {
|
||||
code_point = uv__get_surrogate_value(w_source_ptr, w_source_len);
|
||||
/* Can be invalid UTF-8 but must be valid WTF-8. */
|
||||
assert(code_point >= 0);
|
||||
if (w_source_len < 0 && code_point == 0) {
|
||||
w_source_len = 0;
|
||||
break;
|
||||
}
|
||||
if (code_point < 0x80) {
|
||||
*target++ = code_point;
|
||||
} else if (code_point < 0x800) {
|
||||
*target++ = 0xC0 | (code_point >> 6);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | (code_point & 0x3F);
|
||||
} else if (code_point < 0x10000) {
|
||||
*target++ = 0xE0 | (code_point >> 12);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | (code_point & 0x3F);
|
||||
} else {
|
||||
*target++ = 0xF0 | (code_point >> 18);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | ((code_point >> 12) & 0x3F);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
|
||||
if (target == target_end)
|
||||
break;
|
||||
*target++ = 0x80 | (code_point & 0x3F);
|
||||
/* uv__get_surrogate_value consumed 2 input characters */
|
||||
w_source_ptr++;
|
||||
if (w_source_len > 0)
|
||||
w_source_len--;
|
||||
}
|
||||
target_len = target - *target_ptr;
|
||||
w_source_ptr++;
|
||||
if (w_source_len > 0)
|
||||
w_source_len--;
|
||||
}
|
||||
|
||||
if (target != target_end && target_len_ptr != NULL)
|
||||
/* Did not fill all of the provided buffer, so update the target_len_ptr
|
||||
* output with the space used. */
|
||||
*target_len_ptr = target - *target_ptr;
|
||||
|
||||
/* Check if input fit into target exactly. */
|
||||
if (w_source_len < 0 && target == target_end && w_source_ptr[0] == 0)
|
||||
w_source_len = 0;
|
||||
|
||||
*target++ = '\0';
|
||||
|
||||
/* Characters remained after filling the buffer, compute the remaining length now. */
|
||||
if (w_source_len) {
|
||||
if (target_len_ptr != NULL)
|
||||
*target_len_ptr = target_len + uv_utf16_length_as_wtf8(w_source_ptr, w_source_len);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
/* Copyright libuv contributors. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -26,6 +26,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe);
|
||||
* is the number of bytes written to |d|, including the trailing nul byte.
|
||||
* A return value < 0 is a libuv error code. |s| and |d| can not overlap.
|
||||
*/
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
|
||||
ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de);
|
||||
|
||||
#endif /* UV_SRC_IDNA_H_ */
|
||||
|
132
src/queue.h
132
src/queue.h
@ -18,91 +18,73 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void *QUEUE[2];
|
||||
#define uv__queue_data(pointer, type, field) \
|
||||
((type*) ((char*) (pointer) - offsetof(type, field)))
|
||||
|
||||
/* Private macros. */
|
||||
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
|
||||
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
|
||||
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
|
||||
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
|
||||
#define uv__queue_foreach(q, h) \
|
||||
for ((q) = (h)->next; (q) != (h); (q) = (q)->next)
|
||||
|
||||
/* Public macros. */
|
||||
#define QUEUE_DATA(ptr, type, field) \
|
||||
((type *) ((char *) (ptr) - offsetof(type, field)))
|
||||
static inline void uv__queue_init(struct uv__queue* q) {
|
||||
q->next = q;
|
||||
q->prev = q;
|
||||
}
|
||||
|
||||
/* Important note: mutating the list while QUEUE_FOREACH is
|
||||
* iterating over its elements results in undefined behavior.
|
||||
*/
|
||||
#define QUEUE_FOREACH(q, h) \
|
||||
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
|
||||
static inline int uv__queue_empty(const struct uv__queue* q) {
|
||||
return q == q->next;
|
||||
}
|
||||
|
||||
#define QUEUE_EMPTY(q) \
|
||||
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
|
||||
static inline struct uv__queue* uv__queue_head(const struct uv__queue* q) {
|
||||
return q->next;
|
||||
}
|
||||
|
||||
#define QUEUE_HEAD(q) \
|
||||
(QUEUE_NEXT(q))
|
||||
static inline struct uv__queue* uv__queue_next(const struct uv__queue* q) {
|
||||
return q->next;
|
||||
}
|
||||
|
||||
#define QUEUE_INIT(q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (q); \
|
||||
QUEUE_PREV(q) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_add(struct uv__queue* h, struct uv__queue* n) {
|
||||
h->prev->next = n->next;
|
||||
n->next->prev = h->prev;
|
||||
h->prev = n->prev;
|
||||
h->prev->next = h;
|
||||
}
|
||||
|
||||
#define QUEUE_ADD(h, n) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
|
||||
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(n); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_split(struct uv__queue* h,
|
||||
struct uv__queue* q,
|
||||
struct uv__queue* n) {
|
||||
n->prev = h->prev;
|
||||
n->prev->next = n;
|
||||
n->next = q;
|
||||
h->prev = q->prev;
|
||||
h->prev->next = h;
|
||||
q->prev = n;
|
||||
}
|
||||
|
||||
#define QUEUE_SPLIT(h, q, n) \
|
||||
do { \
|
||||
QUEUE_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(n) = (n); \
|
||||
QUEUE_NEXT(n) = (q); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(q); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
QUEUE_PREV(q) = (n); \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_move(struct uv__queue* h, struct uv__queue* n) {
|
||||
if (uv__queue_empty(h))
|
||||
uv__queue_init(n);
|
||||
else
|
||||
uv__queue_split(h, h->next, n);
|
||||
}
|
||||
|
||||
#define QUEUE_MOVE(h, n) \
|
||||
do { \
|
||||
if (QUEUE_EMPTY(h)) \
|
||||
QUEUE_INIT(n); \
|
||||
else { \
|
||||
QUEUE* q = QUEUE_HEAD(h); \
|
||||
QUEUE_SPLIT(h, q, n); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_insert_head(struct uv__queue* h,
|
||||
struct uv__queue* q) {
|
||||
q->next = h->next;
|
||||
q->prev = h;
|
||||
q->next->prev = q;
|
||||
h->next = q;
|
||||
}
|
||||
|
||||
#define QUEUE_INSERT_HEAD(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
|
||||
QUEUE_PREV(q) = (h); \
|
||||
QUEUE_NEXT_PREV(q) = (q); \
|
||||
QUEUE_NEXT(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_insert_tail(struct uv__queue* h,
|
||||
struct uv__queue* q) {
|
||||
q->next = h;
|
||||
q->prev = h->prev;
|
||||
q->prev->next = q;
|
||||
h->prev = q;
|
||||
}
|
||||
|
||||
#define QUEUE_INSERT_TAIL(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (h); \
|
||||
QUEUE_PREV(q) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(q) = (q); \
|
||||
QUEUE_PREV(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_REMOVE(q) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
|
||||
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
|
||||
} \
|
||||
while (0)
|
||||
static inline void uv__queue_remove(struct uv__queue* q) {
|
||||
q->prev->next = q->next;
|
||||
q->next->prev = q->prev;
|
||||
}
|
||||
|
||||
#endif /* QUEUE_H_ */
|
||||
|
@ -82,7 +82,7 @@ static void uv__random_done(struct uv__work* w, int status) {
|
||||
uv_random_t* req;
|
||||
|
||||
req = container_of(w, uv_random_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (status == 0)
|
||||
status = req->status;
|
||||
|
@ -37,10 +37,10 @@ static unsigned int slow_io_work_running;
|
||||
static unsigned int nthreads;
|
||||
static uv_thread_t* threads;
|
||||
static uv_thread_t default_threads[4];
|
||||
static QUEUE exit_message;
|
||||
static QUEUE wq;
|
||||
static QUEUE run_slow_work_message;
|
||||
static QUEUE slow_io_pending_wq;
|
||||
static struct uv__queue exit_message;
|
||||
static struct uv__queue wq;
|
||||
static struct uv__queue run_slow_work_message;
|
||||
static struct uv__queue slow_io_pending_wq;
|
||||
|
||||
static unsigned int slow_work_thread_threshold(void) {
|
||||
return (nthreads + 1) / 2;
|
||||
@ -56,9 +56,10 @@ static void uv__cancelled(struct uv__work* w) {
|
||||
*/
|
||||
static void worker(void* arg) {
|
||||
struct uv__work* w;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
int is_slow_work;
|
||||
|
||||
uv_thread_setname("libuv-worker");
|
||||
uv_sem_post((uv_sem_t*) arg);
|
||||
arg = NULL;
|
||||
|
||||
@ -68,49 +69,49 @@ static void worker(void* arg) {
|
||||
|
||||
/* Keep waiting while either no work is present or only slow I/O
|
||||
and we're at the threshold for that. */
|
||||
while (QUEUE_EMPTY(&wq) ||
|
||||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
|
||||
QUEUE_NEXT(&run_slow_work_message) == &wq &&
|
||||
while (uv__queue_empty(&wq) ||
|
||||
(uv__queue_head(&wq) == &run_slow_work_message &&
|
||||
uv__queue_next(&run_slow_work_message) == &wq &&
|
||||
slow_io_work_running >= slow_work_thread_threshold())) {
|
||||
idle_threads += 1;
|
||||
uv_cond_wait(&cond, &mutex);
|
||||
idle_threads -= 1;
|
||||
}
|
||||
|
||||
q = QUEUE_HEAD(&wq);
|
||||
q = uv__queue_head(&wq);
|
||||
if (q == &exit_message) {
|
||||
uv_cond_signal(&cond);
|
||||
uv_mutex_unlock(&mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q); /* Signal uv_cancel() that the work req is executing. */
|
||||
|
||||
is_slow_work = 0;
|
||||
if (q == &run_slow_work_message) {
|
||||
/* If we're at the slow I/O threshold, re-schedule until after all
|
||||
other work in the queue is done. */
|
||||
if (slow_io_work_running >= slow_work_thread_threshold()) {
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
uv__queue_insert_tail(&wq, q);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we encountered a request to run slow I/O work but there is none
|
||||
to run, that means it's cancelled => Start over. */
|
||||
if (QUEUE_EMPTY(&slow_io_pending_wq))
|
||||
if (uv__queue_empty(&slow_io_pending_wq))
|
||||
continue;
|
||||
|
||||
is_slow_work = 1;
|
||||
slow_io_work_running++;
|
||||
|
||||
q = QUEUE_HEAD(&slow_io_pending_wq);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
q = uv__queue_head(&slow_io_pending_wq);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
|
||||
/* If there is more slow I/O work, schedule it to be run as well. */
|
||||
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
|
||||
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
|
||||
if (!uv__queue_empty(&slow_io_pending_wq)) {
|
||||
uv__queue_insert_tail(&wq, &run_slow_work_message);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
}
|
||||
@ -118,13 +119,13 @@ static void worker(void* arg) {
|
||||
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
w = QUEUE_DATA(q, struct uv__work, wq);
|
||||
w = uv__queue_data(q, struct uv__work, wq);
|
||||
w->work(w);
|
||||
|
||||
uv_mutex_lock(&w->loop->wq_mutex);
|
||||
w->work = NULL; /* Signal uv_cancel() that the work req is done
|
||||
executing. */
|
||||
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
|
||||
uv__queue_insert_tail(&w->loop->wq, &w->wq);
|
||||
uv_async_send(&w->loop->wq_async);
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
|
||||
@ -139,12 +140,12 @@ static void worker(void* arg) {
|
||||
}
|
||||
|
||||
|
||||
static void post(QUEUE* q, enum uv__work_kind kind) {
|
||||
static void post(struct uv__queue* q, enum uv__work_kind kind) {
|
||||
uv_mutex_lock(&mutex);
|
||||
if (kind == UV__WORK_SLOW_IO) {
|
||||
/* Insert into a separate queue. */
|
||||
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
|
||||
if (!QUEUE_EMPTY(&run_slow_work_message)) {
|
||||
uv__queue_insert_tail(&slow_io_pending_wq, q);
|
||||
if (!uv__queue_empty(&run_slow_work_message)) {
|
||||
/* Running slow I/O tasks is already scheduled => Nothing to do here.
|
||||
The worker that runs said other task will schedule this one as well. */
|
||||
uv_mutex_unlock(&mutex);
|
||||
@ -153,7 +154,7 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
|
||||
q = &run_slow_work_message;
|
||||
}
|
||||
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
uv__queue_insert_tail(&wq, q);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
uv_mutex_unlock(&mutex);
|
||||
@ -220,9 +221,9 @@ static void init_threads(void) {
|
||||
if (uv_mutex_init(&mutex))
|
||||
abort();
|
||||
|
||||
QUEUE_INIT(&wq);
|
||||
QUEUE_INIT(&slow_io_pending_wq);
|
||||
QUEUE_INIT(&run_slow_work_message);
|
||||
uv__queue_init(&wq);
|
||||
uv__queue_init(&slow_io_pending_wq);
|
||||
uv__queue_init(&run_slow_work_message);
|
||||
|
||||
if (uv_sem_init(&sem, 0))
|
||||
abort();
|
||||
@ -285,9 +286,9 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
||||
uv_mutex_lock(&mutex);
|
||||
uv_mutex_lock(&w->loop->wq_mutex);
|
||||
|
||||
cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
|
||||
cancelled = !uv__queue_empty(&w->wq) && w->work != NULL;
|
||||
if (cancelled)
|
||||
QUEUE_REMOVE(&w->wq);
|
||||
uv__queue_remove(&w->wq);
|
||||
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
uv_mutex_unlock(&mutex);
|
||||
@ -297,7 +298,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
||||
|
||||
w->work = uv__cancelled;
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
|
||||
uv__queue_insert_tail(&loop->wq, &w->wq);
|
||||
uv_async_send(&loop->wq_async);
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
|
||||
@ -308,21 +309,21 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
||||
void uv__work_done(uv_async_t* handle) {
|
||||
struct uv__work* w;
|
||||
uv_loop_t* loop;
|
||||
QUEUE* q;
|
||||
QUEUE wq;
|
||||
struct uv__queue* q;
|
||||
struct uv__queue wq;
|
||||
int err;
|
||||
int nevents;
|
||||
|
||||
loop = container_of(handle, uv_loop_t, wq_async);
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
QUEUE_MOVE(&loop->wq, &wq);
|
||||
uv__queue_move(&loop->wq, &wq);
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
|
||||
nevents = 0;
|
||||
|
||||
while (!QUEUE_EMPTY(&wq)) {
|
||||
q = QUEUE_HEAD(&wq);
|
||||
QUEUE_REMOVE(q);
|
||||
while (!uv__queue_empty(&wq)) {
|
||||
q = uv__queue_head(&wq);
|
||||
uv__queue_remove(q);
|
||||
|
||||
w = container_of(q, struct uv__work, wq);
|
||||
err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
|
||||
@ -356,7 +357,7 @@ static void uv__queue_done(struct uv__work* w, int err) {
|
||||
uv_work_t* req;
|
||||
|
||||
req = container_of(w, uv_work_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (req->after_work_cb == NULL)
|
||||
return;
|
||||
|
43
src/timer.c
43
src/timer.c
@ -40,8 +40,8 @@ static int timer_less_than(const struct heap_node* ha,
|
||||
const uv_timer_t* a;
|
||||
const uv_timer_t* b;
|
||||
|
||||
a = container_of(ha, uv_timer_t, heap_node);
|
||||
b = container_of(hb, uv_timer_t, heap_node);
|
||||
a = container_of(ha, uv_timer_t, node.heap);
|
||||
b = container_of(hb, uv_timer_t, node.heap);
|
||||
|
||||
if (a->timeout < b->timeout)
|
||||
return 1;
|
||||
@ -60,6 +60,7 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
handle->timer_cb = NULL;
|
||||
handle->timeout = 0;
|
||||
handle->repeat = 0;
|
||||
uv__queue_init(&handle->node.queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -73,8 +74,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
if (uv__is_closing(handle) || cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
uv_timer_stop(handle);
|
||||
uv_timer_stop(handle);
|
||||
|
||||
clamped_timeout = handle->loop->time + timeout;
|
||||
if (clamped_timeout < timeout)
|
||||
@ -87,7 +87,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
heap_insert(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
(struct heap_node*) &handle->node.heap,
|
||||
timer_less_than);
|
||||
uv__handle_start(handle);
|
||||
|
||||
@ -96,14 +96,16 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
|
||||
|
||||
int uv_timer_stop(uv_timer_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
heap_remove(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_stop(handle);
|
||||
if (uv__is_active(handle)) {
|
||||
heap_remove(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->node.heap,
|
||||
timer_less_than);
|
||||
uv__handle_stop(handle);
|
||||
} else {
|
||||
uv__queue_remove(&handle->node.queue);
|
||||
}
|
||||
|
||||
uv__queue_init(&handle->node.queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -148,7 +150,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
handle = container_of(heap_node, uv_timer_t, node.heap);
|
||||
if (handle->timeout <= loop->time)
|
||||
return 0;
|
||||
|
||||
@ -163,17 +165,30 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
void uv__run_timers(uv_loop_t* loop) {
|
||||
struct heap_node* heap_node;
|
||||
uv_timer_t* handle;
|
||||
struct uv__queue* queue_node;
|
||||
struct uv__queue ready_queue;
|
||||
|
||||
uv__queue_init(&ready_queue);
|
||||
|
||||
for (;;) {
|
||||
heap_node = heap_min(timer_heap(loop));
|
||||
if (heap_node == NULL)
|
||||
break;
|
||||
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
handle = container_of(heap_node, uv_timer_t, node.heap);
|
||||
if (handle->timeout > loop->time)
|
||||
break;
|
||||
|
||||
uv_timer_stop(handle);
|
||||
uv__queue_insert_tail(&ready_queue, &handle->node.queue);
|
||||
}
|
||||
|
||||
while (!uv__queue_empty(&ready_queue)) {
|
||||
queue_node = uv__queue_head(&ready_queue);
|
||||
uv__queue_remove(queue_node);
|
||||
uv__queue_init(queue_node);
|
||||
handle = container_of(queue_node, uv_timer_t, node.queue);
|
||||
|
||||
uv_timer_again(handle);
|
||||
handle->timer_cb(handle);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct pollfd pqry;
|
||||
struct pollfd* pe;
|
||||
struct poll_ctl pc;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv__io_t* w;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
@ -151,18 +151,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
while (!uv__queue_empty(&loop->watcher_queue)) {
|
||||
q = uv__queue_head(&loop->watcher_queue);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
w = uv__queue_data(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifreq *ifr, *p, flg;
|
||||
struct in6_ifreq if6;
|
||||
struct sockaddr_dl* sa_addr;
|
||||
size_t namelen;
|
||||
char* name;
|
||||
|
||||
ifc.ifc_req = NULL;
|
||||
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))
|
||||
|
||||
/* Count all up and running ipv4/ipv6 addresses */
|
||||
namelen = 0;
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
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))
|
||||
continue;
|
||||
|
||||
namelen += strlen(p->ifr_name) + 1;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
@ -1182,11 +1186,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
goto cleanup;
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||
if (*addresses == NULL) {
|
||||
r = UV_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
name = (char*) &(*addresses)[*count];
|
||||
address = *addresses;
|
||||
|
||||
ifr = ifc.ifc_req;
|
||||
@ -1210,7 +1215,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
/* All conditions above must match count loop */
|
||||
|
||||
address->name = uv__strdup(p->ifr_name);
|
||||
namelen = strlen(p->ifr_name) + 1;
|
||||
address->name = memcpy(name, p->ifr_name, namelen);
|
||||
name += namelen;
|
||||
|
||||
if (inet6)
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||
@ -1282,13 +1289,7 @@ cleanup:
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
int count) {
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
135
src/unix/async.c
135
src/unix/async.c
@ -38,6 +38,34 @@
|
||||
#include <sys/eventfd.h>
|
||||
#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 int uv__async_start(uv_loop_t* loop);
|
||||
static void uv__cpu_relax(void);
|
||||
@ -55,7 +83,7 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
handle->pending = 0;
|
||||
handle->u.fd = 0; /* This will be used as a busy flag. */
|
||||
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
|
||||
uv__queue_insert_tail(&loop->async_handles, &handle->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
@ -124,7 +152,7 @@ static void uv__async_spin(uv_async_t* handle) {
|
||||
|
||||
void uv__async_close(uv_async_t* handle) {
|
||||
uv__async_spin(handle);
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__queue_remove(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
@ -132,14 +160,18 @@ void uv__async_close(uv_async_t* handle) {
|
||||
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
char buf[1024];
|
||||
ssize_t r;
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
struct uv__queue queue;
|
||||
struct uv__queue* q;
|
||||
uv_async_t* h;
|
||||
_Atomic int *pending;
|
||||
|
||||
assert(w == &loop->async_io_watcher);
|
||||
|
||||
#if UV__KQUEUE_EVFILT_USER
|
||||
for (;!kqueue_evfilt_user_support;) {
|
||||
#else
|
||||
for (;;) {
|
||||
#endif
|
||||
r = read(w->fd, buf, sizeof(buf));
|
||||
|
||||
if (r == sizeof(buf))
|
||||
@ -157,13 +189,13 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
abort();
|
||||
}
|
||||
|
||||
QUEUE_MOVE(&loop->async_handles, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_async_t, queue);
|
||||
uv__queue_move(&loop->async_handles, &queue);
|
||||
while (!uv__queue_empty(&queue)) {
|
||||
q = uv__queue_head(&queue);
|
||||
h = uv__queue_data(q, uv_async_t, queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_insert_tail(&loop->async_handles, q);
|
||||
|
||||
/* Atomically fetch and clear pending flag */
|
||||
pending = (_Atomic int*) &h->pending;
|
||||
@ -195,6 +227,17 @@ static void uv__async_send(uv_loop_t* loop) {
|
||||
len = sizeof(val);
|
||||
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
|
||||
|
||||
do
|
||||
@ -215,6 +258,9 @@ static void uv__async_send(uv_loop_t* loop) {
|
||||
static int uv__async_start(uv_loop_t* loop) {
|
||||
int pipefd[2];
|
||||
int err;
|
||||
#if UV__KQUEUE_EVFILT_USER
|
||||
struct kevent ev;
|
||||
#endif
|
||||
|
||||
if (loop->async_io_watcher.fd != -1)
|
||||
return 0;
|
||||
@ -226,6 +272,36 @@ static int uv__async_start(uv_loop_t* loop) {
|
||||
|
||||
pipefd[0] = err;
|
||||
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
|
||||
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
|
||||
if (err < 0)
|
||||
@ -236,13 +312,20 @@ static int uv__async_start(uv_loop_t* loop) {
|
||||
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void uv__async_stop(uv_loop_t* loop) {
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
struct uv__queue queue;
|
||||
struct uv__queue* q;
|
||||
uv_async_t* h;
|
||||
|
||||
if (loop->async_io_watcher.fd == -1)
|
||||
@ -251,13 +334,13 @@ void uv__async_stop(uv_loop_t* loop) {
|
||||
/* Make sure no other thread is accessing the async handle fd after the loop
|
||||
* cleanup.
|
||||
*/
|
||||
QUEUE_MOVE(&loop->async_handles, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_async_t, queue);
|
||||
uv__queue_move(&loop->async_handles, &queue);
|
||||
while (!uv__queue_empty(&queue)) {
|
||||
q = uv__queue_head(&queue);
|
||||
h = uv__queue_data(q, uv_async_t, queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_insert_tail(&loop->async_handles, q);
|
||||
|
||||
uv__async_spin(h);
|
||||
}
|
||||
@ -275,20 +358,20 @@ void uv__async_stop(uv_loop_t* loop) {
|
||||
|
||||
|
||||
int uv__async_fork(uv_loop_t* loop) {
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
struct uv__queue queue;
|
||||
struct uv__queue* q;
|
||||
uv_async_t* h;
|
||||
|
||||
if (loop->async_io_watcher.fd == -1) /* never started */
|
||||
return 0;
|
||||
|
||||
QUEUE_MOVE(&loop->async_handles, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_async_t, queue);
|
||||
uv__queue_move(&loop->async_handles, &queue);
|
||||
while (!uv__queue_empty(&queue)) {
|
||||
q = uv__queue_head(&queue);
|
||||
h = uv__queue_data(q, uv_async_t, queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_insert_tail(&loop->async_handles, q);
|
||||
|
||||
/* The state of any thread that set pending is now likely corrupt in this
|
||||
* child because the user called fork, so just clear these flags and move
|
||||
|
@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO(bnoordhuis) share with linux.c */
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
uv_interface_address_t* address;
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
|
||||
int i;
|
||||
#endif
|
||||
size_t namelen;
|
||||
char* name;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
namelen = 0;
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
continue;
|
||||
namelen += strlen(ent->ifa_name) + 1;
|
||||
(*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() */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
|
||||
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||
if (*addresses == NULL) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
name = (char*) &(*addresses)[*count];
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
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) {
|
||||
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__)
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
int i;
|
||||
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
||||
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,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
413
src/unix/core.c
413
src/unix/core.c
@ -52,8 +52,11 @@
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <mach/mach.h>
|
||||
# include <mach/thread_info.h>
|
||||
# include <sys/filio.h>
|
||||
# endif /* defined(__APPLE__) */
|
||||
# include <sys/sysctl.h>
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
@ -90,9 +93,19 @@ extern char** environ;
|
||||
#if defined(__linux__)
|
||||
# include <sched.h>
|
||||
# include <sys/syscall.h>
|
||||
# define gettid() syscall(SYS_gettid)
|
||||
# define uv__accept4 accept4
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/cpuset.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# include <sched.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
|
||||
# include <sanitizer/linux_syscall_hooks.h>
|
||||
#endif
|
||||
@ -155,7 +168,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
break;
|
||||
|
||||
case UV_TTY:
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
uv__tty_close((uv_tty_t*)handle);
|
||||
break;
|
||||
|
||||
case UV_TCP:
|
||||
@ -344,7 +357,7 @@ static void uv__finish_close(uv_handle_t* handle) {
|
||||
}
|
||||
|
||||
uv__handle_unref(handle);
|
||||
QUEUE_REMOVE(&handle->handle_queue);
|
||||
uv__queue_remove(&handle->handle_queue);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb(handle);
|
||||
@ -380,7 +393,7 @@ int uv_backend_fd(const uv_loop_t* loop) {
|
||||
static int uv__loop_alive(const uv_loop_t* loop) {
|
||||
return uv__has_active_handles(loop) ||
|
||||
uv__has_active_reqs(loop) ||
|
||||
!QUEUE_EMPTY(&loop->pending_queue) ||
|
||||
!uv__queue_empty(&loop->pending_queue) ||
|
||||
loop->closing_handles != NULL;
|
||||
}
|
||||
|
||||
@ -389,8 +402,8 @@ static int uv__backend_timeout(const uv_loop_t* loop) {
|
||||
if (loop->stop_flag == 0 &&
|
||||
/* uv__loop_alive(loop) && */
|
||||
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
|
||||
QUEUE_EMPTY(&loop->pending_queue) &&
|
||||
QUEUE_EMPTY(&loop->idle_handles) &&
|
||||
uv__queue_empty(&loop->pending_queue) &&
|
||||
uv__queue_empty(&loop->idle_handles) &&
|
||||
(loop->flags & UV_LOOP_REAP_CHILDREN) == 0 &&
|
||||
loop->closing_handles == NULL)
|
||||
return uv__next_timeout(loop);
|
||||
@ -399,7 +412,7 @@ static int uv__backend_timeout(const uv_loop_t* loop) {
|
||||
|
||||
|
||||
int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
if (QUEUE_EMPTY(&loop->watcher_queue))
|
||||
if (uv__queue_empty(&loop->watcher_queue))
|
||||
return uv__backend_timeout(loop);
|
||||
/* Need to call uv_run to update the backend fd state. */
|
||||
return 0;
|
||||
@ -424,15 +437,15 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
|
||||
* while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
|
||||
* once, which should be done after polling in order to maintain proper
|
||||
* execution order of the conceptual event loop. */
|
||||
if (mode == UV_RUN_DEFAULT) {
|
||||
if (r)
|
||||
uv__update_time(loop);
|
||||
if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) {
|
||||
uv__update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
can_sleep =
|
||||
QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
|
||||
uv__queue_empty(&loop->pending_queue) &&
|
||||
uv__queue_empty(&loop->idle_handles);
|
||||
|
||||
uv__run_pending(loop);
|
||||
uv__run_idle(loop);
|
||||
@ -448,7 +461,7 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
|
||||
|
||||
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
||||
* times to avoid loop starvation.*/
|
||||
for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
|
||||
for (r = 0; r < 8 && !uv__queue_empty(&loop->pending_queue); r++)
|
||||
uv__run_pending(loop);
|
||||
|
||||
/* Run one final update on the provider_idle_time in case uv__io_poll
|
||||
@ -740,7 +753,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
int uv_cwd(char* buffer, size_t* size) {
|
||||
char scratch[1 + UV__PATH_MAX];
|
||||
|
||||
if (buffer == NULL || size == NULL)
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Try to read directly into the user's buffer first... */
|
||||
@ -827,17 +840,17 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
|
||||
|
||||
|
||||
static void uv__run_pending(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
QUEUE pq;
|
||||
struct uv__queue* q;
|
||||
struct uv__queue pq;
|
||||
uv__io_t* w;
|
||||
|
||||
QUEUE_MOVE(&loop->pending_queue, &pq);
|
||||
uv__queue_move(&loop->pending_queue, &pq);
|
||||
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
q = QUEUE_HEAD(&pq);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
w = QUEUE_DATA(q, uv__io_t, pending_queue);
|
||||
while (!uv__queue_empty(&pq)) {
|
||||
q = uv__queue_head(&pq);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
w = uv__queue_data(q, uv__io_t, pending_queue);
|
||||
w->cb(loop, w, POLLOUT);
|
||||
}
|
||||
}
|
||||
@ -892,8 +905,8 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
|
||||
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
|
||||
assert(cb != NULL);
|
||||
assert(fd >= -1);
|
||||
QUEUE_INIT(&w->pending_queue);
|
||||
QUEUE_INIT(&w->watcher_queue);
|
||||
uv__queue_init(&w->pending_queue);
|
||||
uv__queue_init(&w->watcher_queue);
|
||||
w->cb = cb;
|
||||
w->fd = fd;
|
||||
w->events = 0;
|
||||
@ -919,8 +932,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (QUEUE_EMPTY(&w->watcher_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
if (uv__queue_empty(&w->watcher_queue))
|
||||
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
|
||||
|
||||
if (loop->watchers[w->fd] == NULL) {
|
||||
loop->watchers[w->fd] = w;
|
||||
@ -945,8 +958,8 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
w->pevents &= ~events;
|
||||
|
||||
if (w->pevents == 0) {
|
||||
QUEUE_REMOVE(&w->watcher_queue);
|
||||
QUEUE_INIT(&w->watcher_queue);
|
||||
uv__queue_remove(&w->watcher_queue);
|
||||
uv__queue_init(&w->watcher_queue);
|
||||
w->events = 0;
|
||||
|
||||
if (w == loop->watchers[w->fd]) {
|
||||
@ -955,14 +968,14 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
loop->nfds--;
|
||||
}
|
||||
}
|
||||
else if (QUEUE_EMPTY(&w->watcher_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
else if (uv__queue_empty(&w->watcher_queue))
|
||||
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
|
||||
|
||||
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
|
||||
uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
QUEUE_REMOVE(&w->pending_queue);
|
||||
uv__queue_remove(&w->pending_queue);
|
||||
|
||||
/* Remove stale events for this file descriptor */
|
||||
if (w->fd != -1)
|
||||
@ -971,8 +984,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
|
||||
|
||||
|
||||
void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
|
||||
if (QUEUE_EMPTY(&w->pending_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
|
||||
if (uv__queue_empty(&w->pending_queue))
|
||||
uv__queue_insert_tail(&loop->pending_queue, &w->pending_queue);
|
||||
}
|
||||
|
||||
|
||||
@ -988,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;
|
||||
|
||||
if (getrusage(RUSAGE_SELF, &usage))
|
||||
if (getrusage(who, &usage))
|
||||
return UV__ERR(errno);
|
||||
|
||||
rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
|
||||
@ -1020,16 +1033,60 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
/* Most platforms report ru_maxrss in kilobytes; macOS and Solaris are
|
||||
* the outliers because of course they are.
|
||||
*/
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
rusage->ru_maxrss /= 1024; /* macOS reports bytes. */
|
||||
#if defined(__APPLE__)
|
||||
rusage->ru_maxrss /= 1024; /* macOS and iOS report bytes. */
|
||||
#elif defined(__sun)
|
||||
rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */
|
||||
rusage->ru_maxrss *= getpagesize() / 1024; /* Solaris reports pages. */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
#if defined(O_CLOEXEC)
|
||||
int fd;
|
||||
@ -1271,6 +1328,10 @@ static int uv__getpwuid_r(uv_passwd_t *pwd, uid_t uid) {
|
||||
|
||||
|
||||
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
|
||||
#if defined(__ANDROID__) && __ANDROID_API__ < 24
|
||||
/* This function getgrgid_r() was added in Android N (level 24) */
|
||||
return UV_ENOSYS;
|
||||
#else
|
||||
struct group gp;
|
||||
struct group* result;
|
||||
char* buf;
|
||||
@ -1347,6 +1408,7 @@ int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
|
||||
uv__free(buf);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1552,6 +1614,135 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the function succeeds, the return value is 0.
|
||||
* If the function fails, the return value is non-zero.
|
||||
* for Linux, when schedule policy is SCHED_OTHER (default), priority is 0.
|
||||
* So the output parameter priority is actually the nice value.
|
||||
*/
|
||||
int uv_thread_getpriority(uv_thread_t tid, int* priority) {
|
||||
int r;
|
||||
int policy;
|
||||
struct sched_param param;
|
||||
#ifdef __linux__
|
||||
pid_t pid = gettid();
|
||||
#endif
|
||||
|
||||
if (priority == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
r = pthread_getschedparam(tid, &policy, ¶m);
|
||||
if (r != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef __linux__
|
||||
if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) {
|
||||
errno = 0;
|
||||
r = getpriority(PRIO_PROCESS, pid);
|
||||
if (r == -1 && errno != 0)
|
||||
return UV__ERR(errno);
|
||||
*priority = r;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
*priority = param.sched_priority;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static int set_nice_for_calling_thread(int priority) {
|
||||
int r;
|
||||
int nice;
|
||||
|
||||
if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST)
|
||||
return UV_EINVAL;
|
||||
|
||||
pid_t pid = gettid();
|
||||
nice = 0 - priority * 2;
|
||||
r = setpriority(PRIO_PROCESS, pid, nice);
|
||||
if (r != 0)
|
||||
return UV__ERR(errno);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If the function succeeds, the return value is 0.
|
||||
* If the function fails, the return value is non-zero.
|
||||
*/
|
||||
int uv_thread_setpriority(uv_thread_t tid, int priority) {
|
||||
#if !defined(__GNU__)
|
||||
int r;
|
||||
int min;
|
||||
int max;
|
||||
int range;
|
||||
int prio;
|
||||
int policy;
|
||||
struct sched_param param;
|
||||
|
||||
if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST)
|
||||
return UV_EINVAL;
|
||||
|
||||
r = pthread_getschedparam(tid, &policy, ¶m);
|
||||
if (r != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef __linux__
|
||||
/**
|
||||
* for Linux, when schedule policy is SCHED_OTHER (default), priority must be 0,
|
||||
* we should set the nice value in this case.
|
||||
*/
|
||||
if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self()))
|
||||
return set_nice_for_calling_thread(priority);
|
||||
#endif
|
||||
|
||||
#ifdef __PASE__
|
||||
min = 1;
|
||||
max = 127;
|
||||
#else
|
||||
min = sched_get_priority_min(policy);
|
||||
max = sched_get_priority_max(policy);
|
||||
#endif
|
||||
|
||||
if (min == -1 || max == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
range = max - min;
|
||||
|
||||
switch (priority) {
|
||||
case UV_THREAD_PRIORITY_HIGHEST:
|
||||
prio = max;
|
||||
break;
|
||||
case UV_THREAD_PRIORITY_ABOVE_NORMAL:
|
||||
prio = min + range * 3 / 4;
|
||||
break;
|
||||
case UV_THREAD_PRIORITY_NORMAL:
|
||||
prio = min + range / 2;
|
||||
break;
|
||||
case UV_THREAD_PRIORITY_BELOW_NORMAL:
|
||||
prio = min + range / 4;
|
||||
break;
|
||||
case UV_THREAD_PRIORITY_LOWEST:
|
||||
prio = min;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (param.sched_priority != prio) {
|
||||
param.sched_priority = prio;
|
||||
r = pthread_setschedparam(tid, policy, ¶m);
|
||||
if (r != 0)
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* !defined(__GNU__) */
|
||||
/* Simulate success on systems where thread priority is not implemented. */
|
||||
return 0;
|
||||
#endif /* !defined(__GNU__) */
|
||||
}
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
struct utsname buf;
|
||||
@ -1734,11 +1925,31 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined (__FreeBSD__)
|
||||
# define uv__cpu_count(cpuset) CPU_COUNT(cpuset)
|
||||
#elif defined(__NetBSD__)
|
||||
static int uv__cpu_count(cpuset_t* set) {
|
||||
int rc;
|
||||
cpuid_t i;
|
||||
|
||||
rc = 0;
|
||||
for (i = 0;; i++) {
|
||||
int r = cpuset_isset(i, set);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (r)
|
||||
rc++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
unsigned int uv_available_parallelism(void) {
|
||||
long rc = -1;
|
||||
|
||||
#ifdef __linux__
|
||||
cpu_set_t set;
|
||||
long rc;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
|
||||
@ -1747,29 +1958,127 @@ unsigned int uv_available_parallelism(void) {
|
||||
* before falling back to sysconf(_SC_NPROCESSORS_ONLN).
|
||||
*/
|
||||
if (0 == sched_getaffinity(0, sizeof(set), &set))
|
||||
rc = CPU_COUNT(&set);
|
||||
else
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
rc = uv__cpu_count(&set);
|
||||
#elif defined(__MVS__)
|
||||
int rc;
|
||||
|
||||
rc = __get_num_online_cpus();
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#else /* __linux__ */
|
||||
long rc;
|
||||
#elif defined(__FreeBSD__)
|
||||
cpuset_t set;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
|
||||
if (0 == cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set), &set))
|
||||
rc = uv__cpu_count(&set);
|
||||
#elif defined(__NetBSD__)
|
||||
cpuset_t* set = cpuset_create();
|
||||
if (set != NULL) {
|
||||
if (0 == sched_getaffinity_np(getpid(), sizeof(set), &set))
|
||||
rc = uv__cpu_count(&set);
|
||||
cpuset_destroy(set);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int nprocs;
|
||||
size_t i;
|
||||
size_t len = sizeof(nprocs);
|
||||
static const char *mib[] = {
|
||||
"hw.activecpu",
|
||||
"hw.logicalcpu",
|
||||
"hw.ncpu"
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mib); i++) {
|
||||
if (0 == sysctlbyname(mib[i], &nprocs, &len, NULL, 0) &&
|
||||
len == sizeof(nprocs) &&
|
||||
nprocs > 0) {
|
||||
rc = nprocs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
int nprocs;
|
||||
size_t i;
|
||||
size_t len = sizeof(nprocs);
|
||||
static int mib[][2] = {
|
||||
# ifdef HW_NCPUONLINE
|
||||
{ CTL_HW, HW_NCPUONLINE },
|
||||
# endif
|
||||
{ CTL_HW, HW_NCPU }
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mib); i++) {
|
||||
if (0 == sysctl(mib[i], ARRAY_SIZE(mib[i]), &nprocs, &len, NULL, 0) &&
|
||||
len == sizeof(nprocs) &&
|
||||
nprocs > 0) {
|
||||
rc = nprocs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
if (rc < 0)
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
double rc_with_cgroup;
|
||||
uv__cpu_constraint c = {0, 0, 0.0};
|
||||
|
||||
if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) {
|
||||
rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions;
|
||||
if (rc_with_cgroup < rc)
|
||||
rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
int uv__sock_reuseport(int fd) {
|
||||
int on = 1;
|
||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 12 && defined(SO_REUSEPORT_LB)
|
||||
/* FreeBSD 12 introduced a new socket option named SO_REUSEPORT_LB
|
||||
* with the capability of load balancing, it's the substitution of
|
||||
* the SO_REUSEPORTs on Linux and DragonFlyBSD. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
#elif (defined(__linux__) || \
|
||||
defined(_AIX73) || \
|
||||
(defined(__DragonFly__) && __DragonFly_version >= 300600) || \
|
||||
(defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4)) && \
|
||||
defined(SO_REUSEPORT)
|
||||
/* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections
|
||||
* evenly across all of the threads (or processes) that are blocked in
|
||||
* accept() on the same port. As with TCP, SO_REUSEPORT distributes datagrams
|
||||
* evenly across all of the receiving threads (or process).
|
||||
*
|
||||
* DragonFlyBSD 3.6.0 extended SO_REUSEPORT to distribute workload to
|
||||
* available sockets, which made it the equivalent of Linux's SO_REUSEPORT.
|
||||
*
|
||||
* AIX 7.2.5 added the feature that would add the capability to distribute
|
||||
* incoming connections or datagrams across all listening ports for SO_REUSEPORT.
|
||||
*
|
||||
* Solaris 11 supported SO_REUSEPORT, but it's implemented only for
|
||||
* binding to the same address and port, without load balancing.
|
||||
* Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing.
|
||||
*/
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
(void) (fd);
|
||||
(void) (on);
|
||||
/* SO_REUSEPORTs do not have the capability of load balancing on platforms
|
||||
* other than those mentioned above. The semantics are completely different,
|
||||
* therefore we shouldn't enable it, but fail this operation to indicate that
|
||||
* UV_[TCP/UDP]_REUSEPORT is not supported on these platforms. */
|
||||
return UV_ENOTSUP;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,9 +36,45 @@ int uv_uptime(double* uptime) {
|
||||
}
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
/* FIXME: read /proc/meminfo? */
|
||||
*rss = 0;
|
||||
char buf[1024];
|
||||
const char* s;
|
||||
long val;
|
||||
int rc;
|
||||
int i;
|
||||
struct sysinfo si;
|
||||
|
||||
/* rss: 24th element */
|
||||
rc = uv__slurp("/proc/self/stat", buf, sizeof(buf));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* find the last ')' */
|
||||
s = strrchr(buf, ')');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 1; i <= 22; i++) {
|
||||
s = strchr(s + 1, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = strtol(s, NULL, 10);
|
||||
if (val < 0 || errno != 0)
|
||||
goto err;
|
||||
|
||||
do
|
||||
rc = sysinfo(&si);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*rss = val * si.mem_unit;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
@ -33,25 +33,9 @@
|
||||
#include "darwin-stub.h"
|
||||
#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) {
|
||||
#if TARGET_OS_IPHONE
|
||||
return uv__pthread_setname_np(title);
|
||||
return uv__thread_setname(title);
|
||||
#else
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
@ -177,7 +161,7 @@ int uv__set_process_title(const char* title) {
|
||||
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;
|
||||
|
||||
out:
|
||||
|
17
src/unix/darwin-syscalls.h
Normal file
17
src/unix/darwin-syscalls.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef UV_DARWIN_SYSCALLS_H_
|
||||
#define UV_DARWIN_SYSCALLS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* https://github.com/apple/darwin-xnu/blob/master/bsd/sys/socket.h */
|
||||
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
size_t msg_len;
|
||||
};
|
||||
|
||||
ssize_t recvmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
ssize_t sendmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
|
||||
#endif /* UV_DARWIN_SYSCALLS_H_ */
|
@ -25,7 +25,6 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
@ -34,7 +33,6 @@
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uint64_t (*time_func)(void);
|
||||
static mach_timebase_info_data_t timebase;
|
||||
|
||||
|
||||
@ -56,16 +54,12 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
static void uv__hrtime_init_once(void) {
|
||||
if (KERN_SUCCESS != mach_timebase_info(&timebase))
|
||||
abort();
|
||||
|
||||
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
|
||||
if (time_func == NULL)
|
||||
time_func = mach_absolute_time;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
uv_once(&once, uv__hrtime_init_once);
|
||||
return time_func() * timebase.numer / timebase.denom;
|
||||
return mach_continuous_time() * timebase.numer / timebase.denom;
|
||||
}
|
||||
|
||||
|
||||
@ -209,7 +203,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
if (cpuspeed == 0)
|
||||
/* If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable
|
||||
* from Apple, but we can hard-code it here to a plausible value. */
|
||||
cpuspeed = 2400000000;
|
||||
cpuspeed = 2400000000U;
|
||||
|
||||
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
|
||||
(processor_info_array_t*)&info,
|
||||
@ -235,7 +229,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
cpu_info->cpu_times.irq = 0;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed/1000000;
|
||||
cpu_info->speed = (int)(cpuspeed / 1000000);
|
||||
}
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
|
||||
|
||||
|
@ -26,7 +26,12 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/user.h>
|
||||
#if defined(__DragonFly__)
|
||||
# include <sys/event.h>
|
||||
# include <sys/kinfo.h>
|
||||
#else
|
||||
# include <sys/user.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
522
src/unix/fs.c
522
src/unix/fs.c
@ -31,6 +31,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -41,23 +42,12 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_PREADV 1
|
||||
#else
|
||||
# define HAVE_PREADV 0
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <sys/sendfile.h>
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
@ -149,7 +139,7 @@ extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#define POST \
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__req_register(loop); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
@ -213,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;
|
||||
|
||||
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_nsec = (time - ts.tv_sec) * 1e9;
|
||||
|
||||
@ -231,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
|
||||
}
|
||||
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) {
|
||||
#if defined(__linux__) \
|
||||
#if defined(__APPLE__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__GNU__)
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__linux__) \
|
||||
|| defined(__sun)
|
||||
struct timespec ts[2];
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
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__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
@ -406,123 +393,171 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
#if !HAVE_PREADV
|
||||
static ssize_t uv__fs_preadv(uv_file fd,
|
||||
uv_buf_t* bufs,
|
||||
unsigned int nbufs,
|
||||
off_t off) {
|
||||
uv_buf_t* buf;
|
||||
uv_buf_t* end;
|
||||
ssize_t result;
|
||||
ssize_t rc;
|
||||
size_t pos;
|
||||
static ssize_t uv__preadv_or_pwritev_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off,
|
||||
int is_pread) {
|
||||
ssize_t total;
|
||||
ssize_t r;
|
||||
size_t i;
|
||||
size_t n;
|
||||
void* p;
|
||||
|
||||
assert(nbufs > 0);
|
||||
total = 0;
|
||||
for (i = 0; i < (size_t) nbufs; i++) {
|
||||
p = bufs[i].iov_base;
|
||||
n = bufs[i].iov_len;
|
||||
|
||||
result = 0;
|
||||
pos = 0;
|
||||
buf = bufs + 0;
|
||||
end = bufs + nbufs;
|
||||
|
||||
for (;;) {
|
||||
do
|
||||
rc = pread(fd, buf->base + pos, buf->len - pos, off + result);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
if (is_pread)
|
||||
r = pread(fd, p, n, off);
|
||||
else
|
||||
r = pwrite(fd, p, n, off);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (rc == 0)
|
||||
break;
|
||||
if (r == -1) {
|
||||
if (total > 0)
|
||||
return total;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc == -1 && result == 0)
|
||||
return UV__ERR(errno);
|
||||
off += r;
|
||||
total += r;
|
||||
|
||||
if (rc == -1)
|
||||
break; /* We read some data so return that, ignore the error. */
|
||||
|
||||
pos += rc;
|
||||
result += rc;
|
||||
|
||||
if (pos < buf->len)
|
||||
continue;
|
||||
|
||||
pos = 0;
|
||||
buf += 1;
|
||||
|
||||
if (buf == end)
|
||||
break;
|
||||
if ((size_t) r < n)
|
||||
return total;
|
||||
}
|
||||
|
||||
return result;
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
typedef int uv__iovcnt;
|
||||
#else
|
||||
typedef size_t uv__iovcnt;
|
||||
#endif
|
||||
|
||||
|
||||
static ssize_t uv__preadv_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
uv__iovcnt nbufs,
|
||||
off_t off) {
|
||||
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/1);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__pwritev_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
uv__iovcnt nbufs,
|
||||
off_t off) {
|
||||
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/0);
|
||||
}
|
||||
|
||||
|
||||
/* The function pointer cache is an uintptr_t because _Atomic void*
|
||||
* doesn't work on macos/ios/etc...
|
||||
*/
|
||||
static ssize_t uv__preadv_or_pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off,
|
||||
_Atomic uintptr_t* cache,
|
||||
int is_pread) {
|
||||
ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t);
|
||||
void* p;
|
||||
|
||||
p = (void*) atomic_load_explicit(cache, memory_order_relaxed);
|
||||
if (p == NULL) {
|
||||
#ifdef RTLD_DEFAULT
|
||||
/* 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. */
|
||||
#endif /* RTLD_DEFAULT */
|
||||
if (p == NULL)
|
||||
p = is_pread ? uv__preadv_emul : uv__pwritev_emul;
|
||||
atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed);
|
||||
}
|
||||
|
||||
f = p;
|
||||
return f(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__preadv(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
static _Atomic uintptr_t cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
static _Atomic uintptr_t cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static _Atomic int no_preadv;
|
||||
#endif
|
||||
const struct iovec* bufs;
|
||||
unsigned int iovmax;
|
||||
ssize_t result;
|
||||
size_t nbufs;
|
||||
ssize_t r;
|
||||
off_t off;
|
||||
int fd;
|
||||
|
||||
fd = req->file;
|
||||
off = req->off;
|
||||
bufs = (const struct iovec*) req->bufs;
|
||||
nbufs = req->nbufs;
|
||||
|
||||
iovmax = uv__getiovmax();
|
||||
if (req->nbufs > iovmax)
|
||||
req->nbufs = iovmax;
|
||||
if (nbufs > iovmax)
|
||||
nbufs = iovmax;
|
||||
|
||||
if (req->off < 0) {
|
||||
if (req->nbufs == 1)
|
||||
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
|
||||
else
|
||||
result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
|
||||
r = 0;
|
||||
if (off < 0) {
|
||||
if (nbufs == 1)
|
||||
r = read(fd, bufs->iov_base, bufs->iov_len);
|
||||
else if (nbufs > 1)
|
||||
r = readv(fd, bufs, nbufs);
|
||||
} else {
|
||||
if (req->nbufs == 1) {
|
||||
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if HAVE_PREADV
|
||||
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
|
||||
#else
|
||||
# if defined(__linux__)
|
||||
if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry:
|
||||
# endif
|
||||
{
|
||||
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
result = preadv(req->file,
|
||||
(struct iovec*) req->bufs,
|
||||
req->nbufs,
|
||||
req->off);
|
||||
if (result == -1 && errno == ENOSYS) {
|
||||
atomic_store_explicit(&no_preadv, 1, memory_order_relaxed);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (nbufs == 1)
|
||||
r = pread(fd, bufs->iov_base, bufs->iov_len, off);
|
||||
else if (nbufs > 1)
|
||||
r = uv__preadv(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
done:
|
||||
/* Early cleanup of bufs allocation, since we're done with it. */
|
||||
if (req->bufs != req->bufsml)
|
||||
uv__free(req->bufs);
|
||||
|
||||
req->bufs = NULL;
|
||||
req->nbufs = 0;
|
||||
|
||||
#ifdef __PASE__
|
||||
/* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */
|
||||
if (result == -1 && errno == EOPNOTSUPP) {
|
||||
if (r == -1 && errno == EOPNOTSUPP) {
|
||||
struct stat buf;
|
||||
ssize_t rc;
|
||||
rc = uv__fstat(req->file, &buf);
|
||||
rc = uv__fstat(fd, &buf);
|
||||
if (rc == 0 && S_ISDIR(buf.st_mode)) {
|
||||
errno = EISDIR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
/* We don't own the buffer list in the synchronous case. */
|
||||
if (req->cb != NULL)
|
||||
if (req->bufs != req->bufsml)
|
||||
uv__free(req->bufs);
|
||||
|
||||
req->bufs = NULL;
|
||||
req->nbufs = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@ -757,14 +792,23 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
|
||||
static ssize_t uv__fs_realpath(uv_fs_t* req) {
|
||||
char* buf;
|
||||
char* tmp;
|
||||
|
||||
#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
|
||||
buf = realpath(req->path, NULL);
|
||||
if (buf == NULL)
|
||||
tmp = realpath(req->path, NULL);
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
buf = uv__strdup(tmp);
|
||||
free(tmp); /* _Not_ uv__free. */
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
ssize_t len;
|
||||
|
||||
(void)tmp;
|
||||
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
buf = uv__malloc(len + 1);
|
||||
|
||||
@ -899,31 +943,6 @@ out:
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
static unsigned uv__kernel_version(void) {
|
||||
static _Atomic unsigned cached_version;
|
||||
struct utsname u;
|
||||
unsigned version;
|
||||
unsigned major;
|
||||
unsigned minor;
|
||||
unsigned patch;
|
||||
|
||||
version = atomic_load_explicit(&cached_version, memory_order_relaxed);
|
||||
if (version != 0)
|
||||
return version;
|
||||
|
||||
if (-1 == uname(&u))
|
||||
return 0;
|
||||
|
||||
if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
|
||||
return 0;
|
||||
|
||||
version = major * 65536 + minor * 256 + patch;
|
||||
atomic_store_explicit(&cached_version, version, memory_order_relaxed);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
/* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command
|
||||
* in copy_file_range() when it shouldn't. There is no workaround except to
|
||||
* fall back to a regular copy.
|
||||
@ -1053,7 +1072,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
/* sendfile() on iOS(arm64) will throw SIGSYS signal cause crash. */
|
||||
#elif (defined(__APPLE__) && !TARGET_OS_IPHONE) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__)
|
||||
{
|
||||
off_t len;
|
||||
ssize_t r;
|
||||
@ -1117,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__sun) \
|
||||
|| defined(__HAIKU__)
|
||||
#if defined(__APPLE__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__linux__) \
|
||||
|| defined(__sun)
|
||||
struct timespec ts[2];
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
return utimensat(AT_FDCWD, req->path, ts, 0);
|
||||
#elif defined(__APPLE__) \
|
||||
|| 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)
|
||||
#elif defined(_AIX) && !defined(_AIX71)
|
||||
struct utimbuf buf;
|
||||
buf.actime = req->atime;
|
||||
buf.modtime = req->mtime;
|
||||
@ -1156,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
||||
#if defined(__linux__) || \
|
||||
defined(_AIX71) || \
|
||||
defined(__sun) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__GNU__) || \
|
||||
defined(__OpenBSD__)
|
||||
#if defined(__APPLE__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__linux__) \
|
||||
|| defined(__sun)
|
||||
struct timespec ts[2];
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
|
||||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
struct timeval tv[2];
|
||||
tv[0] = uv__fs_to_timeval(req->atime);
|
||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
||||
return lutimes(req->path, tv);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
@ -1182,71 +1194,41 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_write(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static int no_pwritev;
|
||||
#endif
|
||||
const struct iovec* bufs;
|
||||
size_t nbufs;
|
||||
ssize_t r;
|
||||
off_t off;
|
||||
int fd;
|
||||
|
||||
/* Serialize writes on OS X, concurrent write() and pwrite() calls result in
|
||||
* data loss. We can't use a per-file descriptor lock, the descriptor may be
|
||||
* a dup().
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
fd = req->file;
|
||||
off = req->off;
|
||||
bufs = (const struct iovec*) req->bufs;
|
||||
nbufs = req->nbufs;
|
||||
|
||||
if (pthread_mutex_lock(&lock))
|
||||
abort();
|
||||
#endif
|
||||
|
||||
if (req->off < 0) {
|
||||
if (req->nbufs == 1)
|
||||
r = write(req->file, req->bufs[0].base, req->bufs[0].len);
|
||||
else
|
||||
r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
|
||||
r = 0;
|
||||
if (off < 0) {
|
||||
if (nbufs == 1)
|
||||
r = write(fd, bufs->iov_base, bufs->iov_len);
|
||||
else if (nbufs > 1)
|
||||
r = writev(fd, bufs, nbufs);
|
||||
} else {
|
||||
if (req->nbufs == 1) {
|
||||
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
goto done;
|
||||
}
|
||||
#if HAVE_PREADV
|
||||
r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
|
||||
#else
|
||||
# if defined(__linux__)
|
||||
if (no_pwritev) retry:
|
||||
# endif
|
||||
{
|
||||
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
r = pwritev(req->file,
|
||||
(struct iovec*) req->bufs,
|
||||
req->nbufs,
|
||||
req->off);
|
||||
if (r == -1 && errno == ENOSYS) {
|
||||
no_pwritev = 1;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (nbufs == 1)
|
||||
r = pwrite(fd, bufs->iov_base, bufs->iov_len, off);
|
||||
else if (nbufs > 1)
|
||||
r = uv__pwritev(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
done:
|
||||
#if defined(__APPLE__)
|
||||
if (pthread_mutex_unlock(&lock))
|
||||
abort();
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
uv_fs_t fs_req;
|
||||
uv_file srcfd;
|
||||
uv_file dstfd;
|
||||
struct stat src_statsbuf;
|
||||
struct stat dst_statsbuf;
|
||||
struct timespec times[2];
|
||||
int dst_flags;
|
||||
int result;
|
||||
int err;
|
||||
@ -1324,6 +1306,35 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the timestamps of the destination file to match the source file.
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
times[0] = src_statsbuf.st_atimespec;
|
||||
times[1] = src_statsbuf.st_mtimespec;
|
||||
#elif defined(_AIX)
|
||||
times[0].tv_sec = src_statsbuf.st_atime;
|
||||
times[0].tv_nsec = src_statsbuf.st_atime_n;
|
||||
times[1].tv_sec = src_statsbuf.st_mtime;
|
||||
times[1].tv_nsec = src_statsbuf.st_mtime_n;
|
||||
#else
|
||||
times[0] = src_statsbuf.st_atim;
|
||||
times[1] = src_statsbuf.st_mtim;
|
||||
#endif
|
||||
|
||||
if (futimens(dstfd, times) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the ownership and permissions of the destination file to match the
|
||||
* source file.
|
||||
* `cp -p` does not care about errors here, so we don't either. Reuse the
|
||||
* `result` variable to silence a -Wunused-result warning.
|
||||
*/
|
||||
result = fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid);
|
||||
|
||||
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
#ifdef __linux__
|
||||
@ -1741,7 +1752,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
|
||||
uv_fs_t* req;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->result == 0);
|
||||
@ -1752,6 +1763,16 @@ static void uv__fs_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) {
|
||||
uv__req_register(loop);
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_FAST_IO,
|
||||
uv__fs_work,
|
||||
uv__fs_done);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_access(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@ -1878,6 +1899,9 @@ int uv_fs_ftruncate(uv_loop_t* loop,
|
||||
INIT(FTRUNCATE);
|
||||
req->file = file;
|
||||
req->off = off;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_ftruncate(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -1926,6 +1950,9 @@ int uv_fs_link(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
INIT(LINK);
|
||||
PATH2;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_link(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -1938,6 +1965,9 @@ int uv_fs_mkdir(uv_loop_t* loop,
|
||||
INIT(MKDIR);
|
||||
PATH;
|
||||
req->mode = mode;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_mkdir(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -1994,9 +2024,14 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
|
||||
if (bufs == NULL || nbufs == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
req->off = off;
|
||||
req->file = file;
|
||||
|
||||
req->bufs = (uv_buf_t*) bufs; /* Safe, doesn't mutate |bufs| */
|
||||
req->nbufs = nbufs;
|
||||
|
||||
if (cb == NULL)
|
||||
goto post;
|
||||
|
||||
req->bufs = req->bufsml;
|
||||
if (nbufs > ARRAY_SIZE(req->bufsml))
|
||||
req->bufs = uv__malloc(nbufs * sizeof(*bufs));
|
||||
@ -2006,12 +2041,10 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
|
||||
|
||||
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
|
||||
|
||||
req->off = off;
|
||||
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1))
|
||||
return 0;
|
||||
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1))
|
||||
return 0;
|
||||
|
||||
post:
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -2089,6 +2122,9 @@ int uv_fs_rename(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
INIT(RENAME);
|
||||
PATH2;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_rename(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -2135,6 +2171,9 @@ int uv_fs_symlink(uv_loop_t* loop,
|
||||
INIT(SYMLINK);
|
||||
PATH2;
|
||||
req->flags = flags;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_symlink(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -2142,6 +2181,9 @@ int uv_fs_symlink(uv_loop_t* loop,
|
||||
int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
INIT(UNLINK);
|
||||
PATH;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_unlink(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
@ -80,13 +80,13 @@ enum uv__cf_loop_signal_type_e {
|
||||
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
|
||||
|
||||
struct uv__cf_loop_signal_s {
|
||||
QUEUE member;
|
||||
struct uv__queue member;
|
||||
uv_fs_event_t* handle;
|
||||
uv__cf_loop_signal_type_t type;
|
||||
};
|
||||
|
||||
struct uv__fsevents_event_s {
|
||||
QUEUE member;
|
||||
struct uv__queue member;
|
||||
int events;
|
||||
char path[1];
|
||||
};
|
||||
@ -98,7 +98,7 @@ struct uv__cf_loop_state_s {
|
||||
FSEventStreamRef fsevent_stream;
|
||||
uv_sem_t fsevent_sem;
|
||||
uv_mutex_t fsevent_mutex;
|
||||
void* fsevent_handles[2];
|
||||
struct uv__queue fsevent_handles;
|
||||
unsigned int fsevent_handle_count;
|
||||
};
|
||||
|
||||
@ -150,22 +150,22 @@ static void (*pFSEventStreamStop)(FSEventStreamRef);
|
||||
|
||||
#define UV__FSEVENTS_PROCESS(handle, block) \
|
||||
do { \
|
||||
QUEUE events; \
|
||||
QUEUE* q; \
|
||||
struct uv__queue events; \
|
||||
struct uv__queue* q; \
|
||||
uv__fsevents_event_t* event; \
|
||||
int err; \
|
||||
uv_mutex_lock(&(handle)->cf_mutex); \
|
||||
/* Split-off all events and empty original queue */ \
|
||||
QUEUE_MOVE(&(handle)->cf_events, &events); \
|
||||
uv__queue_move(&(handle)->cf_events, &events); \
|
||||
/* Get error (if any) and zero original one */ \
|
||||
err = (handle)->cf_error; \
|
||||
(handle)->cf_error = 0; \
|
||||
uv_mutex_unlock(&(handle)->cf_mutex); \
|
||||
/* Loop through events, deallocating each after processing */ \
|
||||
while (!QUEUE_EMPTY(&events)) { \
|
||||
q = QUEUE_HEAD(&events); \
|
||||
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
|
||||
QUEUE_REMOVE(q); \
|
||||
while (!uv__queue_empty(&events)) { \
|
||||
q = uv__queue_head(&events); \
|
||||
event = uv__queue_data(q, uv__fsevents_event_t, member); \
|
||||
uv__queue_remove(q); \
|
||||
/* NOTE: Checking uv__is_active() is required here, because handle \
|
||||
* callback may close handle and invoking it after it will lead to \
|
||||
* incorrect behaviour */ \
|
||||
@ -193,14 +193,14 @@ static void uv__fsevents_cb(uv_async_t* cb) {
|
||||
|
||||
/* Runs in CF thread, pushed event into handle's event list */
|
||||
static void uv__fsevents_push_event(uv_fs_event_t* handle,
|
||||
QUEUE* events,
|
||||
struct uv__queue* events,
|
||||
int err) {
|
||||
assert(events != NULL || err != 0);
|
||||
uv_mutex_lock(&handle->cf_mutex);
|
||||
|
||||
/* Concatenate two queues */
|
||||
if (events != NULL)
|
||||
QUEUE_ADD(&handle->cf_events, events);
|
||||
uv__queue_add(&handle->cf_events, events);
|
||||
|
||||
/* Propagate error */
|
||||
if (err != 0)
|
||||
@ -224,12 +224,12 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
char* path;
|
||||
char* pos;
|
||||
uv_fs_event_t* handle;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
uv__fsevents_event_t* event;
|
||||
FSEventStreamEventFlags flags;
|
||||
QUEUE head;
|
||||
struct uv__queue head;
|
||||
|
||||
loop = info;
|
||||
state = loop->cf_state;
|
||||
@ -238,9 +238,9 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
|
||||
/* For each handle */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
QUEUE_INIT(&head);
|
||||
uv__queue_foreach(q, &state->fsevent_handles) {
|
||||
handle = uv__queue_data(q, uv_fs_event_t, cf_member);
|
||||
uv__queue_init(&head);
|
||||
|
||||
/* Process and filter out events */
|
||||
for (i = 0; i < numEvents; i++) {
|
||||
@ -276,10 +276,6 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
|
||||
if (len == 0) {
|
||||
/* Since we're using fsevents to watch the file itself,
|
||||
* realpath == path, and we now need to get the basename of the file back
|
||||
@ -318,10 +314,10 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
|
||||
QUEUE_INSERT_TAIL(&head, &event->member);
|
||||
uv__queue_insert_tail(&head, &event->member);
|
||||
}
|
||||
|
||||
if (!QUEUE_EMPTY(&head))
|
||||
if (!uv__queue_empty(&head))
|
||||
uv__fsevents_push_event(handle, &head, 0);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
@ -403,7 +399,7 @@ static void uv__fsevents_destroy_stream(uv__cf_loop_state_t* state) {
|
||||
static void uv__fsevents_reschedule(uv__cf_loop_state_t* state,
|
||||
uv_loop_t* loop,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_fs_event_t* curr;
|
||||
CFArrayRef cf_paths;
|
||||
CFStringRef* paths;
|
||||
@ -446,9 +442,9 @@ static void uv__fsevents_reschedule(uv__cf_loop_state_t* state,
|
||||
|
||||
q = &state->fsevent_handles;
|
||||
for (; i < path_count; i++) {
|
||||
q = QUEUE_NEXT(q);
|
||||
q = uv__queue_next(q);
|
||||
assert(q != &state->fsevent_handles);
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
curr = uv__queue_data(q, uv_fs_event_t, cf_member);
|
||||
|
||||
assert(curr->realpath != NULL);
|
||||
paths[i] =
|
||||
@ -486,8 +482,8 @@ final:
|
||||
|
||||
/* Broadcast error to all handles */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
uv__queue_foreach(q, &state->fsevent_handles) {
|
||||
curr = uv__queue_data(q, uv_fs_event_t, cf_member);
|
||||
uv__fsevents_push_event(curr, NULL, err);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
@ -606,7 +602,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
|
||||
if (err)
|
||||
goto fail_sem_init;
|
||||
|
||||
QUEUE_INIT(&loop->cf_signals);
|
||||
uv__queue_init(&loop->cf_signals);
|
||||
|
||||
err = uv_sem_init(&state->fsevent_sem, 0);
|
||||
if (err)
|
||||
@ -616,7 +612,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
|
||||
if (err)
|
||||
goto fail_fsevent_mutex_init;
|
||||
|
||||
QUEUE_INIT(&state->fsevent_handles);
|
||||
uv__queue_init(&state->fsevent_handles);
|
||||
state->fsevent_need_reschedule = 0;
|
||||
state->fsevent_handle_count = 0;
|
||||
|
||||
@ -675,7 +671,7 @@ fail_mutex_init:
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
uv__cf_loop_signal_t* s;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
|
||||
if (loop->cf_state == NULL)
|
||||
return;
|
||||
@ -688,10 +684,10 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
uv_mutex_destroy(&loop->cf_mutex);
|
||||
|
||||
/* Free any remaining data */
|
||||
while (!QUEUE_EMPTY(&loop->cf_signals)) {
|
||||
q = QUEUE_HEAD(&loop->cf_signals);
|
||||
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
|
||||
QUEUE_REMOVE(q);
|
||||
while (!uv__queue_empty(&loop->cf_signals)) {
|
||||
q = uv__queue_head(&loop->cf_signals);
|
||||
s = uv__queue_data(q, uv__cf_loop_signal_t, member);
|
||||
uv__queue_remove(q);
|
||||
uv__free(s);
|
||||
}
|
||||
|
||||
@ -735,22 +731,22 @@ static void* uv__cf_loop_runner(void* arg) {
|
||||
static void uv__cf_loop_cb(void* arg) {
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* item;
|
||||
QUEUE split_head;
|
||||
struct uv__queue* item;
|
||||
struct uv__queue split_head;
|
||||
uv__cf_loop_signal_t* s;
|
||||
|
||||
loop = arg;
|
||||
state = loop->cf_state;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_MOVE(&loop->cf_signals, &split_head);
|
||||
uv__queue_move(&loop->cf_signals, &split_head);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
while (!QUEUE_EMPTY(&split_head)) {
|
||||
item = QUEUE_HEAD(&split_head);
|
||||
QUEUE_REMOVE(item);
|
||||
while (!uv__queue_empty(&split_head)) {
|
||||
item = uv__queue_head(&split_head);
|
||||
uv__queue_remove(item);
|
||||
|
||||
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
|
||||
s = uv__queue_data(item, uv__cf_loop_signal_t, member);
|
||||
|
||||
/* This was a termination signal */
|
||||
if (s->handle == NULL)
|
||||
@ -778,7 +774,7 @@ int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
item->type = type;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
uv__queue_insert_tail(&loop->cf_signals, &item->member);
|
||||
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
@ -793,6 +789,7 @@ int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
|
||||
/* Runs in UV loop to initialize handle */
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
char* buf;
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
@ -801,13 +798,17 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return err;
|
||||
|
||||
/* Get absolute path to file */
|
||||
handle->realpath = realpath(handle->path, NULL);
|
||||
if (handle->realpath == NULL)
|
||||
buf = realpath(handle->path, NULL);
|
||||
if (buf == NULL)
|
||||
return UV__ERR(errno);
|
||||
handle->realpath = uv__strdup(buf);
|
||||
free(buf); /* _Not_ uv__free. */
|
||||
if (handle->realpath == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->realpath_len = strlen(handle->realpath);
|
||||
|
||||
/* Initialize event queue */
|
||||
QUEUE_INIT(&handle->cf_events);
|
||||
uv__queue_init(&handle->cf_events);
|
||||
handle->cf_error = 0;
|
||||
|
||||
/*
|
||||
@ -832,7 +833,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
/* Insert handle into the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
|
||||
uv__queue_insert_tail(&state->fsevent_handles, &handle->cf_member);
|
||||
state->fsevent_handle_count++;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
@ -872,7 +873,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
/* Remove handle from the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_REMOVE(&handle->cf_member);
|
||||
uv__queue_remove(&handle->cf_member);
|
||||
state->fsevent_handle_count--;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
@ -109,7 +109,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
/* See initialization in uv_getaddrinfo(). */
|
||||
if (req->hints)
|
||||
|
@ -58,7 +58,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
|
@ -394,6 +394,8 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs_pase *ifap = NULL, *cur;
|
||||
size_t namelen;
|
||||
char* name;
|
||||
int inet6, r = 0;
|
||||
|
||||
*count = 0;
|
||||
@ -403,6 +405,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return UV_ENOSYS;
|
||||
|
||||
/* The first loop to get the size of the array to be allocated */
|
||||
namelen = 0;
|
||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||
cur->ifa_addr->sa_family == AF_INET))
|
||||
@ -411,6 +414,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
namelen += strlen(cur->ifa_name) + 1;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
@ -420,11 +424,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||
if (*addresses == NULL) {
|
||||
Qp2freeifaddrs(ifap);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
name = (char*) &(*addresses)[*count];
|
||||
address = *addresses;
|
||||
|
||||
/* The second loop to fill in the array */
|
||||
@ -436,7 +442,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
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);
|
||||
|
||||
@ -497,13 +505,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.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) \
|
||||
do { \
|
||||
@ -71,8 +75,11 @@
|
||||
# include <poll.h>
|
||||
#endif /* _AIX */
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <AvailabilityMacros.h>
|
||||
#if defined(__APPLE__)
|
||||
# include "darwin-syscalls.h"
|
||||
# if !TARGET_OS_IPHONE
|
||||
# include <AvailabilityMacros.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -157,7 +164,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 0x1,
|
||||
UV_LOOP_REAP_CHILDREN = 0x2
|
||||
UV_LOOP_REAP_CHILDREN = 0x2,
|
||||
UV_LOOP_ENABLE_IO_URING_SQPOLL = 0x4
|
||||
};
|
||||
|
||||
/* flags of excluding ifaddr */
|
||||
@ -243,6 +251,7 @@ int uv__close(int fd); /* preserves errno */
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__close_nocancel(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__sock_reuseport(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
@ -287,6 +296,9 @@ int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
int uv__tcp_nodelay(int fd, int on);
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay);
|
||||
|
||||
/* tty */
|
||||
void uv__tty_close(uv_tty_t* handle);
|
||||
|
||||
/* pipe */
|
||||
int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
@ -315,6 +327,8 @@ void uv__prepare_close(uv_prepare_t* handle);
|
||||
void uv__process_close(uv_process_t* handle);
|
||||
void uv__stream_close(uv_stream_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);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
@ -332,23 +346,35 @@ int uv__random_sysctl(void* buf, size_t buflen);
|
||||
/* io_uring */
|
||||
#ifdef __linux__
|
||||
int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uint32_t fsync_flags);
|
||||
int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_read_or_write(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
int is_read);
|
||||
int uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_statx(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
int is_fstat,
|
||||
int is_lstat);
|
||||
int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req);
|
||||
#else
|
||||
#define uv__iou_fs_close(loop, req) 0
|
||||
#define uv__iou_fs_ftruncate(loop, req) 0
|
||||
#define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0
|
||||
#define uv__iou_fs_link(loop, req) 0
|
||||
#define uv__iou_fs_mkdir(loop, req) 0
|
||||
#define uv__iou_fs_open(loop, req) 0
|
||||
#define uv__iou_fs_read_or_write(loop, req, is_read) 0
|
||||
#define uv__iou_fs_rename(loop, req) 0
|
||||
#define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0
|
||||
#define uv__iou_fs_symlink(loop, req) 0
|
||||
#define uv__iou_fs_unlink(loop, req) 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -415,6 +441,7 @@ UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) {
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req);
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
off_t* off_in,
|
||||
@ -429,6 +456,7 @@ int uv__statx(int dirfd,
|
||||
struct uv__statx* statxbuf);
|
||||
void uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf);
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags);
|
||||
unsigned uv__kernel_version(void);
|
||||
#endif
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
@ -460,4 +488,44 @@ uv__fs_copy_file_range(int fd_in,
|
||||
#define UV__CPU_AFFINITY_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
typedef struct {
|
||||
long long quota_per_period;
|
||||
long long period_length;
|
||||
double proportions;
|
||||
} uv__cpu_constraint;
|
||||
|
||||
int uv__get_constrained_cpu(uv__cpu_constraint* constraint);
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && !defined(__illumos__)
|
||||
#ifdef SO_FLOW_NAME
|
||||
/* Since it's impossible to detect the Solaris 11.4 version via OS macros,
|
||||
* so we check the presence of the socket option SO_FLOW_NAME that was first
|
||||
* introduced to Solaris 11.4 and define a custom macro for determining 11.4.
|
||||
*/
|
||||
#define UV__SOLARIS_11_4 (1)
|
||||
#else
|
||||
#define UV__SOLARIS_11_4 (0)
|
||||
#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_ */
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
@ -94,20 +97,47 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent ev;
|
||||
int rc;
|
||||
struct kevent ev[2];
|
||||
struct stat sb;
|
||||
#ifdef __APPLE__
|
||||
char path[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
rc = UV__ERR(errno);
|
||||
if (uv__fstat(fd, &sb))
|
||||
return UV__ERR(errno);
|
||||
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
||||
if (rc == 0)
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
abort();
|
||||
/* On FreeBSD, kqueue only supports EVFILT_READ notification for regular files
|
||||
* and always reports ready events for writing, resulting in busy-looping.
|
||||
*
|
||||
* On Darwin, DragonFlyBSD, NetBSD and OpenBSD, kqueue reports ready events for
|
||||
* regular files as readable and writable only once, acting like an EV_ONESHOT.
|
||||
*
|
||||
* Neither of the above cases should be added to the kqueue.
|
||||
*/
|
||||
if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
|
||||
return UV_EINVAL;
|
||||
|
||||
return rc;
|
||||
#ifdef __APPLE__
|
||||
/* On Darwin (both macOS and iOS), in addition to regular files, FIFOs also don't
|
||||
* work properly with kqueue: the disconnection from the last writer won't trigger
|
||||
* an event for kqueue in spite of what the man pages say. Thus, we also disallow
|
||||
* the case of S_IFIFO. */
|
||||
if (S_ISFIFO(sb.st_mode)) {
|
||||
/* File descriptors of FIFO, pipe and kqueue share the same type of file,
|
||||
* therefore there is no way to tell them apart via stat.st_mode&S_IFMT.
|
||||
* Fortunately, FIFO is the only one that has a persisted file on filesystem,
|
||||
* from which we're able to make the distinction for it. */
|
||||
if (!fcntl(fd, F_GETPATH, path))
|
||||
return UV_EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
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, 2, NULL, 0, NULL))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -133,7 +163,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct timespec spec;
|
||||
unsigned int nevents;
|
||||
unsigned int revents;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv__io_t* w;
|
||||
uv_process_t* process;
|
||||
sigset_t* pset;
|
||||
@ -152,19 +182,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
nevents = 0;
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
while (!uv__queue_empty(&loop->watcher_queue)) {
|
||||
q = uv__queue_head(&loop->watcher_queue);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
w = uv__queue_data(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
@ -262,6 +292,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
|
||||
if (nfds == -1)
|
||||
assert(errno == EINTR);
|
||||
else if (nfds == 0)
|
||||
/* Unlimited timeout should only return with events or signal. */
|
||||
assert(timeout != -1);
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
|
||||
@ -286,8 +319,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
} else if (nfds == 0) {
|
||||
/* Reached the user timeout value. */
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -307,8 +338,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
|
||||
/* Handle kevent NOTE_EXIT results */
|
||||
if (ev->filter == EVFILT_PROC) {
|
||||
QUEUE_FOREACH(q, &loop->process_handles) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
uv__queue_foreach(q, &loop->process_handles) {
|
||||
process = uv__queue_data(q, uv_process_t, queue);
|
||||
if (process->pid == fd) {
|
||||
process->flags |= UV_HANDLE_REAP;
|
||||
loop->flags |= UV_LOOP_REAP_CHILDREN;
|
||||
@ -330,6 +361,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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) {
|
||||
assert(w->events == POLLIN);
|
||||
assert(w->pevents == POLLIN);
|
||||
@ -479,6 +521,26 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
|
||||
*/
|
||||
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
|
||||
path = uv__basename_r(pathbuf);
|
||||
#elif defined(F_KINFO)
|
||||
/* We try to get the file info reference from the file descriptor.
|
||||
* the struct's kf_structsize must be initialised beforehand
|
||||
* whether with the KINFO_FILE_SIZE constant or this way.
|
||||
*/
|
||||
struct stat statbuf;
|
||||
struct kinfo_file kf;
|
||||
|
||||
if (handle->event_watcher.fd != -1 &&
|
||||
(!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) {
|
||||
/* we are purposely not using KINFO_FILE_SIZE here
|
||||
* as it is not available on non intl archs
|
||||
* and here it gives 1392 too on intel.
|
||||
* anyway, the man page also mentions we can proceed
|
||||
* this way.
|
||||
*/
|
||||
kf.kf_structsize = sizeof(kf);
|
||||
if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0)
|
||||
path = uv__basename_r(kf.kf_path);
|
||||
}
|
||||
#endif
|
||||
handle->cb(handle, path, events, 0);
|
||||
|
||||
|
800
src/unix/linux.c
800
src/unix/linux.c
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@
|
||||
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
|
||||
if (uv__is_active(handle)) return 0; \
|
||||
if (cb == NULL) return UV_EINVAL; \
|
||||
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
|
||||
uv__queue_insert_head(&handle->loop->name##_handles, &handle->queue); \
|
||||
handle->name##_cb = cb; \
|
||||
uv__handle_start(handle); \
|
||||
return 0; \
|
||||
@ -40,21 +40,21 @@
|
||||
\
|
||||
int uv_##name##_stop(uv_##name##_t* handle) { \
|
||||
if (!uv__is_active(handle)) return 0; \
|
||||
QUEUE_REMOVE(&handle->queue); \
|
||||
uv__queue_remove(&handle->queue); \
|
||||
uv__handle_stop(handle); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
void uv__run_##name(uv_loop_t* loop) { \
|
||||
uv_##name##_t* h; \
|
||||
QUEUE queue; \
|
||||
QUEUE* q; \
|
||||
QUEUE_MOVE(&loop->name##_handles, &queue); \
|
||||
while (!QUEUE_EMPTY(&queue)) { \
|
||||
q = QUEUE_HEAD(&queue); \
|
||||
h = QUEUE_DATA(q, uv_##name##_t, queue); \
|
||||
QUEUE_REMOVE(q); \
|
||||
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
|
||||
struct uv__queue queue; \
|
||||
struct uv__queue* q; \
|
||||
uv__queue_move(&loop->name##_handles, &queue); \
|
||||
while (!uv__queue_empty(&queue)) { \
|
||||
q = uv__queue_head(&queue); \
|
||||
h = uv__queue_data(q, uv_##name##_t, queue); \
|
||||
uv__queue_remove(q); \
|
||||
uv__queue_insert_tail(&loop->name##_handles, q); \
|
||||
h->name##_cb(h); \
|
||||
} \
|
||||
} \
|
||||
|
@ -50,20 +50,20 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
sizeof(lfields->loop_metrics.metrics));
|
||||
|
||||
heap_init((struct heap*) &loop->timer_heap);
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->idle_handles);
|
||||
QUEUE_INIT(&loop->async_handles);
|
||||
QUEUE_INIT(&loop->check_handles);
|
||||
QUEUE_INIT(&loop->prepare_handles);
|
||||
QUEUE_INIT(&loop->handle_queue);
|
||||
uv__queue_init(&loop->wq);
|
||||
uv__queue_init(&loop->idle_handles);
|
||||
uv__queue_init(&loop->async_handles);
|
||||
uv__queue_init(&loop->check_handles);
|
||||
uv__queue_init(&loop->prepare_handles);
|
||||
uv__queue_init(&loop->handle_queue);
|
||||
|
||||
loop->active_handles = 0;
|
||||
loop->active_reqs.count = 0;
|
||||
loop->nfds = 0;
|
||||
loop->watchers = NULL;
|
||||
loop->nwatchers = 0;
|
||||
QUEUE_INIT(&loop->pending_queue);
|
||||
QUEUE_INIT(&loop->watcher_queue);
|
||||
uv__queue_init(&loop->pending_queue);
|
||||
uv__queue_init(&loop->watcher_queue);
|
||||
|
||||
loop->closing_handles = NULL;
|
||||
uv__update_time(loop);
|
||||
@ -85,7 +85,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
err = uv__process_init(loop);
|
||||
if (err)
|
||||
goto fail_signal_init;
|
||||
QUEUE_INIT(&loop->process_handles);
|
||||
uv__queue_init(&loop->process_handles);
|
||||
|
||||
err = uv_rwlock_init(&loop->cloexec_lock);
|
||||
if (err)
|
||||
@ -152,9 +152,9 @@ int uv_loop_fork(uv_loop_t* loop) {
|
||||
if (w == NULL)
|
||||
continue;
|
||||
|
||||
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
|
||||
if (w->pevents != 0 && uv__queue_empty(&w->watcher_queue)) {
|
||||
w->events = 0; /* Force re-registration in uv__io_poll. */
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(!uv__has_active_reqs(loop));
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
@ -192,8 +192,8 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
uv_rwlock_destroy(&loop->cloexec_lock);
|
||||
|
||||
#if 0
|
||||
assert(QUEUE_EMPTY(&loop->pending_queue));
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->pending_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
assert(loop->nfds == 0);
|
||||
#endif
|
||||
|
||||
@ -217,6 +217,14 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (option == UV_LOOP_USE_IO_URING_SQPOLL) {
|
||||
loop->flags |= UV_LOOP_ENABLE_IO_URING_SQPOLL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (option != UV_LOOP_BLOCK_SIGNAL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
|
@ -211,8 +211,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
which[1] = HW_CPUSPEED;
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
|
||||
cpuspeed = 0;
|
||||
/*
|
||||
* HW_CPUSPEED can return EOPNOTSUPP if cpuspeed is 0,
|
||||
* so ignore that and continue the flow, because we
|
||||
* still care about the rest of the CPU info.
|
||||
*/
|
||||
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0) &&
|
||||
(errno != EOPNOTSUPP)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
size = sizeof(info);
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <termios.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
static QUEUE global_epoll_queue;
|
||||
static struct uv__queue global_epoll_queue;
|
||||
static uv_mutex_t global_epoll_lock;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
@ -178,18 +178,18 @@ static void after_fork(void) {
|
||||
|
||||
|
||||
static void child_fork(void) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_once_t child_once = UV_ONCE_INIT;
|
||||
|
||||
/* reset once */
|
||||
memcpy(&once, &child_once, sizeof(child_once));
|
||||
|
||||
/* reset epoll list */
|
||||
while (!QUEUE_EMPTY(&global_epoll_queue)) {
|
||||
while (!uv__queue_empty(&global_epoll_queue)) {
|
||||
uv__os390_epoll* lst;
|
||||
q = QUEUE_HEAD(&global_epoll_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
lst = QUEUE_DATA(q, uv__os390_epoll, member);
|
||||
q = uv__queue_head(&global_epoll_queue);
|
||||
uv__queue_remove(q);
|
||||
lst = uv__queue_data(q, uv__os390_epoll, member);
|
||||
uv__free(lst->items);
|
||||
lst->items = NULL;
|
||||
lst->size = 0;
|
||||
@ -201,7 +201,7 @@ static void child_fork(void) {
|
||||
|
||||
|
||||
static void epoll_init(void) {
|
||||
QUEUE_INIT(&global_epoll_queue);
|
||||
uv__queue_init(&global_epoll_queue);
|
||||
if (uv_mutex_init(&global_epoll_lock))
|
||||
abort();
|
||||
|
||||
@ -225,7 +225,7 @@ uv__os390_epoll* epoll_create1(int flags) {
|
||||
lst->items[lst->size - 1].revents = 0;
|
||||
uv_once(&once, epoll_init);
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
|
||||
uv__queue_insert_tail(&global_epoll_queue, &lst->member);
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
}
|
||||
|
||||
@ -352,14 +352,14 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
|
||||
|
||||
int epoll_file_close(int fd) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
|
||||
uv_once(&once, epoll_init);
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
QUEUE_FOREACH(q, &global_epoll_queue) {
|
||||
uv__queue_foreach(q, &global_epoll_queue) {
|
||||
uv__os390_epoll* lst;
|
||||
|
||||
lst = QUEUE_DATA(q, uv__os390_epoll, member);
|
||||
lst = uv__queue_data(q, uv__os390_epoll, member);
|
||||
if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
|
||||
lst->items[fd].fd = -1;
|
||||
}
|
||||
@ -371,7 +371,7 @@ int epoll_file_close(int fd) {
|
||||
void epoll_queue_close(uv__os390_epoll* lst) {
|
||||
/* Remove epoll instance from global queue */
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
QUEUE_REMOVE(&lst->member);
|
||||
uv__queue_remove(&lst->member);
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
|
||||
/* Free resources */
|
||||
|
@ -45,7 +45,7 @@ struct epoll_event {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
QUEUE member;
|
||||
struct uv__queue member;
|
||||
struct pollfd* items;
|
||||
unsigned long size;
|
||||
int msg_queue;
|
||||
|
@ -19,6 +19,7 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
@ -30,6 +31,7 @@
|
||||
#include <sys/msg.h>
|
||||
#include <sys/resource.h>
|
||||
#include "zos-base.h"
|
||||
#include "zos-sys-info.h"
|
||||
#if defined(__clang__)
|
||||
#include "csrsic.h"
|
||||
#else
|
||||
@ -66,9 +68,6 @@
|
||||
/* Total number of frames currently on all available frame queues. */
|
||||
#define RCEAFC_OFFSET 0x088
|
||||
|
||||
/* CPC model length from the CSRSI Service. */
|
||||
#define CPCMODEL_LENGTH 16
|
||||
|
||||
/* Pointer to the home (current) ASCB. */
|
||||
#define PSAAOLD 0x224
|
||||
|
||||
@ -258,9 +257,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
idx = 0;
|
||||
while (idx < *count) {
|
||||
cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
|
||||
cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
|
||||
memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
|
||||
memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
|
||||
cpu_info->model = uv__malloc(ZOSCPU_MODEL_LENGTH + 1);
|
||||
if (cpu_info->model == NULL) {
|
||||
uv_free_cpu_info(*cpu_infos, idx);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
__get_cpu_model(cpu_info->model, ZOSCPU_MODEL_LENGTH + 1);
|
||||
cpu_info->cpu_times.user = cpu_usage_avg;
|
||||
/* TODO: implement the following */
|
||||
cpu_info->cpu_times.sys = 0;
|
||||
@ -815,7 +817,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
uv__os390_epoll* ep;
|
||||
int have_signals;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv__io_t* w;
|
||||
uint64_t base;
|
||||
int count;
|
||||
@ -827,19 +829,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
while (!uv__queue_empty(&loop->watcher_queue)) {
|
||||
uv_stream_t* stream;
|
||||
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
q = uv__queue_head(&loop->watcher_queue);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
w = uv__queue_data(q, uv__io_t, watcher_queue);
|
||||
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
|
210
src/unix/pipe.c
210
src/unix/pipe.c
@ -30,6 +30,21 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/* Does the file path contain embedded nul bytes? */
|
||||
static int includes_invalid_nul(const char *s, size_t n) {
|
||||
if (n == 0)
|
||||
return 0;
|
||||
#ifdef __linux__
|
||||
/* Accept abstract socket namespace paths, throughout which nul bytes have
|
||||
* no special significance ("\0foo\0bar").
|
||||
*/
|
||||
if (s[0] == '\0')
|
||||
return 0;
|
||||
#endif
|
||||
return NULL != memchr(s, '\0', n);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
||||
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
|
||||
handle->shutdown_req = NULL;
|
||||
@ -41,26 +56,68 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
||||
|
||||
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
return uv_pipe_bind2(handle, name, strlen(name), 0);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
const char* name,
|
||||
size_t namelen,
|
||||
unsigned int flags) {
|
||||
struct sockaddr_un saddr;
|
||||
const char* pipe_fname;
|
||||
char* pipe_fname;
|
||||
int sockfd;
|
||||
int err;
|
||||
socklen_t addrlen;
|
||||
|
||||
pipe_fname = NULL;
|
||||
|
||||
if (flags & ~UV_PIPE_NO_TRUNCATE)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (name == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* namelen==0 on Linux means autobind the listen socket in the abstract
|
||||
* socket namespace, see `man 7 unix` for details.
|
||||
*/
|
||||
#if !defined(__linux__)
|
||||
if (namelen == 0)
|
||||
return UV_EINVAL;
|
||||
#endif
|
||||
|
||||
if (includes_invalid_nul(name, namelen))
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Truncate long paths. Documented behavior. */
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
namelen = sizeof(saddr.sun_path);
|
||||
|
||||
/* Already bound? */
|
||||
if (uv__stream_fd(handle) >= 0)
|
||||
return UV_EINVAL;
|
||||
if (uv__is_closing(handle)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
/* Make a copy of the file name, it outlives this function's scope. */
|
||||
pipe_fname = uv__strdup(name);
|
||||
if (pipe_fname == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* We've got a copy, don't touch the original any more. */
|
||||
name = NULL;
|
||||
if (uv__is_closing(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Make a copy of the file path unless it is an abstract socket.
|
||||
* We unlink the file later but abstract sockets disappear
|
||||
* automatically since they're not real file system entities.
|
||||
*/
|
||||
if (*name == '\0') {
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
||||
} else {
|
||||
pipe_fname = uv__malloc(namelen + 1);
|
||||
if (pipe_fname == NULL)
|
||||
return UV_ENOMEM;
|
||||
memcpy(pipe_fname, name, namelen);
|
||||
pipe_fname[namelen] = '\0';
|
||||
addrlen = sizeof saddr;
|
||||
}
|
||||
|
||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
@ -68,10 +125,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
|
||||
memcpy(&saddr.sun_path, name, namelen);
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) {
|
||||
err = UV__ERR(errno);
|
||||
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
||||
if (err == UV_ENOENT)
|
||||
@ -83,12 +140,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
|
||||
/* Success. */
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
||||
handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */
|
||||
handle->io_watcher.fd = sockfd;
|
||||
return 0;
|
||||
|
||||
err_socket:
|
||||
uv__free((void*)pipe_fname);
|
||||
uv__free(pipe_fname);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -176,10 +233,56 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
uv_connect_cb cb) {
|
||||
int err;
|
||||
|
||||
err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
|
||||
|
||||
if (err) {
|
||||
handle->delayed_error = err;
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
uv__queue_init(&req->queue);
|
||||
|
||||
/* Force callback to run on next tick in case of error. */
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_connect2(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
size_t namelen,
|
||||
unsigned int flags,
|
||||
uv_connect_cb cb) {
|
||||
struct sockaddr_un saddr;
|
||||
int new_sock;
|
||||
int err;
|
||||
int r;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (flags & ~UV_PIPE_NO_TRUNCATE)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (name == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (namelen == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (includes_invalid_nul(name, namelen))
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Truncate long paths. Documented behavior. */
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
namelen = sizeof(saddr.sun_path);
|
||||
|
||||
new_sock = (uv__stream_fd(handle) == -1);
|
||||
|
||||
@ -191,12 +294,16 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
|
||||
memcpy(&saddr.sun_path, name, namelen);
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (*name == '\0')
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
||||
else
|
||||
addrlen = sizeof saddr;
|
||||
|
||||
do {
|
||||
r = connect(uv__stream_fd(handle),
|
||||
(struct sockaddr*)&saddr, sizeof saddr);
|
||||
r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
@ -228,14 +335,15 @@ out:
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*)handle;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
QUEUE_INIT(&req->queue);
|
||||
uv__queue_init(&req->queue);
|
||||
|
||||
/* Force callback to run on next tick in case of error. */
|
||||
if (err)
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -243,10 +351,20 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
uv__peersockfunc func,
|
||||
char* buffer,
|
||||
size_t* size) {
|
||||
#if defined(__linux__)
|
||||
static const int is_linux = 1;
|
||||
#else
|
||||
static const int is_linux = 0;
|
||||
#endif
|
||||
struct sockaddr_un sa;
|
||||
socklen_t addrlen;
|
||||
size_t slop;
|
||||
char* p;
|
||||
int err;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
memset(&sa, 0, addrlen);
|
||||
err = uv__getsockpeername((const uv_handle_t*) handle,
|
||||
@ -258,17 +376,20 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (sa.sun_path[0] == 0)
|
||||
/* Linux abstract namespace */
|
||||
slop = 1;
|
||||
if (is_linux && sa.sun_path[0] == '\0') {
|
||||
/* Linux abstract namespace. Not zero-terminated. */
|
||||
slop = 0;
|
||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||
else
|
||||
#endif
|
||||
addrlen = strlen(sa.sun_path);
|
||||
} else {
|
||||
p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path));
|
||||
if (p == NULL)
|
||||
p = ARRAY_END(sa.sun_path);
|
||||
addrlen = p - sa.sun_path;
|
||||
}
|
||||
|
||||
|
||||
if ((size_t)addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
if ((size_t)addrlen + slop > *size) {
|
||||
*size = addrlen + slop;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
@ -328,7 +449,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
||||
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
unsigned desired_mode;
|
||||
struct stat pipe_stat;
|
||||
char* name_buffer;
|
||||
char name_buffer[1 + UV__PATH_MAX];
|
||||
size_t name_len;
|
||||
int r;
|
||||
|
||||
@ -341,26 +462,14 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
|
||||
name_len = 0;
|
||||
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;
|
||||
|
||||
name_len = sizeof(name_buffer);
|
||||
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
||||
if (r != 0) {
|
||||
uv__free(name_buffer);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* stat must be used as fstat has a bug on Darwin */
|
||||
if (uv__stat(name_buffer, &pipe_stat) == -1) {
|
||||
uv__free(name_buffer);
|
||||
return -errno;
|
||||
}
|
||||
if (uv__stat(name_buffer, &pipe_stat) == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
desired_mode = 0;
|
||||
if (mode & UV_READABLE)
|
||||
@ -369,15 +478,12 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
|
||||
/* Exit early if pipe already has desired mode. */
|
||||
if ((pipe_stat.st_mode & desired_mode) == desired_mode) {
|
||||
uv__free(name_buffer);
|
||||
if ((pipe_stat.st_mode & desired_mode) == desired_mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pipe_stat.st_mode |= desired_mode;
|
||||
|
||||
r = chmod(name_buffer, pipe_stat.st_mode);
|
||||
uv__free(name_buffer);
|
||||
|
||||
return r != -1 ? 0 : UV__ERR(errno);
|
||||
}
|
||||
@ -386,7 +492,11 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) {
|
||||
uv_os_fd_t temp[2];
|
||||
int err;
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__NetBSD__)
|
||||
int flags = O_CLOEXEC;
|
||||
|
||||
if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
|
@ -137,7 +137,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
sigset_t set;
|
||||
uint64_t time_base;
|
||||
uint64_t time_diff;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv__io_t* w;
|
||||
size_t i;
|
||||
unsigned int nevents;
|
||||
@ -149,19 +149,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
|
||||
/* Take queued watchers and add their fds to our poll fds array. */
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
while (!uv__queue_empty(&loop->watcher_queue)) {
|
||||
q = uv__queue_head(&loop->watcher_queue);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
w = uv__queue_data(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
@ -55,7 +55,8 @@
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || \
|
||||
defined(__GNU__)
|
||||
# include <grp.h>
|
||||
#endif
|
||||
|
||||
@ -63,11 +64,7 @@ extern char **environ;
|
||||
# include "zos-base.h"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#else
|
||||
#define UV_USE_SIGCHLD
|
||||
@ -108,17 +105,17 @@ void uv__wait_children(uv_loop_t* loop) {
|
||||
int status;
|
||||
int options;
|
||||
pid_t pid;
|
||||
QUEUE pending;
|
||||
QUEUE* q;
|
||||
QUEUE* h;
|
||||
struct uv__queue pending;
|
||||
struct uv__queue* q;
|
||||
struct uv__queue* h;
|
||||
|
||||
QUEUE_INIT(&pending);
|
||||
uv__queue_init(&pending);
|
||||
|
||||
h = &loop->process_handles;
|
||||
q = QUEUE_HEAD(h);
|
||||
q = uv__queue_head(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
process = uv__queue_data(q, uv_process_t, queue);
|
||||
q = uv__queue_next(q);
|
||||
|
||||
#ifndef UV_USE_SIGCHLD
|
||||
if ((process->flags & UV_HANDLE_REAP) == 0)
|
||||
@ -149,18 +146,18 @@ void uv__wait_children(uv_loop_t* loop) {
|
||||
|
||||
assert(pid == process->pid);
|
||||
process->status = status;
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INSERT_TAIL(&pending, &process->queue);
|
||||
uv__queue_remove(&process->queue);
|
||||
uv__queue_insert_tail(&pending, &process->queue);
|
||||
}
|
||||
|
||||
h = &pending;
|
||||
q = QUEUE_HEAD(h);
|
||||
q = uv__queue_head(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
process = uv__queue_data(q, uv_process_t, queue);
|
||||
q = uv__queue_next(q);
|
||||
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INIT(&process->queue);
|
||||
uv__queue_remove(&process->queue);
|
||||
uv__queue_init(&process->queue);
|
||||
uv__handle_stop(process);
|
||||
|
||||
if (process->exit_cb == NULL)
|
||||
@ -176,18 +173,27 @@ void uv__wait_children(uv_loop_t* loop) {
|
||||
|
||||
process->exit_cb(process, exit_status, term_signal);
|
||||
}
|
||||
assert(QUEUE_EMPTY(&pending));
|
||||
assert(uv__queue_empty(&pending));
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for initializing stdio streams like options.stdin_stream. Returns
|
||||
* zero on success. See also the cleanup section in uv_spawn().
|
||||
*/
|
||||
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
||||
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
|
||||
* avoided. Since this isn't called on those targets, the function
|
||||
* doesn't even need to be defined for them.
|
||||
*/
|
||||
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||
int mask;
|
||||
int fd;
|
||||
int ret;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
|
||||
size = 64 * 1024;
|
||||
|
||||
switch (container->flags & mask) {
|
||||
case UV_IGNORE:
|
||||
@ -197,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||
assert(container->data.stream != NULL);
|
||||
if (container->data.stream->type != UV_NAMED_PIPE)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
|
||||
else {
|
||||
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_STREAM:
|
||||
@ -269,11 +284,6 @@ static void uv__write_errno(int error_fd) {
|
||||
}
|
||||
|
||||
|
||||
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
||||
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
|
||||
* avoided. Since this isn't called on those targets, the function
|
||||
* doesn't even need to be defined for them.
|
||||
*/
|
||||
static void uv__process_child_init(const uv_process_options_t* options,
|
||||
int stdio_count,
|
||||
int (*pipes)[2],
|
||||
@ -405,7 +415,6 @@ static void uv__process_child_init(const uv_process_options_t* options,
|
||||
|
||||
uv__write_errno(error_fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@ -952,6 +961,7 @@ static int uv__spawn_and_init_child(
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* ISN'T TARGET_OS_TV || TARGET_OS_WATCH */
|
||||
|
||||
int uv_spawn(uv_loop_t* loop,
|
||||
uv_process_t* process,
|
||||
@ -972,13 +982,14 @@ int uv_spawn(uv_loop_t* loop,
|
||||
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
QUEUE_INIT(&process->queue);
|
||||
uv__queue_init(&process->queue);
|
||||
process->status = 0;
|
||||
|
||||
stdio_count = options->stdio_count;
|
||||
@ -1041,7 +1052,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
process->pid = pid;
|
||||
process->exit_cb = options->exit_cb;
|
||||
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
|
||||
uv__queue_insert_tail(&loop->process_handles, &process->queue);
|
||||
uv__handle_start(process);
|
||||
}
|
||||
|
||||
@ -1103,10 +1114,10 @@ int uv_kill(int pid, int signum) {
|
||||
|
||||
|
||||
void uv__process_close(uv_process_t* handle) {
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__queue_remove(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
#ifdef UV_USE_SIGCHLD
|
||||
if (QUEUE_EMPTY(&handle->loop->process_handles))
|
||||
if (uv__queue_empty(&handle->loop->process_handles))
|
||||
uv_signal_stop(&handle->loop->child_watcher);
|
||||
#endif
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ static void uv__signal_handler(int signum) {
|
||||
|
||||
for (handle = uv__signal_first_handle(signum);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
|
||||
handle = RB_NEXT(uv__signal_tree_s, handle)) {
|
||||
int r;
|
||||
|
||||
msg.signum = signum;
|
||||
@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
|
||||
|
||||
|
||||
int uv__signal_loop_fork(uv_loop_t* loop) {
|
||||
struct uv__queue* q;
|
||||
|
||||
if (loop->signal_pipefd[0] == -1)
|
||||
return 0;
|
||||
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
|
||||
@ -286,21 +288,34 @@ int uv__signal_loop_fork(uv_loop_t* loop) {
|
||||
uv__close(loop->signal_pipefd[1]);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
loop->signal_pipefd[1] = -1;
|
||||
|
||||
uv__queue_foreach(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
uv_signal_t* sh;
|
||||
|
||||
if (handle->type != UV_SIGNAL)
|
||||
continue;
|
||||
|
||||
sh = (uv_signal_t*) handle;
|
||||
sh->caught_signals = 0;
|
||||
sh->dispatched_signals = 0;
|
||||
}
|
||||
|
||||
return uv__signal_loop_once_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_loop_cleanup(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
|
||||
/* Stop all the signal watchers that are still attached to this loop. This
|
||||
* ensures that the (shared) signal tree doesn't contain any invalid entries
|
||||
* entries, and that signal handlers are removed when appropriate.
|
||||
* It's safe to use QUEUE_FOREACH here because the handles and the handle
|
||||
* It's safe to use uv__queue_foreach here because the handles and the handle
|
||||
* queue are not modified by uv__signal_stop().
|
||||
*/
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
uv__queue_foreach(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
|
||||
if (handle->type == UV_SIGNAL)
|
||||
uv__signal_stop((uv_signal_t*) handle);
|
||||
|
@ -94,8 +94,8 @@ void uv__stream_init(uv_loop_t* loop,
|
||||
stream->accepted_fd = -1;
|
||||
stream->queued_fds = NULL;
|
||||
stream->delayed_error = 0;
|
||||
QUEUE_INIT(&stream->write_queue);
|
||||
QUEUE_INIT(&stream->write_completed_queue);
|
||||
uv__queue_init(&stream->write_queue);
|
||||
uv__queue_init(&stream->write_completed_queue);
|
||||
stream->write_queue_size = 0;
|
||||
|
||||
if (loop->emfile_fd == -1) {
|
||||
@ -439,15 +439,15 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
|
||||
|
||||
void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
|
||||
uv_write_t* req;
|
||||
QUEUE* q;
|
||||
while (!QUEUE_EMPTY(&stream->write_queue)) {
|
||||
q = QUEUE_HEAD(&stream->write_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
struct uv__queue* q;
|
||||
while (!uv__queue_empty(&stream->write_queue)) {
|
||||
q = uv__queue_head(&stream->write_queue);
|
||||
uv__queue_remove(q);
|
||||
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
req = uv__queue_data(q, uv_write_t, queue);
|
||||
req->error = error;
|
||||
|
||||
QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
|
||||
uv__queue_insert_tail(&stream->write_completed_queue, &req->queue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +457,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
|
||||
assert(stream->flags & UV_HANDLE_CLOSED);
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__req_unregister(stream->loop, stream->connect_req);
|
||||
uv__req_unregister(stream->loop);
|
||||
stream->connect_req->cb(stream->connect_req, UV_ECANCELED);
|
||||
stream->connect_req = NULL;
|
||||
}
|
||||
@ -627,7 +627,7 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
uv_shutdown_t* req;
|
||||
int err;
|
||||
|
||||
assert(QUEUE_EMPTY(&stream->write_queue));
|
||||
assert(uv__queue_empty(&stream->write_queue));
|
||||
if (!(stream->flags & UV_HANDLE_CLOSING)) {
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
@ -642,7 +642,7 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
if ((stream->flags & UV_HANDLE_CLOSING) ||
|
||||
!(stream->flags & UV_HANDLE_SHUT)) {
|
||||
stream->shutdown_req = NULL;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
err = 0;
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
@ -698,7 +698,8 @@ static int uv__write_req_update(uv_stream_t* stream,
|
||||
|
||||
do {
|
||||
len = n < buf->len ? n : buf->len;
|
||||
buf->base += len;
|
||||
if (buf->len != 0)
|
||||
buf->base += len;
|
||||
buf->len -= len;
|
||||
buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */
|
||||
n -= len;
|
||||
@ -714,7 +715,7 @@ static void uv__write_req_finish(uv_write_t* req) {
|
||||
uv_stream_t* stream = req->handle;
|
||||
|
||||
/* Pop the req off tcp->write_queue. */
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
uv__queue_remove(&req->queue);
|
||||
|
||||
/* Only free when there was no error. On error, we touch up write_queue_size
|
||||
* right before making the callback. The reason we don't do that right away
|
||||
@ -731,7 +732,7 @@ static void uv__write_req_finish(uv_write_t* req) {
|
||||
/* Add it to the write_completed_queue where it will have its
|
||||
* callback called in the near future.
|
||||
*/
|
||||
QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
|
||||
uv__queue_insert_tail(&stream->write_completed_queue, &req->queue);
|
||||
uv__io_feed(stream->loop, &stream->io_watcher);
|
||||
}
|
||||
|
||||
@ -837,7 +838,7 @@ static int uv__try_write(uv_stream_t* stream,
|
||||
}
|
||||
|
||||
static void uv__write(uv_stream_t* stream) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_write_t* req;
|
||||
ssize_t n;
|
||||
int count;
|
||||
@ -851,11 +852,11 @@ static void uv__write(uv_stream_t* stream) {
|
||||
count = 32;
|
||||
|
||||
for (;;) {
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
if (uv__queue_empty(&stream->write_queue))
|
||||
return;
|
||||
|
||||
q = QUEUE_HEAD(&stream->write_queue);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
q = uv__queue_head(&stream->write_queue);
|
||||
req = uv__queue_data(q, uv_write_t, queue);
|
||||
assert(req->handle == stream);
|
||||
|
||||
n = uv__try_write(stream,
|
||||
@ -899,20 +900,20 @@ error:
|
||||
|
||||
static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
uv_write_t* req;
|
||||
QUEUE* q;
|
||||
QUEUE pq;
|
||||
struct uv__queue* q;
|
||||
struct uv__queue pq;
|
||||
|
||||
if (QUEUE_EMPTY(&stream->write_completed_queue))
|
||||
if (uv__queue_empty(&stream->write_completed_queue))
|
||||
return;
|
||||
|
||||
QUEUE_MOVE(&stream->write_completed_queue, &pq);
|
||||
uv__queue_move(&stream->write_completed_queue, &pq);
|
||||
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
while (!uv__queue_empty(&pq)) {
|
||||
/* Pop a req off write_completed_queue. */
|
||||
q = QUEUE_HEAD(&pq);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
QUEUE_REMOVE(q);
|
||||
uv__req_unregister(stream->loop, req);
|
||||
q = uv__queue_head(&pq);
|
||||
req = uv__queue_data(q, uv_write_t, queue);
|
||||
uv__queue_remove(q);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
if (req->bufs != NULL) {
|
||||
stream->write_queue_size -= uv__write_req_size(req);
|
||||
@ -979,11 +980,13 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
|
||||
|
||||
static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
|
||||
struct cmsghdr* cmsg;
|
||||
char* p;
|
||||
char* pe;
|
||||
int fd;
|
||||
int err;
|
||||
size_t i;
|
||||
size_t count;
|
||||
|
||||
err = 0;
|
||||
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
|
||||
@ -996,24 +999,26 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
|
||||
assert(count % sizeof(fd) == 0);
|
||||
count /= sizeof(fd);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
memcpy(&fd, (char*) CMSG_DATA(cmsg) + i * sizeof(fd), sizeof(fd));
|
||||
/* Already has accepted fd, queue now */
|
||||
if (stream->accepted_fd != -1) {
|
||||
err = uv__stream_queue_fd(stream, fd);
|
||||
if (err != 0) {
|
||||
/* Close rest */
|
||||
for (; i < count; i++)
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
stream->accepted_fd = fd;
|
||||
p = (void*) CMSG_DATA(cmsg);
|
||||
pe = p + count * sizeof(fd);
|
||||
|
||||
while (p < pe) {
|
||||
memcpy(&fd, p, sizeof(fd));
|
||||
p += sizeof(fd);
|
||||
|
||||
if (err == 0) {
|
||||
if (stream->accepted_fd == -1)
|
||||
stream->accepted_fd = fd;
|
||||
else
|
||||
err = uv__stream_queue_fd(stream, fd);
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
uv__close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -1174,7 +1179,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
stream->shutdown_req = req;
|
||||
stream->flags &= ~UV_HANDLE_WRITABLE;
|
||||
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
if (uv__queue_empty(&stream->write_queue))
|
||||
uv__io_feed(stream->loop, &stream->io_watcher);
|
||||
|
||||
return 0;
|
||||
@ -1227,7 +1232,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
uv__write_callbacks(stream);
|
||||
|
||||
/* Write queue drained. */
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
if (uv__queue_empty(&stream->write_queue))
|
||||
uv__drain(stream);
|
||||
}
|
||||
}
|
||||
@ -1268,9 +1273,9 @@ static void uv__stream_connect(uv_stream_t* stream) {
|
||||
return;
|
||||
|
||||
stream->connect_req = NULL;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
|
||||
if (error < 0 || uv__queue_empty(&stream->write_queue)) {
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
}
|
||||
|
||||
@ -1352,7 +1357,7 @@ int uv_write2(uv_write_t* req,
|
||||
req->handle = stream;
|
||||
req->error = 0;
|
||||
req->send_handle = send_handle;
|
||||
QUEUE_INIT(&req->queue);
|
||||
uv__queue_init(&req->queue);
|
||||
|
||||
req->bufs = req->bufsml;
|
||||
if (nbufs > ARRAY_SIZE(req->bufsml))
|
||||
@ -1367,7 +1372,7 @@ int uv_write2(uv_write_t* req,
|
||||
stream->write_queue_size += uv__count_bufs(bufs, nbufs);
|
||||
|
||||
/* Append the request to write_queue. */
|
||||
QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
|
||||
uv__queue_insert_tail(&stream->write_queue, &req->queue);
|
||||
|
||||
/* If the queue was empty when this function began, we should attempt to
|
||||
* do the write immediately. Otherwise start the write_watcher and wait
|
||||
|
@ -148,7 +148,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct port_event events[1024];
|
||||
struct port_event* pe;
|
||||
struct timespec spec;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv__io_t* w;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
@ -166,16 +166,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(uv__queue_empty(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
while (!uv__queue_empty(&loop->watcher_queue)) {
|
||||
q = uv__queue_head(&loop->watcher_queue);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_init(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
w = uv__queue_data(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
|
||||
if (port_associate(loop->backend_fd,
|
||||
@ -316,8 +316,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
continue; /* Disabled by callback. */
|
||||
|
||||
/* Events Ports operates in oneshot mode, rearm timer on next run. */
|
||||
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
if (w->pevents != 0 && uv__queue_empty(&w->watcher_queue))
|
||||
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
|
||||
uv__metrics_inc_events(loop, nevents);
|
||||
@ -826,6 +826,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
size_t namelen;
|
||||
char* name;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
@ -834,9 +836,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
namelen = 0;
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent))
|
||||
continue;
|
||||
namelen += strlen(ent->ifa_name) + 1;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
@ -845,19 +849,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
|
||||
if (*addresses == NULL) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
name = (char*) &(*addresses)[*count];
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent))
|
||||
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) {
|
||||
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 */
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
int count) {
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
214
src/unix/tcp.c
214
src/unix/tcp.c
@ -27,6 +27,13 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* ifaddrs is not implemented on AIX and IBM i PASE */
|
||||
#if !defined(_AIX)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
static int maybe_bind_socket(int fd) {
|
||||
union uv__sockaddr s;
|
||||
@ -124,7 +131,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
|
||||
if (domain != AF_UNSPEC) {
|
||||
err = new_socket(tcp, domain, 0);
|
||||
if (err) {
|
||||
QUEUE_REMOVE(&tcp->handle_queue);
|
||||
uv__queue_remove(&tcp->handle_queue);
|
||||
if (tcp->io_watcher.fd != -1)
|
||||
uv__close(tcp->io_watcher.fd);
|
||||
tcp->io_watcher.fd = -1;
|
||||
@ -160,6 +167,12 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (flags & UV_TCP_REUSEPORT) {
|
||||
err = uv__sock_reuseport(tcp->io_watcher.fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
@ -198,11 +211,75 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
}
|
||||
|
||||
|
||||
static int uv__is_ipv6_link_local(const struct sockaddr* addr) {
|
||||
const struct sockaddr_in6* a6;
|
||||
uint8_t b[2];
|
||||
|
||||
if (addr->sa_family != AF_INET6)
|
||||
return 0;
|
||||
|
||||
a6 = (const struct sockaddr_in6*) addr;
|
||||
memcpy(b, &a6->sin6_addr, sizeof(b));
|
||||
|
||||
return b[0] == 0xFE && b[1] == 0x80;
|
||||
}
|
||||
|
||||
|
||||
static int uv__ipv6_link_local_scope_id(void) {
|
||||
struct sockaddr_in6* a6;
|
||||
int rv;
|
||||
#if defined(_AIX)
|
||||
/* AIX & IBM i do not have ifaddrs
|
||||
* so fallback to use uv_interface_addresses */
|
||||
uv_interface_address_t* interfaces;
|
||||
uv_interface_address_t* ifa;
|
||||
int count, i;
|
||||
|
||||
if (uv_interface_addresses(&interfaces, &count))
|
||||
return 0;
|
||||
|
||||
rv = 0;
|
||||
|
||||
for (ifa = interfaces; ifa != &interfaces[count]; ifa++) {
|
||||
if (uv__is_ipv6_link_local((struct sockaddr*) &ifa->address)) {
|
||||
rv = ifa->address.address6.sin6_scope_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uv_free_interface_addresses(interfaces, count);
|
||||
|
||||
#else
|
||||
struct ifaddrs* ifa;
|
||||
struct ifaddrs* p;
|
||||
|
||||
if (getifaddrs(&ifa))
|
||||
return 0;
|
||||
|
||||
for (p = ifa; p != NULL; p = p->ifa_next)
|
||||
if (p->ifa_addr != NULL)
|
||||
if (uv__is_ipv6_link_local(p->ifa_addr))
|
||||
break;
|
||||
|
||||
rv = 0;
|
||||
if (p != NULL) {
|
||||
a6 = (struct sockaddr_in6*) p->ifa_addr;
|
||||
rv = a6->sin6_scope_id;
|
||||
}
|
||||
|
||||
freeifaddrs(ifa);
|
||||
#endif /* defined(_AIX) */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_connect_cb cb) {
|
||||
struct sockaddr_in6 tmp6;
|
||||
int err;
|
||||
int r;
|
||||
|
||||
@ -220,6 +297,14 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (uv__is_ipv6_link_local(addr)) {
|
||||
memcpy(&tmp6, addr, sizeof(tmp6));
|
||||
if (tmp6.sin6_scope_id == 0) {
|
||||
tmp6.sin6_scope_id = uv__ipv6_link_local_scope_id();
|
||||
addr = (void*) &tmp6;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(uv__stream_fd(handle), addr, addrlen);
|
||||
@ -252,7 +337,7 @@ out:
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
QUEUE_INIT(&req->queue);
|
||||
uv__queue_init(&req->queue);
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
@ -373,32 +458,121 @@ int uv__tcp_nodelay(int fd, int on) {
|
||||
}
|
||||
|
||||
|
||||
#if (defined(UV__SOLARIS_11_4) && !UV__SOLARIS_11_4) || \
|
||||
(defined(__DragonFly__) && __DragonFly_version < 500702)
|
||||
/* DragonFlyBSD <500702 and Solaris <11.4 require millisecond units
|
||||
* for TCP keepalive options. */
|
||||
#define UV_KEEPALIVE_FACTOR(x) (x *= 1000)
|
||||
#else
|
||||
#define UV_KEEPALIVE_FACTOR(x)
|
||||
#endif
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
int idle;
|
||||
int intvl;
|
||||
int cnt;
|
||||
|
||||
(void) &idle;
|
||||
(void) &intvl;
|
||||
(void) &cnt;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (on) {
|
||||
int intvl = 1; /* 1 second; same as default on Win32 */
|
||||
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
if (!on)
|
||||
return 0;
|
||||
|
||||
/* Solaris/SmartOS, if you don't support keep-alive,
|
||||
* then don't advertise it in your system headers...
|
||||
if (delay < 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
#ifdef __sun
|
||||
/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
|
||||
* compared to other Unix-like systems.
|
||||
* Thus, we need to specialize it on Solaris.
|
||||
*
|
||||
* There are two keep-alive mechanisms on Solaris:
|
||||
* - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours.
|
||||
* If the peer does not respond to the probe within eight minutes, the TCP connection is aborted.
|
||||
* You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD
|
||||
* in milliseconds or TCP_KEEPIDLE in seconds.
|
||||
* The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds.
|
||||
* The maximum is ten days, while the default is two hours. If you receive no response to the probe,
|
||||
* you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection.
|
||||
* The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and
|
||||
* abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval.
|
||||
* The default is eight minutes.
|
||||
*
|
||||
* - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set.
|
||||
* The time between each consequent probes is set by TCP_KEEPINTVL in seconds.
|
||||
* The minimum value is ten seconds. The maximum is ten days, while the default is two hours.
|
||||
* The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response.
|
||||
*/
|
||||
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
|
||||
#if defined(TCP_KEEPALIVE) && !defined(__sun)
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
|
||||
|
||||
idle = delay;
|
||||
/* Kernel expects at least 10 seconds. */
|
||||
if (idle < 10)
|
||||
idle = 10;
|
||||
/* Kernel expects at most 10 days. */
|
||||
if (idle > 10*24*60*60)
|
||||
idle = 10*24*60*60;
|
||||
|
||||
UV_KEEPALIVE_FACTOR(idle);
|
||||
|
||||
/* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris
|
||||
* until version 11.4, but let's take a chance here. */
|
||||
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
intvl = 10; /* required at least 10 seconds */
|
||||
UV_KEEPALIVE_FACTOR(intvl);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
cnt = 1; /* 1 retry, ensure (TCP_KEEPINTVL * TCP_KEEPCNT) is 10 seconds */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
/* Fall back to the first implementation of tcp-alive mechanism for older Solaris,
|
||||
* simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
|
||||
*/
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Note that the consequent probes will not be sent at equal intervals on Solaris,
|
||||
* but will be sent using the exponential backoff algorithm. */
|
||||
int time_to_abort = 10; /* 10 seconds */
|
||||
UV_KEEPALIVE_FACTOR(time_to_abort);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#else /* !defined(__sun) */
|
||||
|
||||
idle = delay;
|
||||
UV_KEEPALIVE_FACTOR(idle);
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPINTVL
|
||||
intvl = 1; /* 1 second; same as default on Win32 */
|
||||
UV_KEEPALIVE_FACTOR(intvl);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPCNT
|
||||
cnt = 10; /* 10 retries; same as hardcoded on Win32 */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__sun) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -456,7 +630,7 @@ void uv__tcp_close(uv_tcp_t* handle) {
|
||||
int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
|
||||
uv_os_sock_t temp[2];
|
||||
int err;
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
|
||||
int flags;
|
||||
|
||||
flags = type | SOCK_CLOEXEC;
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
#include <assert.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);
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_detach(uv_thread_t *tid) {
|
||||
return UV__ERR(pthread_detach(*tid));
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
@ -205,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid,
|
||||
if (cpumask[i])
|
||||
CPU_SET(i, &cpuset);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__OHOS__)
|
||||
if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
||||
r = errno;
|
||||
else
|
||||
@ -233,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid,
|
||||
return UV_EINVAL;
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__OHOS__)
|
||||
if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
|
||||
r = errno;
|
||||
else
|
||||
@ -291,6 +300,18 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* 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) {
|
||||
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
||||
@ -789,11 +810,33 @@ void uv_cond_broadcast(uv_cond_t* cond) {
|
||||
abort();
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
int r;
|
||||
|
||||
errno = 0;
|
||||
r = pthread_cond_wait(cond, mutex);
|
||||
|
||||
/* Workaround for a bug in OS X at least up to 13.6
|
||||
* See https://github.com/libuv/libuv/issues/4165
|
||||
*/
|
||||
if (r == EINVAL)
|
||||
if (errno == EBUSY)
|
||||
return;
|
||||
|
||||
if (r)
|
||||
abort();
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (pthread_cond_wait(cond, mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
int r;
|
||||
@ -853,3 +896,80 @@ void uv_key_set(uv_key_t* key, void* value) {
|
||||
if (pthread_setspecific(*key, value))
|
||||
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
|
||||
|
@ -222,7 +222,7 @@ skip:
|
||||
int rc = r;
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
QUEUE_REMOVE(&tty->handle_queue);
|
||||
uv__queue_remove(&tty->handle_queue);
|
||||
do
|
||||
r = fcntl(fd, F_SETFL, saved_flags);
|
||||
while (r == -1 && errno == EINTR);
|
||||
@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
int fd;
|
||||
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)
|
||||
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:
|
||||
uv__tty_make_raw(&tmp);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
/* Apply changes after draining */
|
||||
@ -335,6 +342,37 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
|
||||
|
||||
void uv__tty_close(uv_tty_t* handle) {
|
||||
int expected;
|
||||
int fd;
|
||||
|
||||
fd = handle->io_watcher.fd;
|
||||
if (fd == -1)
|
||||
goto done;
|
||||
|
||||
/* This is used for uv_tty_reset_mode() */
|
||||
do
|
||||
expected = 0;
|
||||
while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1));
|
||||
|
||||
if (fd == orig_termios_fd) {
|
||||
/* XXX(bnoordhuis) the tcsetattr is probably wrong when there are still
|
||||
* other uv_tty_t handles active that refer to the same tty/pty but it's
|
||||
* hard to recognize that particular situation without maintaining some
|
||||
* kind of process-global data structure, and that still won't work in a
|
||||
* multi-process setup.
|
||||
*/
|
||||
uv__tcsetattr(fd, TCSANOW, &orig_termios);
|
||||
orig_termios_fd = -1;
|
||||
}
|
||||
|
||||
atomic_store(&termios_spinlock, 0);
|
||||
|
||||
done:
|
||||
uv__stream_close((uv_stream_t*) handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
struct winsize ws;
|
||||
int err;
|
||||
@ -452,7 +490,7 @@ int uv_tty_reset_mode(void) {
|
||||
saved_errno = errno;
|
||||
|
||||
if (atomic_exchange(&termios_spinlock, 1))
|
||||
return UV_EBUSY; /* In uv_tty_set_mode(). */
|
||||
return UV_EBUSY; /* In uv_tty_set_mode() or uv__tty_close(). */
|
||||
|
||||
err = 0;
|
||||
if (orig_termios_fd != -1)
|
||||
|
470
src/unix/udp.c
470
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,
|
||||
int domain,
|
||||
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) {
|
||||
@ -62,18 +66,18 @@ void uv__udp_close(uv_udp_t* handle) {
|
||||
|
||||
void uv__udp_finish_close(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
|
||||
assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
|
||||
assert(handle->io_watcher.fd == -1);
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
while (!uv__queue_empty(&handle->write_queue)) {
|
||||
q = uv__queue_head(&handle->write_queue);
|
||||
uv__queue_remove(q);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
req->status = UV_ECANCELED;
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
|
||||
uv__udp_run_completed(handle);
|
||||
@ -90,17 +94,17 @@ void uv__udp_finish_close(uv_udp_t* handle) {
|
||||
|
||||
static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
|
||||
assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
|
||||
handle->flags |= UV_HANDLE_UDP_PROCESSING;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_completed_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
while (!uv__queue_empty(&handle->write_completed_queue)) {
|
||||
q = uv__queue_head(&handle->write_completed_queue);
|
||||
uv__queue_remove(q);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
uv__req_unregister(handle->loop, req);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
uv__req_unregister(handle->loop);
|
||||
|
||||
handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
|
||||
handle->send_queue_count--;
|
||||
@ -121,7 +125,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
req->send_cb(req, req->status);
|
||||
}
|
||||
|
||||
if (QUEUE_EMPTY(&handle->write_queue)) {
|
||||
if (uv__queue_empty(&handle->write_queue)) {
|
||||
/* Pending queue and completion queue empty, stop watcher. */
|
||||
uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
if (!uv__io_active(&handle->io_watcher, POLLIN))
|
||||
@ -141,14 +145,14 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
|
||||
if (revents & POLLIN)
|
||||
uv__udp_recvmsg(handle);
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
if (revents & POLLOUT && !uv__is_closing(handle)) {
|
||||
uv__udp_sendmsg(handle);
|
||||
uv__udp_run_completed(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
struct sockaddr_in6 peers[20];
|
||||
struct iovec iov[ARRAY_SIZE(peers)];
|
||||
struct mmsghdr msgs[ARRAY_SIZE(peers)];
|
||||
@ -173,11 +177,18 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
msgs[k].msg_hdr.msg_control = NULL;
|
||||
msgs[k].msg_hdr.msg_controllen = 0;
|
||||
msgs[k].msg_hdr.msg_flags = 0;
|
||||
msgs[k].msg_len = 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
do
|
||||
nread = recvmsg_x(handle->io_watcher.fd, msgs, chunks, MSG_DONTWAIT);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
#else
|
||||
do
|
||||
nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
#endif
|
||||
|
||||
if (nread < 1) {
|
||||
if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
@ -204,9 +215,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
|
||||
}
|
||||
return nread;
|
||||
#else /* __linux__ || ____FreeBSD__ */
|
||||
#else /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
||||
return UV_ENOSYS;
|
||||
#endif /* __linux__ || ____FreeBSD__ */
|
||||
#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
||||
}
|
||||
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
@ -275,164 +286,25 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
&& handle->recv_cb != NULL);
|
||||
}
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
uv_udp_send_t* req;
|
||||
struct mmsghdr h[20];
|
||||
struct mmsghdr* p;
|
||||
QUEUE* q;
|
||||
ssize_t npkts;
|
||||
size_t pkts;
|
||||
size_t i;
|
||||
|
||||
if (QUEUE_EMPTY(&handle->write_queue))
|
||||
return;
|
||||
|
||||
write_queue_drain:
|
||||
for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
pkts < ARRAY_SIZE(h) && q != &handle->write_queue;
|
||||
++pkts, q = QUEUE_HEAD(q)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
p = &h[pkts];
|
||||
memset(p, 0, sizeof(*p));
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
p->msg_hdr.msg_name = NULL;
|
||||
p->msg_hdr.msg_namelen = 0;
|
||||
} else {
|
||||
p->msg_hdr.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
|
||||
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
|
||||
}
|
||||
|
||||
do
|
||||
npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0);
|
||||
while (npkts == -1 && errno == EINTR);
|
||||
|
||||
if (npkts < 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
return;
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < pkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = UV__ERR(errno);
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Safety: npkts known to be >0 below. Hence cast from ssize_t
|
||||
* to size_t safe.
|
||||
*/
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < (size_t)npkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = req->bufs[0].len;
|
||||
|
||||
/* Sending a datagram is an atomic operation: either all data
|
||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
||||
* why we don't handle partial writes. Just pop the request
|
||||
* off the write queue and onto the completed queue, done.
|
||||
*/
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
|
||||
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
|
||||
if (!QUEUE_EMPTY(&handle->write_queue))
|
||||
goto write_queue_drain;
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
#else /* __linux__ || ____FreeBSD__ */
|
||||
uv_udp_send_t* req;
|
||||
struct msghdr h;
|
||||
QUEUE* q;
|
||||
ssize_t size;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
assert(q != NULL);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
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)
|
||||
break;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
}
|
||||
#endif /* __linux__ || ____FreeBSD__ */
|
||||
}
|
||||
|
||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||
* refinements for programs that use multicast.
|
||||
* refinements for programs that use multicast. Therefore we preferentially
|
||||
* set SO_REUSEPORT over SO_REUSEADDR here, but we set SO_REUSEPORT only
|
||||
* when that socket option doesn't have the capability of load balancing.
|
||||
* Otherwise, we fall back to SO_REUSEADDR.
|
||||
*
|
||||
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
|
||||
* are different from the BSDs: it _shares_ the port rather than steal it
|
||||
* from the current listener. While useful, it's not something we can emulate
|
||||
* on other platforms so we don't enable it.
|
||||
* Linux as of 3.9, DragonflyBSD 3.6, AIX 7.2.5 have the SO_REUSEPORT socket
|
||||
* option but with semantics that are different from the BSDs: it _shares_
|
||||
* the port rather than steals it from the current listener. While useful,
|
||||
* it's not something we can emulate on other platforms so we don't enable it.
|
||||
*
|
||||
* zOS does not support getsockname with SO_REUSEPORT option when using
|
||||
* AF_UNIX.
|
||||
*
|
||||
* Solaris 11.4: SO_REUSEPORT will not load balance when SO_REUSEADDR
|
||||
* is also set, but it's not valid for every socket type.
|
||||
*/
|
||||
static int uv__set_reuse(int fd) {
|
||||
static int uv__sock_reuseaddr(int fd) {
|
||||
int yes;
|
||||
yes = 1;
|
||||
|
||||
@ -448,8 +320,18 @@ static int uv__set_reuse(int fd) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \
|
||||
!defined(__sun__)
|
||||
#elif defined(SO_REUSEPORT) && defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) {
|
||||
if (errno != ENOPROTOOPT)
|
||||
return UV__ERR(errno);
|
||||
/* Not all socket types accept SO_REUSEPORT. */
|
||||
errno = 0;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && \
|
||||
!defined(__linux__) && !defined(__GNU__) && \
|
||||
!defined(__illumos__) && !defined(__DragonFly__) && !defined(_AIX73)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
@ -492,7 +374,8 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
int fd;
|
||||
|
||||
/* Check for bad flags. */
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR |
|
||||
UV_UDP_REUSEPORT | UV_UDP_LINUX_RECVERR))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
@ -515,7 +398,13 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEADDR) {
|
||||
err = uv__set_reuse(fd);
|
||||
err = uv__sock_reuseaddr(fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEPORT) {
|
||||
err = uv__sock_reuseport(fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -708,11 +597,11 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
empty_queue = (handle->send_queue_count == 0);
|
||||
|
||||
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
||||
assert(addrlen <= sizeof(req->addr));
|
||||
assert(addrlen <= sizeof(req->u.storage));
|
||||
if (addr == NULL)
|
||||
req->addr.ss_family = AF_UNSPEC;
|
||||
req->u.storage.ss_family = AF_UNSPEC;
|
||||
else
|
||||
memcpy(&req->addr, addr, addrlen);
|
||||
memcpy(&req->u.storage, addr, addrlen);
|
||||
req->send_cb = send_cb;
|
||||
req->handle = handle;
|
||||
req->nbufs = nbufs;
|
||||
@ -722,14 +611,14 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
|
||||
|
||||
if (req->bufs == NULL) {
|
||||
uv__req_unregister(handle->loop, req);
|
||||
uv__req_unregister(handle->loop);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
|
||||
handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
|
||||
handle->send_queue_count++;
|
||||
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
|
||||
uv__queue_insert_tail(&handle->write_queue, &req->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
|
||||
@ -739,7 +628,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
* away. In such cases the `io_watcher` has to be queued for asynchronous
|
||||
* write.
|
||||
*/
|
||||
if (!QUEUE_EMPTY(&handle->write_queue))
|
||||
if (!uv__queue_empty(&handle->write_queue))
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
} else {
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
@ -755,10 +644,9 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen) {
|
||||
int err;
|
||||
struct msghdr h;
|
||||
ssize_t size;
|
||||
|
||||
assert(nbufs > 0);
|
||||
if (nbufs < 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* already sending a message */
|
||||
if (handle->send_queue_count != 0)
|
||||
@ -772,24 +660,11 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
|
||||
}
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
h.msg_name = (struct sockaddr*) addr;
|
||||
h.msg_namelen = addrlen;
|
||||
h.msg_iov = (struct iovec*) bufs;
|
||||
h.msg_iovlen = nbufs;
|
||||
err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr);
|
||||
if (err > 0)
|
||||
return uv__count_bufs(bufs, 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 UV_EAGAIN;
|
||||
else
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return size;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -1007,15 +882,15 @@ int uv__udp_init_ex(uv_loop_t* loop,
|
||||
handle->send_queue_size = 0;
|
||||
handle->send_queue_count = 0;
|
||||
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
|
||||
QUEUE_INIT(&handle->write_queue);
|
||||
QUEUE_INIT(&handle->write_completed_queue);
|
||||
uv__queue_init(&handle->write_queue);
|
||||
uv__queue_init(&handle->write_completed_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
if (handle->flags & UV_HANDLE_UDP_RECVMMSG)
|
||||
return 1;
|
||||
#endif
|
||||
@ -1037,7 +912,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv__set_reuse(sock);
|
||||
err = uv__sock_reuseaddr(sock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1366,3 +1241,194 @@ int uv__udp_recv_stop(uv_udp_t* handle) {
|
||||
|
||||
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,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb) {
|
||||
@ -533,17 +552,17 @@ int uv_udp_recv_stop(uv_udp_t* handle) {
|
||||
|
||||
|
||||
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
struct uv__queue queue;
|
||||
struct uv__queue* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
QUEUE_MOVE(&loop->handle_queue, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
uv__queue_move(&loop->handle_queue, &queue);
|
||||
while (!uv__queue_empty(&queue)) {
|
||||
q = uv__queue_head(&queue);
|
||||
h = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
|
||||
uv__queue_remove(q);
|
||||
uv__queue_insert_tail(&loop->handle_queue, q);
|
||||
|
||||
if (h->flags & UV_HANDLE_INTERNAL) continue;
|
||||
walk_cb(h, arg);
|
||||
@ -553,14 +572,17 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
|
||||
static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
|
||||
const char* type;
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
if (loop == NULL)
|
||||
loop = uv_default_loop();
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
if (stream == NULL)
|
||||
stream = stderr;
|
||||
|
||||
uv__queue_foreach(q, &loop->handle_queue) {
|
||||
h = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
|
||||
if (only_active && !uv__is_active(h))
|
||||
continue;
|
||||
@ -641,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) {
|
||||
size_t required_len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!uv__is_active(handle)) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
@ -846,7 +871,7 @@ uv_loop_t* uv_loop_new(void) {
|
||||
|
||||
|
||||
int uv_loop_close(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
struct uv__queue* q;
|
||||
uv_handle_t* h;
|
||||
#ifndef NDEBUG
|
||||
void* saved_data;
|
||||
@ -855,8 +880,8 @@ int uv_loop_close(uv_loop_t* loop) {
|
||||
if (uv__has_active_reqs(loop))
|
||||
return UV_EBUSY;
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
uv__queue_foreach(q, &loop->handle_queue) {
|
||||
h = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
if (!(h->flags & UV_HANDLE_INTERNAL))
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "uv/tree.h"
|
||||
@ -125,7 +126,7 @@ enum {
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
UV_HANDLE_TTY_READABLE = 0x01000000,
|
||||
UV_HANDLE_TTY_RAW = 0x02000000,
|
||||
UV_HANDLE_UNUSED0 = 0x02000000,
|
||||
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
|
||||
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
|
||||
|
||||
@ -140,6 +141,10 @@ enum {
|
||||
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);
|
||||
|
||||
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,
|
||||
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,
|
||||
uv_udp_recv_cb recv_cb);
|
||||
|
||||
@ -233,13 +244,13 @@ void uv__threadpool_cleanup(void);
|
||||
#define uv__has_active_reqs(loop) \
|
||||
((loop)->active_reqs.count > 0)
|
||||
|
||||
#define uv__req_register(loop, req) \
|
||||
#define uv__req_register(loop) \
|
||||
do { \
|
||||
(loop)->active_reqs.count++; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__req_unregister(loop, req) \
|
||||
#define uv__req_unregister(loop) \
|
||||
do { \
|
||||
assert(uv__has_active_reqs(loop)); \
|
||||
(loop)->active_reqs.count--; \
|
||||
@ -323,7 +334,7 @@ void uv__threadpool_cleanup(void);
|
||||
(h)->loop = (loop_); \
|
||||
(h)->type = (type_); \
|
||||
(h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
|
||||
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
|
||||
uv__queue_insert_tail(&(loop_)->handle_queue, &(h)->handle_queue); \
|
||||
uv__handle_platform_init(h); \
|
||||
} \
|
||||
while (0)
|
||||
@ -349,7 +360,7 @@ void uv__threadpool_cleanup(void);
|
||||
#define uv__req_init(loop, req, typ) \
|
||||
do { \
|
||||
UV_REQ_INIT(req, typ); \
|
||||
uv__req_register(loop, req); \
|
||||
uv__req_register(loop); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
@ -400,7 +411,6 @@ void uv__metrics_set_provider_entry_time(uv_loop_t* loop);
|
||||
struct uv__iou {
|
||||
uint32_t* sqhead;
|
||||
uint32_t* sqtail;
|
||||
uint32_t* sqarray;
|
||||
uint32_t sqmask;
|
||||
uint32_t* sqflags;
|
||||
uint32_t* cqhead;
|
||||
@ -429,4 +439,36 @@ struct uv__loop_internal_fields_s {
|
||||
#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_ */
|
||||
|
121
src/win/core.c
121
src/win/core.c
@ -255,8 +255,8 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
loop->time = 0;
|
||||
uv_update_time(loop);
|
||||
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->handle_queue);
|
||||
uv__queue_init(&loop->wq);
|
||||
uv__queue_init(&loop->handle_queue);
|
||||
loop->active_reqs.count = 0;
|
||||
loop->active_handles = 0;
|
||||
|
||||
@ -358,7 +358,7 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(!uv__has_active_reqs(loop));
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
@ -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) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
BOOL success;
|
||||
@ -553,12 +462,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
*/
|
||||
lfields->current_timeout = timeout;
|
||||
|
||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
success = GetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
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
|
||||
* 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
|
||||
* case the idle time will need to be updated.
|
||||
*/
|
||||
@ -629,9 +538,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
* while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
|
||||
* once, which should be done after polling in order to maintain proper
|
||||
* execution order of the conceptual event loop. */
|
||||
if (mode == UV_RUN_DEFAULT) {
|
||||
if (r)
|
||||
uv_update_time(loop);
|
||||
if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) {
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
@ -648,10 +556,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
|
||||
uv__metrics_inc_loop_count(loop);
|
||||
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
uv__poll(loop, timeout);
|
||||
else
|
||||
uv__poll_wine(loop, timeout);
|
||||
uv__poll(loop, timeout);
|
||||
|
||||
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
||||
* times to avoid loop starvation.*/
|
||||
|
15
src/win/dl.c
15
src/win/dl.c
@ -27,18 +27,17 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
|
||||
|
||||
int uv_dlopen(const char* filename, uv_lib_t* lib) {
|
||||
WCHAR filename_w[32768];
|
||||
ssize_t r;
|
||||
|
||||
lib->handle = NULL;
|
||||
lib->errmsg = NULL;
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
filename,
|
||||
-1,
|
||||
filename_w,
|
||||
ARRAY_SIZE(filename_w))) {
|
||||
return uv__dlerror(lib, filename, GetLastError());
|
||||
}
|
||||
r = uv_wtf8_length_as_utf16(filename);
|
||||
if (r < 0)
|
||||
return uv__dlerror(lib, filename, ERROR_NO_UNICODE_TRANSLATION);
|
||||
if ((size_t) r > ARRAY_SIZE(filename_w))
|
||||
return uv__dlerror(lib, filename, ERROR_INSUFFICIENT_BUFFER);
|
||||
uv_wtf8_to_utf16(filename, filename_w, r);
|
||||
|
||||
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (lib->handle == NULL) {
|
||||
|
@ -69,7 +69,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
}
|
||||
|
||||
switch (sys_errno) {
|
||||
case ERROR_NOACCESS: return UV_EACCES;
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
|
||||
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
|
||||
@ -78,6 +77,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
|
||||
case WSAEWOULDBLOCK: return UV_EAGAIN;
|
||||
case ERROR_NO_DATA: return UV_EAGAIN;
|
||||
case WSAEALREADY: return UV_EALREADY;
|
||||
case ERROR_INVALID_FLAGS: return UV_EBADF;
|
||||
case ERROR_INVALID_HANDLE: return UV_EBADF;
|
||||
@ -95,7 +95,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAECONNRESET: return UV_ECONNRESET;
|
||||
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
|
||||
case ERROR_FILE_EXISTS: return UV_EEXIST;
|
||||
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
|
||||
case ERROR_NOACCESS: return UV_EFAULT;
|
||||
case WSAEFAULT: return UV_EFAULT;
|
||||
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
|
||||
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
|
||||
@ -126,6 +126,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
|
||||
case WSAEMFILE: return UV_EMFILE;
|
||||
case WSAEMSGSIZE: return UV_EMSGSIZE;
|
||||
case ERROR_BUFFER_OVERFLOW: return UV_ENAMETOOLONG;
|
||||
case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
|
||||
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
|
||||
case WSAENETUNREACH: return UV_ENETUNREACH;
|
||||
@ -157,7 +158,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_ACCESS_DENIED: return UV_EPERM;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
|
||||
case ERROR_BAD_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
|
||||
case WSAESHUTDOWN: return UV_EPIPE;
|
||||
case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
|
||||
@ -168,6 +168,16 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
|
||||
case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT;
|
||||
case ERROR_BAD_EXE_FORMAT: return UV_EFTYPE;
|
||||
default: return UV_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int uv_translate_write_sys_error(int sys_errno) {
|
||||
switch (sys_errno) {
|
||||
case ERROR_BROKEN_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
default:
|
||||
return uv_translate_sys_error(sys_errno);
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ static int uv__split_path(const WCHAR* filename, WCHAR** dir,
|
||||
}
|
||||
}
|
||||
|
||||
*file = wcsdup(filename);
|
||||
*file = _wcsdup(filename);
|
||||
} else {
|
||||
if (dir) {
|
||||
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
|
||||
@ -157,7 +157,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int name_size, is_path_dir, size;
|
||||
int is_path_dir;
|
||||
size_t size;
|
||||
DWORD attr, last_error;
|
||||
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
|
||||
DWORD short_path_buffer_len;
|
||||
@ -176,23 +177,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
|
||||
uv__handle_start(handle);
|
||||
|
||||
/* Convert name to UTF16. */
|
||||
|
||||
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
|
||||
sizeof(WCHAR);
|
||||
pathw = (WCHAR*)uv__malloc(name_size);
|
||||
if (!pathw) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
path,
|
||||
-1,
|
||||
pathw,
|
||||
name_size / sizeof(WCHAR))) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
last_error = uv__convert_utf8_to_utf16(path, &pathw);
|
||||
if (last_error)
|
||||
goto error_uv;
|
||||
|
||||
/* Determine whether path is a file or a directory. */
|
||||
attr = GetFileAttributesW(pathw);
|
||||
@ -266,6 +253,8 @@ short_path_done:
|
||||
}
|
||||
|
||||
dir_to_watch = dir;
|
||||
uv__free(short_path);
|
||||
short_path = NULL;
|
||||
uv__free(pathw);
|
||||
pathw = NULL;
|
||||
}
|
||||
@ -333,6 +322,9 @@ short_path_done:
|
||||
return 0;
|
||||
|
||||
error:
|
||||
last_error = uv_translate_sys_error(last_error);
|
||||
|
||||
error_uv:
|
||||
if (handle->path) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
@ -365,7 +357,7 @@ error:
|
||||
|
||||
uv__free(short_path);
|
||||
|
||||
return uv_translate_sys_error(last_error);
|
||||
return last_error;
|
||||
}
|
||||
|
||||
|
||||
@ -571,7 +563,27 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
} else {
|
||||
err = GET_REQ_ERROR(req);
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
/*
|
||||
* Check whether the ERROR_ACCESS_DENIED is caused by the watched directory
|
||||
* being actually deleted (not an actual error) or a legit error. Retrieve
|
||||
* FileStandardInfo to check whether the directory is pending deletion.
|
||||
*/
|
||||
FILE_STANDARD_INFO info;
|
||||
if (err == ERROR_ACCESS_DENIED &&
|
||||
handle->dirw != NULL &&
|
||||
GetFileInformationByHandleEx(handle->dir_handle,
|
||||
FileStandardInfo,
|
||||
&info,
|
||||
sizeof(info)) &&
|
||||
info.Directory &&
|
||||
info.DeletePending) {
|
||||
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
||||
handle->cb(handle, filename, UV_RENAME, 0);
|
||||
uv__free(filename);
|
||||
filename = NULL;
|
||||
} else {
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
|
852
src/win/fs.c
852
src/win/fs.c
File diff suppressed because it is too large
Load Diff
@ -71,10 +71,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
|
||||
#endif
|
||||
|
||||
|
||||
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
|
||||
* Do we need different versions of this for different architectures? */
|
||||
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
|
||||
static size_t align_offset(size_t off, size_t alignment) {
|
||||
return ((off + alignment - 1) / alignment) * alignment;
|
||||
}
|
||||
|
||||
#ifndef NDIS_IF_MAX_STRING_SIZE
|
||||
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
|
||||
@ -103,16 +102,7 @@ static void uv__getaddrinfo_work(struct uv__work* w) {
|
||||
* Each size calculation is adjusted to avoid unaligned pointers.
|
||||
*/
|
||||
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
int addrinfo_len = 0;
|
||||
int name_len = 0;
|
||||
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
|
||||
struct addrinfoW* addrinfow_ptr;
|
||||
struct addrinfo* addrinfo_ptr;
|
||||
char* alloc_ptr = NULL;
|
||||
char* cur_ptr = NULL;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
|
||||
/* release input parameter memory */
|
||||
uv__free(req->alloc);
|
||||
@ -125,41 +115,44 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
if (req->retcode == 0) {
|
||||
char* alloc_ptr = NULL;
|
||||
size_t cur_off = 0;
|
||||
size_t addrinfo_len;
|
||||
/* Convert addrinfoW to addrinfo. First calculate required length. */
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
struct addrinfoW* addrinfow_ptr = req->addrinfow;
|
||||
while (addrinfow_ptr != NULL) {
|
||||
addrinfo_len += addrinfo_struct_len +
|
||||
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
|
||||
cur_off = align_offset(cur_off, sizeof(void*));
|
||||
cur_off += sizeof(struct addrinfo);
|
||||
/* TODO: This alignment could be smaller, if we could
|
||||
portably get the alignment for sockaddr. */
|
||||
cur_off = align_offset(cur_off, sizeof(void*));
|
||||
cur_off += addrinfow_ptr->ai_addrlen;
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (name_len == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
ssize_t name_len =
|
||||
uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1);
|
||||
if (name_len < 0) {
|
||||
req->retcode = name_len;
|
||||
goto complete;
|
||||
}
|
||||
addrinfo_len += ALIGNED_SIZE(name_len);
|
||||
cur_off += name_len + 1;
|
||||
}
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
}
|
||||
|
||||
/* allocate memory for addrinfo results */
|
||||
alloc_ptr = (char*)uv__malloc(addrinfo_len);
|
||||
addrinfo_len = cur_off;
|
||||
alloc_ptr = uv__malloc(addrinfo_len);
|
||||
|
||||
/* do conversions */
|
||||
if (alloc_ptr != NULL) {
|
||||
cur_ptr = alloc_ptr;
|
||||
struct addrinfo *addrinfo_ptr = (struct addrinfo *)alloc_ptr;
|
||||
cur_off = 0;
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
|
||||
while (addrinfow_ptr != NULL) {
|
||||
for (;;) {
|
||||
cur_off += sizeof(struct addrinfo);
|
||||
assert(cur_off <= addrinfo_len);
|
||||
/* copy addrinfo struct data */
|
||||
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
|
||||
addrinfo_ptr = (struct addrinfo*)cur_ptr;
|
||||
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
|
||||
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
|
||||
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
|
||||
@ -169,48 +162,38 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
addrinfo_ptr->ai_addr = NULL;
|
||||
addrinfo_ptr->ai_next = NULL;
|
||||
|
||||
cur_ptr += addrinfo_struct_len;
|
||||
|
||||
/* copy sockaddr */
|
||||
if (addrinfo_ptr->ai_addrlen > 0) {
|
||||
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
|
||||
alloc_ptr + addrinfo_len);
|
||||
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
|
||||
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
|
||||
cur_off = align_offset(cur_off, sizeof(void *));
|
||||
addrinfo_ptr->ai_addr = (struct sockaddr *)(alloc_ptr + cur_off);
|
||||
cur_off += addrinfo_ptr->ai_addrlen;
|
||||
assert(cur_off <= addrinfo_len);
|
||||
memcpy(addrinfo_ptr->ai_addr,
|
||||
addrinfow_ptr->ai_addr,
|
||||
addrinfo_ptr->ai_addrlen);
|
||||
}
|
||||
|
||||
/* convert canonical name to UTF-8 */
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
ssize_t name_len = addrinfo_len - cur_off;
|
||||
addrinfo_ptr->ai_canonname = alloc_ptr + cur_off;
|
||||
int r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
assert(name_len > 0);
|
||||
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
cur_ptr,
|
||||
name_len,
|
||||
NULL,
|
||||
NULL);
|
||||
assert(name_len > 0);
|
||||
addrinfo_ptr->ai_canonname = cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(name_len);
|
||||
addrinfo_ptr->ai_canonname,
|
||||
(size_t*)&name_len);
|
||||
assert(r == 0);
|
||||
cur_off += name_len + 1;
|
||||
assert(cur_off <= addrinfo_len);
|
||||
}
|
||||
assert(cur_ptr <= alloc_ptr + addrinfo_len);
|
||||
|
||||
/* set next ptr */
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
if (addrinfow_ptr != NULL) {
|
||||
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
|
||||
}
|
||||
if (addrinfow_ptr == NULL)
|
||||
break;
|
||||
cur_off = align_offset(cur_off, sizeof(void *));
|
||||
struct addrinfo *next_addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off);
|
||||
addrinfo_ptr->ai_next = next_addrinfo_ptr;
|
||||
addrinfo_ptr = next_addrinfo_ptr;
|
||||
}
|
||||
req->addrinfo = (struct addrinfo*)alloc_ptr;
|
||||
} else {
|
||||
@ -225,7 +208,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
complete:
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
/* finally do callback with converted result */
|
||||
if (req->getaddrinfo_cb)
|
||||
@ -261,12 +244,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
int nodesize = 0;
|
||||
int servicesize = 0;
|
||||
int hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
int err;
|
||||
long rc;
|
||||
size_t off = 0;
|
||||
size_t nodesize = 0;
|
||||
size_t servicesize = 0;
|
||||
size_t serviceoff = 0;
|
||||
size_t hintssize = 0;
|
||||
size_t hintoff = 0;
|
||||
ssize_t rc;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
return UV_EINVAL;
|
||||
@ -286,56 +270,38 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
|
||||
-1, NULL, 0) * sizeof(WCHAR));
|
||||
if (nodesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
nodesize = strlen(hostname_ascii) + 1;
|
||||
node = hostname_ascii;
|
||||
off += nodesize * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
NULL,
|
||||
0) *
|
||||
sizeof(WCHAR));
|
||||
if (servicesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
rc = uv_wtf8_length_as_utf16(service);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
servicesize = rc;
|
||||
off = align_offset(off, sizeof(WCHAR));
|
||||
serviceoff = off;
|
||||
off += servicesize * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
|
||||
off = align_offset(off, sizeof(void *));
|
||||
hintoff = off;
|
||||
hintssize = sizeof(struct addrinfoW);
|
||||
off += hintssize;
|
||||
}
|
||||
|
||||
/* allocate memory for inputs, and partition it as needed */
|
||||
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
|
||||
if (!alloc_ptr) {
|
||||
err = WSAENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* save alloc_ptr now so we can free if error */
|
||||
req->alloc = (void*)alloc_ptr;
|
||||
req->alloc = uv__malloc(off);
|
||||
if (!req->alloc)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* Convert node string to UTF16 into allocated memory and save pointer in the
|
||||
* request. */
|
||||
* request. The node here has been converted to ascii. */
|
||||
if (node != NULL) {
|
||||
req->node = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
node,
|
||||
-1,
|
||||
(WCHAR*) alloc_ptr,
|
||||
nodesize / sizeof(WCHAR)) == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += nodesize;
|
||||
req->node = (WCHAR*) req->alloc;
|
||||
uv_wtf8_to_utf16(node, req->node, nodesize);
|
||||
} else {
|
||||
req->node = NULL;
|
||||
}
|
||||
@ -343,24 +309,15 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
/* Convert service string to UTF16 into allocated memory and save pointer in
|
||||
* the req. */
|
||||
if (service != NULL) {
|
||||
req->service = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
(WCHAR*) alloc_ptr,
|
||||
servicesize / sizeof(WCHAR)) == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += servicesize;
|
||||
req->service = (WCHAR*) ((char*) req->alloc + serviceoff);
|
||||
uv_wtf8_to_utf16(service, req->service, servicesize);
|
||||
} else {
|
||||
req->service = NULL;
|
||||
}
|
||||
|
||||
/* copy hints to allocated memory and save pointer in req */
|
||||
if (hints != NULL) {
|
||||
req->addrinfow = (struct addrinfoW*)alloc_ptr;
|
||||
req->addrinfow = (struct addrinfoW*) ((char*) req->alloc + hintoff);
|
||||
req->addrinfow->ai_family = hints->ai_family;
|
||||
req->addrinfow->ai_socktype = hints->ai_socktype;
|
||||
req->addrinfow->ai_protocol = hints->ai_protocol;
|
||||
@ -373,7 +330,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
req->addrinfow = NULL;
|
||||
}
|
||||
|
||||
uv__req_register(loop, req);
|
||||
uv__req_register(loop);
|
||||
|
||||
if (getaddrinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
@ -387,19 +344,11 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
uv__getaddrinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
|
||||
error:
|
||||
if (req != NULL) {
|
||||
uv__free(req->alloc);
|
||||
req->alloc = NULL;
|
||||
}
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
NET_LUID luid;
|
||||
wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
|
||||
DWORD bufsize;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
@ -415,31 +364,7 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
if (r != 0)
|
||||
return uv_translate_sys_error(r);
|
||||
|
||||
/* Check how much space we need */
|
||||
bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (bufsize == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (bufsize > *size) {
|
||||
*size = bufsize;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
bufsize = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
wname,
|
||||
-1,
|
||||
buffer,
|
||||
*size,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (bufsize == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
*size = bufsize - 1;
|
||||
return 0;
|
||||
return uv__copy_utf16_to_utf8(wname, -1, buffer, size);
|
||||
}
|
||||
|
||||
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user