libuv 1.42.0.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3650 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2021-07-27 22:08:18 +00:00
parent 5197eb91f7
commit da51e87774
183 changed files with 4013 additions and 1768 deletions

View File

@ -58,6 +58,7 @@ UV_SOURCES = \
deps/libuv/src/unix/async.c \ deps/libuv/src/unix/async.c \
deps/libuv/src/unix/core.c \ deps/libuv/src/unix/core.c \
deps/libuv/src/unix/dl.c \ deps/libuv/src/unix/dl.c \
deps/libuv/src/unix/epoll.c \
deps/libuv/src/unix/fs.c \ deps/libuv/src/unix/fs.c \
deps/libuv/src/unix/getaddrinfo.c \ deps/libuv/src/unix/getaddrinfo.c \
deps/libuv/src/unix/getnameinfo.c \ deps/libuv/src/unix/getnameinfo.c \

View File

@ -2,7 +2,7 @@
If you want to report a bug, you are in the right place! If you want to report a bug, you are in the right place!
If you need help or have a question, go here: If you need help or have a question, go here:
https://github.com/libuv/help/issues/new https://github.com/libuv/libuv/discussions
If you are reporting a libuv test failure, please ensure that you are not If you are reporting a libuv test failure, please ensure that you are not
running the test as root. running the test as root.

View File

@ -0,0 +1,17 @@
name: Sanitizer checks
on: [push, pull_request]
jobs:
asan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Envinfo
run: npx envinfo
- name: ASAN
run: |
mkdir build
cd build && cmake .. -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build . && ./uv_run_tests_a

6
deps/libuv/.mailmap vendored
View File

@ -2,6 +2,7 @@ A. Hauptmann <andreashauptmann@t-online.de>
Aaron Bieber <qbit@deftly.net> <deftly@gmail.com> Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com> Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com> Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
Andy Fiddaman <andy@omniosce.org> <omnios@citrus-it.co.uk>
Bert Belder <bertbelder@gmail.com> <i@bertbelder.com> Bert Belder <bertbelder@gmail.com> <i@bertbelder.com>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl> Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)> Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
@ -10,6 +11,8 @@ Brian White <mscdex@mscdex.net>
Brian White <mscdex@mscdex.net> <mscdex@gmail.com> Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr> Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr>
Christoph Iserlohn <christoph.iserlohn@innoq.com> Christoph Iserlohn <christoph.iserlohn@innoq.com>
Darshan Sen <raisinten@gmail.com>
David Carlier <devnexen@gmail.com>
Devchandra Meetei Leishangthem <dlmeetei@gmail.com> Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com> Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
Frank Denis <github@pureftpd.org> Frank Denis <github@pureftpd.org>
@ -32,6 +35,7 @@ Nicholas Vavilov <vvnicholas@gmail.com>
Nick Logan <ugexe@cpan.org> <nlogan@gmail.com> Nick Logan <ugexe@cpan.org> <nlogan@gmail.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com> Rasmus Christian Pedersen <zerhacken@yahoo.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com> Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
Richard Lau <rlau@redhat.com> <riclau@uk.ibm.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org> Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org> Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
Ryan Emery <seebees@gmail.com> Ryan Emery <seebees@gmail.com>
@ -47,8 +51,10 @@ Timothy J. Fontaine <tjfontaine@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com> Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yazhong Liu <yorkiefixer@gmail.com> Yazhong Liu <yorkiefixer@gmail.com>
Yuki Okumura <mjt@cltn.org> Yuki Okumura <mjt@cltn.org>
cjihrig <cjihrig@gmail.com>
gengjiawen <technicalcute@gmail.com> gengjiawen <technicalcute@gmail.com>
jBarz <jBarz@users.noreply.github.com> <jbarboza@ca.ibm.com> jBarz <jBarz@users.noreply.github.com> <jbarboza@ca.ibm.com>
jBarz <jBarz@users.noreply.github.com> <jbarz@users.noreply.github.com> jBarz <jBarz@users.noreply.github.com> <jbarz@users.noreply.github.com>
ptlomholt <pt@lomholt.com> ptlomholt <pt@lomholt.com>
tjarlama <59913901+tjarlama@users.noreply.github.com> <tjarlama@gmail.com>
zlargon <zlargon1988@gmail.com> zlargon <zlargon1988@gmail.com>

11
deps/libuv/.readthedocs.yaml vendored Normal file
View File

@ -0,0 +1,11 @@
version: 2
sphinx:
builder: html
configuration: null
fail_on_warning: false
python:
version: 3.8
install:
- requirements: docs/requirements.txt

37
deps/libuv/AUTHORS vendored
View File

@ -114,7 +114,6 @@ Dylan Cali <calid1984@gmail.com>
Austin Foxley <austinf@cetoncorp.com> Austin Foxley <austinf@cetoncorp.com>
Benjamin Saunders <ben.e.saunders@gmail.com> Benjamin Saunders <ben.e.saunders@gmail.com>
Geoffry Song <goffrie@gmail.com> Geoffry Song <goffrie@gmail.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
William Light <wrl@illest.net> William Light <wrl@illest.net>
Oleg Efimov <o.efimov@corp.badoo.com> Oleg Efimov <o.efimov@corp.badoo.com>
Lars Gierth <larsg@systemli.org> Lars Gierth <larsg@systemli.org>
@ -123,7 +122,6 @@ Justin Venus <justin.venus@gmail.com>
Kristian Evensen <kristian.evensen@gmail.com> Kristian Evensen <kristian.evensen@gmail.com>
Linus Mårtensson <linus.martensson@sonymobile.com> Linus Mårtensson <linus.martensson@sonymobile.com>
Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com> Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com>
Yorkie <yorkiefixer@gmail.com>
StarWing <weasley.wx@gmail.com> StarWing <weasley.wx@gmail.com>
thierry-FreeBSD <thierry@FreeBSD.org> thierry-FreeBSD <thierry@FreeBSD.org>
Isaiah Norton <isaiah.norton@gmail.com> Isaiah Norton <isaiah.norton@gmail.com>
@ -212,7 +210,7 @@ guworks <ground.up.works@gmail.com>
RossBencina <rossb@audiomulch.com> RossBencina <rossb@audiomulch.com>
Roger A. Light <roger@atchoo.org> Roger A. Light <roger@atchoo.org>
chenttuuvv <chenttuuvv@yahoo.com> chenttuuvv <chenttuuvv@yahoo.com>
Richard Lau <riclau@uk.ibm.com> Richard Lau <rlau@redhat.com>
ronkorving <rkorving@wizcorp.jp> ronkorving <rkorving@wizcorp.jp>
Corbin Simpson <MostAwesomeDude@gmail.com> Corbin Simpson <MostAwesomeDude@gmail.com>
Zachary Hamm <zsh@imipolexg.org> Zachary Hamm <zsh@imipolexg.org>
@ -448,3 +446,36 @@ Aleksej Lebedev <root@zta.lk>
Nikolay Mitev <github@hmel.org> Nikolay Mitev <github@hmel.org>
Ulrik Strid <ulrik.strid@outlook.com> Ulrik Strid <ulrik.strid@outlook.com>
Elad Lahav <elahav@qnx.com> Elad Lahav <elahav@qnx.com>
Elad Nachmias <eladn@pazam.net>
Darshan Sen <raisinten@gmail.com>
Simon Kadisch <simon.kadisch@k13-engineering.at>
Momtchil Momtchev <momtchil@momtchev.com>
Ethel Weston <66453757+ethelweston@users.noreply.github.com>
Drew DeVault <sir@cmpwn.com>
Mark Klein <klein@cscs.ch>
schamberg97 <50446906+schamberg97@users.noreply.github.com>
Bob Weinand <bobwei9@hotmail.com>
Issam E. Maghni <issam.e.maghni@mailbox.org>
Juan Pablo Canepa <jpcanepa@gmail.com>
Shuowang (Wayne) Zhang <shuowang.zhang@ibm.com>
Ondřej Surý <ondrej@sury.org>
Juan José Arboleda <soyjuanarbol@gmail.com>
Zhao Zhili <zhilizhao@tencent.com>
Brandon Cheng <brandon.cheng@protonmail.com>
Matvii Hodovaniuk <matvii@hodovani.uk>
Hayden <me@diatr.us>
yiyuaner <yguoaz@gmail.com>
bbara <bbara93@gmail.com>
SeverinLeonhardt <Severin.Leonhardt@teamviewer.com>
Andy Fiddaman <andy@omniosce.org>
Romain Roffé <rofferom@gmail.com>
Eagle Liang <eagleliang@gmail.com>
Ricky Zhou <ives199511@gmail.com>
Simon Kissane <skissane@gmail.com>
James M Snell <jasnell@gmail.com>
Ali Mohammad Pur <Ali.mpfard@gmail.com>
Erkhes N <71805796+rexes-ND@users.noreply.github.com>
Joshua M. Clulow <josh@sysmgr.org>
Guilherme Íscaro <cabelitostos@gmail.com>
Martin Storsjö <martin@martin.st>
Claes Nästén <pekdon@gmail.com>

View File

@ -30,6 +30,14 @@ if(QEMU)
add_definitions(-D__QEMU__=1) add_definitions(-D__QEMU__=1)
endif() endif()
option(ASAN "Enable AddressSanitizer (ASan)" OFF)
if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")
add_definitions(-D__ASAN__=1)
set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
endif()
# Compiler check # Compiler check
string(CONCAT is-msvc $<OR: string(CONCAT is-msvc $<OR:
$<C_COMPILER_ID:MSVC>, $<C_COMPILER_ID:MSVC>,
@ -95,6 +103,9 @@ list(APPEND uv_cflags ${lint-no-conditional-assignment-msvc})
list(APPEND uv_cflags ${lint-no-unsafe-msvc}) list(APPEND uv_cflags ${lint-no-unsafe-msvc})
list(APPEND uv_cflags ${lint-utf8-msvc} ) 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>)
set(uv_sources set(uv_sources
src/fs-poll.c src/fs-poll.c
src/idna.c src/idna.c
@ -108,7 +119,7 @@ set(uv_sources
src/version.c) src/version.c)
if(WIN32) if(WIN32)
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0600) list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602)
list(APPEND uv_libraries list(APPEND uv_libraries
psapi psapi
user32 user32
@ -199,10 +210,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
src/unix/pthread-fixes.c src/unix/pthread-fixes.c
src/unix/random-getentropy.c src/unix/random-getentropy.c
src/unix/random-getrandom.c src/unix/random-getrandom.c
src/unix/random-sysctl-linux.c) src/unix/random-sysctl-linux.c
src/unix/epoll.c)
endif() endif()
if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux|OS390") if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux")
list(APPEND uv_sources src/unix/proctitle.c) list(APPEND uv_sources src/unix/proctitle.c)
endif() endif()
@ -243,7 +255,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
src/unix/linux-syscalls.c src/unix/linux-syscalls.c
src/unix/procfs-exepath.c src/unix/procfs-exepath.c
src/unix/random-getrandom.c src/unix/random-getrandom.c
src/unix/random-sysctl-linux.c) src/unix/random-sysctl-linux.c
src/unix/epoll.c)
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
@ -256,9 +269,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "OS390") if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
list(APPEND uv_defines PATH_MAX=255) enable_language(CXX)
list(APPEND uv_defines PATH_MAX=1024)
list(APPEND uv_defines _AE_BIMODAL) list(APPEND uv_defines _AE_BIMODAL)
list(APPEND uv_defines _ALL_SOURCE) list(APPEND uv_defines _ALL_SOURCE)
list(APPEND uv_defines _ENHANCED_ASCII_EXT=0xFFFFFFFF)
list(APPEND uv_defines _ISOC99_SOURCE) list(APPEND uv_defines _ISOC99_SOURCE)
list(APPEND uv_defines _LARGE_TIME_API) list(APPEND uv_defines _LARGE_TIME_API)
list(APPEND uv_defines _OPEN_MSGQ_EXT) list(APPEND uv_defines _OPEN_MSGQ_EXT)
@ -269,14 +284,31 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
list(APPEND uv_defines _UNIX03_SOURCE) list(APPEND uv_defines _UNIX03_SOURCE)
list(APPEND uv_defines _UNIX03_THREADS) list(APPEND uv_defines _UNIX03_THREADS)
list(APPEND uv_defines _UNIX03_WITHDRAWN) list(APPEND uv_defines _UNIX03_WITHDRAWN)
list(APPEND uv_defines _XOPEN_SOURCE=600)
list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED) list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED)
list(APPEND uv_sources list(APPEND uv_sources
src/unix/pthread-fixes.c src/unix/pthread-fixes.c
src/unix/os390.c src/unix/os390.c
src/unix/os390-syscalls.c) src/unix/os390-syscalls.c
list(APPEND uv_cflags -Wc,DLL -Wc,exportall -Wc,xplink) src/unix/os390-proctitle.c)
list(APPEND uv_libraries -Wl,xplink) list(APPEND uv_cflags
list(APPEND uv_test_libraries -Wl,xplink) -q64
-qascii
-qexportall
-qgonumber
-qlongname
-qlibansi
-qfloat=IEEE
-qtune=10
-qarch=10
-qasm
-qasmlib=sys1.maclib:sys1.modgen)
find_library(ZOSLIB
NAMES zoslib
PATHS ${ZOSLIB_DIR}
PATH_SUFFIXES lib
)
list(APPEND uv_libraries ${ZOSLIB})
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "OS400") if(CMAKE_SYSTEM_NAME STREQUAL "OS400")
@ -293,9 +325,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS400")
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500) list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500 _REENTRANT)
list(APPEND uv_libraries kstat nsl sendfile socket) list(APPEND uv_libraries kstat nsl sendfile socket)
list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c) list(APPEND uv_sources
src/unix/no-proctitle.c
src/unix/sunos.c)
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Haiku") if(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
@ -318,7 +352,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
src/unix/bsd-ifaddrs.c src/unix/bsd-ifaddrs.c
src/unix/no-proctitle.c src/unix/no-proctitle.c
src/unix/no-fsevents.c) src/unix/no-fsevents.c)
list(APPEND uv_cflags -fno-strict-aliasing)
list(APPEND uv_libraries socket) list(APPEND uv_libraries socket)
endif() endif()
@ -340,6 +373,10 @@ target_include_directories(uv
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>) $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)
if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
target_include_directories(uv PUBLIC $<BUILD_INTERFACE:${ZOSLIB_DIR}/include>)
set_target_properties(uv PROPERTIES LINKER_LANGUAGE CXX)
endif()
target_link_libraries(uv ${uv_libraries}) target_link_libraries(uv ${uv_libraries})
add_library(uv_a STATIC ${uv_sources}) add_library(uv_a STATIC ${uv_sources})
@ -351,6 +388,10 @@ target_include_directories(uv_a
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>) $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)
if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
target_include_directories(uv_a PUBLIC $<BUILD_INTERFACE:${ZOSLIB_DIR}/include>)
set_target_properties(uv_a PROPERTIES LINKER_LANGUAGE CXX)
endif()
target_link_libraries(uv_a ${uv_libraries}) target_link_libraries(uv_a ${uv_libraries})
if(LIBUV_BUILD_TESTS) if(LIBUV_BUILD_TESTS)
@ -448,6 +489,9 @@ if(LIBUV_BUILD_TESTS)
test/test-metrics.c test/test-metrics.c
test/test-multiple-listen.c test/test-multiple-listen.c
test/test-mutexes.c test/test-mutexes.c
test/test-not-readable-nor-writable-on-read-error.c
test/test-not-readable-on-eof.c
test/test-not-writable-after-shutdown.c
test/test-osx-select.c test/test-osx-select.c
test/test-pass-always.c test/test-pass-always.c
test/test-ping-pong.c test/test-ping-pong.c
@ -466,6 +510,7 @@ if(LIBUV_BUILD_TESTS)
test/test-poll-close-doesnt-corrupt-stack.c test/test-poll-close-doesnt-corrupt-stack.c
test/test-poll-close.c test/test-poll-close.c
test/test-poll-closesocket.c test/test-poll-closesocket.c
test/test-poll-multiple-handles.c
test/test-poll-oob.c test/test-poll-oob.c
test/test-poll.c test/test-poll.c
test/test-process-priority.c test/test-process-priority.c
@ -479,6 +524,7 @@ if(LIBUV_BUILD_TESTS)
test/test-semaphore.c test/test-semaphore.c
test/test-shutdown-close.c test/test-shutdown-close.c
test/test-shutdown-eof.c test/test-shutdown-eof.c
test/test-shutdown-simultaneous.c
test/test-shutdown-twice.c test/test-shutdown-twice.c
test/test-signal-multiple-loops.c test/test-signal-multiple-loops.c
test/test-signal-pending-on-close.c test/test-signal-pending-on-close.c
@ -572,6 +618,11 @@ if(LIBUV_BUILD_TESTS)
add_test(NAME uv_test_a add_test(NAME uv_test_a
COMMAND uv_run_tests_a COMMAND uv_run_tests_a
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
set_target_properties(uv_run_benchmarks_a PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(uv_run_tests PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(uv_run_tests_a PROPERTIES LINKER_LANGUAGE CXX)
endif()
endif() endif()
if(UNIX OR MINGW) if(UNIX OR MINGW)

View File

@ -23,11 +23,11 @@ The stable branch is effectively frozen; patches that change the libuv
API/ABI or affect the run-time behavior of applications get rejected. API/ABI or affect the run-time behavior of applications get rejected.
In case of doubt, open an issue in the [issue tracker][], post your question In case of doubt, open an issue in the [issue tracker][], post your question
to the [libuv mailing list], or contact one of [project maintainers][] on [IRC][]. to the [libuv discussions forum], or message the [libuv mailing list].
Especially do so if you plan to work on something big. Nothing is more Especially do so if you plan to work on something big. Nothing is more
frustrating than seeing your hard work go to waste because your vision frustrating than seeing your hard work go to waste because your vision does not
does not align with that of a project maintainers. align with that of the [project maintainers].
### BRANCH ### BRANCH
@ -166,6 +166,6 @@ not send out notifications when you add commits.
[issue tracker]: https://github.com/libuv/libuv/issues [issue tracker]: https://github.com/libuv/libuv/issues
[libuv mailing list]: http://groups.google.com/group/libuv [libuv mailing list]: http://groups.google.com/group/libuv
[IRC]: http://webchat.freenode.net/?channels=libuv [libuv discussions forum]: https://github.com/libuv/libuv/discussions
[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html [Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html
[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md [project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md

236
deps/libuv/ChangeLog vendored
View File

@ -1,4 +1,238 @@
2020.09.26, Version 1.40.0 (Stable) 2021.07.21, Version 1.42.0 (Stable)
Changes since version 1.41.0:
* doc: fix code highlighting (Darshan Sen)
* test: move to ASSERT_NULL and ASSERT_NOT_NULL test macros (tjarlama)
* zos: build in ascii code page (Shuowang (Wayne) Zhang)
* zos: don't use nanosecond timestamp fields (Shuowang (Wayne) Zhang)
* zos: introduce zoslib (Shuowang (Wayne) Zhang)
* zos: use strnlen() from zoslib (Shuowang (Wayne) Zhang)
* zos: use nanosleep() from zoslib (Shuowang (Wayne) Zhang)
* zos: use __getargv() from zoslib to get exe path (Shuowang (Wayne) Zhang)
* zos: treat __rfim_utok as binary (Shuowang (Wayne) Zhang)
* zos: use execvpe() to set environ explictly (Shuowang (Wayne) Zhang)
* zos: use custom proctitle implementation (Shuowang (Wayne) Zhang)
* doc: add instructions for building on z/OS (Shuowang (Wayne) Zhang)
* linux,udp: enable full ICMP error reporting (Ondřej Surý)
* test: fix test-udp-send-unreachable (Ondřej Surý)
* include: fix typo in documentation (Tobias Nießen)
* chore: use for(;;) instead of while (Yash Ladha)
* test: remove string + int warning on udp-pummel (Juan José Arboleda)
* cmake: fix linker flags (Zhao Zhili)
* test: fix stack-use-after-scope (Zhao Zhili)
* unix: expose thread_stack_size() internally (Brandon Cheng)
* darwin: use RLIMIT_STACK for fsevents pthread (Brandon Cheng)
* darwin: abort on pthread_attr_init fail (Brandon Cheng)
* benchmark: remove unreachable code (Matvii Hodovaniuk)
* macos: fix memleaks in uv__get_cpu_speed (George Zhao)
* Make Thread Sanitizer aware of file descriptor close in uv__close() (Ondřej
Surý)
* darwin: fix iOS compilation and functionality (Hayden)
* linux: work around copy_file_range() cephfs bug (Ben Noordhuis)
* zos: implement uv_get_constrained_memory() (Shuowang (Wayne) Zhang)
* zos: fix uv_get_free_memory() (Shuowang (Wayne) Zhang)
* zos: use CVTRLSTG to get total memory accurately (Shuowang (Wayne) Zhang)
* ibmi: Handle interface names longer than 10 chars (Kevin Adler)
* docs: update read-the-docs version of sphinx (Jameson Nash)
* unix: refactor uv_try_write (twosee)
* linux-core: add proper divide by zero assert (yiyuaner)
* misc: remove unnecessary _GNU_SOURCE macros (Darshan Sen)
* test: log to stdout to conform TAP spec (bbara)
* win,fs: fix C4090 warning with MSVC (SeverinLeonhardt)
* build: some systems provide dlopen() in libc (Andy Fiddaman)
* include: add EOVERFLOW status code mapping (Darshan Sen)
* unix,fs: use uv__load_relaxed and uv__store_relaxed (Darshan Sen)
* win: fix string encoding issue of uv_os_gethostname (Eagle Liang)
* unix,process: add uv__write_errno helper function (Ricky Zhou)
* Re-merge "unix,stream: clear read/write states on close/eof" (Jameson Nash)
* unix,core: fix errno handling in uv__getpwuid_r (Darshan Sen)
* errors: map ESOCKTNOSUPPORT errno (Ryan Liptak)
* doc: uv_read_stop always succeeds (Simon Kissane)
* inet: fix inconsistent return value of inet_ntop6 (twosee)
* darwin: fix -Wsometimes-uninitialized warning (twosee)
* stream: introduce uv_try_write2 function (twosee)
* poll,win: UV_PRIORITIZED option should not assert (twosee)
* src: DragonFlyBSD has mmsghdr struct too (David Carlier)
* cleanup,win: Remove _WIN32 guards on threadpool (James M Snell)
* freebsd: fix an incompatible pointer type warning (Darshan Sen)
* core: Correct the conditionals for {cloexec,nonblock}_ioctl (Ali Mohammad
Pur)
* win,tcp: make uv_close work more like unix (Jameson Nash)
* doc: more accurate list of valid send_handle's (twosee)
* win,tcp: translate system errors correctly (twosee)
* unix: implement cpu_relax() on ppc64 (Ben Noordhuis)
* docs: move list of project links under PR control (Jameson Nash)
* test: wrong pointer arithmetic multiplier (Erkhes N)
* doc: switch discussion forum to github (Jameson Nash)
* idna: fix OOB read in punycode decoder (Ben Noordhuis)
* build: make sure -fvisibility=hidden is set (Santiago Gimeno)
* illumos: event ports to epoll (tjarlama)
* illumos,tty: UV_TTY_MODE_IO waits for 4 bytes (Joshua M. Clulow)
* doc: add vtjnash GPG ID (Jameson Nash)
* linux: read CPU model information on ppc (Richard Lau)
* darwin: fix uv_barrier race condition (Guilherme Íscaro)
* unix,stream: fix loop hang after uv_shutdown (Jameson Nash)
* doc,udp: note that suggested_size is 1 max-sized dgram (Ryan Liptak)
* mingw: fix building for ARM/AArch64 (Martin Storsjö)
* unix: strnlen is not available on Solaris 10 (Claes Nästén)
* sunos: restore use of event ports (Andy Fiddaman)
* sunos,cmake: use thread-safe errno (Andy Fiddaman)
2021.02.14, Version 1.41.0 (Stable), 1dff88e5161cba5c59276d2070d2e304e4dcb242
Changes since version 1.40.0:
* mailmap: update contact information for richardlau (Richard Lau)
* build: add asan checks (gengjiawen)
* unix: report bind error in uv_tcp_connect() (Ben Noordhuis)
* doc: uv_tcp_bind() never returns UV_EADDRINUSE (Ben Noordhuis)
* test: fix pump and tcp_write_batch benchmarks (Santiago Gimeno)
* doc: mark IBM i as Tier 2 support (Jesse Gorzinski)
* doc,poll: add notes (repeated cb & cancel pending cb) (Elad Nachmias)
* linux: fix -Wincompatible-pointer-types warning (Ben Noordhuis)
* linux: fix -Wsign-compare warning (Ben Noordhuis)
* android: add system call api guards (Ben Noordhuis)
* unix,win: harmonize uv_read_start() error handling (Ben Noordhuis)
* unix,win: more uv_read_start() argument validation (Ben Noordhuis)
* build: turn on -fno-strict-aliasing (Ben Noordhuis)
* stream: add uv_pipe and uv_socketpair to the API (Jameson Nash)
* unix,win: initialize timer `timeout` field (Ben Noordhuis)
* bsd-ifaddrs: improve comments (Darshan Sen)
* test: remove unnecessary uv_fs_stat() calls (Ben Noordhuis)
* fs: fix utime/futime timestamp rounding errors (Ben Noordhuis)
* test: ensure reliable floating point comparison (Jameson Nash)
* unix,fs: fix uv_fs_sendfile() (Santiago Gimeno)
* unix: fix uv_fs_stat when using statx (Simon Kadisch)
* linux,macos: fix uv_set_process_title regression (Momtchil Momtchev)
* doc: clarify UDP errors and recvmmsg (Ethel Weston)
* test-getaddrinfo: use example.invalid (Drew DeVault)
* Revert "build: fix android autotools build" (Bernardo Ramos)
* unix,fs: on DVS fs, statx returns EOPNOTSUPP (Mark Klein)
* win, fs: mkdir really return UV_EINVAL for invalid names (Nicholas Vavilov)
* tools: migrate tools/make_dist_html.py to python3 (Dominique Dumont)
* unix: fix uv_uptime() on linux (schamberg97)
* unix: check for partial copy_file_range support (Momtchil Momtchev)
* win: bump minimum supported version to windows 8 (Ben Noordhuis)
* poll,unix: ensure safety of rapid fd reuse (Bob Weinand)
* test: fix some warnings (Issam E. Maghni)
* unix: fix uv_uptime() regression (Santiago Gimeno)
* doc: fix versionadded metadata (cjihrig)
* test: fix 'incompatible pointer types' warnings (cjihrig)
* unix: check for EXDEV in uv__fs_sendfile() (Darshan Sen)
2020.09.26, Version 1.40.0 (Stable), 4e69e333252693bd82d6338d6124f0416538dbfc
Changes since version 1.39.0: Changes since version 1.39.0:

101
deps/libuv/LINKS.md vendored Normal file
View File

@ -0,0 +1,101 @@
### Apps / VM
* [BIND 9](https://bind.isc.org/): DNS software system including an authoritative server, a recursive resolver and related utilities.
* [cjdns](https://github.com/cjdelisle/cjdns): Encrypted self-configuring network/VPN routing engine
* [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
* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps.
* [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.
* [H2O](https://github.com/h2o/h2o): An optimized HTTP server with support for HTTP/1.x and HTTP/2.
* [Igropyr](https://github.com/guenchi/Igropyr): a async Scheme http server base on libuv.
* [Julia](http://julialang.org/): Scientific computing programming language
* [Kestrel](https://github.com/aspnet/AspNetCore/tree/master/src/Servers/Kestrel): web server (C# + libuv + [ASP.NET Core](http://github.com/aspnet))
* [Knot DNS Resolver](https://www.knot-resolver.cz/): A minimalistic DNS caching resolver
* [Lever](http://leverlanguage.com): runtime, libuv at the 0.9.0 release
* [libnode](https://github.com/plenluno/libnode): C++ implementation of Node.js
* [libstorj](https://github.com/Storj/libstorj): Library for interacting with Storj network
* [libuv_message_framing](https://github.com/litesync/libuv_message_framing) Message-based communication for libuv
* [luaw](https://github.com/raksoras/luaw): Lua web server backed by libuv
* [Luvit](http://luvit.io): Node.JS for the Lua Inventor
* [mo](https://github.com/wehu/mo): Scheme (guile) + libuv runtime
* [MoarVM](https://github.com/MoarVM/MoarVM): a VM for [Rakudo](http://rakudo.org/) [Raku](http://raku.org)
* [Mysocks](https://github.com/zhou0/mysocks): a cross-platform [Shadowsocks](https://shadowsocks.org) client
* [mediasoup](http://mediasoup.org): Powerful WebRTC SFU for Node.js
* [Neovim](https://neovim.io/): A major refactor of Vim.
* [node9](https://github.com/jvburnes/node9): A portable, hybrid, distributed OS based on Inferno, LuaJIT and Libuv
* [node.js](http://www.nodejs.org/): Javascript (using Google's V8) + libuv
* [node.native](https://github.com/d5/node.native): node.js-like API for C++11
* [nodeuv](https://github.com/nodeuv): An organization with several c++ wrappers for libs which are used in node.js.
* [phastlight](https://github.com/phastlight/phastlight): Command line tool and web server written in PHP 5.3+ inspired by Node.js
* [pilight](https://www.pilight.org/): home automation ("domotica")
* [pixie](https://github.com/pixie-lang/pixie): clojure-inspired lisp with a tracing JIT
* [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
* [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
* [Swish](https://github.com/becls/swish/): Concurrency engine with Erlang-like concepts. Includes a web server.
* [Trevi](https://github.com/Yoseob/Trevi): A powerful Swift Web Application Server Framework Project
* [Urbit](http://urbit.org): runtime
* [uv_callback](https://github.com/litesync/uv_callback) libuv thread communication
* [uvloop](https://github.com/MagicStack/uvloop): Ultra fast implementation of python's asyncio event loop on top of libuv
* [Wren CLI](https://github.com/wren-lang/wren-cli): For io, process, scheduler and timer modules
### Other
* [libtuv](https://github.com/Samsung/libtuv): libuv fork for IoT and embedded systems
### Bindings
* [Ring](http://ring-lang.net)
* [RingLibuv](http://ring-lang.sourceforge.net/doc1.7/libuv.html)
* Ruby
* [libuv](https://github.com/cotag/libuv)
* [uvrb](https://github.com/avalanche123/uvrb)
* [ruv](https://github.com/aq1018/ruv)
* [rbuv](https://github.com/rbuv/rbuv)
* [mruby-uv](https://github.com/mattn/mruby-uv): mruby binding
* Lua
* [luv](https://github.com/creationix/luv)
* [lev](https://github.com/connectFree/lev)
* [lluv](https://github.com/moteus/lua-lluv)
* C++11
* [uvpp](https://github.com/larroy/uvpp) - Not complete, exposes very few aspects of `libuv`
* C++17
* [uvw](https://github.com/skypjack/uvw) - Header-only, event based, tiny and easy to use *libuv* wrapper in modern C++.
* Python
* [Pyuv](https://github.com/saghul/pyuv)
* [uvloop](https://github.com/MagicStack/uvloop) - Ultra fast asyncio event loop.
* [gevent](http://www.gevent.org) - Coroutine-based concurrency library for Python
* C#
* [NetUV](http://github.com/StormHub/NetUV)
* [LibuvSharp](http://github.com/txdv/LibuvSharp)
* Perl 5
* [UV](https://metacpan.org/pod/UV)
* [Raku](https://raku.org/)
* [MoarVM](https://github.com/MoarVM/MoarVM) [uses](http://6guts.wordpress.com/2013/05/31/moarvm-a-virtual-machine-for-nqp-and-rakudo/) libuv
* PHP
* [php-uv](https://github.com/bwoebi/php-uv)
* Go
* [go-uv](https://github.com/mattn/go-uv)
* OCaml
* [luv](https://github.com/aantron/luv)
* [uwt](https://github.com/fdopen/uwt)
* ooc
* [ooc-uv](https://github.com/nddrylliog/ooc-uv)
* dylan
* [uv-dylan](https://github.com/waywardmonkeys/uv-dylan)
* R
* [httpuv](https://github.com/rstudio/httpuv): HTTP and WebSocket server library for R
* [fs](https://fs.r-lib.org/): Cross-platform file system operations
* Java
* [libuv-java](https://java.net/projects/avatar-js/sources/libuv-java/show): Java bindings
* Nim
* [nimuv](https://github.com/2vg/nimuv): Nim bindings
* Lisp
* [cl-libuv](https://github.com/orthecreedence/cl-libuv) Common Lisp bindings
* [cl-async](https://github.com/orthecreedence/cl-async) Common Lisp async abstraction on top of cl-libuv
* [Céu](http://www.ceu-lang.org)
* [Céu-libuv](https://github.com/fsantanna/ceu-libuv)
* Delphi
* [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem
* Haskell
* [Z.Haskell](https://z.haskell.world)

View File

@ -16,6 +16,7 @@ libuv is currently managed by the following individuals:
* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq))
- GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere)
* **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash))
- GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash)
* **John Barboza** ([@jbarz](https://github.com/jbarz)) * **John Barboza** ([@jbarz](https://github.com/jbarz))
* **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) * **Kaoru Takanashi** ([@erw7](https://github.com/erw7))
- GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7) - GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7)

View File

@ -56,7 +56,7 @@ if WINNT
uvinclude_HEADERS += include/uv/win.h include/uv/tree.h uvinclude_HEADERS += include/uv/win.h include/uv/tree.h
AM_CPPFLAGS += -I$(top_srcdir)/src/win \ AM_CPPFLAGS += -I$(top_srcdir)/src/win \
-DWIN32_LEAN_AND_MEAN \ -DWIN32_LEAN_AND_MEAN \
-D_WIN32_WINNT=0x0600 -D_WIN32_WINNT=0x0602
libuv_la_SOURCES += src/win/async.c \ libuv_la_SOURCES += src/win/async.c \
src/win/atomicops-inl.h \ src/win/atomicops-inl.h \
src/win/core.c \ src/win/core.c \
@ -206,6 +206,9 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-metrics.c \ test/test-metrics.c \
test/test-multiple-listen.c \ test/test-multiple-listen.c \
test/test-mutexes.c \ test/test-mutexes.c \
test/test-not-readable-nor-writable-on-read-error.c \
test/test-not-readable-on-eof.c \
test/test-not-writable-after-shutdown.c \
test/test-osx-select.c \ test/test-osx-select.c \
test/test-pass-always.c \ test/test-pass-always.c \
test/test-ping-pong.c \ test/test-ping-pong.c \
@ -225,6 +228,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-poll-close.c \ test/test-poll-close.c \
test/test-poll-close-doesnt-corrupt-stack.c \ test/test-poll-close-doesnt-corrupt-stack.c \
test/test-poll-closesocket.c \ test/test-poll-closesocket.c \
test/test-poll-multiple-handles.c \
test/test-poll-oob.c \ test/test-poll-oob.c \
test/test-process-priority.c \ test/test-process-priority.c \
test/test-process-title.c \ test/test-process-title.c \
@ -237,6 +241,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-semaphore.c \ test/test-semaphore.c \
test/test-shutdown-close.c \ test/test-shutdown-close.c \
test/test-shutdown-eof.c \ test/test-shutdown-eof.c \
test/test-shutdown-simultaneous.c \
test/test-shutdown-twice.c \ test/test-shutdown-twice.c \
test/test-signal-multiple-loops.c \ test/test-signal-multiple-loops.c \
test/test-signal-pending-on-close.c \ test/test-signal-pending-on-close.c \
@ -385,13 +390,10 @@ if ANDROID
uvinclude_HEADERS += include/uv/android-ifaddrs.h uvinclude_HEADERS += include/uv/android-ifaddrs.h
libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_CFLAGS += -D_GNU_SOURCE
libuv_la_SOURCES += src/unix/android-ifaddrs.c \ libuv_la_SOURCES += src/unix/android-ifaddrs.c \
src/unix/linux-core.c \
src/unix/linux-inotify.c \
src/unix/linux-syscalls.c \
src/unix/procfs-exepath.c \
src/unix/pthread-fixes.c \ src/unix/pthread-fixes.c \
src/unix/random-getrandom.c \ src/unix/random-getrandom.c \
src/unix/random-sysctl-linux.c src/unix/random-sysctl-linux.c \
src/unix/epoll.c
endif endif
if CYGWIN if CYGWIN
@ -472,7 +474,8 @@ libuv_la_SOURCES += src/unix/linux-core.c \
src/unix/procfs-exepath.c \ src/unix/procfs-exepath.c \
src/unix/proctitle.c \ src/unix/proctitle.c \
src/unix/random-getrandom.c \ src/unix/random-getrandom.c \
src/unix/random-sysctl-linux.c src/unix/random-sysctl-linux.c \
src/unix/epoll.c
test_run_tests_LDFLAGS += -lutil test_run_tests_LDFLAGS += -lutil
endif endif

22
deps/libuv/README.md vendored
View File

@ -5,7 +5,7 @@
libuv is a multi-platform support library with a focus on asynchronous I/O. It libuv is a multi-platform support library with a focus on asynchronous I/O. It
was primarily developed for use by [Node.js][], but it's also was primarily developed for use by [Node.js][], but it's also
used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/),
[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/wiki/Projects-that-use-libuv). [pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/blob/v1.x/LINKS.md).
## Feature highlights ## Feature highlights
@ -48,9 +48,8 @@ The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-do
## Community ## Community
* [Support](https://github.com/libuv/help) * [Support](https://github.com/libuv/libuv/discussions)
* [Mailing list](http://groups.google.com/group/libuv) * [Mailing list](http://groups.google.com/group/libuv)
* [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4)
## Documentation ## Documentation
@ -286,6 +285,16 @@ listed in `test/benchmark-list.h`.
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
### `-fno-strict-aliasing`
It is recommended to turn on the `-fno-strict-aliasing` compiler flag in
projects that use libuv. The use of ad hoc "inheritance" in the libuv API
may not be safe in the presence of compiler optimizations that depend on
strict aliasing.
MSVC does not have an equivalent flag but it also does not appear to need it
at the time of writing (December 2019.)
### AIX Notes ### AIX Notes
AIX compilation using IBM XL C/C++ requires version 12.1 or greater. AIX compilation using IBM XL C/C++ requires version 12.1 or greater.
@ -298,6 +307,13 @@ describes the package in more detail.
### z/OS Notes ### z/OS Notes
z/OS compilation requires [ZOSLIB](https://github.com/ibmruntimes/zoslib) to be installed. When building with [CMake][], use the flag `-DZOSLIB_DIR` to specify the path to [ZOSLIB](https://github.com/ibmruntimes/zoslib):
```bash
$ (cd build && cmake .. -DBUILD_TESTING=ON -DZOSLIB_DIR=/path/to/zoslib)
$ cmake --build build
```
z/OS creates System V semaphores and message queues. These persist on the system z/OS creates System V semaphores and message queues. These persist on the system
after the process terminates unless the event loop is closed. after the process terminates unless the event loop is closed.

View File

@ -4,14 +4,14 @@
|---|---|---|---| |---|---|---|---|
| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | | GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | |
| macOS | Tier 1 | macOS >= 10.7 | | | macOS | Tier 1 | macOS >= 10.7 | |
| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported | | Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported |
| FreeBSD | Tier 1 | >= 10 | | | FreeBSD | Tier 1 | >= 10 | |
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
| Linux with musl | Tier 2 | musl >= 1.0 | | | Linux with musl | Tier 2 | musl >= 1.0 | |
| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | | SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos |
| Android | Tier 3 | NDK >= r15b | | | Android | Tier 3 | NDK >= r15b | |
| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
| SunOS | Tier 3 | Solaris 121 and later | | | SunOS | Tier 3 | Solaris 121 and later | |
| Other | Tier 3 | N/A | | | Other | Tier 3 | N/A | |

View File

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT([libuv], [1.40.0], [https://github.com/libuv/libuv/issues]) AC_INIT([libuv], [1.42.0], [https://github.com/libuv/libuv/issues])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4]) m4_include([m4/as_case.m4])
@ -24,7 +24,11 @@ AC_ENABLE_SHARED
AC_ENABLE_STATIC AC_ENABLE_STATIC
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
CC_FLAG_VISIBILITY #[-fvisibility=hidden]
CC_ATTRIBUTE_VISIBILITY([default], [
CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"])
])
CC_CHECK_CFLAGS_APPEND([-fno-strict-aliasing])
CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-g])
CC_CHECK_CFLAGS_APPEND([-std=gnu89]) CC_CHECK_CFLAGS_APPEND([-std=gnu89])
CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wall])
@ -42,7 +46,7 @@ AX_PTHREAD([
LIBS="$LIBS $PTHREAD_LIBS" LIBS="$LIBS $PTHREAD_LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
]) ])
AC_CHECK_LIB([dl], [dlopen]) AC_SEARCH_LIBS([dlopen], [dl])
AC_SEARCH_LIBS([kstat_lookup], [kstat]) AC_SEARCH_LIBS([kstat_lookup], [kstat])
AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([gethostbyname], [nsl])
AC_SEARCH_LIBS([perfstat_cpu], [perfstat]) AC_SEARCH_LIBS([perfstat_cpu], [perfstat])

View File

@ -69,8 +69,8 @@ int main() {
hints.ai_flags = 0; hints.ai_flags = 0;
uv_getaddrinfo_t resolver; uv_getaddrinfo_t resolver;
fprintf(stderr, "irc.freenode.net is... "); fprintf(stderr, "irc.libera.chat is... ");
int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints); int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.libera.chat", "6667", &hints);
if (r) { if (r) {
fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r));

42
deps/libuv/docs/requirements.txt vendored Normal file
View File

@ -0,0 +1,42 @@
# primary
Sphinx==3.5.4
# dependencies
alabaster==0.7.12
appdirs==1.4.3
Babel==2.9.0
CacheControl==0.12.6
certifi==2019.11.28
chardet==3.0.4
colorama==0.4.3
contextlib2==0.6.0
distlib==0.3.0
distro==1.4.0
docutils==0.16
html5lib==1.0.1
idna==2.8
imagesize==1.2.0
ipaddr==2.2.0
Jinja2==2.11.3
lockfile==0.12.2
MarkupSafe==1.1.1
msgpack==0.6.2
packaging==20.3
pep517==0.8.2
progress==1.5
Pygments==2.8.1
pyparsing==2.4.6
pytoml==0.1.21
pytz==2021.1
requests==2.22.0
retrying==1.3.3
six==1.14.0
snowballstemmer==2.1.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==1.0.3
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.4
urllib3==1.25.8
webencodings==0.5.1

View File

@ -251,6 +251,10 @@ Error constants
operation not supported on socket operation not supported on socket
.. c:macro:: UV_EOVERFLOW
value too large for defined data type
.. c:macro:: UV_EPERM .. c:macro:: UV_EPERM
operation not permitted operation not permitted
@ -331,6 +335,10 @@ Error constants
illegal byte sequence illegal byte sequence
.. c:macro:: UV_ESOCKTNOSUPPORT
socket type not supported
API API
--- ---

View File

@ -87,6 +87,7 @@ nothing, except start a loop which will exit immediately.
.. rubric:: helloworld/main.c .. rubric:: helloworld/main.c
.. literalinclude:: ../../code/helloworld/main.c .. literalinclude:: ../../code/helloworld/main.c
:language: c
:linenos: :linenos:
This program quits immediately because it has no events to process. A libuv This program quits immediately because it has no events to process. A libuv
@ -202,6 +203,7 @@ event watchers are active.
.. rubric:: idle-basic/main.c .. rubric:: idle-basic/main.c
.. literalinclude:: ../../code/idle-basic/main.c .. literalinclude:: ../../code/idle-basic/main.c
:language: c
:emphasize-lines: 6,10,14-17 :emphasize-lines: 6,10,14-17
Storing context Storing context

View File

@ -20,6 +20,7 @@ these things can be a bit difficult to understand, so let's look at
.. rubric:: src/unix/core.c - uv_run .. rubric:: src/unix/core.c - uv_run
.. literalinclude:: ../../../src/unix/core.c .. literalinclude:: ../../../src/unix/core.c
:language: c
:linenos: :linenos:
:lines: 304-324 :lines: 304-324
:emphasize-lines: 10,19,21 :emphasize-lines: 10,19,21
@ -43,6 +44,7 @@ iteration of the loop still takes places.
.. rubric:: uvstop/main.c .. rubric:: uvstop/main.c
.. literalinclude:: ../../code/uvstop/main.c .. literalinclude:: ../../code/uvstop/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 11 :emphasize-lines: 11

View File

@ -54,6 +54,7 @@ a callback for when the file is opened:
.. rubric:: uvcat/main.c - opening a file .. rubric:: uvcat/main.c - opening a file
.. literalinclude:: ../../code/uvcat/main.c .. literalinclude:: ../../code/uvcat/main.c
:language: c
:linenos: :linenos:
:lines: 41-53 :lines: 41-53
:emphasize-lines: 4, 6-7 :emphasize-lines: 4, 6-7
@ -63,6 +64,7 @@ The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the
.. rubric:: uvcat/main.c - read callback .. rubric:: uvcat/main.c - read callback
.. literalinclude:: ../../code/uvcat/main.c .. literalinclude:: ../../code/uvcat/main.c
:language: c
:linenos: :linenos:
:lines: 26-40 :lines: 26-40
:emphasize-lines: 2,8,12 :emphasize-lines: 2,8,12
@ -87,6 +89,7 @@ callbacks.
.. rubric:: uvcat/main.c - write callback .. rubric:: uvcat/main.c - write callback
.. literalinclude:: ../../code/uvcat/main.c .. literalinclude:: ../../code/uvcat/main.c
:language: c
:linenos: :linenos:
:lines: 16-24 :lines: 16-24
:emphasize-lines: 6 :emphasize-lines: 6
@ -100,6 +103,7 @@ We set the dominos rolling in ``main()``:
.. rubric:: uvcat/main.c .. rubric:: uvcat/main.c
.. literalinclude:: ../../code/uvcat/main.c .. literalinclude:: ../../code/uvcat/main.c
:language: c
:linenos: :linenos:
:lines: 55- :lines: 55-
:emphasize-lines: 2 :emphasize-lines: 2
@ -203,6 +207,7 @@ opened as bidirectional by default.
.. rubric:: uvtee/main.c - read on pipes .. rubric:: uvtee/main.c - read on pipes
.. literalinclude:: ../../code/uvtee/main.c .. literalinclude:: ../../code/uvtee/main.c
:language: c
:linenos: :linenos:
:lines: 61-80 :lines: 61-80
:emphasize-lines: 4,5,15 :emphasize-lines: 4,5,15
@ -218,6 +223,7 @@ these buffers.
.. rubric:: uvtee/main.c - reading buffers .. rubric:: uvtee/main.c - reading buffers
.. literalinclude:: ../../code/uvtee/main.c .. literalinclude:: ../../code/uvtee/main.c
:language: c
:linenos: :linenos:
:lines: 19-22,44-60 :lines: 19-22,44-60
@ -242,6 +248,7 @@ point there is nothing to be read. Most applications will just ignore this.
.. rubric:: uvtee/main.c - Write to pipe .. rubric:: uvtee/main.c - Write to pipe
.. literalinclude:: ../../code/uvtee/main.c .. literalinclude:: ../../code/uvtee/main.c
:language: c
:linenos: :linenos:
:lines: 9-13,23-42 :lines: 9-13,23-42
@ -282,6 +289,7 @@ The file change notification is started using ``uv_fs_event_init()``:
.. rubric:: onchange/main.c - The setup .. rubric:: onchange/main.c - The setup
.. literalinclude:: ../../code/onchange/main.c .. literalinclude:: ../../code/onchange/main.c
:language: c
:linenos: :linenos:
:lines: 26- :lines: 26-
:emphasize-lines: 15 :emphasize-lines: 15
@ -320,6 +328,7 @@ In our example we simply print the arguments and run the command using
.. rubric:: onchange/main.c - file change notification callback .. rubric:: onchange/main.c - file change notification callback
.. literalinclude:: ../../code/onchange/main.c .. literalinclude:: ../../code/onchange/main.c
:language: c
:linenos: :linenos:
:lines: 9-24 :lines: 9-24

View File

@ -72,4 +72,4 @@ There is no need to ``make install``. To build the examples run ``make`` in the
.. _node.js: https://www.nodejs.org .. _node.js: https://www.nodejs.org
.. _libev was removed: https://github.com/joyent/libuv/issues/485 .. _libev was removed: https://github.com/joyent/libuv/issues/485
.. _Rust: https://www.rust-lang.org .. _Rust: https://www.rust-lang.org
.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv .. _variety: https://github.com/libuv/libuv/blob/v1.x/LINKS.md

View File

@ -38,6 +38,7 @@ Here is a simple echo server
.. rubric:: tcp-echo-server/main.c - The listen socket .. rubric:: tcp-echo-server/main.c - The listen socket
.. literalinclude:: ../../code/tcp-echo-server/main.c .. literalinclude:: ../../code/tcp-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 68- :lines: 68-
:emphasize-lines: 4-5,7-10 :emphasize-lines: 4-5,7-10
@ -60,6 +61,7 @@ In this case we also establish interest in reading from this stream.
.. rubric:: tcp-echo-server/main.c - Accepting the client .. rubric:: tcp-echo-server/main.c - Accepting the client
.. literalinclude:: ../../code/tcp-echo-server/main.c .. literalinclude:: ../../code/tcp-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 51-66 :lines: 51-66
:emphasize-lines: 9-10 :emphasize-lines: 9-10
@ -108,6 +110,7 @@ address from a `DHCP`_ server -- DHCP Discover.
.. rubric:: udp-dhcp/main.c - Setup and send UDP packets .. rubric:: udp-dhcp/main.c - Setup and send UDP packets
.. literalinclude:: ../../code/udp-dhcp/main.c .. literalinclude:: ../../code/udp-dhcp/main.c
:language: c
:linenos: :linenos:
:lines: 7-11,104- :lines: 7-11,104-
:emphasize-lines: 8,10-11,17-18,21 :emphasize-lines: 8,10-11,17-18,21
@ -143,6 +146,7 @@ the OS will discard the data that could not fit* (That's UDP for you!).
.. rubric:: udp-dhcp/main.c - Reading packets .. rubric:: udp-dhcp/main.c - Reading packets
.. literalinclude:: ../../code/udp-dhcp/main.c .. literalinclude:: ../../code/udp-dhcp/main.c
:language: c
:linenos: :linenos:
:lines: 17-40 :lines: 17-40
:emphasize-lines: 1,23 :emphasize-lines: 1,23
@ -189,10 +193,11 @@ Querying DNS
libuv provides asynchronous DNS resolution. For this it provides its own libuv provides asynchronous DNS resolution. For this it provides its own
``getaddrinfo`` replacement [#]_. In the callback you can ``getaddrinfo`` replacement [#]_. In the callback you can
perform normal socket operations on the retrieved addresses. Let's connect to perform normal socket operations on the retrieved addresses. Let's connect to
Freenode to see an example of DNS resolution. Libera.chat to see an example of DNS resolution.
.. rubric:: dns/main.c .. rubric:: dns/main.c
.. literalinclude:: ../../code/dns/main.c .. literalinclude:: ../../code/dns/main.c
:language: c
:linenos: :linenos:
:lines: 61- :lines: 61-
:emphasize-lines: 12 :emphasize-lines: 12
@ -209,6 +214,7 @@ call ``uv_freeaddrinfo`` in the callback.
.. rubric:: dns/main.c .. rubric:: dns/main.c
.. literalinclude:: ../../code/dns/main.c .. literalinclude:: ../../code/dns/main.c
:language: c
:linenos: :linenos:
:lines: 42-60 :lines: 42-60
:emphasize-lines: 8,16 :emphasize-lines: 8,16
@ -227,6 +233,7 @@ useful to allow your service to bind to IP addresses when it starts.
.. rubric:: interfaces/main.c .. rubric:: interfaces/main.c
.. literalinclude:: ../../code/interfaces/main.c .. literalinclude:: ../../code/interfaces/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 9,17 :emphasize-lines: 9,17

View File

@ -27,6 +27,7 @@ exits. This is achieved using ``uv_spawn``.
.. rubric:: spawn/main.c .. rubric:: spawn/main.c
.. literalinclude:: ../../code/spawn/main.c .. literalinclude:: ../../code/spawn/main.c
:language: c
:linenos: :linenos:
:lines: 6-8,15- :lines: 6-8,15-
:emphasize-lines: 11,13-17 :emphasize-lines: 11,13-17
@ -54,6 +55,7 @@ which caused the exit.
.. rubric:: spawn/main.c .. rubric:: spawn/main.c
.. literalinclude:: ../../code/spawn/main.c .. literalinclude:: ../../code/spawn/main.c
:language: c
:linenos: :linenos:
:lines: 9-12 :lines: 9-12
:emphasize-lines: 3 :emphasize-lines: 3
@ -104,6 +106,7 @@ does not affect it.
.. rubric:: detach/main.c .. rubric:: detach/main.c
.. literalinclude:: ../../code/detach/main.c .. literalinclude:: ../../code/detach/main.c
:language: c
:linenos: :linenos:
:lines: 9-30 :lines: 9-30
:emphasize-lines: 12,19 :emphasize-lines: 12,19
@ -140,6 +143,7 @@ stop watching. Here is a small example demonstrating the various possibilities:
.. rubric:: signal/main.c .. rubric:: signal/main.c
.. literalinclude:: ../../code/signal/main.c .. literalinclude:: ../../code/signal/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 17-18,27-28 :emphasize-lines: 17-18,27-28
@ -172,6 +176,7 @@ which is:
.. rubric:: proc-streams/test.c .. rubric:: proc-streams/test.c
.. literalinclude:: ../../code/proc-streams/test.c .. literalinclude:: ../../code/proc-streams/test.c
:language: c
The actual program ``proc-streams`` runs this while sharing only ``stderr``. The actual program ``proc-streams`` runs this while sharing only ``stderr``.
The file descriptors of the child process are set using the ``stdio`` field in The file descriptors of the child process are set using the ``stdio`` field in
@ -199,6 +204,7 @@ Then we set the ``fd`` to ``stderr``.
.. rubric:: proc-streams/main.c .. rubric:: proc-streams/main.c
.. literalinclude:: ../../code/proc-streams/main.c .. literalinclude:: ../../code/proc-streams/main.c
:language: c
:linenos: :linenos:
:lines: 15-17,27- :lines: 15-17,27-
:emphasize-lines: 6,10,11,12 :emphasize-lines: 6,10,11,12
@ -217,12 +223,14 @@ A sample CGI script/executable is:
.. rubric:: cgi/tick.c .. rubric:: cgi/tick.c
.. literalinclude:: ../../code/cgi/tick.c .. literalinclude:: ../../code/cgi/tick.c
:language: c
The CGI server combines the concepts from this chapter and :doc:`networking` so The CGI server combines the concepts from this chapter and :doc:`networking` so
that every client is sent ten ticks after which that connection is closed. that every client is sent ten ticks after which that connection is closed.
.. rubric:: cgi/main.c .. rubric:: cgi/main.c
.. literalinclude:: ../../code/cgi/main.c .. literalinclude:: ../../code/cgi/main.c
:language: c
:linenos: :linenos:
:lines: 49-63 :lines: 49-63
:emphasize-lines: 10 :emphasize-lines: 10
@ -232,6 +240,7 @@ Here we simply accept the TCP connection and pass on the socket (*stream*) to
.. rubric:: cgi/main.c .. rubric:: cgi/main.c
.. literalinclude:: ../../code/cgi/main.c .. literalinclude:: ../../code/cgi/main.c
:language: c
:linenos: :linenos:
:lines: 16, 25-45 :lines: 16, 25-45
:emphasize-lines: 8-9,18,20 :emphasize-lines: 8-9,18,20
@ -291,6 +300,7 @@ messaging is no different from TCP, so we'll re-use the echo server example.
.. rubric:: pipe-echo-server/main.c .. rubric:: pipe-echo-server/main.c
.. literalinclude:: ../../code/pipe-echo-server/main.c .. literalinclude:: ../../code/pipe-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 70- :lines: 70-
:emphasize-lines: 5,10,14 :emphasize-lines: 5,10,14
@ -330,6 +340,7 @@ it by the master.
.. rubric:: multi-echo-server/worker.c .. rubric:: multi-echo-server/worker.c
.. literalinclude:: ../../code/multi-echo-server/worker.c .. literalinclude:: ../../code/multi-echo-server/worker.c
:language: c
:linenos: :linenos:
:lines: 7-9,81- :lines: 7-9,81-
:emphasize-lines: 6-8 :emphasize-lines: 6-8
@ -343,6 +354,7 @@ standard input of the worker, we connect the pipe to ``stdin`` using
.. rubric:: multi-echo-server/worker.c .. rubric:: multi-echo-server/worker.c
.. literalinclude:: ../../code/multi-echo-server/worker.c .. literalinclude:: ../../code/multi-echo-server/worker.c
:language: c
:linenos: :linenos:
:lines: 51-79 :lines: 51-79
:emphasize-lines: 10,15,20 :emphasize-lines: 10,15,20
@ -361,6 +373,7 @@ allow load balancing.
.. rubric:: multi-echo-server/main.c .. rubric:: multi-echo-server/main.c
.. literalinclude:: ../../code/multi-echo-server/main.c .. literalinclude:: ../../code/multi-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 9-13 :lines: 9-13
@ -369,6 +382,7 @@ master and the individual process.
.. rubric:: multi-echo-server/main.c .. rubric:: multi-echo-server/main.c
.. literalinclude:: ../../code/multi-echo-server/main.c .. literalinclude:: ../../code/multi-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 51,61-95 :lines: 51,61-95
:emphasize-lines: 17,20-21 :emphasize-lines: 17,20-21
@ -387,6 +401,7 @@ worker in the round-robin.
.. rubric:: multi-echo-server/main.c .. rubric:: multi-echo-server/main.c
.. literalinclude:: ../../code/multi-echo-server/main.c .. literalinclude:: ../../code/multi-echo-server/main.c
:language: c
:linenos: :linenos:
:lines: 31-49 :lines: 31-49
:emphasize-lines: 9,12-13 :emphasize-lines: 9,12-13

View File

@ -39,6 +39,7 @@ wait for it to close using ``uv_thread_join()``.
.. rubric:: thread-create/main.c .. rubric:: thread-create/main.c
.. literalinclude:: ../../code/thread-create/main.c .. literalinclude:: ../../code/thread-create/main.c
:language: c
:linenos: :linenos:
:lines: 26-36 :lines: 26-36
:emphasize-lines: 3-7 :emphasize-lines: 3-7
@ -55,6 +56,7 @@ thread, scheduled pre-emptively by the operating system:
.. rubric:: thread-create/main.c .. rubric:: thread-create/main.c
.. literalinclude:: ../../code/thread-create/main.c .. literalinclude:: ../../code/thread-create/main.c
:language: c
:linenos: :linenos:
:lines: 6-14 :lines: 6-14
:emphasize-lines: 2 :emphasize-lines: 2
@ -124,6 +126,7 @@ example.
.. rubric:: locks/main.c - simple rwlocks .. rubric:: locks/main.c - simple rwlocks
.. literalinclude:: ../../code/locks/main.c .. literalinclude:: ../../code/locks/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 13,16,27,31,42,55 :emphasize-lines: 13,16,27,31,42,55
@ -208,6 +211,7 @@ event loop from performing other activities.
.. rubric:: queue-work/main.c - lazy fibonacci .. rubric:: queue-work/main.c - lazy fibonacci
.. literalinclude:: ../../code/queue-work/main.c .. literalinclude:: ../../code/queue-work/main.c
:language: c
:linenos: :linenos:
:lines: 17-29 :lines: 17-29
@ -221,6 +225,7 @@ The trigger is ``uv_queue_work``:
.. rubric:: queue-work/main.c .. rubric:: queue-work/main.c
.. literalinclude:: ../../code/queue-work/main.c .. literalinclude:: ../../code/queue-work/main.c
:language: c
:linenos: :linenos:
:lines: 31-44 :lines: 31-44
:emphasize-lines: 10 :emphasize-lines: 10
@ -248,6 +253,7 @@ up a signal handler for termination.
.. rubric:: queue-cancel/main.c .. rubric:: queue-cancel/main.c
.. literalinclude:: ../../code/queue-cancel/main.c .. literalinclude:: ../../code/queue-cancel/main.c
:language: c
:linenos: :linenos:
:lines: 43- :lines: 43-
@ -256,6 +262,7 @@ When the user triggers the signal by pressing ``Ctrl+C`` we send
.. rubric:: queue-cancel/main.c .. rubric:: queue-cancel/main.c
.. literalinclude:: ../../code/queue-cancel/main.c .. literalinclude:: ../../code/queue-cancel/main.c
:language: c
:linenos: :linenos:
:lines: 33-41 :lines: 33-41
:emphasize-lines: 6 :emphasize-lines: 6
@ -265,6 +272,7 @@ with ``status`` set to ``UV_ECANCELED``.
.. rubric:: queue-cancel/main.c .. rubric:: queue-cancel/main.c
.. literalinclude:: ../../code/queue-cancel/main.c .. literalinclude:: ../../code/queue-cancel/main.c
:language: c
:linenos: :linenos:
:lines: 28-31 :lines: 28-31
:emphasize-lines: 2 :emphasize-lines: 2
@ -292,6 +300,7 @@ informing the user of the status of running downloads.
.. rubric:: progress/main.c .. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c .. literalinclude:: ../../code/progress/main.c
:language: c
:linenos: :linenos:
:lines: 7-8,35- :lines: 7-8,35-
:emphasize-lines: 2,11 :emphasize-lines: 2,11
@ -317,6 +326,7 @@ with the async watcher whenever it receives a message.
.. rubric:: progress/main.c .. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c .. literalinclude:: ../../code/progress/main.c
:language: c
:linenos: :linenos:
:lines: 10-24 :lines: 10-24
:emphasize-lines: 7-8 :emphasize-lines: 7-8
@ -327,6 +337,7 @@ non-blocking and will return immediately.
.. rubric:: progress/main.c .. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c .. literalinclude:: ../../code/progress/main.c
:language: c
:linenos: :linenos:
:lines: 31-34 :lines: 31-34
@ -336,6 +347,7 @@ Finally it is important to remember to clean up the watcher.
.. rubric:: progress/main.c .. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c .. literalinclude:: ../../code/progress/main.c
:language: c
:linenos: :linenos:
:lines: 26-29 :lines: 26-29
:emphasize-lines: 3 :emphasize-lines: 3

View File

@ -87,6 +87,7 @@ JS object and can be ref/unrefed.
.. rubric:: ref-timer/main.c .. rubric:: ref-timer/main.c
.. literalinclude:: ../../code/ref-timer/main.c .. literalinclude:: ../../code/ref-timer/main.c
:language: c
:linenos: :linenos:
:lines: 5-8, 17- :lines: 5-8, 17-
:emphasize-lines: 9 :emphasize-lines: 9
@ -111,6 +112,7 @@ idle watcher to keep the UI operational.
.. rubric:: idle-compute/main.c .. rubric:: idle-compute/main.c
.. literalinclude:: ../../code/idle-compute/main.c .. literalinclude:: ../../code/idle-compute/main.c
:language: c
:linenos: :linenos:
:lines: 5-9, 34- :lines: 5-9, 34-
:emphasize-lines: 13 :emphasize-lines: 13
@ -123,6 +125,7 @@ keep calling the idle callback again.
.. rubric:: idle-compute/main.c .. rubric:: idle-compute/main.c
.. literalinclude:: ../../code/idle-compute/main.c .. literalinclude:: ../../code/idle-compute/main.c
:language: c
:linenos: :linenos:
:lines: 10-19 :lines: 10-19
@ -215,6 +218,7 @@ progress with the download whenever libuv notifies of I/O readiness.
.. rubric:: uvwget/main.c - The setup .. rubric:: uvwget/main.c - The setup
.. literalinclude:: ../../code/uvwget/main.c .. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos: :linenos:
:lines: 1-9,140- :lines: 1-9,140-
:emphasize-lines: 7,21,24-25 :emphasize-lines: 7,21,24-25
@ -235,6 +239,7 @@ So we add each argument as an URL
.. rubric:: uvwget/main.c - Adding urls .. rubric:: uvwget/main.c - Adding urls
.. literalinclude:: ../../code/uvwget/main.c .. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos: :linenos:
:lines: 39-56 :lines: 39-56
:emphasize-lines: 13-14 :emphasize-lines: 13-14
@ -251,6 +256,7 @@ on sockets whenever ``handle_socket`` is called.
.. rubric:: uvwget/main.c - Setting up polling .. rubric:: uvwget/main.c - Setting up polling
.. literalinclude:: ../../code/uvwget/main.c .. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos: :linenos:
:lines: 102-140 :lines: 102-140
:emphasize-lines: 9,11,15,21,24 :emphasize-lines: 9,11,15,21,24
@ -271,6 +277,7 @@ mask with the new value. ``curl_perform`` is the crux of this program.
.. rubric:: uvwget/main.c - Driving libcurl. .. rubric:: uvwget/main.c - Driving libcurl.
.. literalinclude:: ../../code/uvwget/main.c .. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos: :linenos:
:lines: 81-95 :lines: 81-95
:emphasize-lines: 2,6-7,12 :emphasize-lines: 2,6-7,12
@ -288,6 +295,7 @@ transfers are done.
.. rubric:: uvwget/main.c - Reading transfer status. .. rubric:: uvwget/main.c - Reading transfer status.
.. literalinclude:: ../../code/uvwget/main.c .. literalinclude:: ../../code/uvwget/main.c
:language: c
:linenos: :linenos:
:lines: 58-79 :lines: 58-79
:emphasize-lines: 6,9-10,13-14 :emphasize-lines: 6,9-10,13-14
@ -312,6 +320,7 @@ Let us first look at the interface provided to plugin authors.
.. rubric:: plugin/plugin.h .. rubric:: plugin/plugin.h
.. literalinclude:: ../../code/plugin/plugin.h .. literalinclude:: ../../code/plugin/plugin.h
:language: c
:linenos: :linenos:
You can similarly add more functions that plugin authors can use to do useful You can similarly add more functions that plugin authors can use to do useful
@ -319,6 +328,7 @@ things in your application [#]_. A sample plugin using this API is:
.. rubric:: plugin/hello.c .. rubric:: plugin/hello.c
.. literalinclude:: ../../code/plugin/hello.c .. literalinclude:: ../../code/plugin/hello.c
:language: c
:linenos: :linenos:
Our interface defines that all plugins should have an ``initialize`` function Our interface defines that all plugins should have an ``initialize`` function
@ -340,6 +350,7 @@ This is done by using ``uv_dlopen`` to first load the shared library
.. rubric:: plugin/main.c .. rubric:: plugin/main.c
.. literalinclude:: ../../code/plugin/main.c .. literalinclude:: ../../code/plugin/main.c
:language: c
:linenos: :linenos:
:lines: 7- :lines: 7-
:emphasize-lines: 15, 18, 24 :emphasize-lines: 15, 18, 24
@ -393,6 +404,7 @@ Here is a simple example which prints white text on a red background:
.. rubric:: tty/main.c .. rubric:: tty/main.c
.. literalinclude:: ../../code/tty/main.c .. literalinclude:: ../../code/tty/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 11-12,14,17,27 :emphasize-lines: 11-12,14,17,27
@ -403,6 +415,7 @@ escape codes.
.. rubric:: tty-gravity/main.c .. rubric:: tty-gravity/main.c
.. literalinclude:: ../../code/tty-gravity/main.c .. literalinclude:: ../../code/tty-gravity/main.c
:language: c
:linenos: :linenos:
:emphasize-lines: 19,25,38 :emphasize-lines: 19,25,38

View File

@ -17,7 +17,7 @@ was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_,
.. _Luvit: https://luvit.io .. _Luvit: https://luvit.io
.. _Julia: https://julialang.org .. _Julia: https://julialang.org
.. _pyuv: https://github.com/saghul/pyuv .. _pyuv: https://github.com/saghul/pyuv
.. _others: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv .. _others: https://github.com/libuv/libuv/blob/v1.x/LINKS.md
Features Features

View File

@ -533,7 +533,7 @@ API
.. note:: .. note::
This function currently only returns a non-zero value on Linux, based This function currently only returns a non-zero value on Linux, based
on cgroups if it is present. on cgroups if it is present, and on z/OS based on RLIMIT_MEMLIMIT.
.. versionadded:: 1.29.0 .. versionadded:: 1.29.0

View File

@ -118,3 +118,21 @@ API
function is blocking. function is blocking.
.. versionadded:: 1.16.0 .. versionadded:: 1.16.0
.. c:function:: int uv_pipe(uv_file fds[2], int read_flags, int write_flags)
Create a pair of connected pipe handles.
Data may be written to `fds[1]` and read from `fds[0]`.
The resulting handles can be passed to `uv_pipe_open`, used with `uv_spawn`,
or for any other purpose.
Valid values for `flags` are:
- UV_NONBLOCK_PIPE: Opens the specified socket handle for `OVERLAPPED`
or `FIONBIO`/`O_NONBLOCK` I/O usage.
This is recommended for handles that will be used by libuv,
and not usually recommended otherwise.
Equivalent to :man:`pipe(2)` with the `O_CLOEXEC` flag set.
.. versionadded:: 1.41.0

View File

@ -86,36 +86,63 @@ API
.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) .. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
Starts polling the file descriptor. `events` is a bitmask made up of Starts polling the file descriptor. `events` is a bitmask made up of
UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. As soon as an `UV_READABLE`, `UV_WRITABLE`, `UV_PRIORITIZED` and `UV_DISCONNECT`. As soon
event is detected the callback will be called with `status` set to 0, and the as an event is detected the callback will be called with `status` set to 0,
detected events set on the `events` field. and the detected events set on the `events` field.
The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band The `UV_PRIORITIZED` event is used to watch for sysfs interrupts or TCP
messages. out-of-band messages.
The UV_DISCONNECT event is optional in the sense that it may not be The `UV_DISCONNECT` event is optional in the sense that it may not be
reported and the user is free to ignore it, but it can help optimize the shutdown reported and the user is free to ignore it, but it can help optimize the
path because an extra read or write call might be avoided. shutdown path because an extra read or write call might be avoided.
If an error happens while polling, `status` will be < 0 and corresponds If an error happens while polling, `status` will be < 0 and corresponds
with one of the UV_E* error codes (see :ref:`errors`). The user should with one of the `UV_E*` error codes (see :ref:`errors`). The user should
not close the socket while the handle is active. If the user does that not close the socket while the handle is active. If the user does that
anyway, the callback *may* be called reporting an error status, but this anyway, the callback *may* be called reporting an error status, but this is
is **not** guaranteed. **not** guaranteed.
.. note:: .. note::
Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so Calling :c:func:`uv_poll_start` on a handle that is already active is
will update the events mask that is being watched for. fine. Doing so will update the events mask that is being watched for.
.. note:: .. note::
Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set Though `UV_DISCONNECT` can be set, it is unsupported on AIX and as such
on the `events` field in the callback. will not be set on the `events` field in the callback.
.. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. .. note::
.. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event. If one of the events `UV_READABLE` or `UV_WRITABLE` are set, the
callback will be called again, as long as the given fd/socket remains
readable or writable accordingly. Particularly in each of the following
scenarios:
* The callback has been called because the socket became
readable/writable and the callback did not conduct a read/write on
this socket at all.
* The callback committed a read on the socket, and has not read all the
available data (when `UV_READABLE` is set).
* The callback committed a write on the socket, but it remained
writable afterwards (when `UV_WRITABLE` is set).
* The socket has already became readable/writable before calling
:c:func:`uv_poll_start` on a poll handle associated with this socket,
and since then the state of the socket did not changed.
In all of the above listed scenarios, the socket remains readable or
writable and hence the callback will be called again (depending on the
events set in the bitmask). This behaviour is known as level
triggering.
.. versionchanged:: 1.9.0 Added the `UV_DISCONNECT` event.
.. versionchanged:: 1.14.0 Added the `UV_PRIORITIZED` event.
.. c:function:: int uv_poll_stop(uv_poll_t* poll) .. c:function:: int uv_poll_stop(uv_poll_t* poll)
Stop polling the file descriptor, the callback will no longer be called. Stop polling the file descriptor, the callback will no longer be called.
.. note::
Calling :c:func:`uv_poll_stop` is effective immediately: any pending
callback is also canceled, even if the socket state change notification
was already pending.
.. seealso:: The :c:type:`uv_handle_t` API functions also apply. .. seealso:: The :c:type:`uv_handle_t` API functions also apply.

View File

@ -119,12 +119,14 @@ Data types
* flags may be specified to create a duplex data stream. * flags may be specified to create a duplex data stream.
*/ */
UV_READABLE_PIPE = 0x10, UV_READABLE_PIPE = 0x10,
UV_WRITABLE_PIPE = 0x20 UV_WRITABLE_PIPE = 0x20,
/* /*
* Open the child pipe handle in overlapped mode on Windows. * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
* On Unix it is silently ignored. * handle in non-blocking mode in the child. This may cause loss of data,
* if the child is not designed to handle to encounter this mode,
* but can also be significantly more efficient.
*/ */
UV_OVERLAPPED_PIPE = 0x40 UV_NONBLOCK_PIPE = 0x40
} uv_stdio_flags; } uv_stdio_flags;

View File

@ -139,6 +139,11 @@ API
be made several times until there is no more data to read or be made several times until there is no more data to read or
:c:func:`uv_read_stop` is called. :c:func:`uv_read_stop` is called.
.. versionchanged:: 1.38.0 :c:func:`uv_read_start()` now consistently
returns `UV_EALREADY` when called twice, and `UV_EINVAL` when the
stream is closing. With older libuv versions, it returns `UV_EALREADY`
on Windows but not UNIX, and `UV_EINVAL` on UNIX but not Windows.
.. c:function:: int uv_read_stop(uv_stream_t*) .. c:function:: int uv_read_stop(uv_stream_t*)
Stop reading data from the stream. The :c:type:`uv_read_cb` callback will Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
@ -146,6 +151,11 @@ API
This function is idempotent and may be safely called on a stopped stream. This function is idempotent and may be safely called on a stopped stream.
This function will always succeed; hence, checking its return value is
unnecessary. A non-zero return indicates that finishing releasing resources
may be pending on the next input event on that TTY on Windows, and does not
indicate failure.
.. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb) .. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
Write data to stream. Buffers are written in order. Example: Write data to stream. Buffers are written in order. Example:
@ -183,8 +193,9 @@ API
initialized with `ipc` == 1. initialized with `ipc` == 1.
.. note:: .. note::
`send_handle` must be a TCP socket or pipe, which is a server or a connection (listening `send_handle` must be a TCP, pipe and UDP handle on Unix, or a TCP
or connected state). Bound sockets or pipes will be assumed to be servers. handle on Windows, which is a server or a connection (listening or
connected state). Bound sockets or pipes will be assumed to be servers.
.. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs) .. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)
@ -197,6 +208,16 @@ API
* < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent * < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent
immediately). immediately).
.. c:function:: int uv_try_write2(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle)
Same as :c:func:`uv_try_write` and extended write function for sending
handles over a pipe like c:func:`uv_write2`.
Try to send a handle is not supported on Windows,
where it returns ``UV_EAGAIN``.
.. versionadded:: 1.42.0
.. c:function:: int uv_is_readable(const uv_stream_t* handle) .. c:function:: int uv_is_readable(const uv_stream_t* handle)
Returns 1 if the stream is readable, 0 otherwise. Returns 1 if the stream is readable, 0 otherwise.

View File

@ -81,10 +81,9 @@ API
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``. initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
When the port is already taken, you can expect to see an ``UV_EADDRINUSE`` When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect`. That is,
:c:func:`uv_tcp_connect`. That is, a successful call to this function does a successful call to this function does not guarantee that the call
not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` will succeed as well.
will succeed as well.
`flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support `flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
is disabled and only IPv6 is used. is disabled and only IPv6 is used.
@ -128,3 +127,20 @@ API
:c:func:`uv_tcp_close_reset` calls is not allowed. :c:func:`uv_tcp_close_reset` calls is not allowed.
.. versionadded:: 1.32.0 .. versionadded:: 1.32.0
.. c:function:: int uv_socketpair(int type, int protocol, uv_os_sock_t socket_vector[2], int flags0, int flags1)
Create a pair of connected sockets with the specified properties.
The resulting handles can be passed to `uv_tcp_open`, used with `uv_spawn`,
or for any other purpose.
Valid values for `flags0` and `flags1` are:
- UV_NONBLOCK_PIPE: Opens the specified socket handle for `OVERLAPPED`
or `FIONBIO`/`O_NONBLOCK` I/O usage.
This is recommended for handles that will be used by libuv,
and not usually recommended otherwise.
Equivalent to :man:`socketpair(2)` with a domain of AF_UNIX.
.. versionadded:: 1.41.0

View File

@ -53,6 +53,14 @@ Data types
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
*/ */
UV_UDP_MMSG_FREE = 16, UV_UDP_MMSG_FREE = 16,
/*
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
* Linux. This stops the Linux kernel from supressing some ICMP error messages
* and enables full ICMP error reporting for faster failover.
* This flag is no-op on platforms other than Linux.
*/
UV_UDP_LINUX_RECVERR = 32,
/* /*
* Indicates that recvmmsg should be used, if available. * Indicates that recvmmsg should be used, if available.
*/ */
@ -73,7 +81,8 @@ Data types
* `nread`: Number of bytes that have been received. * `nread`: Number of bytes that have been received.
0 if there is no more data to read. Note that 0 may also mean that an 0 if there is no more data to read. Note that 0 may also mean that an
empty datagram was received (in this case `addr` is not NULL). < 0 if empty datagram was received (in this case `addr` is not NULL). < 0 if
a transmission error was detected. a transmission error was detected; if using :man:`recvmmsg(2)` no more
chunks will be received and the buffer can be freed safely.
* `buf`: :c:type:`uv_buf_t` with the received data. * `buf`: :c:type:`uv_buf_t` with the received data.
* `addr`: ``struct sockaddr*`` containing the address of the sender. * `addr`: ``struct sockaddr*`` containing the address of the sender.
Can be NULL. Valid for the duration of the callback only. Can be NULL. Valid for the duration of the callback only.
@ -84,10 +93,11 @@ Data types
on error. on error.
When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set, When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set,
those must not be freed. There will be a final callback with `nread` set to 0, those must not be freed. If no errors occur, there will be a final callback with
`addr` set to NULL and the buffer pointing at the initially allocated data with `nread` set to 0, `addr` set to NULL and the buffer pointing at the initially
the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE` flag set. allocated data with the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE`
The callee can now safely free the provided buffer. flag set. If a UDP socket error occurs, `nread` will be < 0. In either scenario,
the callee can now safely free the provided buffer.
.. versionchanged:: 1.40.0 added the `UV_UDP_MMSG_FREE` flag. .. versionchanged:: 1.40.0 added the `UV_UDP_MMSG_FREE` flag.
@ -176,7 +186,8 @@ API
with the address and port to bind to. with the address and port to bind to.
:param flags: Indicate how the socket will be bound, :param flags: Indicate how the socket will be bound,
``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported. ``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, and ``UV_UDP_RECVERR``
are supported.
:returns: 0 on success, or an error code < 0 on failure. :returns: 0 on success, or an error code < 0 on failure.
@ -393,6 +404,11 @@ API
:returns: 0 on success, or an error code < 0 on failure. :returns: 0 on success, or an error code < 0 on failure.
.. note::
When using :man:`recvmmsg(2)`, the number of messages received at a time is limited
by the number of max size dgrams that will fit into the buffer allocated in `alloc_cb`, and
`suggested_size` in `alloc_cb` for udp_recv is always set to the size of 1 max size dgram.
.. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms). .. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms).
The use of this feature requires a buffer larger than The use of this feature requires a buffer larger than
2 * 64KB to be passed to `alloc_cb`. 2 * 64KB to be passed to `alloc_cb`.

View File

@ -126,6 +126,7 @@ extern "C" {
XX(ENOTEMPTY, "directory not empty") \ XX(ENOTEMPTY, "directory not empty") \
XX(ENOTSOCK, "socket operation on non-socket") \ XX(ENOTSOCK, "socket operation on non-socket") \
XX(ENOTSUP, "operation not supported on socket") \ XX(ENOTSUP, "operation not supported on socket") \
XX(EOVERFLOW, "value too large for defined data type") \
XX(EPERM, "operation not permitted") \ XX(EPERM, "operation not permitted") \
XX(EPIPE, "broken pipe") \ XX(EPIPE, "broken pipe") \
XX(EPROTO, "protocol error") \ XX(EPROTO, "protocol error") \
@ -148,6 +149,7 @@ extern "C" {
XX(ENOTTY, "inappropriate ioctl for device") \ XX(ENOTTY, "inappropriate ioctl for device") \
XX(EFTYPE, "inappropriate file type or format") \ XX(EFTYPE, "inappropriate file type or format") \
XX(EILSEQ, "illegal byte sequence") \ XX(EILSEQ, "illegal byte sequence") \
XX(ESOCKTNOSUPPORT, "socket type not supported") \
#define UV_HANDLE_TYPE_MAP(XX) \ #define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \ XX(ASYNC, async) \
@ -475,6 +477,12 @@ UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
UV_EXTERN int uv_pipe(uv_file fds[2], int read_flags, int write_flags);
UV_EXTERN int uv_socketpair(int type,
int protocol,
uv_os_sock_t socket_vector[2],
int flags0,
int flags1);
#define UV_STREAM_FIELDS \ #define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \ /* number of bytes queued for writing */ \
@ -520,6 +528,10 @@ UV_EXTERN int uv_write2(uv_write_t* req,
UV_EXTERN int uv_try_write(uv_stream_t* handle, UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[], const uv_buf_t bufs[],
unsigned int nbufs); unsigned int nbufs);
UV_EXTERN int uv_try_write2(uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle);
/* uv_write_t is a subclass of uv_req_t. */ /* uv_write_t is a subclass of uv_req_t. */
struct uv_write_s { struct uv_write_s {
@ -620,7 +632,14 @@ enum uv_udp_flags {
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
*/ */
UV_UDP_MMSG_FREE = 16, UV_UDP_MMSG_FREE = 16,
/*
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
* Linux. This stops the Linux kernel from suppressing some ICMP error
* messages and enables full ICMP error reporting for faster failover.
* This flag is no-op on platforms other than Linux.
*/
UV_UDP_LINUX_RECVERR = 32,
/* /*
* Indicates that recvmmsg should be used, if available. * Indicates that recvmmsg should be used, if available.
*/ */
@ -933,10 +952,13 @@ typedef enum {
UV_WRITABLE_PIPE = 0x20, UV_WRITABLE_PIPE = 0x20,
/* /*
* Open the child pipe handle in overlapped mode on Windows. * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
* On Unix it is silently ignored. * handle in non-blocking mode in the child. This may cause loss of data,
* if the child is not designed to handle to encounter this mode,
* but can also be significantly more efficient.
*/ */
UV_OVERLAPPED_PIPE = 0x40 UV_NONBLOCK_PIPE = 0x40,
UV_OVERLAPPED_PIPE = 0x40 /* old name, for compatibility */
} uv_stdio_flags; } uv_stdio_flags;
typedef struct uv_stdio_container_s { typedef struct uv_stdio_container_s {

View File

@ -445,4 +445,16 @@
# define UV__EILSEQ (-4027) # define UV__EILSEQ (-4027)
#endif #endif
#if defined(EOVERFLOW) && !defined(_WIN32)
# define UV__EOVERFLOW UV__ERR(EOVERFLOW)
#else
# define UV__EOVERFLOW (-4026)
#endif
#if defined(ESOCKTNOSUPPORT) && !defined(_WIN32)
# define UV__ESOCKTNOSUPPORT UV__ERR(ESOCKTNOSUPPORT)
#else
# define UV__ESOCKTNOSUPPORT (-4025)
#endif
#endif /* UV_ERRNO_H_ */ #endif /* UV_ERRNO_H_ */

View File

@ -251,7 +251,7 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \ __left = __right = &__node; \
\ \
while (1) { \ for (;;) { \
if (__comp < 0) { \ if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \ __tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \ if (__tmp == NULL) \

View File

@ -31,7 +31,7 @@
*/ */
#define UV_VERSION_MAJOR 1 #define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 40 #define UV_VERSION_MINOR 42
#define UV_VERSION_PATCH 0 #define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX "" #define UV_VERSION_SUFFIX ""

49
deps/libuv/src/idna.c vendored
View File

@ -19,6 +19,7 @@
#include "uv.h" #include "uv.h"
#include "idna.h" #include "idna.h"
#include <assert.h>
#include <string.h> #include <string.h>
static unsigned uv__utf8_decode1_slow(const char** p, static unsigned uv__utf8_decode1_slow(const char** p,
@ -32,7 +33,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
if (a > 0xF7) if (a > 0xF7)
return -1; return -1;
switch (*p - pe) { switch (pe - *p) {
default: default:
if (a > 0xEF) { if (a > 0xEF) {
min = 0x10000; min = 0x10000;
@ -62,6 +63,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
a = 0; a = 0;
break; break;
} }
/* Fall through. */
case 0:
return -1; /* Invalid continuation byte. */ return -1; /* Invalid continuation byte. */
} }
@ -88,6 +91,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
unsigned uv__utf8_decode1(const char** p, const char* pe) { unsigned uv__utf8_decode1(const char** p, const char* pe) {
unsigned a; unsigned a;
assert(*p < pe);
a = (unsigned char) *(*p)++; a = (unsigned char) *(*p)++;
if (a < 128) if (a < 128)
@ -96,9 +101,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
return uv__utf8_decode1_slow(p, pe, a); return uv__utf8_decode1_slow(p, pe, a);
} }
#define foreach_codepoint(c, p, pe) \
for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
static int uv__idna_toascii_label(const char* s, const char* se, static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) { char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789"; static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
@ -121,15 +123,22 @@ static int uv__idna_toascii_label(const char* s, const char* se,
ss = s; ss = s;
todo = 0; todo = 0;
foreach_codepoint(c, &s, se) { /* Note: after this loop we've visited all UTF-8 characters and know
* they're legal so we no longer need to check for decode errors.
*/
while (s < se) {
c = uv__utf8_decode1(&s, se);
if (c == -1u)
return UV_EINVAL;
if (c < 128) if (c < 128)
h++; h++;
else if (c == (unsigned) -1)
return UV_EINVAL;
else else
todo++; todo++;
} }
/* Only write "xn--" when there are non-ASCII characters. */
if (todo > 0) { if (todo > 0) {
if (*d < de) *(*d)++ = 'x'; if (*d < de) *(*d)++ = 'x';
if (*d < de) *(*d)++ = 'n'; if (*d < de) *(*d)++ = 'n';
@ -137,9 +146,13 @@ static int uv__idna_toascii_label(const char* s, const char* se,
if (*d < de) *(*d)++ = '-'; if (*d < de) *(*d)++ = '-';
} }
/* Write ASCII characters. */
x = 0; x = 0;
s = ss; s = ss;
foreach_codepoint(c, &s, se) { while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != -1u);
if (c > 127) if (c > 127)
continue; continue;
@ -166,10 +179,15 @@ static int uv__idna_toascii_label(const char* s, const char* se,
while (todo > 0) { while (todo > 0) {
m = -1; m = -1;
s = ss; s = ss;
foreach_codepoint(c, &s, se)
while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != -1u);
if (c >= n) if (c >= n)
if (c < m) if (c < m)
m = c; m = c;
}
x = m - n; x = m - n;
y = h + 1; y = h + 1;
@ -181,7 +199,10 @@ static int uv__idna_toascii_label(const char* s, const char* se,
n = m; n = m;
s = ss; s = ss;
foreach_codepoint(c, &s, se) { while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != -1u);
if (c < n) if (c < n)
if (++delta == 0) if (++delta == 0)
return UV_E2BIG; /* Overflow. */ return UV_E2BIG; /* Overflow. */
@ -245,8 +266,6 @@ static int uv__idna_toascii_label(const char* s, const char* se,
return 0; return 0;
} }
#undef foreach_codepoint
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
const char* si; const char* si;
const char* st; const char* st;
@ -256,10 +275,14 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
ds = d; ds = d;
for (si = s; si < se; /* empty */) { si = s;
while (si < se) {
st = si; st = si;
c = uv__utf8_decode1(&si, se); c = uv__utf8_decode1(&si, se);
if (c == -1u)
return UV_EINVAL;
if (c != '.') if (c != '.')
if (c != 0x3002) /* 。 */ if (c != 0x3002) /* 。 */
if (c != 0xFF0E) /* */ if (c != 0xFF0E) /* */

View File

@ -141,8 +141,9 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
*tp++ = ':'; *tp++ = ':';
*tp++ = '\0'; *tp++ = '\0';
if (UV_E2BIG == uv__strscpy(dst, tmp, size)) if ((size_t) (tp - tmp) > size)
return UV_ENOSPC; return UV_ENOSPC;
uv__strscpy(dst, tmp, size);
return 0; return 0;
} }

View File

@ -161,7 +161,6 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
void uv__threadpool_cleanup(void) { void uv__threadpool_cleanup(void) {
#ifndef _WIN32
unsigned int i; unsigned int i;
if (nthreads == 0) if (nthreads == 0)
@ -181,7 +180,6 @@ void uv__threadpool_cleanup(void) {
threads = NULL; threads = NULL;
nthreads = 0; nthreads = 0;
#endif
} }

View File

@ -58,6 +58,7 @@ static int timer_less_than(const struct heap_node* ha,
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL; handle->timer_cb = NULL;
handle->timeout = 0;
handle->repeat = 0; handle->repeat = 0;
return 0; return 0;
} }

View File

@ -214,7 +214,7 @@ static int uv__async_start(uv_loop_t* loop) {
pipefd[0] = err; pipefd[0] = err;
pipefd[1] = -1; pipefd[1] = -1;
#else #else
err = uv__make_pipe(pipefd, UV__F_NONBLOCK); err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
if (err < 0) if (err < 0)
return err; return err;
#endif #endif

View File

@ -52,9 +52,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
UV_UNUSED(static void cpu_relax(void)) { UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ volatile("yield"); __asm__ __volatile__ ("yield" ::: "memory");
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
#endif #endif
} }

View File

@ -42,8 +42,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return 1; return 1;
#if !defined(__CYGWIN__) && !defined(__MSYS__) #if !defined(__CYGWIN__) && !defined(__MSYS__)
/* /*
* If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
* equals to `AF_LINK` or not. Otherwise, the result depends on the operation * equals `AF_LINK`. Otherwise, the result depends on the operating
* system with `AF_LINK` or `PF_INET`. * system with `AF_LINK` or `PF_INET`.
*/ */
if (exclude_type == UV__EXCLUDE_IFPHYS) if (exclude_type == UV__EXCLUDE_IFPHYS)

View File

@ -88,6 +88,10 @@ extern char** environ;
# define uv__accept4 accept4 # define uv__accept4 accept4
#endif #endif
#if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
# include <sanitizer/linux_syscall_hooks.h>
#endif
static int uv__run_pending(uv_loop_t* loop); static int uv__run_pending(uv_loop_t* loop);
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */ /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
@ -539,7 +543,13 @@ int uv__close_nocancel(int fd) {
return close$NOCANCEL$UNIX2003(fd); return close$NOCANCEL$UNIX2003(fd);
#endif #endif
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#elif defined(__linux__) #elif defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
long rc;
__sanitizer_syscall_pre_close(fd);
rc = syscall(SYS_close, fd);
__sanitizer_syscall_post_close(rc, fd);
return rc;
#elif defined(__linux__) && !defined(__SANITIZE_THREAD__)
return syscall(SYS_close, fd); return syscall(SYS_close, fd);
#else #else
return close(fd); return close(fd);
@ -574,7 +584,7 @@ int uv__close(int fd) {
return uv__close_nocheckstdio(fd); return uv__close_nocheckstdio(fd);
} }
#if UV__NONBLOCK_IS_IOCTL
int uv__nonblock_ioctl(int fd, int set) { int uv__nonblock_ioctl(int fd, int set) {
int r; int r;
@ -589,7 +599,6 @@ int uv__nonblock_ioctl(int fd, int set) {
} }
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
int uv__cloexec_ioctl(int fd, int set) { int uv__cloexec_ioctl(int fd, int set) {
int r; int r;
@ -925,13 +934,12 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
if (w->pevents == 0) { if (w->pevents == 0) {
QUEUE_REMOVE(&w->watcher_queue); QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue); QUEUE_INIT(&w->watcher_queue);
w->events = 0;
if (loop->watchers[w->fd] != NULL) { if (w == loop->watchers[w->fd]) {
assert(loop->watchers[w->fd] == w);
assert(loop->nfds > 0); assert(loop->nfds > 0);
loop->watchers[w->fd] = NULL; loop->watchers[w->fd] = NULL;
loop->nfds--; loop->nfds--;
w->events = 0;
} }
} }
else if (QUEUE_EMPTY(&w->watcher_queue)) else if (QUEUE_EMPTY(&w->watcher_queue))
@ -1175,7 +1183,9 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (buf == NULL) if (buf == NULL)
return UV_ENOMEM; return UV_ENOMEM;
do
r = getpwuid_r(uid, &pw, buf, bufsize, &result); r = getpwuid_r(uid, &pw, buf, bufsize, &result);
while (r == EINTR);
if (r != ERANGE) if (r != ERANGE)
break; break;
@ -1185,7 +1195,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (r != 0) { if (r != 0) {
uv__free(buf); uv__free(buf);
return -r; return UV__ERR(r);
} }
if (result == NULL) { if (result == NULL) {

View File

@ -33,9 +33,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <unistd.h> /* sysconf */ #include <unistd.h> /* sysconf */
#if !TARGET_OS_IPHONE
#include "darwin-stub.h" #include "darwin-stub.h"
#endif
static uv_once_t once = UV_ONCE_INIT; static uv_once_t once = UV_ONCE_INIT;
static uint64_t (*time_func)(void); static uint64_t (*time_func)(void);
@ -223,10 +221,10 @@ static int uv__get_cpu_speed(uint64_t* speed) {
err = UV_ENOENT; err = UV_ENOENT;
core_foundation_handle = dlopen("/System/Library/Frameworks/" core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/" "CoreFoundation.framework/"
"Versions/A/CoreFoundation", "CoreFoundation",
RTLD_LAZY | RTLD_LOCAL); RTLD_LAZY | RTLD_LOCAL);
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/" iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
"Versions/A/IOKit", "IOKit",
RTLD_LAZY | RTLD_LOCAL); RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL || iokit_handle == NULL) if (core_foundation_handle == NULL || iokit_handle == NULL)
@ -304,6 +302,12 @@ static int uv__get_cpu_speed(uint64_t* speed) {
pIOObjectRelease(it); pIOObjectRelease(it);
err = 0; err = 0;
if (device_type_str != NULL)
pCFRelease(device_type_str);
if (clock_frequency_str != NULL)
pCFRelease(clock_frequency_str);
out: out:
if (core_foundation_handle != NULL) if (core_foundation_handle != NULL)
dlclose(core_foundation_handle); dlclose(core_foundation_handle);

422
deps/libuv/src/unix/epoll.c vendored Normal file
View File

@ -0,0 +1,422 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <sys/epoll.h>
int uv__epoll_init(uv_loop_t* loop) {
int fd;
fd = epoll_create1(O_CLOEXEC);
/* epoll_create1() can fail either because it's not implemented (old kernel)
* or because it doesn't understand the O_CLOEXEC flag.
*/
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
fd = epoll_create(256);
if (fd != -1)
uv__cloexec(fd, 1);
}
loop->backend_fd = fd;
if (fd == -1)
return UV__ERR(errno);
return 0;
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if (events[i].data.fd == fd)
events[i].data.fd = -1;
/* Remove the file descriptor from the epoll.
* This avoids a problem where the same file description remains open
* in another process, causing repeated junk epoll events.
*
* We pass in a dummy epoll_event, to work around a bug in old kernels.
*/
if (loop->backend_fd >= 0) {
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
*/
memset(&dummy, 0, sizeof(dummy));
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
}
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct epoll_event e;
int rc;
memset(&e, 0, sizeof(e));
e.events = POLLIN;
e.data.fd = -1;
rc = 0;
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
if (errno != EEXIST)
rc = UV__ERR(errno);
if (rc == 0)
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
* effectively infinite on 32 bits architectures. To avoid blocking
* indefinitely, we cap the timeout and poll again if necessary.
*
* Note that "30 minutes" is a simplification because it depends on
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
* that being the largest value I have seen in the wild (and only once.)
*/
static const int max_safe_timeout = 1789569;
static int no_epoll_pwait_cached;
static int no_epoll_wait_cached;
int no_epoll_pwait;
int no_epoll_wait;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
sigset_t sigset;
uint64_t sigmask;
uint64_t base;
int have_signals;
int nevents;
int count;
int nfds;
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
memset(&e, 0, sizeof(e));
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.data.fd = w->fd;
if (w->events == 0)
op = EPOLL_CTL_ADD;
else
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
sigmask = 0;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigmask |= 1 << (SIGPROF - 1);
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
user_timeout = 0;
}
/* You could argue there is a dependency between these two but
* ultimately we don't care about their ordering with respect
* to one another. Worst case, we make a few system calls that
* could have been avoided because another thread already knows
* they fail with ENOSYS. Hardly the end of the world.
*/
no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* See the comment for max_safe_timeout for an explanation of why
* this is necessary. Executive summary: kernel bug workaround.
*/
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
abort();
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
nfds = epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
&sigset);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_pwait_cached, 1);
no_epoll_pwait = 1;
}
} else {
nfds = epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_wait_cached, 1);
no_epoll_wait = 1;
}
}
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
abort();
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
if (errno == ENOSYS) {
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
continue;
}
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
have_signals = 0;
nevents = 0;
{
/* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
union {
struct epoll_event* events;
uv__io_t* watchers;
} x;
x.events = events;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = x.watchers;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
}
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->data.fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |=
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
if (pe->events != 0) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
}
nevents++;
}
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}

View File

@ -265,8 +265,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11 #if __FreeBSD__ >= 11 && !defined(__DragonFly__)
return sendmmsg(fd, mmsg, vlen, /* flags */ 0); return sendmmsg(fd,
(struct mmsghdr*) mmsg,
vlen,
0 /* flags */);
#else #else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#endif #endif
@ -274,8 +277,12 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11 #if __FreeBSD__ >= 11 && !defined(__DragonFly__)
return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */); return recvmmsg(fd,
(struct mmsghdr*) mmsg,
vlen,
0 /* flags */,
NULL /* timeout */);
#else #else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#endif #endif

View File

@ -56,8 +56,13 @@
# define HAVE_PREADV 0 # define HAVE_PREADV 0
#endif #endif
#if defined(__linux__)
# include "sys/utsname.h"
#endif
#if defined(__linux__) || defined(__sun) #if defined(__linux__) || defined(__sun)
# include <sys/sendfile.h> # include <sys/sendfile.h>
# include <sys/sysmacros.h>
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
@ -212,14 +217,30 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
struct timespec ts; struct timespec ts;
ts.tv_sec = time; ts.tv_sec = time;
ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000; ts.tv_nsec = (time - ts.tv_sec) * 1e9;
/* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we
* stick to microsecond resolution for the sake of consistency with other
* platforms. I'm the original author of this compatibility hack but I'm
* less convinced it's useful nowadays.
*/
ts.tv_nsec -= ts.tv_nsec % 1000;
if (ts.tv_nsec < 0) {
ts.tv_nsec += 1e9;
ts.tv_sec -= 1;
}
return ts; return ts;
} }
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
struct timeval tv; struct timeval tv;
tv.tv_sec = time; tv.tv_sec = time;
tv.tv_usec = (uint64_t)(time * 1000000) % 1000000; tv.tv_usec = (time - tv.tv_sec) * 1e6;
if (tv.tv_usec < 0) {
tv.tv_usec += 1e6;
tv.tv_sec -= 1;
}
return tv; return tv;
} }
@ -227,9 +248,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \ #if defined(__linux__) \
|| defined(_AIX71) \ || defined(_AIX71) \
|| defined(__HAIKU__) || defined(__HAIKU__)
/* utimesat() has nanosecond resolution but we stick to microseconds
* for the sake of consistency with other platforms.
*/
struct timespec ts[2]; struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime); ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime); ts[1] = uv__fs_to_timespec(req->mtime);
@ -887,6 +905,50 @@ out:
} }
#ifdef __linux__
static unsigned uv__kernel_version(void) {
static unsigned cached_version;
struct utsname u;
unsigned version;
unsigned major;
unsigned minor;
unsigned patch;
version = uv__load_relaxed(&cached_version);
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;
uv__store_relaxed(&cached_version, version);
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.
*/
static int uv__is_buggy_cephfs(int fd) {
struct statfs s;
if (-1 == fstatfs(fd, &s))
return 0;
if (s.f_type != /* CephFS */ 0xC36400)
return 0;
return uv__kernel_version() < /* 4.20.0 */ 0x041400;
}
#endif /* __linux__ */
static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_sendfile(uv_fs_t* req) {
int in_fd; int in_fd;
int out_fd; int out_fd;
@ -903,14 +965,25 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
#ifdef __linux__ #ifdef __linux__
{ {
static int copy_file_range_support = 1; static int no_copy_file_range_support;
if (copy_file_range_support) { if (uv__load_relaxed(&no_copy_file_range_support) == 0) {
r = uv__fs_copy_file_range(in_fd, NULL, out_fd, &off, req->bufsml[0].len, 0); r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
if (r == -1 && errno == ENOSYS) { if (r == -1 && errno == ENOSYS) {
/* ENOSYS - it will never work */
errno = 0;
uv__store_relaxed(&no_copy_file_range_support, 1);
} else if (r == -1 && errno == EACCES && uv__is_buggy_cephfs(in_fd)) {
/* EACCES - pre-4.20 kernels have a bug where CephFS uses the RADOS
copy-from command when it shouldn't */
errno = 0;
uv__store_relaxed(&no_copy_file_range_support, 1);
} else if (r == -1 && (errno == ENOTSUP || errno == EXDEV)) {
/* ENOTSUP - it could work on another file system type */
/* EXDEV - it will not work when in_fd and out_fd are not on the same
mounted filesystem (pre Linux 5.3) */
errno = 0; errno = 0;
copy_file_range_support = 0;
} else { } else {
goto ok; goto ok;
} }
@ -1010,9 +1083,6 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|| defined(_AIX71) \ || defined(_AIX71) \
|| defined(__sun) \ || defined(__sun) \
|| defined(__HAIKU__) || defined(__HAIKU__)
/* utimesat() has nanosecond resolution but we stick to microseconds
* for the sake of consistency with other platforms.
*/
struct timespec ts[2]; struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime); ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime); ts[1] = uv__fs_to_timespec(req->mtime);
@ -1220,7 +1290,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
if (fstatfs(dstfd, &s) == -1) if (fstatfs(dstfd, &s) == -1)
goto out; goto out;
if (s.f_type != /* CIFS */ 0xFF534D42u) if ((unsigned) s.f_type != /* CIFS */ 0xFF534D42u)
goto out; goto out;
} }
@ -1340,7 +1410,8 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_birthtim.tv_nsec = src->st_ctimensec; dst->st_birthtim.tv_nsec = src->st_ctimensec;
dst->st_flags = 0; dst->st_flags = 0;
dst->st_gen = 0; dst->st_gen = 0;
#elif !defined(_AIX) && ( \ #elif !defined(_AIX) && \
!defined(__MVS__) && ( \
defined(__DragonFly__) || \ defined(__DragonFly__) || \
defined(__FreeBSD__) || \ defined(__FreeBSD__) || \
defined(__OpenBSD__) || \ defined(__OpenBSD__) || \
@ -1420,8 +1491,9 @@ static int uv__fs_statx(int fd,
case -1: case -1:
/* EPERM happens when a seccomp filter rejects the system call. /* EPERM happens when a seccomp filter rejects the system call.
* Has been observed with libseccomp < 2.3.3 and docker < 18.04. * Has been observed with libseccomp < 2.3.3 and docker < 18.04.
* EOPNOTSUPP is used on DVS exported filesystems
*/ */
if (errno != EINVAL && errno != EPERM && errno != ENOSYS) if (errno != EINVAL && errno != EPERM && errno != ENOSYS && errno != EOPNOTSUPP)
return -1; return -1;
/* Fall through. */ /* Fall through. */
default: default:
@ -1434,12 +1506,12 @@ static int uv__fs_statx(int fd,
return UV_ENOSYS; return UV_ENOSYS;
} }
buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor; buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
buf->st_mode = statxbuf.stx_mode; buf->st_mode = statxbuf.stx_mode;
buf->st_nlink = statxbuf.stx_nlink; buf->st_nlink = statxbuf.stx_nlink;
buf->st_uid = statxbuf.stx_uid; buf->st_uid = statxbuf.stx_uid;
buf->st_gid = statxbuf.stx_gid; buf->st_gid = statxbuf.stx_gid;
buf->st_rdev = statxbuf.stx_rdev_major; buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
buf->st_ino = statxbuf.stx_ino; buf->st_ino = statxbuf.stx_ino;
buf->st_size = statxbuf.stx_size; buf->st_size = statxbuf.stx_size;
buf->st_blksize = statxbuf.stx_blksize; buf->st_blksize = statxbuf.stx_blksize;

View File

@ -595,8 +595,7 @@ out:
static int uv__fsevents_loop_init(uv_loop_t* loop) { static int uv__fsevents_loop_init(uv_loop_t* loop) {
CFRunLoopSourceContext ctx; CFRunLoopSourceContext ctx;
uv__cf_loop_state_t* state; uv__cf_loop_state_t* state;
pthread_attr_t attr_storage; pthread_attr_t attr;
pthread_attr_t* attr;
int err; int err;
if (loop->cf_state != NULL) if (loop->cf_state != NULL)
@ -641,25 +640,19 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
goto fail_signal_source_create; goto fail_signal_source_create;
} }
/* In the unlikely event that pthread_attr_init() fails, create the thread if (pthread_attr_init(&attr))
* with the default stack size. We'll use a little more address space but abort();
* that in itself is not a fatal error.
*/
attr = &attr_storage;
if (pthread_attr_init(attr))
attr = NULL;
if (attr != NULL) if (pthread_attr_setstacksize(&attr, uv__thread_stack_size()))
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
abort(); abort();
loop->cf_state = state; loop->cf_state = state;
/* uv_thread_t is an alias for pthread_t. */ /* uv_thread_t is an alias for pthread_t. */
err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop)); err = UV__ERR(pthread_create(&loop->cf_thread, &attr, uv__cf_loop_runner, loop));
if (attr != NULL) if (pthread_attr_destroy(&attr))
pthread_attr_destroy(attr); abort();
if (err) if (err)
goto fail_thread_create; goto fail_thread_create;

View File

@ -21,9 +21,6 @@
/* Expose glibc-specific EAI_* error codes. Needs to be defined before we /* Expose glibc-specific EAI_* error codes. Needs to be defined before we
* include any headers. * include any headers.
*/ */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"

View File

@ -26,7 +26,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
@ -166,7 +165,7 @@ static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
srclen = strlen(src); srclen = strlen(src);
if (srclen > length) if (srclen > length)
abort(); srclen = length;
for (i = 0; i < srclen; i++) for (i = 0; i < srclen; i++)
dst[i] = a2e[src[i]]; dst[i] = a2e[src[i]];
/* padding the remaining part with spaces */ /* padding the remaining part with spaces */
@ -360,6 +359,10 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
if (rc != 0) if (rc != 0)
return rc; return rc;
if (err.bytes_available > 0) {
return -1;
}
/* convert ebcdic loca_adapter_address to ascii first */ /* convert ebcdic loca_adapter_address to ascii first */
iconv_e2a(rcvr.loca_adapter_address, mac_addr, iconv_e2a(rcvr.loca_adapter_address, mac_addr,
sizeof(rcvr.loca_adapter_address)); sizeof(rcvr.loca_adapter_address));
@ -443,9 +446,42 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
} }
address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0; address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
if (!address->is_internal) { if (!address->is_internal) {
int rc = get_ibmi_physical_address(address->name, &address->phys_addr); int rc = -1;
if (rc != 0) size_t name_len = strlen(address->name);
r = rc; /* To get the associated MAC address, we must convert the address to a
* line description. Normally, the name field contains the line
* description name, but for VLANs it has the VLAN appended with a
* period. Since object names can also contain periods and numbers, there
* is no way to know if a returned name is for a VLAN or not. eg.
* *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1
*
* Instead, we apply the same heuristic used by some of the XPF ioctls:
* - names > 10 *must* contain a VLAN
* - assume names <= 10 do not contain a VLAN and try directly
* - if >10 or QDCRLIND returned an error, try to strip off a VLAN
* and try again
* - if we still get an error or couldn't find a period, leave the MAC as
* 00:00:00:00:00:00
*/
if (name_len <= 10) {
/* Assume name does not contain a VLAN ID */
rc = get_ibmi_physical_address(address->name, &address->phys_addr);
}
if (name_len > 10 || rc != 0) {
/* The interface name must contain a VLAN ID suffix. Attempt to strip
* it off so we can get the line description to pass to QDCRLIND.
*/
char* temp_name = uv__strdup(address->name);
char* dot = strrchr(temp_name, '.');
if (dot != NULL) {
*dot = '\0';
if (strlen(temp_name) <= 10) {
rc = get_ibmi_physical_address(temp_name, &address->phys_addr);
}
}
uv__free(temp_name);
}
} }
address++; address++;

View File

@ -62,6 +62,17 @@
# include <AvailabilityMacros.h> # include <AvailabilityMacros.h>
#endif #endif
/*
* Define common detection for active Thread Sanitizer
* - clang uses __has_feature(thread_sanitizer)
* - gcc-7+ uses __SANITIZE_THREAD__
*/
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# define __SANITIZE_THREAD__ 1
# endif
#endif
#if defined(PATH_MAX) #if defined(PATH_MAX)
# define UV__PATH_MAX PATH_MAX # define UV__PATH_MAX PATH_MAX
#else #else
@ -165,9 +176,11 @@ struct uv__stream_queued_fds_s {
defined(__NetBSD__) defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl #define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl #define uv__nonblock uv__nonblock_ioctl
#define UV__NONBLOCK_IS_IOCTL 1
#else #else
#define uv__cloexec uv__cloexec_fcntl #define uv__cloexec uv__cloexec_fcntl
#define uv__nonblock uv__nonblock_fcntl #define uv__nonblock uv__nonblock_fcntl
#define UV__NONBLOCK_IS_IOCTL 0
#endif #endif
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute /* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
@ -246,6 +259,7 @@ int uv__signal_loop_fork(uv_loop_t* loop);
/* platform specific */ /* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type); uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop); int uv__kqueue_init(uv_loop_t* loop);
int uv__epoll_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop); int uv__platform_loop_init(uv_loop_t* loop);
void uv__platform_loop_delete(uv_loop_t* loop); void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
@ -261,6 +275,7 @@ void uv__prepare_close(uv_prepare_t* handle);
void uv__process_close(uv_process_t* handle); void uv__process_close(uv_process_t* handle);
void uv__stream_close(uv_stream_t* handle); void uv__stream_close(uv_stream_t* handle);
void uv__tcp_close(uv_tcp_t* handle); void uv__tcp_close(uv_tcp_t* handle);
size_t uv__thread_stack_size(void);
void uv__udp_close(uv_udp_t* handle); void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd); uv_handle_type uv__handle_type(int fd);
@ -282,12 +297,6 @@ int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) ((handle)->io_watcher.fd) #define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */ #endif /* defined(__APPLE__) */
#ifdef O_NONBLOCK
# define UV__F_NONBLOCK O_NONBLOCK
#else
# define UV__F_NONBLOCK 1
#endif
int uv__make_pipe(int fds[2], int flags); int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__) #if defined(__APPLE__)
@ -327,7 +336,8 @@ int uv__getsockpeername(const uv_handle_t* handle,
#if defined(__linux__) || \ #if defined(__linux__) || \
defined(__FreeBSD__) || \ defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) defined(__FreeBSD_kernel__) || \
defined(__DragonFly__)
#define HAVE_MMSG 1 #define HAVE_MMSG 1
struct uv__mmsghdr { struct uv__mmsghdr {
struct msghdr msg_hdr; struct msghdr msg_hdr;
@ -340,5 +350,11 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
#define HAVE_MMSG 0 #define HAVE_MMSG 0
#endif #endif
#if defined(__sun)
#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
size_t strnlen(const char* s, size_t maxlen);
#endif
#endif
#endif /* UV_UNIX_INTERNAL_H_ */ #endif /* UV_UNIX_INTERNAL_H_ */

View File

@ -82,29 +82,12 @@ static int read_times(FILE* statfile_fp,
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static uint64_t read_cpufreq(unsigned int cpunum); static uint64_t read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop) { int uv__platform_loop_init(uv_loop_t* loop) {
int fd;
fd = epoll_create1(O_CLOEXEC);
/* epoll_create1() can fail either because it's not implemented (old kernel)
* or because it doesn't understand the O_CLOEXEC flag.
*/
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
fd = epoll_create(256);
if (fd != -1)
uv__cloexec(fd, 1);
}
loop->backend_fd = fd;
loop->inotify_fd = -1; loop->inotify_fd = -1;
loop->inotify_watchers = NULL; loop->inotify_watchers = NULL;
if (fd == -1) return uv__epoll_init(loop);
return UV__ERR(errno);
return 0;
} }
@ -134,380 +117,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if (events[i].data.fd == fd)
events[i].data.fd = -1;
/* Remove the file descriptor from the epoll.
* This avoids a problem where the same file description remains open
* in another process, causing repeated junk epoll events.
*
* We pass in a dummy epoll_event, to work around a bug in old kernels.
*/
if (loop->backend_fd >= 0) {
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
*/
memset(&dummy, 0, sizeof(dummy));
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
}
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct epoll_event e;
int rc;
memset(&e, 0, sizeof(e));
e.events = POLLIN;
e.data.fd = -1;
rc = 0;
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
if (errno != EEXIST)
rc = UV__ERR(errno);
if (rc == 0)
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
* effectively infinite on 32 bits architectures. To avoid blocking
* indefinitely, we cap the timeout and poll again if necessary.
*
* Note that "30 minutes" is a simplification because it depends on
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
* that being the largest value I have seen in the wild (and only once.)
*/
static const int max_safe_timeout = 1789569;
static int no_epoll_pwait_cached;
static int no_epoll_wait_cached;
int no_epoll_pwait;
int no_epoll_wait;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
sigset_t sigset;
uint64_t sigmask;
uint64_t base;
int have_signals;
int nevents;
int count;
int nfds;
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
memset(&e, 0, sizeof(e));
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.data.fd = w->fd;
if (w->events == 0)
op = EPOLL_CTL_ADD;
else
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
sigmask = 0;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigmask |= 1 << (SIGPROF - 1);
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
user_timeout = 0;
}
/* You could argue there is a dependency between these two but
* ultimately we don't care about their ordering with respect
* to one another. Worst case, we make a few system calls that
* could have been avoided because another thread already knows
* they fail with ENOSYS. Hardly the end of the world.
*/
no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* See the comment for max_safe_timeout for an explanation of why
* this is necessary. Executive summary: kernel bug workaround.
*/
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
abort();
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
nfds = epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
&sigset);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_pwait_cached, 1);
no_epoll_pwait = 1;
}
} else {
nfds = epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_wait_cached, 1);
no_epoll_wait = 1;
}
}
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
abort();
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
if (errno == ENOSYS) {
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
continue;
}
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
have_signals = 0;
nevents = 0;
{
/* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
union {
struct epoll_event* events;
uv__io_t* watchers;
} x;
x.events = events;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = x.watchers;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
}
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->data.fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |=
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
if (pe->events != 0) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
}
nevents++;
}
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) { uint64_t uv__hrtime(uv_clocktype_t type) {
static clock_t fast_clock_id = -1; static clock_t fast_clock_id = -1;
@ -602,22 +211,53 @@ err:
return UV_EINVAL; return UV_EINVAL;
} }
static int uv__slurp(const char* filename, char* buf, size_t len) {
ssize_t n;
int fd;
assert(len > 0);
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return fd;
do
n = read(fd, buf, len - 1);
while (n == -1 && errno == EINTR);
if (uv__close_nocheckstdio(fd))
abort();
if (n < 0)
return UV__ERR(errno);
buf[n] = '\0';
return 0;
}
int uv_uptime(double* uptime) { int uv_uptime(double* uptime) {
static volatile int no_clock_boottime; static volatile int no_clock_boottime;
char buf[128];
struct timespec now; struct timespec now;
int r; int r;
/* Try /proc/uptime first, then fallback to clock_gettime(). */
if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
if (1 == sscanf(buf, "%lf", uptime))
return 0;
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
* is suspended. * is suspended.
*/ */
if (no_clock_boottime) { if (no_clock_boottime) {
retry: r = clock_gettime(CLOCK_MONOTONIC, &now); retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
} }
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
no_clock_boottime = 1; no_clock_boottime = 1;
goto retry; goto retry_clock_gettime;
} }
if (r) if (r)
@ -709,14 +349,19 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
} }
/* Also reads the CPU frequency on x86. The other architectures only have /* Also reads the CPU frequency on ppc and x86. The other architectures only
* a BogoMIPS field, which may not be very accurate. * have a BogoMIPS field, which may not be very accurate.
* *
* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
*/ */
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
#if defined(__PPC__)
static const char model_marker[] = "cpu\t\t: ";
static const char speed_marker[] = "clock\t\t: ";
#else
static const char model_marker[] = "model name\t: "; static const char model_marker[] = "model name\t: ";
static const char speed_marker[] = "cpu MHz\t\t: "; static const char speed_marker[] = "cpu MHz\t\t: ";
#endif
const char* inferred_model; const char* inferred_model;
unsigned int model_idx; unsigned int model_idx;
unsigned int speed_idx; unsigned int speed_idx;
@ -738,6 +383,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
#if defined(__arm__) || \ #if defined(__arm__) || \
defined(__i386__) || \ defined(__i386__) || \
defined(__mips__) || \ defined(__mips__) || \
defined(__PPC__) || \
defined(__x86_64__) defined(__x86_64__)
fp = uv__open_file("/proc/cpuinfo"); fp = uv__open_file("/proc/cpuinfo");
if (fp == NULL) if (fp == NULL)
@ -786,7 +432,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
} }
fclose(fp); fclose(fp);
#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ #endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ */
/* Now we want to make sure that all the models contain *something* because /* Now we want to make sure that all the models contain *something* because
* it's not safe to leave them as null. Copy the last entry unless there * it's not safe to leave them as null. Copy the last entry unless there
@ -824,9 +470,9 @@ static int read_times(FILE* statfile_fp,
char buf[1024]; char buf[1024];
ticks = (unsigned int)sysconf(_SC_CLK_TCK); ticks = (unsigned int)sysconf(_SC_CLK_TCK);
multiplier = ((uint64_t)1000L / ticks);
assert(ticks != (unsigned int) -1); assert(ticks != (unsigned int) -1);
assert(ticks != 0); assert(ticks != 0);
multiplier = ((uint64_t)1000L / ticks);
rewind(statfile_fp); rewind(statfile_fp);
@ -1025,32 +671,6 @@ void uv__set_process_title(const char* title) {
} }
static int uv__slurp(const char* filename, char* buf, size_t len) {
ssize_t n;
int fd;
assert(len > 0);
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return fd;
do
n = read(fd, buf, len - 1);
while (n == -1 && errno == EINTR);
if (uv__close_nocheckstdio(fd))
abort();
if (n < 0)
return UV__ERR(errno);
buf[n] = '\0';
return 0;
}
static uint64_t uv__read_proc_meminfo(const char* what) { static uint64_t uv__read_proc_meminfo(const char* what) {
uint64_t rc; uint64_t rc;
char* p; char* p;

View File

@ -178,7 +178,7 @@ static void uv__inotify_read(uv_loop_t* loop,
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */ /* needs to be large enough for sizeof(inotify_event) + strlen(path) */
char buf[4096]; char buf[4096];
while (1) { for (;;) {
do do
size = read(loop->inotify_fd, buf, sizeof(buf)); size = read(loop->inotify_fd, buf, sizeof(buf));
while (size == -1 && errno == EINTR); while (size == -1 && errno == EINTR);

View File

@ -194,37 +194,37 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_preadv) #if !defined(__NR_preadv) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#else
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif #endif
} }
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_pwritev) #if !defined(__NR_pwritev) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#else
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif #endif
} }
int uv__dup3(int oldfd, int newfd, int flags) { int uv__dup3(int oldfd, int newfd, int flags) {
#if defined(__NR_dup3) #if !defined(__NR_dup3) || defined(__ANDROID_API__) && __ANDROID_API__ < 21
return syscall(__NR_dup3, oldfd, newfd, flags);
#else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#else
return syscall(__NR_dup3, oldfd, newfd, flags);
#endif #endif
} }
ssize_t ssize_t
uv__fs_copy_file_range(int fd_in, uv__fs_copy_file_range(int fd_in,
ssize_t* off_in, off_t* off_in,
int fd_out, int fd_out,
ssize_t* off_out, off_t* off_out,
size_t len, size_t len,
unsigned int flags) unsigned int flags)
{ {
@ -247,21 +247,18 @@ int uv__statx(int dirfd,
int flags, int flags,
unsigned int mask, unsigned int mask,
struct uv__statx* statxbuf) { struct uv__statx* statxbuf) {
/* __NR_statx make Android box killed by SIGSYS. #if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
* That looks like a seccomp2 sandbox filter rejecting the system call.
*/
#if defined(__NR_statx) && !defined(__ANDROID__)
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#else
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#endif #endif
} }
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
#if defined(__NR_getrandom) #if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28
return syscall(__NR_getrandom, buf, buflen, flags);
#else
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#else
return syscall(__NR_getrandom, buf, buflen, flags);
#endif #endif
} }

View File

@ -22,9 +22,6 @@
#ifndef UV_LINUX_SYSCALL_H_ #ifndef UV_LINUX_SYSCALL_H_
#define UV_LINUX_SYSCALL_H_ #define UV_LINUX_SYSCALL_H_
#undef _GNU_SOURCE
#define _GNU_SOURCE
#include <stdint.h> #include <stdint.h>
#include <signal.h> #include <signal.h>
#include <sys/types.h> #include <sys/types.h>
@ -66,9 +63,9 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset)
int uv__dup3(int oldfd, int newfd, int flags); int uv__dup3(int oldfd, int newfd, int flags);
ssize_t ssize_t
uv__fs_copy_file_range(int fd_in, uv__fs_copy_file_range(int fd_in,
ssize_t* off_in, off_t* off_in,
int fd_out, int fd_out,
ssize_t* off_out, off_t* off_out,
size_t len, size_t len,
unsigned int flags); unsigned int flags);
int uv__statx(int dirfd, int uv__statx(int dirfd,

136
deps/libuv/src/unix/os390-proctitle.c vendored Normal file
View File

@ -0,0 +1,136 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdlib.h>
#include <string.h>
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char* process_title = NULL;
static void* args_mem = NULL;
static void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
char** uv_setup_args(int argc, char** argv) {
char** new_argv;
size_t size;
char* s;
int i;
if (argc <= 0)
return argv;
/* Calculate how much memory we need for the argv strings. */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
/* Copy over the strings and set up the pointer table. */
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = strlen(argv[i]) + 1;
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
args_mem = new_argv;
process_title = uv__strdup(argv[0]);
return new_argv;
}
int uv_set_process_title(const char* title) {
char* new_title;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL)
return UV_ENOBUFS;
/* We cannot free this pointer when libuv shuts down,
* the process may still be using it.
*/
new_title = uv__strdup(title);
if (new_title == NULL)
return UV_ENOMEM;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (process_title != NULL)
uv__free(process_title);
process_title = new_title;
uv_mutex_unlock(&process_title_mutex);
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return UV_EINVAL;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL || process_title == NULL)
return UV_ENOBUFS;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
len = strlen(process_title);
if (size <= len) {
uv_mutex_unlock(&process_title_mutex);
return UV_ENOBUFS;
}
strcpy(buffer, process_title);
uv_mutex_unlock(&process_title_mutex);
return 0;
}
void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}

View File

@ -27,12 +27,6 @@
#include <termios.h> #include <termios.h>
#include <sys/msg.h> #include <sys/msg.h>
#define CW_INTRPT 1
#define CW_CONDVAR 32
#pragma linkage(BPX4CTW, OS)
#pragma linkage(BPX1CTW, OS)
static QUEUE global_epoll_queue; static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock; static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT; static uv_once_t once = UV_ONCE_INIT;
@ -55,7 +49,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
if (!mdir) if (!mdir)
return -1; return -1;
while (1) { for (;;) {
dirent = readdir(mdir); dirent = readdir(mdir);
if (!dirent) if (!dirent)
break; break;
@ -381,46 +375,6 @@ void epoll_queue_close(uv__os390_epoll* lst) {
} }
int nanosleep(const struct timespec* req, struct timespec* rem) {
unsigned nano;
unsigned seconds;
unsigned events;
unsigned secrem;
unsigned nanorem;
int rv;
int err;
int rsn;
nano = (int)req->tv_nsec;
seconds = req->tv_sec;
events = CW_CONDVAR | CW_INTRPT;
secrem = 0;
nanorem = 0;
#if defined(_LP64)
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
#else
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
#endif
/* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
* Don't leak EAGAIN, that just means the timeout expired.
*/
if (rv == -1)
if (err == EAGAIN)
rv = 0;
else
errno = err;
if (rem != NULL && (rv == 0 || err == EINTR)) {
rem->tv_nsec = nanorem;
rem->tv_sec = secrem;
}
return rv;
}
char* mkdtemp(char* path) { char* mkdtemp(char* path) {
static const char* tempchars = static const char* tempchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@ -550,15 +504,6 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) {
} }
size_t strnlen(const char* str, size_t maxlen) {
char* p = memchr(str, 0, maxlen);
if (p == NULL)
return maxlen;
else
return p - str;
}
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) { int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -28,6 +28,7 @@
#include <dirent.h> #include <dirent.h>
#include <poll.h> #include <poll.h>
#include <pthread.h> #include <pthread.h>
#include "zos-base.h"
#define EPOLL_CTL_ADD 1 #define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2 #define EPOLL_CTL_DEL 2
@ -57,7 +58,6 @@ int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, i
int epoll_file_close(int fd); int epoll_file_close(int fd);
/* utility functions */ /* utility functions */
int nanosleep(const struct timespec* req, struct timespec* rem);
int scandir(const char* maindir, struct dirent*** namelist, int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent *), int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, int (*compar)(const struct dirent **,

View File

@ -28,6 +28,8 @@
#include <builtins.h> #include <builtins.h>
#include <termios.h> #include <termios.h>
#include <sys/msg.h> #include <sys/msg.h>
#include <sys/resource.h>
#include "zos-base.h"
#if defined(__clang__) #if defined(__clang__)
#include "csrsic.h" #include "csrsic.h"
#else #else
@ -61,12 +63,6 @@
/* Address of the rsm control and enumeration area. */ /* Address of the rsm control and enumeration area. */
#define CVTRCEP_OFFSET 0x490 #define CVTRCEP_OFFSET 0x490
/*
Number of frames currently available to system.
Excluded are frames backing perm storage, frames offline, and bad frames.
*/
#define RCEPOOL_OFFSET 0x004
/* Total number of frames currently on all available frame queues. */ /* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088 #define RCEAFC_OFFSET 0x088
@ -144,102 +140,8 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
} }
/* static int getexe(char* buf, size_t len) {
Get the exe path using the thread entry information return uv__strscpy(buf, __getargv()[0], len);
in the address space.
*/
static int getexe(const int pid, char* buf, size_t len) {
struct {
int pid;
int thid[2];
char accesspid;
char accessthid;
char asid[2];
char loginname[8];
char flag;
char len;
} Input_data;
union {
struct {
char gthb[4];
int pid;
int thid[2];
char accesspid;
char accessthid[3];
int lenused;
int offsetProcess;
int offsetConTTY;
int offsetPath;
int offsetCommand;
int offsetFileData;
int offsetThread;
} Output_data;
char buf[2048];
} Output_buf;
struct Output_path_type {
char gthe[4];
short int len;
char path[1024];
};
int Input_length;
int Output_length;
void* Input_address;
void* Output_address;
struct Output_path_type* Output_path;
int rv;
int rc;
int rsn;
Input_length = PGTH_LEN;
Output_length = sizeof(Output_buf);
Output_address = &Output_buf;
Input_address = &Input_data;
memset(&Input_data, 0, sizeof Input_data);
Input_data.flag |= PGTHAPATH;
Input_data.pid = pid;
Input_data.accesspid = PGTH_CURRENT;
#ifdef _LP64
BPX4GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#else
BPX1GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#endif
if (rv == -1) {
errno = rc;
return -1;
}
/* Check highest byte to ensure data availability */
assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
/* Get the offset from the lowest 3 bytes */
Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
(Output_buf.Output_data.offsetPath & 0x00FFFFFF));
if (Output_path->len >= len) {
errno = ENOBUFS;
return -1;
}
uv__strscpy(buf, Output_path->path, len);
return 0;
} }
@ -259,8 +161,7 @@ int uv_exepath(char* buffer, size_t* size) {
if (buffer == NULL || size == NULL || *size == 0) if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL; return UV_EINVAL;
pid = getpid(); res = getexe(args, sizeof(args));
res = getexe(pid, args, sizeof(args));
if (res < 0) if (res < 0)
return UV_EINVAL; return UV_EINVAL;
@ -275,25 +176,25 @@ uint64_t uv_get_free_memory(void) {
data_area_ptr rcep = {0}; data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; freeram = (uint64_t)*((uint32_t*)(rcep.deref + RCEAFC_OFFSET)) * 4096;
return freeram; return freeram;
} }
uint64_t uv_get_total_memory(void) { uint64_t uv_get_total_memory(void) {
uint64_t totalram; /* Use CVTRLSTG to get the size of actual real storage online at IPL in K. */
return (uint64_t)((int)((char *__ptr32 *__ptr32 *)0)[4][214]) * 1024;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
return totalram;
} }
uint64_t uv_get_constrained_memory(void) { uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */ struct rlimit rl;
/* RLIMIT_MEMLIMIT return value is in megabytes rather than bytes. */
if (getrlimit(RLIMIT_MEMLIMIT, &rl) == 0)
return rl.rlim_cur * 1024 * 1024;
return 0; /* There is no memory limit set. */
} }
@ -733,6 +634,10 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
/* Some event that we are not interested in. */ /* Some event that we are not interested in. */
return 0; return 0;
/* `__rfim_utok` is treated as text when it should be treated as binary while
* running in ASCII mode, resulting in an unwanted autoconversion.
*/
__a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
handle = *(uv_fs_event_t**)(msg.__rfim_utok); handle = *(uv_fs_event_t**)(msg.__rfim_utok);
handle->cb(handle, uv__basename_r(handle->path), events, 0); handle->cb(handle, uv__basename_r(handle->path), events, 0);
return 1; return 1;
@ -959,9 +864,6 @@ update_timeout:
} }
} }
void uv__set_process_title(const char* title) {
/* do nothing */
}
int uv__io_fork(uv_loop_t* loop) { int uv__io_fork(uv_loop_t* loop) {
/* /*

View File

@ -379,3 +379,57 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
return r != -1 ? 0 : UV__ERR(errno); return r != -1 ? 0 : UV__ERR(errno);
} }
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__)
int flags = O_CLOEXEC;
if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
flags |= UV_FS_O_NONBLOCK;
if (pipe2(temp, flags))
return UV__ERR(errno);
if (flags & UV_FS_O_NONBLOCK) {
fds[0] = temp[0];
fds[1] = temp[1];
return 0;
}
#else
if (pipe(temp))
return UV__ERR(errno);
if ((err = uv__cloexec(temp[0], 1)))
goto fail;
if ((err = uv__cloexec(temp[1], 1)))
goto fail;
#endif
if (read_flags & UV_NONBLOCK_PIPE)
if ((err = uv__nonblock(temp[0], 1)))
goto fail;
if (write_flags & UV_NONBLOCK_PIPE)
if ((err = uv__nonblock(temp[1], 1)))
goto fail;
fds[0] = temp[0];
fds[1] = temp[1];
return 0;
fail:
uv__close(temp[0]);
uv__close(temp[1]);
return err;
}
int uv__make_pipe(int fds[2], int flags) {
return uv_pipe(fds,
flags & UV_NONBLOCK_PIPE,
flags & UV_NONBLOCK_PIPE);
}

View File

@ -79,9 +79,10 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
* Workaround for e.g. kqueue fds not supporting ioctls. * Workaround for e.g. kqueue fds not supporting ioctls.
*/ */
err = uv__nonblock(fd, 1); err = uv__nonblock(fd, 1);
#if UV__NONBLOCK_IS_IOCTL
if (err == UV_ENOTTY) if (err == UV_ENOTTY)
if (uv__nonblock == uv__nonblock_ioctl)
err = uv__nonblock_fcntl(fd, 1); err = uv__nonblock_fcntl(fd, 1);
#endif
if (err) if (err)
return err; return err;
@ -116,12 +117,21 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
uv__io_t** watchers;
uv__io_t* w;
int events; int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
UV_PRIORITIZED)) == 0); UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle)); assert(!uv__is_closing(handle));
watchers = handle->loop->watchers;
w = &handle->io_watcher;
if (uv__fd_exists(handle->loop, w->fd))
if (watchers[w->fd] != w)
return UV_EEXIST;
uv__poll_stop(handle); uv__poll_stop(handle);
if (pevents == 0) if (pevents == 0)

View File

@ -44,6 +44,10 @@ extern char **environ;
# include <grp.h> # include <grp.h>
#endif #endif
#if defined(__MVS__)
# include "zos-base.h"
#endif
static void uv__chld(uv_signal_t* handle, int signum) { static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process; uv_process_t* process;
@ -111,68 +115,6 @@ static void uv__chld(uv_signal_t* handle, int signum) {
assert(QUEUE_EMPTY(&pending)); assert(QUEUE_EMPTY(&pending));
} }
static int uv__make_socketpair(int fds[2]) {
#if defined(__FreeBSD__) || defined(__linux__)
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
return UV__ERR(errno);
return 0;
#else
int err;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return UV__ERR(errno);
err = uv__cloexec(fds[0], 1);
if (err == 0)
err = uv__cloexec(fds[1], 1);
if (err != 0) {
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
}
return 0;
#endif
}
int uv__make_pipe(int fds[2], int flags) {
#if defined(__FreeBSD__) || defined(__linux__)
if (pipe2(fds, flags | O_CLOEXEC))
return UV__ERR(errno);
return 0;
#else
if (pipe(fds))
return UV__ERR(errno);
if (uv__cloexec(fds[0], 1))
goto fail;
if (uv__cloexec(fds[1], 1))
goto fail;
if (flags & UV__F_NONBLOCK) {
if (uv__nonblock(fds[0], 1))
goto fail;
if (uv__nonblock(fds[1], 1))
goto fail;
}
return 0;
fail:
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
#endif
}
/* /*
* Used for initializing stdio streams like options.stdin_stream. Returns * Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn(). * zero on success. See also the cleanup section in uv_spawn().
@ -192,7 +134,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
if (container->data.stream->type != UV_NAMED_PIPE) if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL; return UV_EINVAL;
else else
return uv__make_socketpair(fds); return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
case UV_INHERIT_FD: case UV_INHERIT_FD:
case UV_INHERIT_STREAM: case UV_INHERIT_STREAM:
@ -259,6 +201,12 @@ static void uv__write_int(int fd, int val) {
} }
static void uv__write_errno(int error_fd) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) #if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be /* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function * avoided. Since this isn't called on those targets, the function
@ -287,10 +235,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
if (use_fd < 0 || use_fd >= fd) if (use_fd < 0 || use_fd >= fd)
continue; continue;
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
if (pipes[fd][1] == -1) { if (pipes[fd][1] == -1)
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
} }
for (fd = 0; fd < stdio_count; fd++) { for (fd = 0; fd < stdio_count; fd++) {
@ -307,10 +253,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
close_fd = use_fd; close_fd = use_fd;
if (use_fd < 0) { if (use_fd < 0)
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
} }
} }
@ -319,10 +263,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
else else
fd = dup2(use_fd, fd); fd = dup2(use_fd, fd);
if (fd == -1) { if (fd == -1)
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
if (fd <= 2) if (fd <= 2)
uv__nonblock_fcntl(fd, 0); uv__nonblock_fcntl(fd, 0);
@ -338,10 +280,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
uv__close(use_fd); uv__close(use_fd);
} }
if (options->cwd != NULL && chdir(options->cwd)) { if (options->cwd != NULL && chdir(options->cwd))
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will /* When dropping privileges from root, the `setgroups` call will
@ -354,15 +294,11 @@ static void uv__process_child_init(const uv_process_options_t* options,
SAVE_ERRNO(setgroups(0, NULL)); SAVE_ERRNO(setgroups(0, NULL));
} }
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid))
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid))
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
}
if (options->env != NULL) { if (options->env != NULL) {
environ = options->env; environ = options->env;
@ -385,22 +321,23 @@ static void uv__process_child_init(const uv_process_options_t* options,
if (SIG_ERR != signal(n, SIG_DFL)) if (SIG_ERR != signal(n, SIG_DFL))
continue; continue;
uv__write_int(error_fd, UV__ERR(errno)); uv__write_errno(error_fd);
_exit(127);
} }
/* Reset signal mask. */ /* Reset signal mask. */
sigemptyset(&set); sigemptyset(&set);
err = pthread_sigmask(SIG_SETMASK, &set, NULL); err = pthread_sigmask(SIG_SETMASK, &set, NULL);
if (err != 0) { if (err != 0)
uv__write_int(error_fd, UV__ERR(err)); uv__write_errno(error_fd);
_exit(127);
}
#ifdef __MVS__
execvpe(options->file, options->args, environ);
#else
execvp(options->file, options->args); execvp(options->file, options->args);
uv__write_int(error_fd, UV__ERR(errno)); #endif
_exit(127);
uv__write_errno(error_fd);
} }
#endif #endif

View File

@ -84,10 +84,7 @@ char** uv_setup_args(int argc, char** argv) {
} }
new_argv[i] = NULL; new_argv[i] = NULL;
/* argv is not adjacent on z/os, we use just argv[0] on that platform. */
#ifndef __MVS__
pt.cap = argv[i - 1] + size - argv[0]; pt.cap = argv[i - 1] + size - argv[0];
#endif
args_mem = new_argv; args_mem = new_argv;
process_title = pt; process_title = pt;
@ -119,6 +116,7 @@ int uv_set_process_title(const char* title) {
memcpy(pt->str, title, len); memcpy(pt->str, title, len);
memset(pt->str + len, '\0', pt->cap - len); memset(pt->str + len, '\0', pt->cap - len);
pt->len = len; pt->len = len;
uv__set_process_title(pt->str);
uv_mutex_unlock(&process_title_mutex); uv_mutex_unlock(&process_title_mutex);

View File

@ -265,7 +265,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
if (loop->signal_pipefd[0] != -1) if (loop->signal_pipefd[0] != -1)
return 0; return 0;
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK); err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE);
if (err) if (err)
return err; return err;

View File

@ -164,7 +164,7 @@ static void uv__stream_osx_select(void* arg) {
else else
max_fd = s->int_fd; max_fd = s->int_fd;
while (1) { for (;;) {
/* Terminate on semaphore */ /* Terminate on semaphore */
if (uv_sem_trywait(&s->close_sem) == 0) if (uv_sem_trywait(&s->close_sem) == 0)
break; break;
@ -195,7 +195,7 @@ static void uv__stream_osx_select(void* arg) {
/* Empty socketpair's buffer in case of interruption */ /* Empty socketpair's buffer in case of interruption */
if (FD_ISSET(s->int_fd, s->sread)) if (FD_ISSET(s->int_fd, s->sread))
while (1) { for (;;) {
r = read(s->int_fd, buf, sizeof(buf)); r = read(s->int_fd, buf, sizeof(buf));
if (r == sizeof(buf)) if (r == sizeof(buf))
@ -799,33 +799,21 @@ static int uv__handle_fd(uv_handle_t* handle) {
} }
} }
static void uv__write(uv_stream_t* stream) { static int uv__try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle) {
struct iovec* iov; struct iovec* iov;
QUEUE* q;
uv_write_t* req;
int iovmax; int iovmax;
int iovcnt; int iovcnt;
ssize_t n; ssize_t n;
int err;
start:
assert(uv__stream_fd(stream) >= 0);
if (QUEUE_EMPTY(&stream->write_queue))
return;
q = QUEUE_HEAD(&stream->write_queue);
req = QUEUE_DATA(q, uv_write_t, queue);
assert(req->handle == stream);
/* /*
* Cast to iovec. We had to have our own uv_buf_t instead of iovec * Cast to iovec. We had to have our own uv_buf_t instead of iovec
* because Windows's WSABUF is not an iovec. * because Windows's WSABUF is not an iovec.
*/ */
assert(sizeof(uv_buf_t) == sizeof(struct iovec)); iov = (struct iovec*) bufs;
iov = (struct iovec*) &(req->bufs[req->write_index]); iovcnt = nbufs;
iovcnt = req->nbufs - req->write_index;
iovmax = uv__getiovmax(); iovmax = uv__getiovmax();
@ -837,8 +825,7 @@ start:
* Now do the actual writev. Note that we've been updating the pointers * Now do the actual writev. Note that we've been updating the pointers
* inside the iov each time we write. So there is no need to offset it. * inside the iov each time we write. So there is no need to offset it.
*/ */
if (send_handle != NULL) {
if (req->send_handle) {
int fd_to_send; int fd_to_send;
struct msghdr msg; struct msghdr msg;
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
@ -847,12 +834,10 @@ start:
struct cmsghdr alias; struct cmsghdr alias;
} scratch; } scratch;
if (uv__is_closing(req->send_handle)) { if (uv__is_closing(send_handle))
err = UV_EBADF; return UV_EBADF;
goto error;
}
fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); fd_to_send = uv__handle_fd((uv_handle_t*) send_handle);
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
@ -882,29 +867,54 @@ start:
do do
n = sendmsg(uv__stream_fd(stream), &msg, 0); n = sendmsg(uv__stream_fd(stream), &msg, 0);
while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
/* Ensure the handle isn't sent again in case this is a partial write. */
if (n >= 0)
req->send_handle = NULL;
} else { } else {
do do
n = uv__writev(uv__stream_fd(stream), iov, iovcnt); n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
} }
if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) { if (n >= 0)
err = UV__ERR(errno); return n;
goto error;
}
if (n >= 0 && uv__write_req_update(stream, req, n)) { if (IS_TRANSIENT_WRITE_ERROR(errno, send_handle))
return UV_EAGAIN;
return UV__ERR(errno);
}
static void uv__write(uv_stream_t* stream) {
QUEUE* q;
uv_write_t* req;
ssize_t n;
assert(uv__stream_fd(stream) >= 0);
for (;;) {
if (QUEUE_EMPTY(&stream->write_queue))
return;
q = QUEUE_HEAD(&stream->write_queue);
req = QUEUE_DATA(q, uv_write_t, queue);
assert(req->handle == stream);
n = uv__try_write(stream,
&(req->bufs[req->write_index]),
req->nbufs - req->write_index,
req->send_handle);
/* Ensure the handle isn't sent again in case this is a partial write. */
if (n >= 0) {
req->send_handle = NULL;
if (uv__write_req_update(stream, req, n)) {
uv__write_req_finish(req); uv__write_req_finish(req);
return; /* TODO(bnoordhuis) Start trying to write the next request. */ return; /* TODO(bnoordhuis) Start trying to write the next request. */
} }
} else if (n != UV_EAGAIN)
break;
/* If this is a blocking stream, try again. */ /* If this is a blocking stream, try again. */
if (stream->flags & UV_HANDLE_BLOCKING_WRITES) if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
goto start; continue;
/* We're not done. */ /* We're not done. */
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
@ -913,13 +923,12 @@ start:
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
return; return;
}
error: req->error = n;
req->error = err; // XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events
uv__write_req_finish(req); uv__write_req_finish(req);
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
if (!uv__io_active(&stream->io_watcher, POLLIN))
uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
} }
@ -1001,8 +1010,8 @@ uv_handle_type uv__handle_type(int fd) {
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
stream->flags |= UV_HANDLE_READ_EOF; stream->flags |= UV_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING; stream->flags &= ~UV_HANDLE_READING;
stream->flags &= ~UV_HANDLE_READABLE;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
if (!uv__io_active(&stream->io_watcher, POLLOUT))
uv__handle_stop(stream); uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
stream->read_cb(stream, UV_EOF, buf); stream->read_cb(stream, UV_EOF, buf);
@ -1188,11 +1197,11 @@ static void uv__read(uv_stream_t* stream) {
#endif #endif
} else { } else {
/* Error. User should call uv_close(). */ /* Error. User should call uv_close(). */
stream->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
stream->read_cb(stream, UV__ERR(errno), &buf); stream->read_cb(stream, UV__ERR(errno), &buf);
if (stream->flags & UV_HANDLE_READING) { if (stream->flags & UV_HANDLE_READING) {
stream->flags &= ~UV_HANDLE_READING; stream->flags &= ~UV_HANDLE_READING;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
if (!uv__io_active(&stream->io_watcher, POLLOUT))
uv__handle_stop(stream); uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
} }
@ -1276,6 +1285,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
req->cb = cb; req->cb = cb;
stream->shutdown_req = req; stream->shutdown_req = req;
stream->flags |= UV_HANDLE_SHUTTING; stream->flags |= UV_HANDLE_SHUTTING;
stream->flags &= ~UV_HANDLE_WRITABLE;
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
@ -1390,14 +1400,9 @@ static void uv__stream_connect(uv_stream_t* stream) {
} }
int uv_write2(uv_write_t* req, static int uv__check_before_write(uv_stream_t* stream,
uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs, unsigned int nbufs,
uv_stream_t* send_handle, uv_stream_t* send_handle) {
uv_write_cb cb) {
int empty_queue;
assert(nbufs > 0); assert(nbufs > 0);
assert((stream->type == UV_TCP || assert((stream->type == UV_TCP ||
stream->type == UV_NAMED_PIPE || stream->type == UV_NAMED_PIPE ||
@ -1410,7 +1415,7 @@ int uv_write2(uv_write_t* req,
if (!(stream->flags & UV_HANDLE_WRITABLE)) if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE; return UV_EPIPE;
if (send_handle) { if (send_handle != NULL) {
if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
return UV_EINVAL; return UV_EINVAL;
@ -1430,6 +1435,22 @@ int uv_write2(uv_write_t* req,
#endif #endif
} }
return 0;
}
int uv_write2(uv_write_t* req,
uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle,
uv_write_cb cb) {
int empty_queue;
int err;
err = uv__check_before_write(stream, nbufs, send_handle);
if (err < 0)
return err;
/* It's legal for write_queue_size > 0 even when the write_queue is empty; /* It's legal for write_queue_size > 0 even when the write_queue is empty;
* it means there are error-state requests in the write_completed_queue that * it means there are error-state requests in the write_completed_queue that
* will touch up write_queue_size later, see also uv__write_req_finish(). * will touch up write_queue_size later, see also uv__write_req_finish().
@ -1498,72 +1519,37 @@ int uv_write(uv_write_t* req,
} }
void uv_try_write_cb(uv_write_t* req, int status) {
/* Should not be called */
abort();
}
int uv_try_write(uv_stream_t* stream, int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[], const uv_buf_t bufs[],
unsigned int nbufs) { unsigned int nbufs) {
int r; return uv_try_write2(stream, bufs, nbufs, NULL);
int has_pollout; }
size_t written;
size_t req_size;
uv_write_t req; int uv_try_write2(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle) {
int err;
/* Connecting or already writing some data */ /* Connecting or already writing some data */
if (stream->connect_req != NULL || stream->write_queue_size != 0) if (stream->connect_req != NULL || stream->write_queue_size != 0)
return UV_EAGAIN; return UV_EAGAIN;
has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); err = uv__check_before_write(stream, nbufs, NULL);
if (err < 0)
return err;
r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); return uv__try_write(stream, bufs, nbufs, send_handle);
if (r != 0)
return r;
/* Remove not written bytes from write queue size */
written = uv__count_bufs(bufs, nbufs);
if (req.bufs != NULL)
req_size = uv__write_req_size(&req);
else
req_size = 0;
written -= req_size;
stream->write_queue_size -= req_size;
/* Unqueue request, regardless of immediateness */
QUEUE_REMOVE(&req.queue);
uv__req_unregister(stream->loop, &req);
if (req.bufs != req.bufsml)
uv__free(req.bufs);
req.bufs = NULL;
/* Do not poll for writable, if we wasn't before calling this */
if (!has_pollout) {
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
}
if (written == 0 && req_size != 0)
return req.error < 0 ? req.error : UV_EAGAIN;
else
return written;
} }
int uv_read_start(uv_stream_t* stream, int uv__read_start(uv_stream_t* stream,
uv_alloc_cb alloc_cb, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) { uv_read_cb read_cb) {
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY); stream->type == UV_TTY);
if (stream->flags & UV_HANDLE_CLOSING)
return UV_EINVAL;
if (!(stream->flags & UV_HANDLE_READABLE))
return UV_ENOTCONN;
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
* expresses the desired state of the user. * expresses the desired state of the user.
*/ */
@ -1593,7 +1579,6 @@ int uv_read_stop(uv_stream_t* stream) {
stream->flags &= ~UV_HANDLE_READING; stream->flags &= ~UV_HANDLE_READING;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
if (!uv__io_active(&stream->io_watcher, POLLOUT))
uv__handle_stop(stream); uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);

View File

@ -865,3 +865,14 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
uv__free(addresses); uv__free(addresses);
} }
#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
size_t strnlen(const char* s, size_t maxlen) {
const char* end;
end = memchr(s, '\0', maxlen);
if (end == NULL)
return maxlen;
return end - s;
}
#endif

View File

@ -214,14 +214,15 @@ int uv__tcp_connect(uv_connect_t* req,
if (handle->connect_req != NULL) if (handle->connect_req != NULL)
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
if (handle->delayed_error != 0)
goto out;
err = maybe_new_socket(handle, err = maybe_new_socket(handle,
addr->sa_family, addr->sa_family,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
if (err) if (err)
return err; return err;
handle->delayed_error = 0;
do { do {
errno = 0; errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen); r = connect(uv__stream_fd(handle), addr, addrlen);
@ -249,6 +250,8 @@ int uv__tcp_connect(uv_connect_t* req,
return UV__ERR(errno); return UV__ERR(errno);
} }
out:
uv__req_init(handle->loop, req, UV_CONNECT); uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb; req->cb = cb;
req->handle = (uv_stream_t*) handle; req->handle = (uv_stream_t*) handle;
@ -459,3 +462,49 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
void uv__tcp_close(uv_tcp_t* handle) { void uv__tcp_close(uv_tcp_t* handle) {
uv__stream_close((uv_stream_t*)handle); uv__stream_close((uv_stream_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__)
int flags;
flags = type | SOCK_CLOEXEC;
if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
flags |= SOCK_NONBLOCK;
if (socketpair(AF_UNIX, flags, protocol, temp))
return UV__ERR(errno);
if (flags & UV_FS_O_NONBLOCK) {
fds[0] = temp[0];
fds[1] = temp[1];
return 0;
}
#else
if (socketpair(AF_UNIX, type, protocol, temp))
return UV__ERR(errno);
if ((err = uv__cloexec(temp[0], 1)))
goto fail;
if ((err = uv__cloexec(temp[1], 1)))
goto fail;
#endif
if (flags0 & UV_NONBLOCK_PIPE)
if ((err = uv__nonblock(temp[0], 1)))
goto fail;
if (flags1 & UV_NONBLOCK_PIPE)
if ((err = uv__nonblock(temp[1], 1)))
goto fail;
fds[0] = temp[0];
fds[1] = temp[1];
return 0;
fail:
uv__close(temp[0]);
uv__close(temp[1]);
return err;
}

View File

@ -107,8 +107,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
} }
last = (--b->out == 0); last = (--b->out == 0);
if (!last) uv_cond_signal(&b->cond);
uv_cond_signal(&b->cond); /* Not needed for last thread. */
uv_mutex_unlock(&b->mutex); uv_mutex_unlock(&b->mutex);
return last; return last;
@ -122,9 +121,10 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_mutex_lock(&b->mutex); uv_mutex_lock(&b->mutex);
assert(b->in == 0); assert(b->in == 0);
assert(b->out == 0); while (b->out != 0)
uv_cond_wait(&b->cond, &b->mutex);
if (b->in != 0 || b->out != 0) if (b->in != 0)
abort(); abort();
uv_mutex_unlock(&b->mutex); uv_mutex_unlock(&b->mutex);
@ -168,7 +168,7 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
* On Linux, threads created by musl have a much smaller stack than threads * On Linux, threads created by musl have a much smaller stack than threads
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
*/ */
static size_t thread_stack_size(void) { size_t uv__thread_stack_size(void) {
#if defined(__APPLE__) || defined(__linux__) #if defined(__APPLE__) || defined(__linux__)
struct rlimit lim; struct rlimit lim;
@ -234,7 +234,7 @@ int uv_thread_create_ex(uv_thread_t* tid,
attr = NULL; attr = NULL;
if (stack_size == 0) { if (stack_size == 0) {
stack_size = thread_stack_size(); stack_size = uv__thread_stack_size();
} else { } else {
pagesize = (size_t)getpagesize(); pagesize = (size_t)getpagesize();
/* Round up to the nearest page boundary. */ /* Round up to the nearest page boundary. */

View File

@ -242,6 +242,24 @@ static void uv__tty_make_raw(struct termios* tio) {
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tio->c_cflag &= ~(CSIZE | PARENB); tio->c_cflag &= ~(CSIZE | PARENB);
tio->c_cflag |= CS8; tio->c_cflag |= CS8;
/*
* By default, most software expects a pending read to block until at
* least one byte becomes available. As per termio(7I), this requires
* setting the MIN and TIME parameters appropriately.
*
* As a somewhat unfortunate artifact of history, the MIN and TIME slots
* in the control character array overlap with the EOF and EOL slots used
* for canonical mode processing. Because the EOF character needs to be
* the ASCII EOT value (aka Control-D), it has the byte value 4. When
* switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
* reads will block until at least four bytes have been input.
*
* Other platforms with a distinct MIN slot like Linux and FreeBSD appear
* to default to a MIN value of 1, so we'll force that value here:
*/
tio->c_cc[VMIN] = 1;
tio->c_cc[VTIME] = 0;
#else #else
cfmakeraw(tio); cfmakeraw(tio);
#endif /* #ifdef __sun */ #endif /* #ifdef __sun */

View File

@ -32,8 +32,6 @@
#endif #endif
#include <sys/un.h> #include <sys/un.h>
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#endif #endif
@ -504,6 +502,28 @@ static int uv__set_reuse(int fd) {
return 0; return 0;
} }
/*
* The Linux kernel suppresses some ICMP error messages by default for UDP
* sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
* error reporting, hopefully resulting in faster failover to working name
* servers.
*/
static int uv__set_recverr(int fd, sa_family_t ss_family) {
#if defined(__linux__)
int yes;
yes = 1;
if (ss_family == AF_INET) {
if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
return UV__ERR(errno);
} else if (ss_family == AF_INET6) {
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
return UV__ERR(errno);
}
#endif
return 0;
}
int uv__udp_bind(uv_udp_t* handle, int uv__udp_bind(uv_udp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
@ -514,7 +534,7 @@ int uv__udp_bind(uv_udp_t* handle,
int fd; int fd;
/* Check for bad flags. */ /* Check for bad flags. */
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
return UV_EINVAL; return UV_EINVAL;
/* Cannot set IPv6-only mode on non-IPv6 socket. */ /* Cannot set IPv6-only mode on non-IPv6 socket. */
@ -530,6 +550,12 @@ int uv__udp_bind(uv_udp_t* handle,
handle->io_watcher.fd = fd; handle->io_watcher.fd = fd;
} }
if (flags & UV_UDP_LINUX_RECVERR) {
err = uv__set_recverr(fd, addr->sa_family);
if (err)
return err;
}
if (flags & UV_UDP_REUSEADDR) { if (flags & UV_UDP_REUSEADDR) {
err = uv__set_reuse(fd); err = uv__set_reuse(fd);
if (err) if (err)

View File

@ -832,6 +832,25 @@ void uv_loop_delete(uv_loop_t* loop) {
} }
int uv_read_start(uv_stream_t* stream,
uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
if (stream == NULL || alloc_cb == NULL || read_cb == NULL)
return UV_EINVAL;
if (stream->flags & UV_HANDLE_CLOSING)
return UV_EINVAL;
if (stream->flags & UV_HANDLE_READING)
return UV_EALREADY;
if (!(stream->flags & UV_HANDLE_READABLE))
return UV_ENOTCONN;
return uv__read_start(stream, alloc_cb, read_cb);
}
void uv_os_free_environ(uv_env_item_t* envitems, int count) { void uv_os_free_environ(uv_env_item_t* envitems, int count) {
int i; int i;
@ -853,7 +872,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
} }
#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */ /* Also covers __clang__ and __INTEL_COMPILER. Disabled on Windows because
* threads have already been forcibly terminated by the operating system
* by the time destructors run, ergo, it's not safe to try to clean them up.
*/
#if defined(__GNUC__) && !defined(_WIN32)
__attribute__((destructor)) __attribute__((destructor))
#endif #endif
void uv_library_shutdown(void) { void uv_library_shutdown(void) {

View File

@ -68,6 +68,8 @@ extern int snprintf(char*, size_t, const char*, ...);
#define uv__store_relaxed(p, v) do *p = v; while (0) #define uv__store_relaxed(p, v) do *p = v; while (0)
#endif #endif
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
/* Handle flags. Some flags are specific to Windows or UNIX. */ /* Handle flags. Some flags are specific to Windows or UNIX. */
enum { enum {
/* Used by all handles. */ /* Used by all handles. */
@ -106,8 +108,7 @@ enum {
UV_HANDLE_TCP_KEEPALIVE = 0x02000000, UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000, UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000, UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000, UV_HANDLE_SHARED_TCP_SOCKET = 0x10000000,
UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
/* Only used by uv_udp_t handles. */ /* Only used by uv_udp_t handles. */
UV_HANDLE_UDP_PROCESSING = 0x01000000, UV_HANDLE_UDP_PROCESSING = 0x01000000,
@ -136,6 +137,10 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
void uv__loop_close(uv_loop_t* loop); void uv__loop_close(uv_loop_t* loop);
int uv__read_start(uv_stream_t* stream,
uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv__tcp_bind(uv_tcp_t* tcp, int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int addrlen, unsigned int addrlen,

View File

@ -39,10 +39,11 @@ static char INLINE uv__atomic_exchange_set(char volatile* target) {
return _InterlockedOr8(target, 1); return _InterlockedOr8(target, 1);
} }
#else /* GCC */ #else /* GCC, Clang in mingw mode */
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
static inline char uv__atomic_exchange_set(char volatile* target) { static inline char uv__atomic_exchange_set(char volatile* target) {
#if defined(__i386__) || defined(__x86_64__)
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
const char one = 1; const char one = 1;
char old_value; char old_value;
__asm__ __volatile__ ("lock xchgb %0, %1\n\t" __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
@ -50,6 +51,9 @@ static inline char uv__atomic_exchange_set(char volatile* target) {
: "0"(one), "m"(*target) : "0"(one), "m"(*target)
: "memory"); : "memory");
return old_value; return old_value;
#else
return __sync_fetch_and_or(target, 1);
#endif
} }
#endif #endif

View File

@ -105,7 +105,6 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL;
case WSAEPFNOSUPPORT: return UV_EINVAL; case WSAEPFNOSUPPORT: return UV_EINVAL;
case WSAESOCKTNOSUPPORT: return UV_EINVAL;
case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
case ERROR_BUS_RESET: return UV_EIO; case ERROR_BUS_RESET: return UV_EIO;
case ERROR_CRC: return UV_EIO; case ERROR_CRC: return UV_EIO;
@ -168,6 +167,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
case ERROR_INVALID_FUNCTION: return UV_EISDIR; case ERROR_INVALID_FUNCTION: return UV_EISDIR;
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT;
default: return UV_UNKNOWN; default: return UV_UNKNOWN;
} }
} }

View File

@ -92,30 +92,24 @@
return; \ return; \
} }
#define MILLIONu (1000U * 1000U) #define MILLION ((int64_t) 1000 * 1000)
#define BILLIONu (1000U * 1000U * 1000U) #define BILLION ((int64_t) 1000 * 1000 * 1000)
#define FILETIME_TO_UINT(filetime) \ static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
(*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu) filetime -= 116444736 * BILLION;
ts->tv_sec = (long) (filetime / (10 * MILLION));
#define FILETIME_TO_TIME_T(filetime) \ ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U);
(FILETIME_TO_UINT(filetime) / (10u * MILLIONu)) if (ts->tv_nsec < 0) {
ts->tv_sec -= 1;
#define FILETIME_TO_TIME_NS(filetime, secs) \ ts->tv_nsec += 1e9;
((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U) }
}
#define FILETIME_TO_TIMESPEC(ts, filetime) \
do { \
(ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
(ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
} while(0)
#define TIME_T_TO_FILETIME(time, filetime_ptr) \ #define TIME_T_TO_FILETIME(time, filetime_ptr) \
do { \ do { \
uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \ int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \
(uint64_t) 116444736 * BILLIONu; \ (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
} while(0) } while(0)
#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
@ -1224,7 +1218,8 @@ void fs__mkdir(uv_fs_t* req) {
SET_REQ_RESULT(req, 0); SET_REQ_RESULT(req, 0);
} else { } else {
SET_REQ_WIN32_ERROR(req, GetLastError()); SET_REQ_WIN32_ERROR(req, GetLastError());
if (req->sys_errno_ == ERROR_INVALID_NAME) if (req->sys_errno_ == ERROR_INVALID_NAME ||
req->sys_errno_ == ERROR_DIRECTORY)
req->result = UV_EINVAL; req->result = UV_EINVAL;
} }
} }
@ -1243,7 +1238,7 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
uint64_t v; uint64_t v;
char* path; char* path;
path = req->path; path = (char*)req->path;
len = wcslen(req->file.pathw); len = wcslen(req->file.pathw);
ep = req->file.pathw + len; ep = req->file.pathw + len;
if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
@ -1791,10 +1786,14 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
((_S_IREAD | _S_IWRITE) >> 6); ((_S_IREAD | _S_IWRITE) >> 6);
FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime); uv__filetime_to_timespec(&statbuf->st_atim,
FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime); file_info.BasicInformation.LastAccessTime.QuadPart);
FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime); uv__filetime_to_timespec(&statbuf->st_ctim,
FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime); file_info.BasicInformation.ChangeTime.QuadPart);
uv__filetime_to_timespec(&statbuf->st_mtim,
file_info.BasicInformation.LastWriteTime.QuadPart);
uv__filetime_to_timespec(&statbuf->st_birthtim,
file_info.BasicInformation.CreationTime.QuadPart);
statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;

View File

@ -115,8 +115,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/* /*
* Pipes * Pipes
*/ */
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, int uv__create_stdio_pipe_pair(uv_loop_t* loop,
char* name, size_t nameSize); uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);

View File

@ -202,17 +202,17 @@ static void close_pipe(uv_pipe_t* pipe) {
} }
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, static int uv__pipe_server(
char* name, size_t nameSize) { HANDLE* pipeHandle_ptr, DWORD access,
char* name, size_t nameSize, char* random) {
HANDLE pipeHandle; HANDLE pipeHandle;
int err; int err;
char* ptr = (char*)handle;
for (;;) { for (;;) {
uv_unique_pipe_name(ptr, name, nameSize); uv_unique_pipe_name(random, name, nameSize);
pipeHandle = CreateNamedPipeA(name, pipeHandle = CreateNamedPipeA(name,
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, access | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
NULL); NULL);
@ -226,20 +226,11 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
goto error; goto error;
} }
/* Pipe name collision. Increment the pointer and try again. */ /* Pipe name collision. Increment the random number and try again. */
ptr++; random++;
} }
if (CreateIoCompletionPort(pipeHandle, *pipeHandle_ptr = pipeHandle;
loop->iocp,
(ULONG_PTR)handle,
0) == NULL) {
err = GetLastError();
goto error;
}
uv_pipe_connection_init(handle);
handle->handle = pipeHandle;
return 0; return 0;
@ -251,6 +242,214 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
} }
static int uv__create_pipe_pair(
HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr,
unsigned int server_flags, unsigned int client_flags,
int inherit_client, char* random) {
/* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access;
DWORD client_access;
HANDLE server_pipe;
HANDLE client_pipe;
int err;
server_pipe = INVALID_HANDLE_VALUE;
client_pipe = INVALID_HANDLE_VALUE;
server_access = 0;
if (server_flags & UV_READABLE_PIPE)
server_access |= PIPE_ACCESS_INBOUND;
if (server_flags & UV_WRITABLE_PIPE)
server_access |= PIPE_ACCESS_OUTBOUND;
if (server_flags & UV_NONBLOCK_PIPE)
server_access |= FILE_FLAG_OVERLAPPED;
server_access |= WRITE_DAC;
client_access = 0;
if (client_flags & UV_READABLE_PIPE)
client_access |= GENERIC_READ;
else
client_access |= FILE_READ_ATTRIBUTES;
if (client_flags & UV_WRITABLE_PIPE)
client_access |= GENERIC_WRITE;
else
client_access |= FILE_WRITE_ATTRIBUTES;
client_access |= WRITE_DAC;
/* Create server pipe handle. */
err = uv__pipe_server(&server_pipe,
server_access,
pipe_name,
sizeof(pipe_name),
random);
if (err)
goto error;
/* Create client pipe handle. */
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = inherit_client;
client_pipe = CreateFileA(pipe_name,
client_access,
0,
&sa,
OPEN_EXISTING,
(client_flags & UV_NONBLOCK_PIPE) ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (client_pipe == INVALID_HANDLE_VALUE) {
err = GetLastError();
goto error;
}
#ifndef NDEBUG
/* Validate that the pipe was opened in the right mode. */
{
DWORD mode;
BOOL r;
r = GetNamedPipeHandleState(client_pipe, &mode, NULL, NULL, NULL, NULL, 0);
if (r == TRUE) {
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
} else {
fprintf(stderr, "libuv assertion failure: GetNamedPipeHandleState failed\n");
}
}
#endif
/* Do a blocking ConnectNamedPipe. This should not block because we have
* both ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
err = GetLastError();
goto error;
}
}
*client_pipe_ptr = client_pipe;
*server_pipe_ptr = server_pipe;
return 0;
error:
if (server_pipe != INVALID_HANDLE_VALUE)
CloseHandle(server_pipe);
if (client_pipe != INVALID_HANDLE_VALUE)
CloseHandle(client_pipe);
return err;
}
int uv_pipe(uv_file fds[2], int read_flags, int write_flags) {
uv_file temp[2];
int err;
HANDLE readh;
HANDLE writeh;
/* Make the server side the inbound (read) end, */
/* so that both ends will have FILE_READ_ATTRIBUTES permission. */
/* TODO: better source of local randomness than &fds? */
read_flags |= UV_READABLE_PIPE;
write_flags |= UV_WRITABLE_PIPE;
err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]);
if (err != 0)
return err;
temp[0] = _open_osfhandle((intptr_t) readh, 0);
if (temp[0] == -1) {
if (errno == UV_EMFILE)
err = UV_EMFILE;
else
err = UV_UNKNOWN;
CloseHandle(readh);
CloseHandle(writeh);
return err;
}
temp[1] = _open_osfhandle((intptr_t) writeh, 0);
if (temp[1] == -1) {
if (errno == UV_EMFILE)
err = UV_EMFILE;
else
err = UV_UNKNOWN;
_close(temp[0]);
CloseHandle(writeh);
return err;
}
fds[0] = temp[0];
fds[1] = temp[1];
return 0;
}
int uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
/* The parent_pipe is always the server_pipe and kept by libuv.
* The child_pipe is always the client_pipe and is passed to the child.
* The flags are specified with respect to their usage in the child. */
HANDLE server_pipe;
HANDLE client_pipe;
unsigned int server_flags;
unsigned int client_flags;
int err;
server_pipe = INVALID_HANDLE_VALUE;
client_pipe = INVALID_HANDLE_VALUE;
server_flags = 0;
client_flags = 0;
if (flags & UV_READABLE_PIPE) {
/* The server needs inbound (read) access too, otherwise CreateNamedPipe()
* won't give us the FILE_READ_ATTRIBUTES permission. We need that to probe
* the state of the write buffer when we're trying to shutdown the pipe. */
server_flags |= UV_READABLE_PIPE | UV_WRITABLE_PIPE;
client_flags |= UV_READABLE_PIPE;
}
if (flags & UV_WRITABLE_PIPE) {
server_flags |= UV_READABLE_PIPE;
client_flags |= UV_WRITABLE_PIPE;
}
server_flags |= UV_NONBLOCK_PIPE;
if (flags & UV_NONBLOCK_PIPE || parent_pipe->ipc) {
client_flags |= UV_NONBLOCK_PIPE;
}
err = uv__create_pipe_pair(&server_pipe, &client_pipe,
server_flags, client_flags, 1, (char*) server_pipe);
if (err)
goto error;
if (CreateIoCompletionPort(server_pipe,
loop->iocp,
(ULONG_PTR) parent_pipe,
0) == NULL) {
err = GetLastError();
goto error;
}
uv_pipe_connection_init(parent_pipe);
parent_pipe->handle = server_pipe;
*child_pipe_ptr = client_pipe;
/* The server end is now readable and/or writable. */
if (flags & UV_READABLE_PIPE)
parent_pipe->flags |= UV_HANDLE_WRITABLE;
if (flags & UV_WRITABLE_PIPE)
parent_pipe->flags |= UV_HANDLE_READABLE;
return 0;
error:
if (server_pipe != INVALID_HANDLE_VALUE)
CloseHandle(server_pipe);
if (client_pipe != INVALID_HANDLE_VALUE)
CloseHandle(client_pipe);
return err;
}
static int uv_set_pipe_handle(uv_loop_t* loop, static int uv_set_pipe_handle(uv_loop_t* loop,
uv_pipe_t* handle, uv_pipe_t* handle,
HANDLE pipeHandle, HANDLE pipeHandle,
@ -712,9 +911,8 @@ error:
handle->name = NULL; handle->name = NULL;
} }
if (pipeHandle != INVALID_HANDLE_VALUE) { if (pipeHandle != INVALID_HANDLE_VALUE)
CloseHandle(pipeHandle); CloseHandle(pipeHandle);
}
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, err); SET_REQ_ERROR(req, err);

View File

@ -488,7 +488,8 @@ static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
assert(handle->type == UV_POLL); assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING)); assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
UV_PRIORITIZED)) == 0);
handle->events = events; handle->events = events;
handle->poll_cb = cb; handle->poll_cb = cb;

View File

@ -95,102 +95,6 @@ void uv_disable_stdio_inheritance(void) {
} }
static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access = 0;
DWORD client_access = 0;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
int err;
int overlap;
if (flags & UV_READABLE_PIPE) {
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
* give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
* state of the write buffer when we're trying to shutdown the pipe. */
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
}
if (flags & UV_WRITABLE_PIPE) {
server_access |= PIPE_ACCESS_INBOUND;
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
}
/* Create server pipe handle. */
err = uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name));
if (err)
goto error;
/* Create child pipe handle. */
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
child_pipe = CreateFileA(pipe_name,
client_access,
0,
&sa,
OPEN_EXISTING,
overlap ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (child_pipe == INVALID_HANDLE_VALUE) {
err = GetLastError();
goto error;
}
#ifndef NDEBUG
/* Validate that the pipe was opened in the right mode. */
{
DWORD mode;
BOOL r = GetNamedPipeHandleState(child_pipe,
&mode,
NULL,
NULL,
NULL,
NULL,
0);
assert(r == TRUE);
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
}
#endif
/* Do a blocking ConnectNamedPipe. This should not block because we have both
* ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
err = GetLastError();
goto error;
}
}
/* The server end is now readable and/or writable. */
if (flags & UV_READABLE_PIPE)
server_pipe->flags |= UV_HANDLE_WRITABLE;
if (flags & UV_WRITABLE_PIPE)
server_pipe->flags |= UV_HANDLE_READABLE;
*child_pipe_ptr = child_pipe;
return 0;
error:
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
uv_pipe_cleanup(loop, server_pipe);
}
if (child_pipe != INVALID_HANDLE_VALUE) {
CloseHandle(child_pipe);
}
return err;
}
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process; HANDLE current_process;

View File

@ -642,7 +642,7 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
assert(r==nb); assert(r==nb);
B[nb] = L'\0'; B[nb] = L'\0';
while (1) { for (;;) {
wchar_t AA = *A++; wchar_t AA = *A++;
wchar_t BB = *B++; wchar_t BB = *B++;
if (AA < BB) { if (AA < BB) {

View File

@ -65,18 +65,11 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
} }
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv__read_start(uv_stream_t* handle,
uv_alloc_cb alloc_cb,
uv_read_cb read_cb) { uv_read_cb read_cb) {
int err; int err;
if (handle->flags & UV_HANDLE_READING) {
return UV_EALREADY;
}
if (!(handle->flags & UV_HANDLE_READABLE)) {
return UV_ENOTCONN;
}
err = ERROR_INVALID_PARAMETER; err = ERROR_INVALID_PARAMETER;
switch (handle->type) { switch (handle->type) {
case UV_TCP: case UV_TCP:
@ -195,6 +188,16 @@ int uv_try_write(uv_stream_t* stream,
} }
int uv_try_write2(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle) {
if (send_handle != NULL)
return UV_EAGAIN;
return uv_try_write(stream, bufs, nbufs);
}
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;

View File

@ -236,12 +236,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING && if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) { handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->socket == INVALID_SOCKET);
if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
closesocket(handle->socket);
handle->socket = INVALID_SOCKET;
handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
}
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
@ -599,6 +594,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
} }
} }
/* If this flag is set, we already made this listen call in xfer. */
if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
listen(handle->socket, backlog) == SOCKET_ERROR) { listen(handle->socket, backlog) == SOCKET_ERROR) {
return WSAGetLastError(); return WSAGetLastError();
@ -769,7 +765,7 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) {
} }
// Check if Windows version is 10.0.16299 or later // Check if Windows version is 10.0.16299 or later
static int uv__is_fast_loopback_fail_supported() { static int uv__is_fast_loopback_fail_supported(void) {
OSVERSIONINFOW os_info; OSVERSIONINFOW os_info;
if (!pRtlGetVersion) if (!pRtlGetVersion)
return 0; return 0;
@ -800,9 +796,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
if (err) if (err)
return err; return err;
if (handle->delayed_error) { if (handle->delayed_error != 0)
return handle->delayed_error; goto out;
}
if (!(handle->flags & UV_HANDLE_BOUND)) { if (!(handle->flags & UV_HANDLE_BOUND)) {
if (addrlen == sizeof(uv_addr_ip4_any_)) { if (addrlen == sizeof(uv_addr_ip4_any_)) {
@ -815,8 +810,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return err; return err;
if (handle->delayed_error) if (handle->delayed_error != 0)
return handle->delayed_error; goto out;
} }
if (!handle->tcp.conn.func_connectex) { if (!handle->tcp.conn.func_connectex) {
@ -844,11 +839,21 @@ static int uv_tcp_try_connect(uv_connect_t* req,
NULL); NULL);
} }
out:
UV_REQ_INIT(req, UV_CONNECT); UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle; req->handle = (uv_stream_t*) handle;
req->cb = cb; req->cb = cb;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
if (handle->delayed_error != 0) {
/* Process the req without IOCP. */
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*)req);
return 0;
}
success = handle->tcp.conn.func_connectex(handle->socket, success = handle->tcp.conn.func_connectex(handle->socket,
(const struct sockaddr*) &converted, (const struct sockaddr*) &converted,
addrlen, addrlen,
@ -1015,6 +1020,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
*/ */
err = WSAECONNRESET; err = WSAECONNRESET;
} }
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
handle->read_cb((uv_stream_t*)handle, handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(err), uv_translate_sys_error(err),
@ -1096,6 +1102,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
* Unix. */ * Unix. */
err = WSAECONNRESET; err = WSAECONNRESET;
} }
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
handle->read_cb((uv_stream_t*)handle, handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(err), uv_translate_sys_error(err),
@ -1149,10 +1156,15 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
} }
handle->stream.conn.write_reqs_pending--; handle->stream.conn.write_reqs_pending--;
if (handle->stream.conn.shutdown_req != NULL && if (handle->stream.conn.write_reqs_pending == 0) {
handle->stream.conn.write_reqs_pending == 0) { if (handle->flags & UV_HANDLE_CLOSING) {
closesocket(handle->socket);
handle->socket = INVALID_SOCKET;
}
if (handle->stream.conn.shutdown_req != NULL) {
uv_want_endgame(loop, (uv_handle_t*)handle); uv_want_endgame(loop, (uv_handle_t*)handle);
} }
}
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
@ -1215,7 +1227,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
UNREGISTER_HANDLE_REQ(loop, handle, req); UNREGISTER_HANDLE_REQ(loop, handle, req);
err = 0; err = 0;
if (REQ_SUCCESS(req)) { if (handle->delayed_error) {
/* To smooth over the differences between unixes errors that
* were reported synchronously on the first connect can be delayed
* until the next tick--which is now.
*/
err = handle->delayed_error;
handle->delayed_error = 0;
} else if (REQ_SUCCESS(req)) {
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
/* use UV_ECANCELED for consistency with Unix */ /* use UV_ECANCELED for consistency with Unix */
err = ERROR_OPERATION_ABORTED; err = ERROR_OPERATION_ABORTED;
@ -1320,7 +1339,7 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
if (handle->socket != INVALID_SOCKET) { if (handle->socket != INVALID_SOCKET) {
err = uv__tcp_nodelay(handle, handle->socket, enable); err = uv__tcp_nodelay(handle, handle->socket, enable);
if (err) if (err)
return err; return uv_translate_sys_error(err);
} }
if (enable) { if (enable) {
@ -1339,7 +1358,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
if (handle->socket != INVALID_SOCKET) { if (handle->socket != INVALID_SOCKET) {
err = uv__tcp_keepalive(handle, handle->socket, enable, delay); err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
if (err) if (err)
return err; return uv_translate_sys_error(err);
} }
if (enable) { if (enable) {
@ -1386,9 +1405,24 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
} }
static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) {
SOCKET socket = tcp->socket; SOCKET socket;
int non_ifs_lsp; int non_ifs_lsp;
int reading;
int writing;
socket = tcp->socket;
reading = tcp->flags & UV_HANDLE_READING;
writing = tcp->stream.conn.write_reqs_pending > 0;
if (!reading && !writing)
return;
/* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel
* them each explicitly with CancelIoEx (like unix). */
if (reading)
CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
if (writing)
CancelIo((HANDLE) socket);
/* Check if we have any non-IFS LSPs stacked on top of TCP */ /* Check if we have any non-IFS LSPs stacked on top of TCP */
non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
@ -1408,71 +1442,41 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
NULL, NULL,
NULL) != 0) { NULL) != 0) {
/* Failed. We can't do CancelIo. */ /* Failed. We can't do CancelIo. */
return -1; return;
} }
} }
assert(socket != 0 && socket != INVALID_SOCKET); assert(socket != 0 && socket != INVALID_SOCKET);
if (!CancelIo((HANDLE) socket)) { if (socket != tcp->socket) {
return GetLastError(); if (reading)
CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
if (writing)
CancelIo((HANDLE) socket);
} }
/* It worked. */
return 0;
} }
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
int close_socket = 1; if (tcp->flags & UV_HANDLE_CONNECTION) {
uv_tcp_try_cancel_reqs(tcp);
if (tcp->flags & UV_HANDLE_READ_PENDING) { if (tcp->flags & UV_HANDLE_READING) {
/* In order for winsock to do a graceful close there must not be any any uv_read_stop((uv_stream_t*) tcp);
* pending reads, or the socket must be shut down for writing */
if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
/* Just do shutdown on non-shared sockets, which ensures graceful close. */
shutdown(tcp->socket, SD_SEND);
} else if (uv_tcp_try_cancel_io(tcp) == 0) {
/* In case of a shared socket, we try to cancel all outstanding I/O,. If
* that works, don't close the socket yet - wait for the read req to
* return and close the socket in uv_tcp_endgame. */
close_socket = 0;
} else {
/* When cancelling isn't possible - which could happen when an LSP is
* present on an old Windows version, we will have to close the socket
* with a read pending. That is not nice because trailing sent bytes may
* not make it to the other side. */
} }
} else {
} else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && if (tcp->tcp.serv.accept_reqs != NULL) {
tcp->tcp.serv.accept_reqs != NULL) { /* First close the incoming sockets to cancel the accept operations before
/* Under normal circumstances closesocket() will ensure that all pending * we free their resources. */
* accept reqs are canceled. However, when the socket is shared the
* presence of another reference to the socket in another process will keep
* the accept reqs going, so we have to ensure that these are canceled. */
if (uv_tcp_try_cancel_io(tcp) != 0) {
/* When cancellation is not possible, there is another option: we can
* close the incoming sockets, which will also cancel the accept
* operations. However this is not cool because we might inadvertently
* close a socket that just accepted a new connection, which will cause
* the connection to be aborted. */
unsigned int i; unsigned int i;
for (i = 0; i < uv_simultaneous_server_accepts; i++) { for (i = 0; i < uv_simultaneous_server_accepts; i++) {
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
if (req->accept_socket != INVALID_SOCKET && if (req->accept_socket != INVALID_SOCKET) {
!HasOverlappedIoCompleted(&req->u.io.overlapped)) {
closesocket(req->accept_socket); closesocket(req->accept_socket);
req->accept_socket = INVALID_SOCKET; req->accept_socket = INVALID_SOCKET;
} }
} }
} }
} assert(!(tcp->flags & UV_HANDLE_READING));
if (tcp->flags & UV_HANDLE_READING) {
tcp->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, tcp);
} }
if (tcp->flags & UV_HANDLE_LISTENING) { if (tcp->flags & UV_HANDLE_LISTENING) {
@ -1480,10 +1484,15 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
DECREASE_ACTIVE_COUNT(loop, tcp); DECREASE_ACTIVE_COUNT(loop, tcp);
} }
if (close_socket) { /* If any overlapped req failed to cancel, calling `closesocket` now would
* cause Win32 to send an RST packet. Try to avoid that for writes, if
* possibly applicable, by waiting to process the completion notifications
* first (which typically should be cancellations). There's not much we can
* do about canceled reads, which also will generate an RST packet. */
if (!(tcp->flags & UV_HANDLE_CONNECTION) ||
tcp->stream.conn.write_reqs_pending == 0) {
closesocket(tcp->socket); closesocket(tcp->socket);
tcp->socket = INVALID_SOCKET; tcp->socket = INVALID_SOCKET;
tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
} }
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
@ -1571,3 +1580,118 @@ int uv__tcp_connect(uv_connect_t* req,
return 0; return 0;
} }
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
/* Added in Windows 7 SP1. Specify this to avoid race conditions, */
/* but also manually clear the inherit flag in case this failed. */
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
SOCKET server = INVALID_SOCKET;
SOCKET client0 = INVALID_SOCKET;
SOCKET client1 = INVALID_SOCKET;
SOCKADDR_IN name;
LPFN_ACCEPTEX func_acceptex;
WSAOVERLAPPED overlap;
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32];
int namelen;
int err;
DWORD bytes;
DWORD flags;
DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT;
DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT;
if (flags0 & UV_NONBLOCK_PIPE)
client0_flags |= WSA_FLAG_OVERLAPPED;
if (flags1 & UV_NONBLOCK_PIPE)
client1_flags |= WSA_FLAG_OVERLAPPED;
server = WSASocketW(AF_INET, type, protocol, NULL, 0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
if (server == INVALID_SOCKET)
goto wsaerror;
if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0))
goto error;
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
name.sin_port = 0;
if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0)
goto wsaerror;
if (listen(server, 1) != 0)
goto wsaerror;
namelen = sizeof(name);
if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0)
goto wsaerror;
client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags);
if (client0 == INVALID_SOCKET)
goto wsaerror;
if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0))
goto error;
if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0)
goto wsaerror;
client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags);
if (client1 == INVALID_SOCKET)
goto wsaerror;
if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
goto error;
if (!uv_get_acceptex_function(server, &func_acceptex)) {
err = WSAEAFNOSUPPORT;
goto cleanup;
}
memset(&overlap, 0, sizeof(overlap));
if (!func_acceptex(server,
client1,
accept_buffer,
0,
sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage),
&bytes,
&overlap)) {
err = WSAGetLastError();
if (err == ERROR_IO_PENDING) {
/* Result should complete immediately, since we already called connect,
* but emperically, we sometimes have to poll the kernel a couple times
* until it notices that. */
while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) {
err = WSAGetLastError();
if (err != WSA_IO_INCOMPLETE)
goto cleanup;
SwitchToThread();
}
}
else {
goto cleanup;
}
}
if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char*) &server, sizeof(server)) != 0) {
goto wsaerror;
}
closesocket(server);
fds[0] = client0;
fds[1] = client1;
return 0;
wsaerror:
err = WSAGetLastError();
goto cleanup;
error:
err = GetLastError();
goto cleanup;
cleanup:
if (server != INVALID_SOCKET)
closesocket(server);
if (client0 != INVALID_SOCKET)
closesocket(client0);
if (client1 != INVALID_SOCKET)
closesocket(client1);
assert(err);
return uv_translate_sys_error(err);
}

View File

@ -284,7 +284,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
handle->flags &= ~UV_HANDLE_ZERO_READ; handle->flags &= ~UV_HANDLE_ZERO_READ;
handle->recv_buffer = uv_buf_init(NULL, 0); handle->recv_buffer = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer);
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
return; return;
@ -501,7 +501,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
/* Do a nonblocking receive. /* Do a nonblocking receive.
* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ * TODO: try to read multiple datagrams at once. FIONREAD maybe? */
buf = uv_buf_init(NULL, 0); buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
if (buf.base == NULL || buf.len == 0) { if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
goto done; goto done;

View File

@ -1664,26 +1664,33 @@ int uv_os_unsetenv(const char* name) {
int uv_os_gethostname(char* buffer, size_t* size) { int uv_os_gethostname(char* buffer, size_t* size) {
char buf[UV_MAXHOSTNAMESIZE]; WCHAR buf[UV_MAXHOSTNAMESIZE];
size_t len; size_t len;
char* utf8_str;
int convert_result;
if (buffer == NULL || size == NULL || *size == 0) if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL; return UV_EINVAL;
uv__once_init(); /* Initialize winsock */ uv__once_init(); /* Initialize winsock */
if (gethostname(buf, sizeof(buf)) != 0) if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
return uv_translate_sys_error(WSAGetLastError()); return uv_translate_sys_error(WSAGetLastError());
buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
len = strlen(buf);
if (convert_result != 0)
return convert_result;
len = strlen(utf8_str);
if (len >= *size) { if (len >= *size) {
*size = len + 1; *size = len + 1;
uv__free(utf8_str);
return UV_ENOBUFS; return UV_ENOBUFS;
} }
memcpy(buffer, buf, len + 1); memcpy(buffer, utf8_str, len + 1);
uv__free(utf8_str);
*size = len; *size = len;
return 0; return 0;
} }

View File

@ -68,7 +68,7 @@ static int test_async_pummel(int nthreads) {
int i; int i;
tids = calloc(nthreads, sizeof(tids[0])); tids = calloc(nthreads, sizeof(tids[0]));
ASSERT(tids != NULL); ASSERT_NOT_NULL(tids);
ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb)); ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb));
ACCESS_ONCE(const char*, handle.data) = running; ACCESS_ONCE(const char*, handle.data) = running;

View File

@ -79,7 +79,7 @@ static int test_async(int nthreads) {
int i; int i;
threads = calloc(nthreads, sizeof(threads[0])); threads = calloc(nthreads, sizeof(threads[0]));
ASSERT(threads != NULL); ASSERT_NOT_NULL(threads);
for (i = 0; i < nthreads; i++) { for (i = 0; i < nthreads; i++) {
ctx = threads + i; ctx = threads + i;

View File

@ -86,7 +86,7 @@ BENCHMARK_IMPL(million_async) {
timeout = 5000; timeout = 5000;
container = malloc(sizeof(*container)); container = malloc(sizeof(*container));
ASSERT(container != NULL); ASSERT_NOT_NULL(container);
container->async_events = 0; container->async_events = 0;
container->handles_seen = 0; container->handles_seen = 0;

View File

@ -49,7 +49,7 @@ BENCHMARK_IMPL(million_timers) {
int i; int i;
timers = malloc(NUM_TIMERS * sizeof(timers[0])); timers = malloc(NUM_TIMERS * sizeof(timers[0]));
ASSERT(timers != NULL); ASSERT_NOT_NULL(timers);
loop = uv_default_loop(); loop = uv_default_loop();
timeout = 0; timeout = 0;

View File

@ -114,7 +114,7 @@ static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) {
buf = uv_buf_init("PING", 4); buf = uv_buf_init("PING", 4);
sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe); sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
pc = calloc(1, sizeof(*pc)); pc = calloc(1, sizeof(*pc));
ASSERT(pc != NULL); ASSERT_NOT_NULL(pc);
if (ipc_pipe->type == UV_TCP) if (ipc_pipe->type == UV_TCP)
ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle)); ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle));
@ -295,7 +295,7 @@ static void sv_connection_cb(uv_stream_t* server_handle, int status) {
ASSERT(status == 0); ASSERT(status == 0);
storage = malloc(sizeof(*storage)); storage = malloc(sizeof(*storage));
ASSERT(storage != NULL); ASSERT_NOT_NULL(storage);
if (server_handle->type == UV_TCP) if (server_handle->type == UV_TCP)
ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage)); ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage));
@ -372,8 +372,8 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) {
servers = calloc(num_servers, sizeof(servers[0])); servers = calloc(num_servers, sizeof(servers[0]));
clients = calloc(num_clients, sizeof(clients[0])); clients = calloc(num_clients, sizeof(clients[0]));
ASSERT(servers != NULL); ASSERT_NOT_NULL(servers);
ASSERT(clients != NULL); ASSERT_NOT_NULL(clients);
/* We're making the assumption here that from the perspective of the /* We're making the assumption here that from the perspective of the
* OS scheduler, threads are functionally equivalent to and interchangeable * OS scheduler, threads are functionally equivalent to and interchangeable

View File

@ -114,11 +114,11 @@ static void connect_cb(uv_connect_t* req, int status) {
return; return;
} }
ASSERT(req != NULL); ASSERT_NOT_NULL(req);
ASSERT(status == 0); ASSERT(status == 0);
conn = (conn_rec*)req->data; conn = (conn_rec*)req->data;
ASSERT(conn != NULL); ASSERT_NOT_NULL(conn);
#if DEBUG #if DEBUG
printf("connect_cb %d\n", conn->i); printf("connect_cb %d\n", conn->i);
@ -137,7 +137,7 @@ static void connect_cb(uv_connect_t* req, int status) {
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
ASSERT(stream != NULL); ASSERT_NOT_NULL(stream);
#if DEBUG #if DEBUG
printf("read_cb %d\n", p->i); printf("read_cb %d\n", p->i);
@ -161,7 +161,7 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
static void close_cb(uv_handle_t* handle) { static void close_cb(uv_handle_t* handle) {
conn_rec* p = (conn_rec*)handle->data; conn_rec* p = (conn_rec*)handle->data;
ASSERT(handle != NULL); ASSERT_NOT_NULL(handle);
closed_streams++; closed_streams++;
#if DEBUG #if DEBUG

View File

@ -390,6 +390,7 @@ HELPER_IMPL(tcp_pump_server) {
r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb); r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
ASSERT(r == 0); ASSERT(r == 0);
notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT); uv_run(loop, UV_RUN_DEFAULT);
return 0; return 0;
@ -411,6 +412,7 @@ HELPER_IMPL(pipe_pump_server) {
r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb); r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb);
ASSERT(r == 0); ASSERT(r == 0);
notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT); uv_run(loop, UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();

View File

@ -71,7 +71,7 @@ static void connect_cb(uv_connect_t* req, int status) {
static void write_cb(uv_write_t* req, int status) { static void write_cb(uv_write_t* req, int status) {
ASSERT(req != NULL); ASSERT_NOT_NULL(req);
ASSERT(status == 0); ASSERT(status == 0);
write_cb_called++; write_cb_called++;
} }
@ -103,7 +103,7 @@ BENCHMARK_IMPL(tcp_write_batch) {
int r; int r;
write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS); write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS);
ASSERT(write_reqs != NULL); ASSERT_NOT_NULL(write_reqs);
/* Prepare the data to write out. */ /* Prepare the data to write out. */
for (i = 0; i < NUM_WRITE_REQS; i++) { for (i = 0; i < NUM_WRITE_REQS; i++) {

View File

@ -72,7 +72,7 @@ static void alloc_cb(uv_handle_t* handle,
static void send_cb(uv_udp_send_t* req, int status) { static void send_cb(uv_udp_send_t* req, int status) {
struct sender_state* s; struct sender_state* s;
ASSERT(req != NULL); ASSERT_NOT_NULL(req);
if (status != 0) { if (status != 0) {
ASSERT(status == UV_ECANCELED); ASSERT(status == UV_ECANCELED);
@ -127,7 +127,7 @@ static void recv_cb(uv_udp_t* handle,
static void close_cb(uv_handle_t* handle) { static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL); ASSERT_NOT_NULL(handle);
close_cb_called++; close_cb_called++;
} }
@ -179,11 +179,11 @@ static int pummel(unsigned int n_senders,
uv_unref((uv_handle_t*)&s->udp_handle); uv_unref((uv_handle_t*)&s->udp_handle);
} }
bufs[0] = uv_buf_init(EXPECTED + 0, 10); bufs[0] = uv_buf_init(&EXPECTED[0], 10);
bufs[1] = uv_buf_init(EXPECTED + 10, 10); bufs[1] = uv_buf_init(&EXPECTED[10], 10);
bufs[2] = uv_buf_init(EXPECTED + 20, 10); bufs[2] = uv_buf_init(&EXPECTED[20], 10);
bufs[3] = uv_buf_init(EXPECTED + 30, 10); bufs[3] = uv_buf_init(&EXPECTED[30], 10);
bufs[4] = uv_buf_init(EXPECTED + 40, 5); bufs[4] = uv_buf_init(&EXPECTED[40], 5);
for (i = 0; i < n_senders; i++) { for (i = 0; i < n_senders; i++) {
struct sender_state* s = senders + i; struct sender_state* s = senders + i;

View File

@ -47,7 +47,7 @@ static void connection_cb(uv_stream_t* stream, int status) {
ASSERT(stream == (uv_stream_t*)&tcp_server); ASSERT(stream == (uv_stream_t*)&tcp_server);
conn = malloc(sizeof *conn); conn = malloc(sizeof *conn);
ASSERT(conn != NULL); ASSERT_NOT_NULL(conn);
r = uv_tcp_init(stream->loop, &conn->handle); r = uv_tcp_init(stream->loop, &conn->handle);
ASSERT(r == 0); ASSERT(r == 0);
@ -114,6 +114,7 @@ HELPER_IMPL(tcp4_blackhole_server) {
r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb); r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
ASSERT(r == 0); ASSERT(r == 0);
notify_parent_process();
r = uv_run(loop, UV_RUN_DEFAULT); r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(0 && "Blackhole server dropped out of event loop."); ASSERT(0 && "Blackhole server dropped out of event loop.");

View File

@ -280,7 +280,7 @@ static void on_connection(uv_stream_t* server, int status) {
ASSERT(status == 0); ASSERT(status == 0);
handle = (dnshandle*) malloc(sizeof *handle); handle = (dnshandle*) malloc(sizeof *handle);
ASSERT(handle != NULL); ASSERT_NOT_NULL(handle);
/* initialize read buffer state */ /* initialize read buffer state */
handle->state.prevbuf_ptr = 0; handle->state.prevbuf_ptr = 0;

View File

@ -65,25 +65,35 @@ static void after_write(uv_write_t* req, int status) {
static void after_shutdown(uv_shutdown_t* req, int status) { static void after_shutdown(uv_shutdown_t* req, int status) {
ASSERT_EQ(status, 0);
uv_close((uv_handle_t*) req->handle, on_close); uv_close((uv_handle_t*) req->handle, on_close);
free(req); free(req);
} }
static void on_shutdown(uv_shutdown_t* req, int status) {
ASSERT_EQ(status, 0);
free(req);
}
static void after_read(uv_stream_t* handle, static void after_read(uv_stream_t* handle,
ssize_t nread, ssize_t nread,
const uv_buf_t* buf) { const uv_buf_t* buf) {
int i; int i;
write_req_t *wr; write_req_t *wr;
uv_shutdown_t* sreq; uv_shutdown_t* sreq;
int shutdown = 0;
if (nread < 0) { if (nread < 0) {
/* Error or EOF */ /* Error or EOF */
ASSERT(nread == UV_EOF); ASSERT_EQ(nread, UV_EOF);
free(buf->base); free(buf->base);
sreq = malloc(sizeof* sreq); sreq = malloc(sizeof* sreq);
ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown)); if (uv_is_writable(handle)) {
ASSERT_EQ(0, uv_shutdown(sreq, handle, after_shutdown));
}
return; return;
} }
@ -96,29 +106,42 @@ static void after_read(uv_stream_t* handle,
/* /*
* Scan for the letter Q which signals that we should quit the server. * Scan for the letter Q which signals that we should quit the server.
* If we get QS it means close the stream. * If we get QS it means close the stream.
* If we get QSS it means shutdown the stream.
* If we get QSH it means disable linger before close the socket.
*/ */
if (!server_closed) {
for (i = 0; i < nread; i++) { for (i = 0; i < nread; i++) {
if (buf->base[i] == 'Q') { if (buf->base[i] == 'Q') {
if (i + 1 < nread && buf->base[i + 1] == 'S') { if (i + 1 < nread && buf->base[i + 1] == 'S') {
int reset = 0;
if (i + 2 < nread && buf->base[i + 2] == 'S')
shutdown = 1;
if (i + 2 < nread && buf->base[i + 2] == 'H')
reset = 1;
if (reset && handle->type == UV_TCP)
ASSERT_EQ(0, uv_tcp_close_reset((uv_tcp_t*) handle, on_close));
else if (shutdown)
break;
else
uv_close((uv_handle_t*) handle, on_close);
free(buf->base); free(buf->base);
uv_close((uv_handle_t*)handle, on_close);
return; return;
} else { } else if (!server_closed) {
uv_close(server, on_server_close); uv_close(server, on_server_close);
server_closed = 1; server_closed = 1;
} }
} }
} }
}
wr = (write_req_t*) malloc(sizeof *wr); wr = (write_req_t*) malloc(sizeof *wr);
ASSERT(wr != NULL); ASSERT_NOT_NULL(wr);
wr->buf = uv_buf_init(buf->base, nread); wr->buf = uv_buf_init(buf->base, nread);
if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
FATAL("uv_write failed"); FATAL("uv_write failed");
} }
if (shutdown)
ASSERT_EQ(0, uv_shutdown(malloc(sizeof* sreq), handle, on_shutdown));
} }
@ -155,14 +178,14 @@ static void on_connection(uv_stream_t* server, int status) {
switch (serverType) { switch (serverType) {
case TCP: case TCP:
stream = malloc(sizeof(uv_tcp_t)); stream = malloc(sizeof(uv_tcp_t));
ASSERT(stream != NULL); ASSERT_NOT_NULL(stream);
r = uv_tcp_init(loop, (uv_tcp_t*)stream); r = uv_tcp_init(loop, (uv_tcp_t*)stream);
ASSERT(r == 0); ASSERT(r == 0);
break; break;
case PIPE: case PIPE:
stream = malloc(sizeof(uv_pipe_t)); stream = malloc(sizeof(uv_pipe_t));
ASSERT(stream != NULL); ASSERT_NOT_NULL(stream);
r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0); r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
ASSERT(r == 0); ASSERT(r == 0);
break; break;
@ -197,7 +220,7 @@ static uv_udp_send_t* send_alloc(void) {
} }
static void on_send(uv_udp_send_t* req, int status) { static void on_send(uv_udp_send_t* req, int status) {
ASSERT(req != NULL); ASSERT_NOT_NULL(req);
ASSERT(status == 0); ASSERT(status == 0);
req->data = send_freelist; req->data = send_freelist;
send_freelist = req; send_freelist = req;
@ -209,6 +232,7 @@ static void on_recv(uv_udp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned flags) { unsigned flags) {
uv_buf_t sndbuf; uv_buf_t sndbuf;
uv_udp_send_t* req;
if (nread == 0) { if (nread == 0) {
/* Everything OK, but nothing read. */ /* Everything OK, but nothing read. */
@ -218,8 +242,8 @@ static void on_recv(uv_udp_t* handle,
ASSERT(nread > 0); ASSERT(nread > 0);
ASSERT(addr->sa_family == AF_INET); ASSERT(addr->sa_family == AF_INET);
uv_udp_send_t* req = send_alloc(); req = send_alloc();
ASSERT(req != NULL); ASSERT_NOT_NULL(req);
sndbuf = uv_buf_init(rcvbuf->base, nread); sndbuf = uv_buf_init(rcvbuf->base, nread);
ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
} }
@ -228,7 +252,7 @@ static int tcp4_echo_start(int port) {
struct sockaddr_in addr; struct sockaddr_in addr;
int r; int r;
ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr)); ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr));
server = (uv_handle_t*)&tcpServer; server = (uv_handle_t*)&tcpServer;
serverType = TCP; serverType = TCP;

View File

@ -28,6 +28,16 @@
/* Actual benchmarks and helpers are defined in benchmark-list.h */ /* Actual benchmarks and helpers are defined in benchmark-list.h */
#include "benchmark-list.h" #include "benchmark-list.h"
#ifdef __MVS__
#include "zos-base.h"
/* Initialize environment and zoslib */
__attribute__((constructor)) void init() {
zoslib_config_t config;
init_zoslib_config(&config);
init_zoslib(config);
}
#endif
static int maybe_run_test(int argc, char **argv); static int maybe_run_test(int argc, char **argv);
@ -44,8 +54,6 @@ int main(int argc, char **argv) {
fflush(stderr); fflush(stderr);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS;
} }

Some files were not shown because too many files have changed in this diff Show More