deps: upgrade libuv to 1.10.0
Fixes: https://github.com/nodejs/node/issues/4351 Fixes: https://github.com/nodejs/node/issues/6763 Refs: https://github.com/nodejs/node/pull/8280 PR-URL: https://github.com/nodejs/node/pull/9267 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Родитель
2d472a36c1
Коммит
63243bcb33
|
@ -6,6 +6,9 @@
|
|||
*.pyc
|
||||
*.sdf
|
||||
*.suo
|
||||
.vs/
|
||||
*.VC.db
|
||||
*.VC.opendb
|
||||
core
|
||||
vgcore.*
|
||||
.buildstamp
|
||||
|
|
|
@ -11,6 +11,7 @@ Christoph Iserlohn <christoph.iserlohn@innoq.com>
|
|||
Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
|
||||
Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
|
||||
Frank Denis <github@pureftpd.org>
|
||||
Imran Iqbal <imrani@ca.ibm.com> <imran@imraniqbal.org>
|
||||
Isaac Z. Schlueter <i@izs.me>
|
||||
Jason Williams <necmon@yahoo.com>
|
||||
Justin Venus <justin.venus@gmail.com> <justin.venus@orbitz.com>
|
||||
|
|
|
@ -257,3 +257,23 @@ Michael Fero <michael.fero@datastax.com>
|
|||
Robert Jefe Lindstaedt <robert.lindstaedt@gmail.com>
|
||||
Myles Borins <myles.borins@gmail.com>
|
||||
Tony Theodore <tonyt@logyst.com>
|
||||
Jason Ginchereau <jasongin@microsoft.com>
|
||||
Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
|
||||
Pierre-Marie de Rodat <pmderodat@kawie.fr>
|
||||
Brian Maher <brian@brimworks.com>
|
||||
neevek <i@neevek.net>
|
||||
John Barboza <jbarboza@ca.ibm.com>
|
||||
liuxiaobo <icexile@qq.com>
|
||||
Michele Caini <michele.caini@gmail.com>
|
||||
Bartosz Sosnowski <bartosz@janeasystems.com>
|
||||
Matej Knopp <matej.knopp@gmail.com>
|
||||
sunjin.lee <kod21236@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Jeffrey Clark <dude@zaplabs.com>
|
||||
Bart Robinson <bartarr@gmail.com>
|
||||
Vit Gottwald <vit.gottwald@gmail.com>
|
||||
Vladimír Čunát <vladimir.cunat@nic.cz>
|
||||
Alex Hultman <alexhultman@gmail.com>
|
||||
Brad King <brad.king@kitware.com>
|
||||
Philippe Laferriere <laferriere.phil@gmail.com>
|
||||
Will Speak <lithiumflame@gmail.com>
|
||||
|
|
|
@ -165,5 +165,5 @@ not send out notifications when you add commits.
|
|||
[issue tracker]: https://github.com/libuv/libuv/issues
|
||||
[libuv mailing list]: http://groups.google.com/group/libuv
|
||||
[IRC]: http://webchat.freelibuv.net/?channels=libuv
|
||||
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
|
||||
[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html
|
||||
[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md
|
||||
|
|
|
@ -1,3 +1,221 @@
|
|||
2016.10.25, Version 1.10.0 (Stable)
|
||||
|
||||
Changes since version 1.9.1:
|
||||
|
||||
* Now working on version 1.9.2 (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: add cjihrig GPG ID (cjihrig)
|
||||
|
||||
* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé)
|
||||
|
||||
* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra
|
||||
Corretgé)
|
||||
|
||||
* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis)
|
||||
|
||||
* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno)
|
||||
|
||||
* license: libuv is no longer a Node project (Saúl Ibarra Corretgé)
|
||||
|
||||
* license: add license text we've been using for a while (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: add licensing information to README (Saúl Ibarra Corretgé)
|
||||
|
||||
* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic)
|
||||
|
||||
* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau)
|
||||
|
||||
* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal)
|
||||
|
||||
* doc: update docs with AIX related information (Imran Iqbal)
|
||||
|
||||
* test: silence build warnings (Kári Tristan Helgason)
|
||||
|
||||
* doc: add iWuzHere GPG ID (Imran Iqbal)
|
||||
|
||||
* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari)
|
||||
|
||||
* build: fix build on DragonFly (Michael Neumann)
|
||||
|
||||
* unix: correctly detect named pipes on DragonFly (Michael Neumann)
|
||||
|
||||
* test: make tap output the default (Ben Noordhuis)
|
||||
|
||||
* test: don't dump output for skipped tests (Ben Noordhuis)
|
||||
|
||||
* test: improve formatting of diagnostic messages (Ben Noordhuis)
|
||||
|
||||
* test: remove unused RETURN_TODO macro (Ben Noordhuis)
|
||||
|
||||
* doc: fix stream typos (Pierre-Marie de Rodat)
|
||||
|
||||
* doc: update coding style link (Imran Iqbal)
|
||||
|
||||
* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal)
|
||||
|
||||
* build: check for warnings for -fvisibility=hidden (Imran Iqbal)
|
||||
|
||||
* unix: remove unneeded TODO note (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: skip tty_pty test if pty is not available (Luca Bruno)
|
||||
|
||||
* sunos: set phys_addr of interface_address using ARP (Brian Maher)
|
||||
|
||||
* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé)
|
||||
|
||||
* unix: don't convert stat buffer when syscall fails (Ben Noordhuis)
|
||||
|
||||
* win: compare entire filename in watch events (cjihrig)
|
||||
|
||||
* doc: add a note on safe reuse of uv_write_t (neevek)
|
||||
|
||||
* linux: fix potential event loop stall (Ben Noordhuis)
|
||||
|
||||
* unix,win: make uv_get_process_title() stricter (cjihrig)
|
||||
|
||||
* test: close server before initiating new connection (John Barboza)
|
||||
|
||||
* test: account for multiple handles in one ipc read (John Barboza)
|
||||
|
||||
* unix: fix errno and retval conflict (liuxiaobo)
|
||||
|
||||
* doc: add missing entry in uv_fs_type enum (Michele Caini)
|
||||
|
||||
* unix: preserve loop->data across loop init/done (Ben Noordhuis)
|
||||
|
||||
* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis)
|
||||
|
||||
* win: simplify memory copy logic in fs.c (Ben Noordhuis)
|
||||
|
||||
* win: fix compilation on mingw (Bartosz Sosnowski)
|
||||
|
||||
* win: ensure 32-bit printf precision (Matej Knopp)
|
||||
|
||||
* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis)
|
||||
|
||||
* test: fix OOB buffer access (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: fix android build error. (sunjin.lee)
|
||||
|
||||
* win: evaluate timers when system wakes up (Bartosz Sosnowski)
|
||||
|
||||
* doc: add supported platforms description (Saúl Ibarra Corretgé)
|
||||
|
||||
* win: fix lstat reparse point without link data (Jason Ginchereau)
|
||||
|
||||
* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé)
|
||||
|
||||
* zos: add support for new platform (John Barboza)
|
||||
|
||||
* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé)
|
||||
|
||||
* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson)
|
||||
|
||||
* build: GNU/kFreeBSD support (Jeffrey Clark)
|
||||
|
||||
* zos: use PLO instruction for atomic operations (John Barboza)
|
||||
|
||||
* zos: use pthread helper functions (John Barboza)
|
||||
|
||||
* zos: implement uv__fs_futime (John Barboza)
|
||||
|
||||
* unix: expand range of values for usleep (John Barboza)
|
||||
|
||||
* zos: track unbound handles and bind before listen (John Barboza)
|
||||
|
||||
* test: improve tap output on test failures (Santiago Gimeno)
|
||||
|
||||
* test: refactor fs_event_close_in_callback (Julien Gilli)
|
||||
|
||||
* zos: implement uv__io_check_fd (John Barboza)
|
||||
|
||||
* unix: unneccessary use const qualifier in container_of (John Barboza)
|
||||
|
||||
* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal)
|
||||
|
||||
* doc: add santigimeno to maintainers (Santiago Gimeno)
|
||||
|
||||
* win: fix typo in type name (Saúl Ibarra Corretgé)
|
||||
|
||||
* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno)
|
||||
|
||||
* win: add disk read/write count to uv_getrusage (Imran Iqbal)
|
||||
|
||||
* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé)
|
||||
|
||||
* test: improve spawn_setuid_setgid test (Santiago Gimeno)
|
||||
|
||||
* test: fix building pty test on Android (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé)
|
||||
|
||||
* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé)
|
||||
|
||||
* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno)
|
||||
|
||||
* doc: update supported fields for uv_rusage_t (Imran Iqbal)
|
||||
|
||||
* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno)
|
||||
|
||||
* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno)
|
||||
|
||||
* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis)
|
||||
|
||||
* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson)
|
||||
|
||||
* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno)
|
||||
|
||||
* doc: add ABI tracker link to README (Saúl Ibarra Corretgé)
|
||||
|
||||
* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski)
|
||||
|
||||
* test: fix fs_fstat on Android (Vit Gottwald)
|
||||
|
||||
* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski)
|
||||
|
||||
* doc: add description of uv_handle_type (Vit Gottwald)
|
||||
|
||||
* build: use -pthreads for tests with autotools (Julien Gilli)
|
||||
|
||||
* win: fix leaky fs request buffer (Jason Ginchereau)
|
||||
|
||||
* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát)
|
||||
|
||||
* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman)
|
||||
|
||||
* win: fix winapi function pointer typedef syntax (Brad King)
|
||||
|
||||
* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis)
|
||||
|
||||
* test: make threadpool_cancel_single deterministic (Ben Noordhuis)
|
||||
|
||||
* test: make threadpool saturation reliable (Ben Noordhuis)
|
||||
|
||||
* unix: don't malloc in uv_thread_create() (Ben Noordhuis)
|
||||
|
||||
* unix: don't include CoreServices globally on macOS (Brad King)
|
||||
|
||||
* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere)
|
||||
|
||||
* win: remove unused static variables (Ben Noordhuis)
|
||||
|
||||
* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis)
|
||||
|
||||
* signal: replace pthread_once with uv_once (Santiago Gimeno)
|
||||
|
||||
* test: fix sign-compare warning (Will Speak)
|
||||
|
||||
* common: fix unused variable warning (Brad King)
|
||||
|
||||
|
||||
2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c
|
||||
|
||||
Changes since version 1.9.0:
|
||||
|
|
|
@ -1,5 +1,29 @@
|
|||
libuv is part of the Node project: http://nodejs.org/
|
||||
libuv may be distributed alone under Node's license:
|
||||
libuv is licensed for use as follows:
|
||||
|
||||
====
|
||||
Copyright (c) 2015-present libuv project contributors.
|
||||
|
||||
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.
|
||||
====
|
||||
|
||||
This license applies to parts of libuv originating from the
|
||||
https://github.com/joyent/libuv repository:
|
||||
|
||||
====
|
||||
|
||||
|
|
|
@ -7,8 +7,13 @@ libuv is currently managed by the following individuals:
|
|||
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
|
||||
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
|
||||
* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig))
|
||||
- GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig)
|
||||
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
|
||||
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
|
||||
* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere))
|
||||
- GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere)
|
||||
* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno))
|
||||
- GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno)
|
||||
* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
|
||||
- GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul)
|
||||
|
||||
|
@ -34,4 +39,3 @@ be garbage collected since nothing references it, so we'll create a tag for it:
|
|||
Commit the changes and push:
|
||||
|
||||
$ git push origin pubkey-saghul
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ libuv_la_SOURCES = src/fs-poll.c \
|
|||
if SUNOS
|
||||
# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
|
||||
# on other platforms complain that the argument is unused during compilation.
|
||||
libuv_la_CFLAGS += -pthread
|
||||
libuv_la_CFLAGS += -pthreads
|
||||
endif
|
||||
|
||||
if WINNT
|
||||
|
@ -48,6 +48,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \
|
|||
libuv_la_SOURCES += src/win/async.c \
|
||||
src/win/atomicops-inl.h \
|
||||
src/win/core.c \
|
||||
src/win/detect-wakeup.c \
|
||||
src/win/dl.c \
|
||||
src/win/error.c \
|
||||
src/win/fs-event.c \
|
||||
|
@ -128,7 +129,18 @@ EXTRA_DIST = test/fixtures/empty_file \
|
|||
|
||||
TESTS = test/run-tests
|
||||
check_PROGRAMS = test/run-tests
|
||||
if OS390
|
||||
test_run_tests_CFLAGS =
|
||||
else
|
||||
test_run_tests_CFLAGS = -Wno-long-long
|
||||
endif
|
||||
|
||||
if SUNOS
|
||||
# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
|
||||
# on other platforms complain that the argument is unused during compilation.
|
||||
test_run_tests_CFLAGS += -pthreads
|
||||
endif
|
||||
|
||||
test_run_tests_LDFLAGS =
|
||||
test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/dns-server.c \
|
||||
|
@ -215,6 +227,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||
test/test-socket-buffer-size.c \
|
||||
test/test-spawn.c \
|
||||
test/test-stdio-over-pipes.c \
|
||||
test/test-tcp-alloc-cb-fail.c \
|
||||
test/test-tcp-bind-error.c \
|
||||
test/test-tcp-bind6-error.c \
|
||||
test/test-tcp-close-accept.c \
|
||||
|
@ -246,6 +259,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||
test/test-timer.c \
|
||||
test/test-tmpdir.c \
|
||||
test/test-tty.c \
|
||||
test/test-udp-alloc-cb-fail.c \
|
||||
test/test-udp-bind.c \
|
||||
test/test-udp-create-socket-early.c \
|
||||
test/test-udp-dgram-too-big.c \
|
||||
|
@ -277,10 +291,29 @@ if AIX
|
|||
test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
test_run_tests_CFLAGS += -D_GNU_SOURCE
|
||||
endif
|
||||
|
||||
if SUNOS
|
||||
test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
|
||||
endif
|
||||
|
||||
if OS390
|
||||
test_run_tests_CFLAGS += -D_UNIX03_THREADS \
|
||||
-D_UNIX03_SOURCE \
|
||||
-D_OPEN_SYS_IF_EXT=1 \
|
||||
-D_OPEN_SYS_SOCK_IPV6 \
|
||||
-D_OPEN_MSGQ_EXT \
|
||||
-D_XOPEN_SOURCE_EXTENDED \
|
||||
-D_ALL_SOURCE \
|
||||
-D_LARGE_TIME_API \
|
||||
-D_OPEN_SYS_FILE_EXT \
|
||||
-DPATH_MAX=255 \
|
||||
-qCHARS=signed \
|
||||
-qXPLINK \
|
||||
-qFLOAT=IEEE
|
||||
endif
|
||||
|
||||
if AIX
|
||||
libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE
|
||||
|
@ -312,6 +345,7 @@ endif
|
|||
|
||||
if DRAGONFLY
|
||||
include_HEADERS += include/uv-bsd.h
|
||||
libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
|
@ -350,6 +384,28 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
|
|||
libuv_la_SOURCES += src/unix/sunos.c
|
||||
endif
|
||||
|
||||
if OS390
|
||||
include_HEADERS += include/pthread-fixes.h include/pthread-barrier.h
|
||||
libuv_la_CFLAGS += -D_UNIX03_THREADS \
|
||||
-D_UNIX03_SOURCE \
|
||||
-D_OPEN_SYS_IF_EXT=1 \
|
||||
-D_OPEN_MSGQ_EXT \
|
||||
-D_XOPEN_SOURCE_EXTENDED \
|
||||
-D_ALL_SOURCE \
|
||||
-D_LARGE_TIME_API \
|
||||
-D_OPEN_SYS_SOCK_IPV6 \
|
||||
-D_OPEN_SYS_FILE_EXT \
|
||||
-DUV_PLATFORM_SEM_T=int \
|
||||
-DPATH_MAX=255 \
|
||||
-qCHARS=signed \
|
||||
-qXPLINK \
|
||||
-qFLOAT=IEEE
|
||||
libuv_la_LDFLAGS += -qXPLINK
|
||||
libuv_la_SOURCES += src/unix/pthread-fixes.c \
|
||||
src/unix/pthread-barrier.c
|
||||
libuv_la_SOURCES += src/unix/os390.c
|
||||
endif
|
||||
|
||||
if HAVE_PKG_CONFIG
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = @PACKAGE_NAME@.pc
|
||||
|
|
|
@ -48,6 +48,7 @@ OBJS = src/fs-poll.o \
|
|||
src/version.o \
|
||||
src/win/async.o \
|
||||
src/win/core.o \
|
||||
src/win/detect-wakeup.o \
|
||||
src/win/dl.o \
|
||||
src/win/error.o \
|
||||
src/win/fs-event.o \
|
||||
|
|
|
@ -39,6 +39,12 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve
|
|||
scheme. The API change and backwards compatibility rules are those indicated by
|
||||
SemVer. libuv will keep a stable ABI across major releases.
|
||||
|
||||
The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/).
|
||||
|
||||
## Licensing
|
||||
|
||||
libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE).
|
||||
|
||||
## Community
|
||||
|
||||
* [Mailing list](http://groups.google.com/group/libuv)
|
||||
|
@ -220,18 +226,7 @@ Run:
|
|||
|
||||
## Supported Platforms
|
||||
|
||||
Microsoft Windows operating systems since Windows XP SP2. It can be built
|
||||
with either Visual Studio or MinGW. Consider using
|
||||
[Visual Studio Express 2010][] or later if you do not have a full Visual
|
||||
Studio license.
|
||||
|
||||
Linux using the GCC toolchain.
|
||||
|
||||
OS X using the GCC or XCode toolchain.
|
||||
|
||||
Solaris 121 and later using GCC toolchain.
|
||||
|
||||
AIX 6 and later using GCC toolchain (see notes).
|
||||
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
|
||||
|
||||
### AIX Notes
|
||||
|
||||
|
@ -250,7 +245,6 @@ See the [guidelines for contributing][].
|
|||
[node.js]: http://nodejs.org/
|
||||
[GYP]: http://code.google.com/p/gyp/
|
||||
[Python]: https://www.python.org/downloads/
|
||||
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
|
||||
[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
|
||||
[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
|
||||
[x32]: https://en.wikipedia.org/wiki/X32_ABI
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# Supported platforms
|
||||
|
||||
| System | Support type | Supported versions | Notes |
|
||||
|---|---|---|---|
|
||||
| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | |
|
||||
| macOS | Tier 1 | macOS >= 10.7 | |
|
||||
| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported |
|
||||
| FreeBSD | Tier 1 | >= 9 (see note) | |
|
||||
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
|
||||
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
|
||||
| Linux with musl | Tier 2 | musl >= 1.0 | |
|
||||
| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos |
|
||||
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
|
||||
| Other | Tier 3 | N/A | |
|
||||
|
||||
#### Note on FreeBSD 9
|
||||
|
||||
While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until
|
||||
it reaches end of life, in December 2016.
|
||||
|
||||
## Support types
|
||||
|
||||
* **Tier 1**: Officially supported and tested with CI. Any contributed patch
|
||||
MUST NOT break such systems. These are supported by @libuv/collaborators.
|
||||
|
||||
* **Tier 2**: Officially supported, but not necessarily tested with CI. These
|
||||
systems are maintained to the best of @libuv/collaborators ability,
|
||||
without being a top priority.
|
||||
|
||||
* **Tier 3**: Community maintained. These systems may inadvertently break and the
|
||||
community and interested parties are expected to help with the maintenance.
|
||||
|
||||
## Adding support for a new platform
|
||||
|
||||
**IMPORTANT**: Before attempting to add support for a new platform please open
|
||||
an issue about it for discussion.
|
||||
|
||||
### Unix
|
||||
|
||||
I/O handling is abstracted by an internal `uv__io_t` handle. The new platform
|
||||
will need to implement some of the functions, the prototypes are in
|
||||
``src/unix/internal.h``.
|
||||
|
||||
If the new platform requires extra fields for any handle structure, create a
|
||||
new include file in ``include/`` with the name ``uv-theplatform.h`` and add
|
||||
the appropriate defines there.
|
||||
|
||||
All functionality related to the new platform must be implemented in its own
|
||||
file inside ``src/unix/`` unless it's already done in a common file, in which
|
||||
case adding an `ifdef` is fine.
|
||||
|
||||
Two build systems are supported: autotools and GYP. Ideally both need to be
|
||||
supported, but if GYP does not support the new platform it can be left out.
|
||||
|
||||
### Windows
|
||||
|
||||
Windows is treated as a single platform, so adding support for a new platform
|
||||
would mean adding support for a new version.
|
||||
|
||||
Compilation and runtime must succeed for the minimum supported version. If a
|
||||
new API is to be used, it must be done optionally, only in supported versions.
|
||||
|
||||
### Common
|
||||
|
||||
Some common notes when adding support for new platforms:
|
||||
|
||||
* Generally libuv tries to avoid compile time checks. Do not add any to the
|
||||
autotools based build system or use version checking macros.
|
||||
Dynamically load functions and symbols if they are not supported by the
|
||||
minimum supported version.
|
|
@ -1,4 +1,4 @@
|
|||
version: v1.9.1.build{build}
|
||||
version: v1.10.0.build{build}
|
||||
|
||||
install:
|
||||
- cinst -y nsis
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
'configurations': {
|
||||
'Debug': {
|
||||
'defines': [ 'DEBUG', '_DEBUG' ],
|
||||
'cflags': [ '-g', '-O0', '-fwrapv' ],
|
||||
'cflags': [ '-g' ],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'target_conditions': [
|
||||
|
@ -35,6 +35,9 @@
|
|||
'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ],
|
||||
},
|
||||
'conditions': [
|
||||
['OS != "zos"', {
|
||||
'cflags': [ '-O0', '-fwrapv' ]
|
||||
}],
|
||||
['OS == "android"', {
|
||||
'cflags': [ '-fPIE' ],
|
||||
'ldflags': [ '-fPIE', '-pie' ]
|
||||
|
@ -151,7 +154,7 @@
|
|||
'cflags': [ '-pthreads' ],
|
||||
'ldflags': [ '-pthreads' ],
|
||||
}],
|
||||
[ 'OS not in "solaris android"', {
|
||||
[ 'OS not in "solaris android zos"', {
|
||||
'cflags': [ '-pthread' ],
|
||||
'ldflags': [ '-pthread' ],
|
||||
}],
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
AC_INIT([libuv], [1.9.1], [https://github.com/libuv/libuv/issues])
|
||||
AC_INIT([libuv], [1.10.0], [https://github.com/libuv/libuv/issues])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
m4_include([m4/libuv-extra-automake-flags.m4])
|
||||
m4_include([m4/as_case.m4])
|
||||
|
@ -24,10 +24,12 @@ AC_ENABLE_SHARED
|
|||
AC_ENABLE_STATIC
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
CC_CHECK_CFLAGS_APPEND([-fvisibility=hidden])
|
||||
AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [
|
||||
CC_CHECK_CFLAGS_APPEND([-pedantic])
|
||||
])
|
||||
CC_FLAG_VISIBILITY #[-fvisibility=hidden]
|
||||
CC_CHECK_CFLAGS_APPEND([-g])
|
||||
CC_CHECK_CFLAGS_APPEND([-std=gnu89])
|
||||
CC_CHECK_CFLAGS_APPEND([-pedantic])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wall])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wextra])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter])
|
||||
|
@ -52,10 +54,11 @@ AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])
|
|||
AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])])
|
||||
AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])])
|
||||
AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])])
|
||||
AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[freebsd*], [true], [false])])
|
||||
AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])])
|
||||
AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])])
|
||||
AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])])
|
||||
AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])])
|
||||
AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])])
|
||||
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
|
||||
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
|
||||
AS_CASE([$host_os],[mingw*], [
|
||||
|
|
|
@ -8,6 +8,9 @@ In libuv errors are negative numbered constants. As a rule of thumb, whenever
|
|||
there is a status parameter, or an API functions returns an integer, a negative
|
||||
number will imply an error.
|
||||
|
||||
When a function which takes a callback returns an error, the callback will never
|
||||
be called.
|
||||
|
||||
.. note::
|
||||
Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on
|
||||
Windows they are defined by libuv to arbitrary negative numbers.
|
||||
|
@ -329,3 +332,13 @@ API
|
|||
|
||||
Returns the error name for the given error code. Leaks a few bytes
|
||||
of memory when you call it with an unknown error code.
|
||||
|
||||
.. c:function:: int uv_translate_sys_error(int sys_errno)
|
||||
|
||||
Returns the libuv error code equivalent to the given platform dependent error
|
||||
code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error
|
||||
codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`).
|
||||
|
||||
If `sys_errno` is already a libuv error, it is simply returned.
|
||||
|
||||
.. versionchanged:: 1.10.0 function declared public.
|
||||
|
|
|
@ -91,7 +91,8 @@ Data types
|
|||
UV_FS_SYMLINK,
|
||||
UV_FS_READLINK,
|
||||
UV_FS_CHOWN,
|
||||
UV_FS_FCHOWN
|
||||
UV_FS_FCHOWN,
|
||||
UV_FS_REALPATH
|
||||
} uv_fs_type;
|
||||
|
||||
.. c:type:: uv_dirent_t
|
||||
|
@ -258,6 +259,12 @@ API
|
|||
|
||||
Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively.
|
||||
|
||||
.. note::
|
||||
AIX: This function only works for AIX 7.1 and newer. It can still be called on older
|
||||
versions but will return ``UV_ENOSYS``.
|
||||
|
||||
.. versionchanged:: 1.10.0 sub-second precission is supported on Windows
|
||||
|
||||
.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
|
||||
|
||||
Equivalent to :man:`link(2)`.
|
||||
|
@ -281,7 +288,26 @@ API
|
|||
|
||||
.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
|
||||
|
||||
Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``.
|
||||
Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle <https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx>`_.
|
||||
|
||||
.. warning::
|
||||
This function has certain platform specific caveats that were discovered when used in Node.
|
||||
|
||||
* macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are
|
||||
found while resolving the given path. This limit is hardcoded and cannot be sidestepped.
|
||||
* Windows: while this function works in the common case, there are a number of corner cases
|
||||
where it doesn't:
|
||||
|
||||
- Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk)
|
||||
cannot be resolved.
|
||||
- Inconsistent casing when using drive letters.
|
||||
- Resolved path bypasses subst'd drives.
|
||||
|
||||
While this function can still be used, it's not recommended if scenarios such as the
|
||||
above need to be supported.
|
||||
|
||||
The background story and some more details on these issues can be checked
|
||||
`here <https://github.com/nodejs/node/issues/7726>`_.
|
||||
|
||||
.. note::
|
||||
This function is not implemented on Windows XP and Windows Server 2003.
|
||||
|
|
|
@ -8,6 +8,20 @@ FS Event handles allow the user to monitor a given path for changes, for example
|
|||
if the file was renamed or there was a generic change in it. This handle uses
|
||||
the best backend for the job on each platform.
|
||||
|
||||
.. note::
|
||||
For AIX, the non default IBM bos.ahafs package has to be installed.
|
||||
The AIX Event Infrastructure file system (ahafs) has some limitations:
|
||||
|
||||
- ahafs tracks monitoring per process and is not thread safe. A separate process
|
||||
must be spawned for each monitor for the same event.
|
||||
- Events for file modification (writing to a file) are not received if only the
|
||||
containing folder is watched.
|
||||
|
||||
See documentation_ for more details.
|
||||
|
||||
.. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/
|
||||
|
||||
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
|
|
@ -17,6 +17,34 @@ Data types
|
|||
|
||||
The base libuv handle type.
|
||||
|
||||
.. c:type:: uv_handle_type
|
||||
|
||||
The kind of the libuv handle.
|
||||
|
||||
::
|
||||
|
||||
typedef enum {
|
||||
UV_UNKNOWN_HANDLE = 0,
|
||||
UV_ASYNC,
|
||||
UV_CHECK,
|
||||
UV_FS_EVENT,
|
||||
UV_FS_POLL,
|
||||
UV_HANDLE,
|
||||
UV_IDLE,
|
||||
UV_NAMED_PIPE,
|
||||
UV_POLL,
|
||||
UV_PREPARE,
|
||||
UV_PROCESS,
|
||||
UV_STREAM,
|
||||
UV_TCP,
|
||||
UV_TIMER,
|
||||
UV_TTY,
|
||||
UV_UDP,
|
||||
UV_SIGNAL,
|
||||
UV_FILE,
|
||||
UV_HANDLE_TYPE_MAX
|
||||
} uv_handle_type;
|
||||
|
||||
.. c:type:: uv_any_handle
|
||||
|
||||
Union of all handle types.
|
||||
|
@ -24,12 +52,28 @@ Data types
|
|||
.. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
|
||||
|
||||
Type definition for callback passed to :c:func:`uv_read_start` and
|
||||
:c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t`
|
||||
structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment)
|
||||
is provided, but it doesn't need to be honored. Setting the buffer's length to 0
|
||||
will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or
|
||||
:c:func:`uv_udp_recv_start`. The user must allocate memory and fill the supplied
|
||||
:c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length,
|
||||
a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the
|
||||
:c:type:`uv_read_cb` callback.
|
||||
|
||||
A suggested size (65536 at the moment in most cases) is provided, but it's just an indication,
|
||||
not related in any way to the pending data to be read. The user is free to allocate the amount
|
||||
of memory they decide.
|
||||
|
||||
As an example, applications with custom allocation schemes such as using freelists, allocation
|
||||
pools or slab based allocators may decide to use a different size which matches the memory
|
||||
chunks they already have.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
.. c:type:: void (*uv_close_cb)(uv_handle_t* handle)
|
||||
|
||||
Type definition for callback passed to :c:func:`uv_close`.
|
||||
|
@ -42,6 +86,10 @@ Public members
|
|||
|
||||
Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly.
|
||||
|
||||
.. c:member:: uv_loop_t* uv_handle_t.type
|
||||
|
||||
Pointer to the :c:type:`uv_handle_type`. Readonly.
|
||||
|
||||
.. c:member:: void* uv_handle_t.data
|
||||
|
||||
Space for user-defined arbitrary data. libuv does not use this field.
|
||||
|
|
|
@ -17,11 +17,11 @@ Data types
|
|||
|
||||
.. c:member:: char* uv_buf_t.base
|
||||
|
||||
Pointer to the base of the buffer. Readonly.
|
||||
Pointer to the base of the buffer.
|
||||
|
||||
.. c:member:: size_t uv_buf_t.len
|
||||
|
||||
Total bytes in the buffer. Readonly.
|
||||
Total bytes in the buffer.
|
||||
|
||||
.. note::
|
||||
On Windows this field is ULONG.
|
||||
|
@ -69,21 +69,24 @@ Data types
|
|||
uv_timeval_t ru_utime; /* user CPU time used */
|
||||
uv_timeval_t ru_stime; /* system CPU time used */
|
||||
uint64_t ru_maxrss; /* maximum resident set size */
|
||||
uint64_t ru_ixrss; /* integral shared memory size */
|
||||
uint64_t ru_idrss; /* integral unshared data size */
|
||||
uint64_t ru_isrss; /* integral unshared stack size */
|
||||
uint64_t ru_minflt; /* page reclaims (soft page faults) */
|
||||
uint64_t ru_ixrss; /* integral shared memory size (X) */
|
||||
uint64_t ru_idrss; /* integral unshared data size (X) */
|
||||
uint64_t ru_isrss; /* integral unshared stack size (X) */
|
||||
uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */
|
||||
uint64_t ru_majflt; /* page faults (hard page faults) */
|
||||
uint64_t ru_nswap; /* swaps */
|
||||
uint64_t ru_nswap; /* swaps (X) */
|
||||
uint64_t ru_inblock; /* block input operations */
|
||||
uint64_t ru_oublock; /* block output operations */
|
||||
uint64_t ru_msgsnd; /* IPC messages sent */
|
||||
uint64_t ru_msgrcv; /* IPC messages received */
|
||||
uint64_t ru_nsignals; /* signals received */
|
||||
uint64_t ru_nvcsw; /* voluntary context switches */
|
||||
uint64_t ru_nivcsw; /* involuntary context switches */
|
||||
uint64_t ru_msgsnd; /* IPC messages sent (X) */
|
||||
uint64_t ru_msgrcv; /* IPC messages received (X) */
|
||||
uint64_t ru_nsignals; /* signals received (X) */
|
||||
uint64_t ru_nvcsw; /* voluntary context switches (X) */
|
||||
uint64_t ru_nivcsw; /* involuntary context switches (X) */
|
||||
} uv_rusage_t;
|
||||
|
||||
Members marked with `(X)` are unsupported on Windows.
|
||||
See :man:`getrusage(2)` for supported fields on Unix
|
||||
|
||||
.. c:type:: uv_cpu_info_t
|
||||
|
||||
Data type for CPU information.
|
||||
|
@ -183,7 +186,9 @@ API
|
|||
|
||||
.. c:function:: int uv_get_process_title(char* buffer, size_t size)
|
||||
|
||||
Gets the title of the current process.
|
||||
Gets the title of the current process. If `buffer` is `NULL` or `size` is
|
||||
zero, `UV_EINVAL` is returned. If `size` cannot accommodate the process
|
||||
title and terminating `NULL` character, the function returns `UV_ENOBUFS`.
|
||||
|
||||
.. c:function:: int uv_set_process_title(const char* title)
|
||||
|
||||
|
@ -203,6 +208,7 @@ API
|
|||
|
||||
.. note::
|
||||
On Windows not all fields are set, the unsupported fields are filled with zeroes.
|
||||
See :c:type:`uv_rusage_t` for more details.
|
||||
|
||||
.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count)
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@ Data types
|
|||
|
||||
.. c:type:: uv_write_t
|
||||
|
||||
Write request type.
|
||||
Write request type. Careful attention must be paid when reusing objects of
|
||||
this type. When a stream is in non-blocking mode, write requests sent
|
||||
with ``uv_write`` will be queued. Reusing objects at this point is undefined
|
||||
behaviour. It is safe to reuse the ``uv_write_t`` object only after the
|
||||
callback passed to ``uv_write`` is fired.
|
||||
|
||||
.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
|
||||
|
@ -61,7 +65,7 @@ Data types
|
|||
|
||||
.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
|
||||
|
||||
Callback called after s shutdown request has been completed. `status` will
|
||||
Callback called after a shutdown request has been completed. `status` will
|
||||
be 0 in case of success, < 0 otherwise.
|
||||
|
||||
.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
|
||||
|
@ -92,7 +96,7 @@ Public members
|
|||
|
||||
.. c:member:: uv_stream_t* uv_write_t.send_handle
|
||||
|
||||
Pointer to the stream being sent using this write request..
|
||||
Pointer to the stream being sent using this write request.
|
||||
|
||||
.. seealso:: The :c:type:`uv_handle_t` members also apply.
|
||||
|
||||
|
@ -169,6 +173,10 @@ API
|
|||
uv_write(&req1, stream, a, 2, cb);
|
||||
uv_write(&req2, stream, b, 2, cb);
|
||||
|
||||
.. note::
|
||||
The memory pointed to by the buffers must remain valid until the callback gets called.
|
||||
This also holds for :c:func:`uv_write2`.
|
||||
|
||||
.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
|
||||
|
||||
Extended write function for sending handles over a pipe. The pipe must be
|
||||
|
|
|
@ -53,7 +53,7 @@ API
|
|||
|
||||
.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
|
||||
|
||||
Enable / disable Nagle's algorithm.
|
||||
Enable `TCP_NODELAY`, which disables Nagle's algorithm.
|
||||
|
||||
.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ API
|
|||
If `repeat` is non-zero, the callback fires first after `timeout`
|
||||
milliseconds and then repeatedly after `repeat` milliseconds.
|
||||
|
||||
.. note::
|
||||
Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information.
|
||||
|
||||
.. c:function:: int uv_timer_stop(uv_timer_t* handle)
|
||||
|
||||
Stop the timer, the callback will not be called anymore.
|
||||
|
|
|
@ -39,6 +39,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
2 * sizeof(sem_t) + \
|
||||
2 * sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#else
|
||||
# define UV_BARRIER_STRUCT_PADDING 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/* Copyright (c) 2013, Sony Mobile Communications AB
|
||||
* Copyright (c) 2012, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
/*Android doesn't provide pthread_barrier_t for now.*/
|
||||
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
|
||||
|
||||
/* Anything except 0 will do here.*/
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
unsigned count;
|
||||
} pthread_barrier_t;
|
||||
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count);
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier);
|
||||
int pthread_barrier_destroy(pthread_barrier_t *barrier);
|
||||
#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
|
||||
|
||||
int pthread_yield(void);
|
||||
|
||||
/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by
|
||||
* replacing all calls to pthread_sigmask with sigprocmask. See:
|
||||
* https://android.googlesource.com/platform/bionic/+/9bf330b5
|
||||
* https://code.google.com/p/android/issues/detail?id=15337
|
||||
*/
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
|
||||
#ifdef pthread_sigmask
|
||||
#undef pthread_sigmask
|
||||
#endif
|
||||
#define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */
|
|
@ -408,6 +408,7 @@
|
|||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
# define UV__EHOSTDOWN (-64)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_MVS_H
|
||||
#define UV_MVS_H
|
||||
|
||||
#define UV_PLATFORM_SEM_T int
|
||||
|
||||
#endif /* UV_MVS_H */
|
|
@ -50,9 +50,10 @@
|
|||
# include "uv-sunos.h"
|
||||
#elif defined(__APPLE__)
|
||||
# include "uv-darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
#elif defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "uv-bsd.h"
|
||||
#endif
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 9
|
||||
#define UV_VERSION_PATCH 1
|
||||
#define UV_VERSION_MINOR 10
|
||||
#define UV_VERSION_PATCH 0
|
||||
#define UV_VERSION_IS_RELEASE 1
|
||||
#define UV_VERSION_SUFFIX ""
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ typedef struct pollfd {
|
|||
{0xb5367df0, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_ACCEPTEX)
|
||||
typedef BOOL (PASCAL *LPFN_ACCEPTEX)
|
||||
(SOCKET sListenSocket,
|
||||
SOCKET sAcceptSocket,
|
||||
PVOID lpOutputBuffer,
|
||||
|
@ -126,7 +126,7 @@ typedef struct pollfd {
|
|||
LPDWORD lpdwBytesReceived,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_CONNECTEX)
|
||||
typedef BOOL (PASCAL *LPFN_CONNECTEX)
|
||||
(SOCKET s,
|
||||
const struct sockaddr* name,
|
||||
int namelen,
|
||||
|
@ -135,7 +135,7 @@ typedef struct pollfd {
|
|||
LPDWORD lpdwBytesSent,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
|
||||
typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS)
|
||||
(PVOID lpOutputBuffer,
|
||||
DWORD dwReceiveDataLength,
|
||||
DWORD dwLocalAddressLength,
|
||||
|
@ -145,13 +145,13 @@ typedef struct pollfd {
|
|||
LPSOCKADDR* RemoteSockaddr,
|
||||
LPINT RemoteSockaddrLength);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
|
||||
typedef BOOL (PASCAL *LPFN_DISCONNECTEX)
|
||||
(SOCKET hSocket,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
DWORD dwFlags,
|
||||
DWORD reserved);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
|
||||
typedef BOOL (PASCAL *LPFN_TRANSMITFILE)
|
||||
(SOCKET hSocket,
|
||||
HANDLE hFile,
|
||||
DWORD nNumberOfBytesToWrite,
|
||||
|
|
|
@ -363,6 +363,8 @@ typedef enum {
|
|||
} uv_membership;
|
||||
|
||||
|
||||
UV_EXTERN int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
UV_EXTERN const char* uv_strerror(int err);
|
||||
UV_EXTERN const char* uv_err_name(int err);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||
pqry.fd = pc.fd;
|
||||
rc = pollset_query(loop->backend_fd, &pqry);
|
||||
switch (rc) {
|
||||
case -1:
|
||||
case -1:
|
||||
assert(0 && "Failed to query pollset for file descriptor");
|
||||
abort();
|
||||
case 0:
|
||||
|
@ -333,20 +333,20 @@ int uv_exepath(char* buffer, size_t* size) {
|
|||
|
||||
pi.pi_pid = getpid();
|
||||
res = getargs(&pi, sizeof(pi), args, sizeof(args));
|
||||
if (res < 0)
|
||||
if (res < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Possibilities for args:
|
||||
* i) an absolute path such as: /home/user/myprojects/nodejs/node
|
||||
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
|
||||
* iii) a bare filename such as "node", after exporting PATH variable
|
||||
* iii) a bare filename such as "node", after exporting PATH variable
|
||||
* to its location.
|
||||
*/
|
||||
|
||||
/* Case i) and ii) absolute or relative paths */
|
||||
if (strchr(args, '/') != NULL) {
|
||||
if (realpath(args, abspath) != abspath)
|
||||
if (realpath(args, abspath) != abspath)
|
||||
return -errno;
|
||||
|
||||
abspath_size = strlen(abspath);
|
||||
|
@ -360,7 +360,7 @@ int uv_exepath(char* buffer, size_t* size) {
|
|||
|
||||
return 0;
|
||||
} else {
|
||||
/* Case iii). Search PATH environment variable */
|
||||
/* Case iii). Search PATH environment variable */
|
||||
char trypath[PATH_MAX];
|
||||
char *clonedpath = NULL;
|
||||
char *token = NULL;
|
||||
|
@ -376,7 +376,7 @@ int uv_exepath(char* buffer, size_t* size) {
|
|||
token = strtok(clonedpath, ":");
|
||||
while (token != NULL) {
|
||||
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
|
||||
if (realpath(trypath, abspath) == abspath) {
|
||||
if (realpath(trypath, abspath) == abspath) {
|
||||
/* Check the match is executable */
|
||||
if (access(abspath, X_OK) == 0) {
|
||||
abspath_size = strlen(abspath);
|
||||
|
@ -452,7 +452,7 @@ static char *uv__rawname(char *cp) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Determine whether given pathname is a directory
|
||||
* Returns 0 if the path is a directory, -1 if not
|
||||
*
|
||||
|
@ -472,7 +472,7 @@ static int uv__path_is_a_directory(char* filename) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Check whether AHAFS is mounted.
|
||||
* Returns 0 if AHAFS is mounted, or an error code < 0 on failure
|
||||
*/
|
||||
|
@ -547,7 +547,7 @@ static int uv__makedir_p(const char *dir) {
|
|||
return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Creates necessary subdirectories in the AIX Event Infrastructure
|
||||
* file system for monitoring the object specified.
|
||||
* Returns code from mkdir call
|
||||
|
@ -665,7 +665,7 @@ static int uv__skip_lines(char **p, int n) {
|
|||
/*
|
||||
* Parse the event occurrence data to figure out what event just occurred
|
||||
* and take proper action.
|
||||
*
|
||||
*
|
||||
* The buf is a pointer to the buffer containing the event occurrence data
|
||||
* Returns 0 on success, -1 if unrecoverable error in parsing
|
||||
*
|
||||
|
@ -891,9 +891,10 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
|||
const int out = (*(volatile int*) ptr);
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
return out;
|
||||
#elif defined(__MVS__)
|
||||
return __plo_CS(ptr, (unsigned int*) ptr,
|
||||
oldval, (unsigned int*) &newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
|
@ -63,6 +66,14 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
|
|||
__compare_and_swap(ptr, &oldval, newval);
|
||||
# endif /* if defined(__64BIT__) */
|
||||
return out;
|
||||
#elif defined (__MVS__)
|
||||
# ifdef _LP64
|
||||
return __plo_CSGR(ptr, (unsigned long long*) ptr,
|
||||
oldval, (unsigned long long*) &newval);
|
||||
# else
|
||||
return __plo_CS(ptr, (unsigned int*) ptr,
|
||||
oldval, (unsigned int*) &newval);
|
||||
# endif
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -40,11 +41,8 @@
|
|||
#include <sys/resource.h> /* getrusage */
|
||||
#include <pwd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
# include <sys/filio.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
@ -52,16 +50,16 @@
|
|||
#ifdef __APPLE__
|
||||
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
# include <sys/filio.h>
|
||||
# include <sys/ioctl.h>
|
||||
# if defined(O_CLOEXEC)
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__)
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/filio.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/wait.h>
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
|
||||
|
@ -74,14 +72,14 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _AIX
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
# include <dlfcn.h> /* for dlsym */
|
||||
#endif
|
||||
|
||||
#if defined(__MVS__)
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop);
|
||||
|
||||
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
|
||||
|
@ -508,8 +506,8 @@ int uv__close_nocheckstdio(int fd) {
|
|||
rc = close(fd);
|
||||
if (rc == -1) {
|
||||
rc = -errno;
|
||||
if (rc == -EINTR)
|
||||
rc = -EINPROGRESS; /* For platform/libc consistency. */
|
||||
if (rc == -EINTR || rc == -EINPROGRESS)
|
||||
rc = 0; /* The close is in progress, not an error. */
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
@ -523,10 +521,7 @@ int uv__close(int fd) {
|
|||
}
|
||||
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
|
||||
defined(_AIX) || defined(__DragonFly__)
|
||||
|
||||
int uv__nonblock(int fd, int set) {
|
||||
int uv__nonblock_ioctl(int fd, int set) {
|
||||
int r;
|
||||
|
||||
do
|
||||
|
@ -540,7 +535,7 @@ int uv__nonblock(int fd, int set) {
|
|||
}
|
||||
|
||||
|
||||
int uv__cloexec(int fd, int set) {
|
||||
int uv__cloexec_ioctl(int fd, int set) {
|
||||
int r;
|
||||
|
||||
do
|
||||
|
@ -553,10 +548,8 @@ int uv__cloexec(int fd, int set) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
|
||||
defined(_AIX) || defined(__DragonFly__)) */
|
||||
|
||||
int uv__nonblock(int fd, int set) {
|
||||
int uv__nonblock_fcntl(int fd, int set) {
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
|
@ -587,7 +580,7 @@ int uv__nonblock(int fd, int set) {
|
|||
}
|
||||
|
||||
|
||||
int uv__cloexec(int fd, int set) {
|
||||
int uv__cloexec_fcntl(int fd, int set) {
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
|
@ -617,9 +610,6 @@ int uv__cloexec(int fd, int set) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
|
||||
defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
|
||||
/* This function is not execve-safe, there is a race window
|
||||
* between the call to dup() and fcntl(FD_CLOEXEC).
|
||||
|
@ -931,6 +921,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
|||
rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
|
||||
rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
|
||||
|
||||
#if !defined(__MVS__)
|
||||
rusage->ru_maxrss = usage.ru_maxrss;
|
||||
rusage->ru_ixrss = usage.ru_ixrss;
|
||||
rusage->ru_idrss = usage.ru_idrss;
|
||||
|
@ -945,6 +936,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
|||
rusage->ru_nsignals = usage.ru_nsignals;
|
||||
rusage->ru_nvcsw = usage.ru_nvcsw;
|
||||
rusage->ru_nivcsw = usage.ru_nivcsw;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1244,3 +1236,9 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
|
|||
int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
return uv__getpwuid_r(pwd);
|
||||
}
|
||||
|
||||
|
||||
int uv_translate_sys_error(int sys_errno) {
|
||||
/* If < 0 then it's already a libuv error. */
|
||||
return sys_errno <= 0 ? sys_errno : -sys_errno;
|
||||
}
|
||||
|
|
|
@ -196,14 +196,24 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,10 @@
|
|||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel_) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_PREADV 1
|
||||
#else
|
||||
|
@ -151,9 +152,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|
|||
goto skip;
|
||||
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
|
||||
r = uv__utimesat(req->file, NULL, ts, 0);
|
||||
if (r == 0)
|
||||
|
@ -167,9 +168,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|
|||
skip:
|
||||
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
|
||||
|
||||
r = utimes(path, tv);
|
||||
|
@ -193,14 +194,15 @@ skip:
|
|||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__sun)
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
# if defined(__sun)
|
||||
return futimesat(req->file, NULL, tv);
|
||||
# else
|
||||
|
@ -209,10 +211,18 @@ skip:
|
|||
#elif defined(_AIX71)
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__MVS__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
atr.att_mtimechg = 1;
|
||||
atr.att_atimechg = 1;
|
||||
atr.att_mtime = req->mtime;
|
||||
atr.att_atime = req->atime;
|
||||
return __fchattr(req->file, &atr, sizeof(atr));
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
@ -251,7 +261,7 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
|||
*/
|
||||
if (r >= 0 && uv__cloexec(r, 1) != 0) {
|
||||
r = uv__close(r);
|
||||
if (r != 0 && r != -EINPROGRESS)
|
||||
if (r != 0)
|
||||
abort();
|
||||
r = -1;
|
||||
}
|
||||
|
@ -336,22 +346,30 @@ done:
|
|||
}
|
||||
|
||||
|
||||
#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
|
||||
static int uv__fs_scandir_filter(uv__dirent_t* dent) {
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)
|
||||
#define UV_CONST_DIRENT uv__dirent_t
|
||||
#else
|
||||
static int uv__fs_scandir_filter(const uv__dirent_t* dent) {
|
||||
#define UV_CONST_DIRENT const uv__dirent_t
|
||||
#endif
|
||||
|
||||
|
||||
static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) {
|
||||
return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
|
||||
return strcmp((*a)->d_name, (*b)->d_name);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_scandir(uv_fs_t* req) {
|
||||
uv__dirent_t **dents;
|
||||
int saved_errno;
|
||||
int n;
|
||||
|
||||
dents = NULL;
|
||||
n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort);
|
||||
n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort);
|
||||
|
||||
/* NOTE: We will use nbufs as an index field */
|
||||
req->nbufs = 0;
|
||||
|
@ -595,7 +613,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
|||
|
||||
return -1;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
|
||||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__)
|
||||
{
|
||||
off_t len;
|
||||
ssize_t r;
|
||||
|
@ -608,6 +629,15 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
|||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
len = 0;
|
||||
r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
|
||||
#elif defined(__FreeBSD_kernel__)
|
||||
len = 0;
|
||||
r = bsd_sendfile(in_fd,
|
||||
out_fd,
|
||||
req->off,
|
||||
req->bufsml[0].len,
|
||||
NULL,
|
||||
&len,
|
||||
0);
|
||||
#else
|
||||
/* The darwin sendfile takes len as an input for the length to send,
|
||||
* so make sure to initialize it with the caller's value. */
|
||||
|
@ -768,6 +798,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
|||
dst->st_flags = 0;
|
||||
dst->st_gen = 0;
|
||||
#elif !defined(_AIX) && ( \
|
||||
defined(_GNU_SOURCE) || \
|
||||
defined(_BSD_SOURCE) || \
|
||||
defined(_SVID_SOURCE) || \
|
||||
defined(_XOPEN_SOURCE) || \
|
||||
|
@ -810,8 +841,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
|||
static int uv__fs_stat(const char *path, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &pbuf);
|
||||
uv__to_stat(&pbuf, buf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -819,8 +853,11 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) {
|
|||
static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = lstat(path, &pbuf);
|
||||
uv__to_stat(&pbuf, buf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -828,8 +865,11 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
|
|||
static int uv__fs_fstat(int fd, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = fstat(fd, &pbuf);
|
||||
uv__to_stat(&pbuf, buf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#endif /* _AIX */
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <CoreServices/CoreServices.h>
|
||||
# include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -132,7 +132,8 @@ enum {
|
|||
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
|
||||
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
|
||||
UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
|
||||
UV_UDP_PROCESSING = 0x20000 /* Handle is running the send callback queue. */
|
||||
UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */
|
||||
UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */
|
||||
};
|
||||
|
||||
/* loop flags */
|
||||
|
@ -152,11 +153,26 @@ struct uv__stream_queued_fds_s {
|
|||
};
|
||||
|
||||
|
||||
#if defined(_AIX) || \
|
||||
defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__linux__)
|
||||
#define uv__cloexec uv__cloexec_ioctl
|
||||
#define uv__nonblock uv__nonblock_ioctl
|
||||
#else
|
||||
#define uv__cloexec uv__cloexec_fcntl
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
#endif
|
||||
|
||||
/* core */
|
||||
int uv__nonblock(int fd, int set);
|
||||
int uv__cloexec_ioctl(int fd, int set);
|
||||
int uv__cloexec_fcntl(int fd, int set);
|
||||
int uv__nonblock_ioctl(int fd, int set);
|
||||
int uv__nonblock_fcntl(int fd, int set);
|
||||
int uv__close(int fd);
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__cloexec(int fd, int set);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__dup(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
|
|
|
@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
|
||||
timeout = real_timeout - timeout;
|
||||
if (timeout > 0)
|
||||
continue;
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
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) {
|
||||
|
@ -484,12 +486,20 @@ int uv_exepath(char* buffer, size_t* size) {
|
|||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,11 +28,15 @@
|
|||
#include <unistd.h>
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
void* saved_data;
|
||||
int err;
|
||||
|
||||
uv__signal_global_once_init();
|
||||
|
||||
saved_data = loop->data;
|
||||
memset(loop, 0, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
|
||||
heap_init((struct heap*) &loop->timer_heap);
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->active_reqs);
|
||||
|
|
|
@ -147,14 +147,24 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -169,14 +169,24 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* 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 "internal.h"
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct pollfd p[1];
|
||||
int rv;
|
||||
|
||||
p[0].fd = fd;
|
||||
p[0].events = POLLIN;
|
||||
|
||||
do
|
||||
rv = poll(p, 1, 0);
|
||||
while (rv == -1 && errno == EINTR);
|
||||
|
||||
if (rv == -1)
|
||||
abort();
|
||||
|
||||
if (p[0].revents & POLLNVAL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -80,6 +80,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
|||
}
|
||||
|
||||
/* Success. */
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
||||
handle->io_watcher.fd = sockfd;
|
||||
return 0;
|
||||
|
@ -97,6 +98,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
|||
if (uv__stream_fd(handle) == -1)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
/* On zOS, backlog=0 has undefined behaviour */
|
||||
if (backlog == 0)
|
||||
backlog = 1;
|
||||
else if (backlog < 0)
|
||||
backlog = SOMAXCONN;
|
||||
#endif
|
||||
|
||||
if (listen(uv__stream_fd(handle), backlog))
|
||||
return -errno;
|
||||
|
||||
|
|
|
@ -59,7 +59,14 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err == -ENOTTY)
|
||||
if (uv__nonblock == uv__nonblock_ioctl)
|
||||
err = uv__nonblock_fcntl(fd, 1);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
# include <grp.h>
|
||||
#endif
|
||||
|
||||
|
@ -232,7 +232,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
|
|||
return 0;
|
||||
|
||||
err = uv__close(pipefds[1]);
|
||||
if (err != 0 && err != -EINPROGRESS)
|
||||
if (err != 0)
|
||||
abort();
|
||||
|
||||
pipefds[1] = -1;
|
||||
|
|
|
@ -87,10 +87,13 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (process_title.len > 0)
|
||||
strncpy(buffer, process_title.str, size);
|
||||
else if (size > 0)
|
||||
buffer[0] = '\0';
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
else if (size <= process_title.len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title.str, process_title.len + 1);
|
||||
buffer[process_title.len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
|
|||
static void uv__signal_stop(uv_signal_t* handle);
|
||||
|
||||
|
||||
static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
|
||||
static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
|
||||
static struct uv__signal_tree_s uv__signal_tree =
|
||||
RB_INITIALIZER(uv__signal_tree);
|
||||
static int uv__signal_lock_pipefd[2];
|
||||
|
@ -64,7 +64,7 @@ static void uv__signal_global_init(void) {
|
|||
|
||||
|
||||
void uv__signal_global_once_init(void) {
|
||||
pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -291,7 +291,10 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
|||
timeout.tv_sec = 0;
|
||||
timeout.tv_nsec = 1;
|
||||
|
||||
ret = kevent(kq, filter, 1, events, 1, &timeout);
|
||||
do
|
||||
ret = kevent(kq, filter, 1, events, 1, &timeout);
|
||||
while (ret == -1 && errno == EINTR);
|
||||
|
||||
uv__close(kq);
|
||||
|
||||
if (ret == -1)
|
||||
|
@ -571,7 +574,6 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
|||
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||
int err;
|
||||
|
||||
/* TODO document this */
|
||||
assert(server->loop == client->loop);
|
||||
|
||||
if (server->accepted_fd == -1)
|
||||
|
@ -602,6 +604,8 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
client->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
done:
|
||||
/* Process queued fds */
|
||||
if (server->queued_fds != NULL) {
|
||||
|
@ -962,8 +966,8 @@ uv_handle_type uv__handle_type(int fd) {
|
|||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX)
|
||||
/* on AIX the getsockname call returns an empty sa structure
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
|
@ -1122,8 +1126,9 @@ static void uv__read(uv_stream_t* stream) {
|
|||
&& (count-- > 0)) {
|
||||
assert(stream->alloc_cb != NULL);
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
/* User indicates it can't or won't handle the read. */
|
||||
stream->read_cb(stream, UV_ENOBUFS, &buf);
|
||||
return;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#endif
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <sys/loadavg.h>
|
||||
#include <sys/time.h>
|
||||
|
@ -540,9 +542,10 @@ int uv_set_process_title(const char* title) {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -692,13 +695,57 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
|||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspired By:
|
||||
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
|
||||
* http://www.pauliesworld.org/project/getmac.c
|
||||
*/
|
||||
static int uv__set_phys_addr(uv_interface_address_t* address,
|
||||
struct ifaddrs* ent) {
|
||||
|
||||
struct sockaddr_dl* sa_addr;
|
||||
int sockfd;
|
||||
int i;
|
||||
struct arpreq arpreq;
|
||||
|
||||
/* This appears to only work as root */
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
for (i = 0; i < sizeof(address->phys_addr); i++) {
|
||||
if (address->phys_addr[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
memset(&arpreq, 0, sizeof(arpreq));
|
||||
if (address->address.address4.sin_family == AF_INET) {
|
||||
struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
|
||||
sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
|
||||
} else if (address->address.address4.sin_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
|
||||
memcpy(sin->sin6_addr.s6_addr,
|
||||
address->address.address6.sin6_addr.s6_addr,
|
||||
sizeof(address->address.address6.sin6_addr.s6_addr));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0)
|
||||
return -errno;
|
||||
|
||||
if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
|
||||
uv__close(sockfd);
|
||||
return -errno;
|
||||
}
|
||||
memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
#ifdef SUNOS_NO_IFADDRS
|
||||
return -ENOSYS;
|
||||
#else
|
||||
uv_interface_address_t* address;
|
||||
struct sockaddr_dl* sa_addr;
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
int i;
|
||||
|
@ -751,28 +798,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|||
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
|
||||
(ent->ifa_flags & IFF_LOOPBACK));
|
||||
|
||||
uv__set_phys_addr(address, ent);
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -115,6 +115,10 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
|||
IPV6_V6ONLY,
|
||||
&on,
|
||||
sizeof on) == -1) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == EOPNOTSUPP)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +134,7 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
|||
}
|
||||
tcp->delayed_error = -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
if (addr->sa_family == AF_INET6)
|
||||
tcp->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
|
@ -158,11 +163,17 @@ int uv__tcp_connect(uv_connect_t* req,
|
|||
|
||||
handle->delayed_error = 0;
|
||||
|
||||
do
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(uv__stream_fd(handle), addr, addrlen);
|
||||
while (r == -1 && errno == EINTR);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
/* We not only check the return value, but also check the errno != 0.
|
||||
* Because in rare cases connect() will return -1 but the errno
|
||||
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
|
||||
* and actually the tcp three-way handshake is completed.
|
||||
*/
|
||||
if (r == -1 && errno != 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED)
|
||||
|
@ -266,10 +277,32 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef __MVS__
|
||||
/* on zOS the listen call does not bind automatically
|
||||
if the socket is unbound. Hence the manual binding to
|
||||
an arbitrary port is required to be done manually
|
||||
*/
|
||||
|
||||
if (!(tcp->flags & UV_HANDLE_BOUND)) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
|
||||
if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
|
||||
return -errno;
|
||||
|
||||
if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
|
||||
return -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen(tcp->io_watcher.fd, backlog))
|
||||
return -errno;
|
||||
|
||||
tcp->connection_cb = cb;
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
/* Start listening for connections. */
|
||||
tcp->io_watcher.cb = uv__server_io;
|
||||
|
|
|
@ -32,31 +32,16 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __MVS__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
struct thread_ctx {
|
||||
void (*entry)(void* arg);
|
||||
void* arg;
|
||||
};
|
||||
|
||||
|
||||
static void* uv__thread_start(void *arg)
|
||||
{
|
||||
struct thread_ctx *ctx_p;
|
||||
struct thread_ctx ctx;
|
||||
|
||||
ctx_p = arg;
|
||||
ctx = *ctx_p;
|
||||
uv__free(ctx_p);
|
||||
ctx.entry(ctx.arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
struct thread_ctx* ctx;
|
||||
int err;
|
||||
pthread_attr_t* attr;
|
||||
#if defined(__APPLE__)
|
||||
|
@ -64,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
|||
struct rlimit lim;
|
||||
#endif
|
||||
|
||||
ctx = uv__malloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
ctx->entry = entry;
|
||||
ctx->arg = arg;
|
||||
|
||||
/* On OSX threads other than the main thread are created with a reduced stack
|
||||
* size by default, adjust it to RLIMIT_STACK.
|
||||
*/
|
||||
|
@ -94,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
|||
attr = NULL;
|
||||
#endif
|
||||
|
||||
err = pthread_create(tid, attr, uv__thread_start, ctx);
|
||||
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
if (err)
|
||||
uv__free(ctx);
|
||||
|
||||
return -err;
|
||||
}
|
||||
|
||||
|
@ -302,6 +277,85 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
|||
return -EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
#elif defined(__MVS__)
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
uv_sem_t semid;
|
||||
struct sembuf buf;
|
||||
int err;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = value;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
|
||||
if (semid == -1)
|
||||
return -errno;
|
||||
|
||||
if (-1 == semop(semid, &buf, 1)) {
|
||||
err = errno;
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
return -err;
|
||||
}
|
||||
|
||||
*sem = semid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = 1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
if (-1 == semop(*sem, &buf, 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status)
|
||||
abort();
|
||||
}
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = IPC_NOWAIT;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status) {
|
||||
if (errno == EAGAIN)
|
||||
return -EAGAIN;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
|
@ -354,7 +408,7 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
|||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
return -pthread_cond_init(cond, NULL);
|
||||
|
|
|
@ -31,8 +31,8 @@ static int timer_less_than(const struct heap_node* ha,
|
|||
const uv_timer_t* a;
|
||||
const uv_timer_t* b;
|
||||
|
||||
a = container_of(ha, const uv_timer_t, heap_node);
|
||||
b = container_of(hb, const uv_timer_t, heap_node);
|
||||
a = container_of(ha, uv_timer_t, heap_node);
|
||||
b = container_of(hb, uv_timer_t, heap_node);
|
||||
|
||||
if (a->timeout < b->timeout)
|
||||
return 1;
|
||||
|
@ -135,7 +135,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
|||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
handle = container_of(heap_node, const uv_timer_t, heap_node);
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
if (handle->timeout <= loop->time)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -30,13 +30,17 @@
|
|||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__MVS__) && !defined(IMAXBEL)
|
||||
#define IMAXBEL 0
|
||||
#endif
|
||||
|
||||
static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int dummy;
|
||||
|
||||
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
|
||||
|
@ -57,6 +61,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
|||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
int saved_flags;
|
||||
char path[256];
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
|
@ -113,6 +118,22 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
|||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pacify the compiler. */
|
||||
(void) &saved_flags;
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
|
@ -120,13 +141,20 @@ skip:
|
|||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (r) {
|
||||
int rc = r;
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
QUEUE_REMOVE(&tty->handle_queue);
|
||||
return r;
|
||||
do
|
||||
r = fcntl(fd, F_SETFL, saved_flags);
|
||||
while (r == -1 && errno == EINTR);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -135,9 +163,6 @@ skip:
|
|||
else
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
|
@ -147,7 +172,7 @@ skip:
|
|||
static void uv__tty_make_raw(struct termios* tio) {
|
||||
assert(tio != NULL);
|
||||
|
||||
#ifdef __sun
|
||||
#if defined __sun || defined __MVS__
|
||||
/*
|
||||
* This implementation of cfmakeraw for Solaris and derivatives is taken from
|
||||
* http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
|
||||
|
@ -268,14 +293,14 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
|||
return UV_UDP;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX)
|
||||
/* on AIX the getsockname call returns an empty sa structure
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
if (len == 0)
|
||||
return UV_NAMED_PIPE;
|
||||
#endif /* defined(_AIX) */
|
||||
#endif /* defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_TCP;
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__MVS__)
|
||||
#include <xti.h>
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
|
||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
|
@ -165,8 +168,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
|||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -331,6 +335,8 @@ int uv__udp_bind(uv_udp_t* handle,
|
|||
if (addr->sa_family == AF_INET6)
|
||||
handle->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
|
@ -507,6 +513,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle,
|
|||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
@ -550,6 +560,10 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
|
|||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
@ -668,7 +682,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle,
|
|||
int option4,
|
||||
int option6,
|
||||
int val) {
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
char arg = val;
|
||||
#elif defined(__OpenBSD__)
|
||||
unsigned char arg = val;
|
||||
|
@ -700,19 +714,27 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
|||
if (ttl < 1 || ttl > 255)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (!(handle->flags & UV_HANDLE_IPV6))
|
||||
return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Solaris and derivatives such as SmartOS, the length of socket options
|
||||
* is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
|
||||
* so hardcode the size of these options on this platform,
|
||||
* and use the general uv__setsockopt_maybe_char call on other platforms.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
|
||||
return uv__setsockopt(handle,
|
||||
IP_TTL,
|
||||
IPV6_UNICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_TTL,
|
||||
|
@ -728,14 +750,14 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
|||
* IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
|
@ -751,14 +773,14 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
|||
* IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
|
|
|
@ -613,6 +613,9 @@ uv_loop_t* uv_loop_new(void) {
|
|||
int uv_loop_close(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
uv_handle_t* h;
|
||||
#ifndef NDEBUG
|
||||
void* saved_data;
|
||||
#endif
|
||||
|
||||
if (!QUEUE_EMPTY(&(loop)->active_reqs))
|
||||
return UV_EBUSY;
|
||||
|
@ -626,7 +629,9 @@ int uv_loop_close(uv_loop_t* loop) {
|
|||
uv__loop_close(loop);
|
||||
|
||||
#ifndef NDEBUG
|
||||
saved_data = loop->data;
|
||||
memset(loop, -1, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
#endif
|
||||
if (loop == default_loop_ptr)
|
||||
default_loop_ptr = NULL;
|
||||
|
|
|
@ -31,13 +31,10 @@
|
|||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
static uv_loop_t default_loop_struct;
|
||||
static uv_loop_t* default_loop_ptr;
|
||||
|
||||
/* uv_once initialization guards */
|
||||
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
|
||||
|
||||
|
@ -80,6 +77,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
|||
}
|
||||
#endif
|
||||
|
||||
static uv_loop_t** uv__loops;
|
||||
static int uv__loops_size;
|
||||
static int uv__loops_capacity;
|
||||
#define UV__LOOPS_CHUNK_SIZE 8
|
||||
static uv_mutex_t uv__loops_lock;
|
||||
|
||||
static void uv__loops_init() {
|
||||
uv_mutex_init(&uv__loops_lock);
|
||||
uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
|
||||
if (!uv__loops)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
uv__loops_size = 0;
|
||||
uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static int uv__loops_add(uv_loop_t* loop) {
|
||||
uv_loop_t** new_loops;
|
||||
int new_capacity, i;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
if (uv__loops_size == uv__loops_capacity) {
|
||||
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
|
||||
if (!new_loops)
|
||||
goto failed_loops_realloc;
|
||||
uv__loops = new_loops;
|
||||
for (i = uv__loops_capacity; i < new_capacity; ++i)
|
||||
uv__loops[i] = NULL;
|
||||
uv__loops_capacity = new_capacity;
|
||||
}
|
||||
uv__loops[uv__loops_size] = loop;
|
||||
++uv__loops_size;
|
||||
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return 0;
|
||||
|
||||
failed_loops_realloc:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
uv_loop_t** new_loops;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
|
||||
if (uv__loops[loop_index] == loop)
|
||||
break;
|
||||
}
|
||||
/* If loop was not found, ignore */
|
||||
if (loop_index == uv__loops_size)
|
||||
goto loop_removed;
|
||||
|
||||
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
|
||||
uv__loops[uv__loops_size - 1] = NULL;
|
||||
--uv__loops_size;
|
||||
|
||||
/* If we didn't grow to big skip downsizing */
|
||||
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
|
||||
goto loop_removed;
|
||||
|
||||
/* Downsize only if more than half of buffer is free */
|
||||
smaller_capacity = uv__loops_capacity / 2;
|
||||
if (uv__loops_size >= smaller_capacity)
|
||||
goto loop_removed;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
|
||||
if (!new_loops)
|
||||
goto loop_removed;
|
||||
uv__loops = new_loops;
|
||||
uv__loops_capacity = smaller_capacity;
|
||||
|
||||
loop_removed:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
void uv__wake_all_loops() {
|
||||
int i;
|
||||
uv_loop_t* loop;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
for (i = 0; i < uv__loops_size; ++i) {
|
||||
loop = uv__loops[i];
|
||||
assert(loop);
|
||||
if (loop->iocp != INVALID_HANDLE_VALUE)
|
||||
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
|
||||
}
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
static void uv_init(void) {
|
||||
/* Tell Windows that we will handle critical errors. */
|
||||
|
@ -101,6 +190,9 @@ static void uv_init(void) {
|
|||
_CrtSetReportHook(uv__crt_dbg_report_handler);
|
||||
#endif
|
||||
|
||||
/* Initialize tracking of all uv loops */
|
||||
uv__loops_init();
|
||||
|
||||
/* Fetch winapi function pointers. This must be done first because other
|
||||
* initialization code might need these function pointers to be loaded.
|
||||
*/
|
||||
|
@ -120,6 +212,9 @@ static void uv_init(void) {
|
|||
|
||||
/* Initialize utilities */
|
||||
uv__util_init();
|
||||
|
||||
/* Initialize system wakeup detection */
|
||||
uv__init_detect_system_wakeup();
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,6 +273,10 @@ int uv_loop_init(uv_loop_t* loop) {
|
|||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
|
@ -199,6 +298,8 @@ void uv__once_init(void) {
|
|||
void uv__loop_close(uv_loop_t* loop) {
|
||||
size_t i;
|
||||
|
||||
uv__loops_remove(loop);
|
||||
|
||||
/* close the async handle without needing an extra loop iteration */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
loop->wq_async.close_cb = NULL;
|
||||
|
@ -323,9 +424,13 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
|
|||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Package was dequeued */
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
/* Package was dequeued, but see if it is not a empty package
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "winapi.h"
|
||||
|
||||
static void uv__register_system_resume_callback();
|
||||
|
||||
void uv__init_detect_system_wakeup() {
|
||||
/* Try registering system power event callback. This is the cleanest
|
||||
* method, but it will only work on Win8 and above.
|
||||
*/
|
||||
uv__register_system_resume_callback();
|
||||
}
|
||||
|
||||
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting) {
|
||||
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
|
||||
uv__wake_all_loops();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__register_system_resume_callback() {
|
||||
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
|
||||
_HPOWERNOTIFY registration_handle;
|
||||
|
||||
if (pPowerRegisterSuspendResumeNotification == NULL)
|
||||
return;
|
||||
|
||||
recipient.Callback = uv__system_resume_callback;
|
||||
recipient.Context = NULL;
|
||||
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
|
||||
&recipient,
|
||||
®istration_handle);
|
||||
}
|
|
@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
|||
}
|
||||
|
||||
|
||||
static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
|
||||
int str_len;
|
||||
|
||||
str_len = wcslen(str);
|
||||
|
||||
/*
|
||||
Since we only care about equality, return early if the strings
|
||||
aren't the same length
|
||||
*/
|
||||
if (str_len != (file_name_len / sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
return _wcsnicmp(str, file_name, str_len);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
uv_fs_event_t* handle) {
|
||||
FILE_NOTIFY_INFORMATION* file_info;
|
||||
|
@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
|||
* or if the filename filter matches.
|
||||
*/
|
||||
if (handle->dirw ||
|
||||
_wcsnicmp(handle->filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
|
||||
_wcsnicmp(handle->short_filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0) {
|
||||
file_info_cmp(handle->filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0 ||
|
||||
file_info_cmp(handle->short_filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0) {
|
||||
|
||||
if (handle->dirw) {
|
||||
/*
|
||||
|
@ -407,7 +425,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
|||
}
|
||||
|
||||
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
|
||||
file_info->FileNameLength / sizeof(WCHAR),
|
||||
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
|
||||
file_info->FileName);
|
||||
|
||||
filenamew[size - 1] = L'\0';
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
|
||||
116444736000000000ULL; \
|
||||
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
|
||||
|
@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
|||
const char* new_path, const int copy_path) {
|
||||
char* buf;
|
||||
char* pos;
|
||||
ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
|
||||
ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
|
||||
|
||||
/* new_path can only be set if path is also set. */
|
||||
assert(new_path == NULL || path != NULL);
|
||||
|
@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
|||
req->fs.info.new_pathw = NULL;
|
||||
}
|
||||
|
||||
if (!copy_path) {
|
||||
req->path = path;
|
||||
} else if (path) {
|
||||
req->path = path;
|
||||
if (path != NULL && copy_path) {
|
||||
memcpy(pos, path, path_len);
|
||||
assert(path_len == buf_sz - (pos - buf));
|
||||
req->path = pos;
|
||||
} else {
|
||||
req->path = NULL;
|
||||
}
|
||||
|
||||
req->flags |= UV_FS_FREE_PATHS;
|
||||
|
@ -233,6 +230,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
|
|||
req->ptr = NULL;
|
||||
req->path = NULL;
|
||||
req->cb = cb;
|
||||
memset(&req->fs, 0, sizeof(req->fs));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1091,17 +1089,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
|
|||
statbuf->st_mode = 0;
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
|
||||
/*
|
||||
* It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
|
||||
* any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
|
||||
* the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
|
||||
* calculated below will indicate a normal directory or file, as if
|
||||
* FILE_ATTRIBUTE_REPARSE_POINT was not present.
|
||||
*/
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
} else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
if (statbuf->st_mode == 0) {
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
|
@ -1429,8 +1438,8 @@ static void fs__fchmod(uv_fs_t* req) {
|
|||
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
|
||||
FILETIME filetime_a, filetime_m;
|
||||
|
||||
TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
|
||||
TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
|
||||
TIME_T_TO_FILETIME(atime, &filetime_a);
|
||||
TIME_T_TO_FILETIME(mtime, &filetime_m);
|
||||
|
||||
if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
|
||||
return -1;
|
||||
|
@ -1885,9 +1894,13 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
|||
uv__free(req->ptr);
|
||||
}
|
||||
|
||||
if (req->fs.info.bufs != req->fs.info.bufsml)
|
||||
uv__free(req->fs.info.bufs);
|
||||
|
||||
req->path = NULL;
|
||||
req->file.pathw = NULL;
|
||||
req->fs.info.new_pathw = NULL;
|
||||
req->fs.info.bufs = NULL;
|
||||
req->ptr = NULL;
|
||||
|
||||
req->flags |= UV_FS_CLEANEDUP;
|
||||
|
|
|
@ -381,4 +381,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
|
|||
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/*
|
||||
* Wake all loops with fake message
|
||||
*/
|
||||
void uv__wake_all_loops();
|
||||
|
||||
/*
|
||||
* Init system wake-up detection
|
||||
*/
|
||||
void uv__init_detect_system_wakeup();
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
|
|
|
@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle);
|
|||
|
||||
|
||||
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1634,8 +1634,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
|||
}
|
||||
}
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -496,8 +496,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
|||
*/
|
||||
if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
|
||||
if (handle->tcp.conn.read_buffer.len == 0) {
|
||||
if (handle->tcp.conn.read_buffer.base == NULL ||
|
||||
handle->tcp.conn.read_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
|
||||
return;
|
||||
}
|
||||
|
@ -1004,8 +1006,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
|||
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#include "stream-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
#ifndef InterlockedOr
|
||||
# define InterlockedOr _InterlockedOr
|
||||
#endif
|
||||
|
||||
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
||||
|
||||
|
@ -54,6 +57,9 @@
|
|||
|
||||
#define MAX_INPUT_BUFFER_LENGTH 8192
|
||||
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
|
@ -105,7 +111,11 @@ static int uv_tty_virtual_offset = -1;
|
|||
static int uv_tty_virtual_height = -1;
|
||||
static int uv_tty_virtual_width = -1;
|
||||
|
||||
static CRITICAL_SECTION uv_tty_output_lock;
|
||||
/* We use a semaphore rather than a mutex or critical section because in some
|
||||
cases (uv__cancel_read_console) we need take the lock in the main thread and
|
||||
release it in another thread. Using a semaphore ensures that in such
|
||||
scenario the main thread will still block when trying to acquire the lock. */
|
||||
static uv_sem_t uv_tty_output_lock;
|
||||
|
||||
static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
|
@ -118,9 +128,18 @@ static char uv_tty_default_fg_bright = 0;
|
|||
static char uv_tty_default_bg_bright = 0;
|
||||
static char uv_tty_default_inverse = 0;
|
||||
|
||||
typedef enum {
|
||||
UV_SUPPORTED,
|
||||
UV_UNCHECKED,
|
||||
UV_UNSUPPORTED
|
||||
} uv_vtermstate_t;
|
||||
/* Determine whether or not ANSI support is enabled. */
|
||||
static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
|
||||
static void uv__determine_vterm_state(HANDLE handle);
|
||||
|
||||
void uv_console_init() {
|
||||
InitializeCriticalSection(&uv_tty_output_lock);
|
||||
if (uv_sem_init(&uv_tty_output_lock, 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
@ -158,7 +177,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
|||
|
||||
/* Obtain the the tty_output_lock because the virtual window state is */
|
||||
/* shared between all uv_tty_t handles. */
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
if (uv__vterm_state == UV_UNCHECKED)
|
||||
uv__determine_vterm_state(handle);
|
||||
|
||||
/* Store the global tty output handle. This handle is used by TTY read */
|
||||
/* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
|
||||
|
@ -170,7 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
|||
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,10 +316,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
if (!SetConsoleMode(tty->handle, flags)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
default:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
/* If currently reading, stop, and restart reading. */
|
||||
|
@ -313,6 +333,14 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
|||
was_reading = 0;
|
||||
}
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
if (!SetConsoleMode(tty->handle, flags)) {
|
||||
err = uv_translate_sys_error(GetLastError());
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
return err;
|
||||
}
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
/* Update flag. */
|
||||
tty->flags &= ~UV_HANDLE_TTY_RAW;
|
||||
tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
|
||||
|
@ -342,9 +370,9 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
|||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
uv_tty_update_virtual_window(&info);
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
*width = uv_tty_virtual_width;
|
||||
*height = uv_tty_virtual_height;
|
||||
|
@ -413,6 +441,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
|||
DWORD chars, read_chars;
|
||||
LONG status;
|
||||
COORD pos;
|
||||
BOOL read_console_success;
|
||||
|
||||
assert(data);
|
||||
|
||||
|
@ -442,11 +471,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (ReadConsoleW(handle->handle,
|
||||
(void*) utf16,
|
||||
chars,
|
||||
&read_chars,
|
||||
NULL)) {
|
||||
read_console_success = ReadConsoleW(handle->handle,
|
||||
(void*) utf16,
|
||||
chars,
|
||||
&read_chars,
|
||||
NULL);
|
||||
|
||||
if (read_console_success) {
|
||||
read_bytes = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
utf16,
|
||||
|
@ -461,33 +492,36 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
|||
SET_REQ_ERROR(req, GetLastError());
|
||||
}
|
||||
|
||||
InterlockedExchange(&uv__read_console_status, COMPLETED);
|
||||
status = InterlockedExchange(&uv__read_console_status, COMPLETED);
|
||||
|
||||
/* If we canceled the read by sending a VK_RETURN event, restore the screen
|
||||
state to undo the visual effect of the VK_RETURN*/
|
||||
if (InterlockedOr(&uv__restore_screen_state, 0)) {
|
||||
HANDLE active_screen_buffer = CreateFileA("conout$",
|
||||
if (status == TRAP_REQUESTED) {
|
||||
/* If we canceled the read by sending a VK_RETURN event, restore the
|
||||
screen state to undo the visual effect of the VK_RETURN */
|
||||
if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
|
||||
HANDLE active_screen_buffer;
|
||||
active_screen_buffer = CreateFileA("conout$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (active_screen_buffer != INVALID_HANDLE_VALUE) {
|
||||
pos = uv__saved_screen_state.dwCursorPosition;
|
||||
if (active_screen_buffer != INVALID_HANDLE_VALUE) {
|
||||
pos = uv__saved_screen_state.dwCursorPosition;
|
||||
|
||||
/* If the cursor was at the bottom line of the screen buffer, the
|
||||
VK_RETURN would have caused the buffer contents to scroll up by
|
||||
one line. The right position to reset the cursor to is therefore one
|
||||
line higher */
|
||||
if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
|
||||
pos.Y--;
|
||||
/* If the cursor was at the bottom line of the screen buffer, the
|
||||
VK_RETURN would have caused the buffer contents to scroll up by one
|
||||
line. The right position to reset the cursor to is therefore one line
|
||||
higher */
|
||||
if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
|
||||
pos.Y--;
|
||||
|
||||
SetConsoleCursorPosition(active_screen_buffer, pos);
|
||||
CloseHandle(active_screen_buffer);
|
||||
SetConsoleCursorPosition(active_screen_buffer, pos);
|
||||
CloseHandle(active_screen_buffer);
|
||||
}
|
||||
}
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
POST_COMPLETION_FOR_REQ(loop, req);
|
||||
return 0;
|
||||
}
|
||||
|
@ -504,8 +538,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
|||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
|
||||
if (handle->tty.rd.read_line_buffer.len == 0) {
|
||||
if (handle->tty.rd.read_line_buffer.base == NULL ||
|
||||
handle->tty.rd.read_line_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle,
|
||||
UV_ENOBUFS,
|
||||
&handle->tty.rd.read_line_buffer);
|
||||
|
@ -673,14 +709,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
|||
if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
|
||||
GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
|
||||
uv_tty_update_virtual_window(&info);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -828,8 +864,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
|||
if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
|
||||
/* Allocate a buffer if needed */
|
||||
if (buf_used == 0) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1013,11 +1050,16 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
|
|||
|
||||
assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
|
||||
|
||||
/* Hold the output lock during the cancellation, to ensure that further
|
||||
writes don't interfere with the screen state. It will be the ReadConsole
|
||||
thread's responsibility to release the lock. */
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
|
||||
if (status != IN_PROGRESS) {
|
||||
/* Either we have managed to set a trap for the other thread before
|
||||
ReadConsole is called, or ReadConsole has returned because the user
|
||||
has pressed ENTER. In either case, there is nothing else to do. */
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1602,12 +1644,39 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|||
/* state. */
|
||||
*error = ERROR_SUCCESS;
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
for (i = 0; i < nbufs; i++) {
|
||||
uv_buf_t buf = bufs[i];
|
||||
unsigned int j;
|
||||
|
||||
if (uv__vterm_state == UV_SUPPORTED) {
|
||||
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (utf16_buf_used == 0) {
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
utf16_buf,
|
||||
utf16_buf_used)) {
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
FLUSH_TEXT();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < buf.len; j++) {
|
||||
unsigned char c = buf.base[j];
|
||||
|
||||
|
@ -2012,7 +2081,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
|||
handle->tty.wr.previous_eol = previous_eol;
|
||||
handle->tty.wr.ansi_parser_state = ansi_parser_state;
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
if (*error == STATUS_SUCCESS) {
|
||||
return 0;
|
||||
|
@ -2165,3 +2234,24 @@ int uv_tty_reset_mode(void) {
|
|||
/* Not necessary to do anything. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine whether or not this version of windows supports
|
||||
* proper ANSI color codes. Should be supported as of windows
|
||||
* 10 version 1511, build number 10.0.10586.
|
||||
*/
|
||||
static void uv__determine_vterm_state(HANDLE handle) {
|
||||
DWORD dwMode = 0;
|
||||
|
||||
if (!GetConsoleMode(handle, &dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(handle, dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
uv__vterm_state = UV_SUPPORTED;
|
||||
}
|
||||
|
|
|
@ -289,8 +289,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|||
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
|
||||
handle->recv_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
|
||||
if (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);
|
||||
return;
|
||||
}
|
||||
|
@ -506,8 +507,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|||
|
||||
/* Do a nonblocking receive */
|
||||
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,10 @@
|
|||
/* The number of nanoseconds in one second. */
|
||||
#define UV__NANOSEC 1000000000
|
||||
|
||||
/* Max user name length, from iphlpapi.h */
|
||||
#ifndef UNLEN
|
||||
# define UNLEN 256
|
||||
#endif
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
|
@ -416,6 +420,11 @@ static int uv__get_process_title() {
|
|||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
|
||||
EnterCriticalSection(&process_title_lock);
|
||||
|
@ -429,7 +438,14 @@ int uv_get_process_title(char* buffer, size_t size) {
|
|||
}
|
||||
|
||||
assert(process_title);
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -1062,6 +1078,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
|||
FILETIME createTime, exitTime, kernelTime, userTime;
|
||||
SYSTEMTIME kernelSystemTime, userSystemTime;
|
||||
PROCESS_MEMORY_COUNTERS memCounters;
|
||||
IO_COUNTERS ioCounters;
|
||||
int ret;
|
||||
|
||||
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
|
||||
|
@ -1086,6 +1103,11 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
|||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
|
||||
if (ret == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
||||
|
||||
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
|
||||
|
@ -1101,6 +1123,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
|||
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
|
||||
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
|
||||
|
||||
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
|
||||
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,9 +49,14 @@ sCancelSynchronousIo pCancelSynchronousIo;
|
|||
sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
|
||||
void uv_winapi_init() {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE powrprof_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
|
@ -143,4 +148,12 @@ void uv_winapi_init() {
|
|||
|
||||
pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
|
||||
GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
|
||||
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4684,6 +4684,40 @@ typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
|
|||
DWORD cchFilePath,
|
||||
DWORD dwFlags);
|
||||
|
||||
/* from powerbase.h */
|
||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||
# define DEVICE_NOTIFY_CALLBACK 2
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMEAUTOMATIC
|
||||
# define PBT_APMRESUMEAUTOMATIC 18
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMESUSPEND
|
||||
# define PBT_APMRESUMESUSPEND 7
|
||||
#endif
|
||||
|
||||
typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
|
||||
PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting
|
||||
);
|
||||
typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
|
||||
|
||||
typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
|
||||
_PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
|
||||
PVOID Context;
|
||||
} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
|
||||
|
||||
typedef PVOID _HPOWERNOTIFY;
|
||||
typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
|
||||
|
||||
typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
|
||||
(DWORD Flags,
|
||||
HANDLE Recipient,
|
||||
_PHPOWERNOTIFY RegistrationHandle);
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
|
@ -4707,4 +4741,8 @@ extern sWakeConditionVariable pWakeConditionVariable;
|
|||
extern sCancelSynchronousIo pCancelSynchronousIo;
|
||||
extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
|
|
|
@ -56,6 +56,7 @@ int main(int argc, char **argv) {
|
|||
case 1: return run_tests(0);
|
||||
case 2: return maybe_run_test(argc, argv);
|
||||
case 3: return run_test_part(argv[1], argv[2]);
|
||||
case 4: return maybe_run_test(argc, argv);
|
||||
default:
|
||||
fprintf(stderr, "Too many arguments.\n");
|
||||
fflush(stderr);
|
||||
|
@ -177,5 +178,17 @@ static int maybe_run_test(int argc, char **argv) {
|
|||
return spawn_stdin_stdout();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) {
|
||||
uv_uid_t uid = atoi(argv[2]);
|
||||
uv_gid_t gid = atoi(argv[3]);
|
||||
|
||||
ASSERT(uid == getuid());
|
||||
ASSERT(gid == getgid());
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
return run_test(argv[1], 0, 1);
|
||||
}
|
||||
|
|
|
@ -43,11 +43,6 @@
|
|||
|
||||
/* Do platform-specific initialization. */
|
||||
int platform_init(int argc, char **argv) {
|
||||
const char* tap;
|
||||
|
||||
tap = getenv("UV_TAP_OUTPUT");
|
||||
tap_output = (tap != NULL && atoi(tap) > 0);
|
||||
|
||||
/* Disable stdio output buffering. */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
@ -206,7 +201,11 @@ int process_wait(process_info_t* vec, int n, int timeout) {
|
|||
if (pthread_attr_init(&attr))
|
||||
abort();
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (pthread_attr_setstacksize(&attr, 1024 * 1024))
|
||||
#else
|
||||
if (pthread_attr_setstacksize(&attr, 256 * 1024))
|
||||
#endif
|
||||
abort();
|
||||
|
||||
r = pthread_create(&tid, &attr, dowait, &args);
|
||||
|
@ -294,8 +293,7 @@ long int process_output_size(process_info_t *p) {
|
|||
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
ssize_t nwritten;
|
||||
int process_copy_output(process_info_t* p, FILE* stream) {
|
||||
char buf[1024];
|
||||
int r;
|
||||
|
||||
|
@ -306,20 +304,8 @@ int process_copy_output(process_info_t *p, int fd) {
|
|||
}
|
||||
|
||||
/* TODO: what if the line is longer than buf */
|
||||
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
|
||||
/* TODO: what if write doesn't write the whole buffer... */
|
||||
nwritten = 0;
|
||||
|
||||
if (tap_output)
|
||||
nwritten += write(fd, "#", 1);
|
||||
|
||||
nwritten += write(fd, buf, strlen(buf));
|
||||
|
||||
if (nwritten < 0) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL)
|
||||
print_lines(buf, strlen(buf), stream);
|
||||
|
||||
if (ferror(p->stdout_file)) {
|
||||
perror("read");
|
||||
|
@ -390,11 +376,23 @@ void process_cleanup(process_info_t *p) {
|
|||
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
void rewind_cursor(void) {
|
||||
#if defined(__MVS__)
|
||||
fprintf(stderr, "\047[2K\r");
|
||||
#else
|
||||
fprintf(stderr, "\033[2K\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Pause the calling thread for a number of milliseconds. */
|
||||
void uv_sleep(int msec) {
|
||||
usleep(msec * 1000);
|
||||
int sec;
|
||||
int usec;
|
||||
|
||||
sec = msec / 1000;
|
||||
usec = (msec % 1000) * 1000;
|
||||
if (sec > 0)
|
||||
sleep(sec);
|
||||
if (usec > 0)
|
||||
usleep(usec);
|
||||
}
|
||||
|
|
|
@ -44,11 +44,6 @@
|
|||
|
||||
/* Do platform-specific initialization. */
|
||||
int platform_init(int argc, char **argv) {
|
||||
const char* tap;
|
||||
|
||||
tap = getenv("UV_TAP_OUTPUT");
|
||||
tap_output = (tap != NULL && atoi(tap) > 0);
|
||||
|
||||
/* Disable the "application crashed" popup. */
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
|
@ -213,10 +208,9 @@ long int process_output_size(process_info_t *p) {
|
|||
}
|
||||
|
||||
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
int process_copy_output(process_info_t* p, FILE* stream) {
|
||||
DWORD read;
|
||||
char buf[1024];
|
||||
char *line, *start;
|
||||
|
||||
if (SetFilePointer(p->stdio_out,
|
||||
0,
|
||||
|
@ -225,29 +219,8 @@ int process_copy_output(process_info_t *p, int fd) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
write(fd, "#", 1);
|
||||
|
||||
while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) &&
|
||||
read > 0) {
|
||||
if (tap_output) {
|
||||
start = buf;
|
||||
|
||||
while ((line = strchr(start, '\n')) != NULL) {
|
||||
write(fd, start, line - start + 1);
|
||||
write(fd, "#", 1);
|
||||
start = line + 1;
|
||||
}
|
||||
|
||||
if (start < buf + read)
|
||||
write(fd, start, buf + read - start);
|
||||
} else {
|
||||
write(fd, buf, read);
|
||||
}
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
write(fd, "\n", 1);
|
||||
while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0)
|
||||
print_lines(buf, read, stream);
|
||||
|
||||
if (GetLastError() != ERROR_HANDLE_EOF)
|
||||
return -1;
|
||||
|
|
|
@ -28,31 +28,6 @@
|
|||
|
||||
char executable_path[sizeof(executable_path)];
|
||||
|
||||
int tap_output = 0;
|
||||
|
||||
|
||||
static void log_progress(int total,
|
||||
int passed,
|
||||
int failed,
|
||||
int todos,
|
||||
int skipped,
|
||||
const char* name) {
|
||||
int progress;
|
||||
|
||||
if (total == 0)
|
||||
total = 1;
|
||||
|
||||
progress = 100 * (passed + failed + skipped + todos) / total;
|
||||
fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
|
||||
progress,
|
||||
passed,
|
||||
failed,
|
||||
todos,
|
||||
skipped,
|
||||
name);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
const char* fmt(double d) {
|
||||
static char buf[1024];
|
||||
|
@ -95,7 +70,6 @@ int run_tests(int benchmark_output) {
|
|||
int total;
|
||||
int passed;
|
||||
int failed;
|
||||
int todos;
|
||||
int skipped;
|
||||
int current;
|
||||
int test_result;
|
||||
|
@ -109,15 +83,12 @@ int run_tests(int benchmark_output) {
|
|||
}
|
||||
}
|
||||
|
||||
if (tap_output) {
|
||||
fprintf(stderr, "1..%d\n", total);
|
||||
fflush(stderr);
|
||||
}
|
||||
fprintf(stderr, "1..%d\n", total);
|
||||
fflush(stderr);
|
||||
|
||||
/* Run all tests. */
|
||||
passed = 0;
|
||||
failed = 0;
|
||||
todos = 0;
|
||||
skipped = 0;
|
||||
current = 1;
|
||||
for (task = TASKS; task->main; task++) {
|
||||
|
@ -125,30 +96,15 @@ int run_tests(int benchmark_output) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!tap_output)
|
||||
rewind_cursor();
|
||||
|
||||
if (!benchmark_output && !tap_output) {
|
||||
log_progress(total, passed, failed, todos, skipped, task->task_name);
|
||||
}
|
||||
|
||||
test_result = run_test(task->task_name, benchmark_output, current);
|
||||
switch (test_result) {
|
||||
case TEST_OK: passed++; break;
|
||||
case TEST_TODO: todos++; break;
|
||||
case TEST_SKIP: skipped++; break;
|
||||
default: failed++;
|
||||
}
|
||||
current++;
|
||||
}
|
||||
|
||||
if (!tap_output)
|
||||
rewind_cursor();
|
||||
|
||||
if (!benchmark_output && !tap_output) {
|
||||
log_progress(total, passed, failed, todos, skipped, "Done.\n");
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
|
@ -166,10 +122,6 @@ void log_tap_result(int test_count,
|
|||
result = "ok";
|
||||
directive = "";
|
||||
break;
|
||||
case TEST_TODO:
|
||||
result = "not ok";
|
||||
directive = " # TODO ";
|
||||
break;
|
||||
case TEST_SKIP:
|
||||
result = "ok";
|
||||
directive = " # SKIP ";
|
||||
|
@ -179,8 +131,7 @@ void log_tap_result(int test_count,
|
|||
directive = "";
|
||||
}
|
||||
|
||||
if ((status == TEST_SKIP || status == TEST_TODO) &&
|
||||
process_output_size(process) > 0) {
|
||||
if (status == TEST_SKIP && process_output_size(process) > 0) {
|
||||
process_read_last_line(process, reason, sizeof reason);
|
||||
} else {
|
||||
reason[0] = '\0';
|
||||
|
@ -194,7 +145,7 @@ void log_tap_result(int test_count,
|
|||
int run_test(const char* test,
|
||||
int benchmark_output,
|
||||
int test_count) {
|
||||
char errmsg[1024] = "no error";
|
||||
char errmsg[1024] = "";
|
||||
process_info_t processes[1024];
|
||||
process_info_t *main_proc;
|
||||
task_entry_t* task;
|
||||
|
@ -319,22 +270,13 @@ out:
|
|||
FATAL("process_wait failed");
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
log_tap_result(test_count, test, status, &processes[i]);
|
||||
log_tap_result(test_count, test, status, &processes[i]);
|
||||
|
||||
/* Show error and output from processes if the test failed. */
|
||||
if (status != 0 || task->show_output) {
|
||||
if (tap_output) {
|
||||
fprintf(stderr, "#");
|
||||
} else if (status == TEST_TODO) {
|
||||
fprintf(stderr, "\n`%s` todo\n", test);
|
||||
} else if (status == TEST_SKIP) {
|
||||
fprintf(stderr, "\n`%s` skipped\n", test);
|
||||
} else if (status != 0) {
|
||||
fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
|
||||
} else {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {
|
||||
if (strlen(errmsg) > 0)
|
||||
fprintf(stderr, "# %s\n", errmsg);
|
||||
fprintf(stderr, "# ");
|
||||
fflush(stderr);
|
||||
|
||||
for (i = 0; i < process_count; i++) {
|
||||
|
@ -354,15 +296,11 @@ out:
|
|||
default:
|
||||
fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
|
||||
fflush(stderr);
|
||||
process_copy_output(&processes[i], fileno(stderr));
|
||||
process_copy_output(&processes[i], stderr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tap_output) {
|
||||
fprintf(stderr, "=============================================================\n");
|
||||
}
|
||||
|
||||
/* In benchmark mode show concise output from the main process. */
|
||||
} else if (benchmark_output) {
|
||||
switch (process_output_size(main_proc)) {
|
||||
|
@ -378,7 +316,7 @@ out:
|
|||
|
||||
default:
|
||||
for (i = 0; i < process_count; i++) {
|
||||
process_copy_output(&processes[i], fileno(stderr));
|
||||
process_copy_output(&processes[i], stderr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -464,3 +402,21 @@ void print_tests(FILE* stream) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void print_lines(const char* buffer, size_t size, FILE* stream) {
|
||||
const char* start;
|
||||
const char* end;
|
||||
|
||||
start = buffer;
|
||||
while ((end = memchr(start, '\n', &buffer[size] - start))) {
|
||||
fprintf(stream, "# %.*s\n", (int) (end - start), start);
|
||||
fflush(stream);
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (start < &buffer[size]) {
|
||||
fprintf(stream, "# %s\n", start);
|
||||
fflush(stream);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,8 @@ int run_test_part(const char* test, const char* part);
|
|||
*/
|
||||
void print_tests(FILE* stream);
|
||||
|
||||
/* Print lines in |buffer| as TAP diagnostics to |stream|. */
|
||||
void print_lines(const char* buffer, size_t size, FILE* stream);
|
||||
|
||||
/*
|
||||
* Stuff that should be implemented by test-runner-<platform>.h
|
||||
|
@ -148,8 +150,8 @@ int process_wait(process_info_t *vec, int n, int timeout);
|
|||
/* Returns the number of bytes in the stdio output buffer for process `p`. */
|
||||
long int process_output_size(process_info_t *p);
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd);
|
||||
/* Copy the contents of the stdio output buffer to `stream`. */
|
||||
int process_copy_output(process_info_t* p, FILE* stream);
|
||||
|
||||
/* Copy the last line of the stdio output buffer to `buffer` */
|
||||
int process_read_last_line(process_info_t *p,
|
||||
|
@ -172,7 +174,4 @@ void process_cleanup(process_info_t *p);
|
|||
/* Move the console cursor one line up and back to the first column. */
|
||||
void rewind_cursor(void);
|
||||
|
||||
/* trigger output as tap */
|
||||
extern int tap_output;
|
||||
|
||||
#endif /* RUNNER_H_ */
|
||||
|
|
|
@ -136,7 +136,6 @@ const char* fmt(double d);
|
|||
/* Reserved test exit codes. */
|
||||
enum test_status {
|
||||
TEST_OK = 0,
|
||||
TEST_TODO,
|
||||
TEST_SKIP
|
||||
};
|
||||
|
||||
|
@ -145,13 +144,6 @@ enum test_status {
|
|||
return TEST_OK; \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_TODO(explanation) \
|
||||
do { \
|
||||
fprintf(stderr, "%s\n", explanation); \
|
||||
fflush(stderr); \
|
||||
return TEST_TODO; \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_SKIP(explanation) \
|
||||
do { \
|
||||
fprintf(stderr, "%s\n", explanation); \
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
|
|
|
@ -38,12 +38,12 @@ static uv_tcp_t client_handle;
|
|||
|
||||
|
||||
TEST_IMPL(emfile) {
|
||||
#ifdef _AIX
|
||||
#if defined(_AIX) || defined(__MVS__)
|
||||
/* On AIX, if a 'accept' call fails ECONNRESET is set on the socket
|
||||
* which causes uv__emfile_trick to not work as intended and this test
|
||||
* to fail.
|
||||
*/
|
||||
RETURN_SKIP("uv__emfile_trick does not work on AIX");
|
||||
RETURN_SKIP("uv__emfile_trick does not work on this OS");
|
||||
#endif
|
||||
struct sockaddr_in addr;
|
||||
struct rlimit limits;
|
||||
|
|
|
@ -48,3 +48,22 @@ TEST_IMPL(error_message) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(sys_error) {
|
||||
#if defined(_WIN32)
|
||||
ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES);
|
||||
ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE);
|
||||
ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE);
|
||||
#else
|
||||
ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM);
|
||||
ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE);
|
||||
ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL);
|
||||
#endif
|
||||
ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL);
|
||||
ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE);
|
||||
ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES);
|
||||
ASSERT(uv_translate_sys_error(0) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -29,12 +29,19 @@
|
|||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */
|
||||
# define CREATE_TIMEOUT 100
|
||||
#else
|
||||
# define CREATE_TIMEOUT 1
|
||||
#endif
|
||||
|
||||
static uv_fs_event_t fs_event;
|
||||
static const char file_prefix[] = "fsevent-";
|
||||
static const int fs_event_file_count = 16;
|
||||
|
@ -53,6 +60,14 @@ static char fs_event_filename[PATH_MAX];
|
|||
static char fs_event_filename[1024];
|
||||
#endif /* defined(PATH_MAX) */
|
||||
static int timer_cb_touch_called;
|
||||
static int timer_cb_exact_called;
|
||||
|
||||
static void fs_event_fail(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
ASSERT(0 && "should never be called");
|
||||
}
|
||||
|
||||
static void create_dir(const char* name) {
|
||||
int r;
|
||||
|
@ -143,7 +158,10 @@ static void fs_event_create_files(uv_timer_t* handle) {
|
|||
if (++fs_event_created < fs_event_file_count) {
|
||||
/* Create another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
|
||||
ASSERT(0 == uv_timer_start(&timer,
|
||||
fs_event_create_files,
|
||||
CREATE_TIMEOUT,
|
||||
0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,6 +272,14 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
|
|||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
#ifdef _WIN32
|
||||
/* Each file created (or deleted) will cause this callback to be called twice
|
||||
* under Windows: once with the name of the file, and second time with the
|
||||
* name of the directory. We will ignore the callback for the directory
|
||||
* itself. */
|
||||
if (filename && strcmp(filename, file_prefix_in_subdir) == 0)
|
||||
return;
|
||||
#endif
|
||||
fs_event_cb_called++;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
|
@ -345,6 +371,21 @@ static void timer_cb_touch(uv_timer_t* timer) {
|
|||
timer_cb_touch_called++;
|
||||
}
|
||||
|
||||
static void timer_cb_exact(uv_timer_t* handle) {
|
||||
int r;
|
||||
|
||||
if (timer_cb_exact_called == 0) {
|
||||
touch_file("watch_dir/file.js");
|
||||
} else {
|
||||
uv_close((uv_handle_t*)handle, NULL);
|
||||
r = uv_fs_event_stop(&fs_event);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &fs_event, NULL);
|
||||
}
|
||||
|
||||
++timer_cb_exact_called;
|
||||
}
|
||||
|
||||
static void timer_cb_watch_twice(uv_timer_t* handle) {
|
||||
uv_fs_event_t* handles = handle->data;
|
||||
uv_close((uv_handle_t*) (handles + 0), NULL);
|
||||
|
@ -353,6 +394,10 @@ static void timer_cb_watch_twice(uv_timer_t* handle) {
|
|||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_dir) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
|
@ -432,6 +477,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) {
|
|||
|
||||
|
||||
TEST_IMPL(fs_event_watch_file) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
|
@ -467,7 +516,54 @@ TEST_IMPL(fs_event_watch_file) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_exact_path) {
|
||||
/*
|
||||
This test watches a file named "file.jsx" and modifies a file named
|
||||
"file.js". The test verifies that no events occur for file.jsx.
|
||||
*/
|
||||
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Setup */
|
||||
remove("watch_dir/file.js");
|
||||
remove("watch_dir/file.jsx");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file.js");
|
||||
create_file("watch_dir/file.jsx");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
|
||||
ASSERT(r == 0);
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(timer_cb_exact_called == 2);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_dir/file.js");
|
||||
remove("watch_dir/file.jsx");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_twice) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
const char path[] = "test/fixtures/empty_file";
|
||||
uv_fs_event_t watchers[2];
|
||||
uv_timer_t timer;
|
||||
|
@ -489,6 +585,9 @@ TEST_IMPL(fs_event_watch_file_twice) {
|
|||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_current_dir) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
@ -559,6 +658,10 @@ TEST_IMPL(fs_event_watch_file_root_dir) {
|
|||
#endif
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_after_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
|
@ -593,6 +696,10 @@ TEST_IMPL(fs_event_no_callback_after_close) {
|
|||
}
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_on_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
|
@ -626,12 +733,6 @@ TEST_IMPL(fs_event_no_callback_on_close) {
|
|||
}
|
||||
|
||||
|
||||
static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
ASSERT(0 && "should never be called");
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
int r;
|
||||
|
||||
|
@ -646,6 +747,9 @@ static void timer_cb(uv_timer_t* handle) {
|
|||
|
||||
|
||||
TEST_IMPL(fs_event_immediate_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
@ -668,6 +772,9 @@ TEST_IMPL(fs_event_immediate_close) {
|
|||
|
||||
|
||||
TEST_IMPL(fs_event_close_with_pending_event) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
|
@ -698,20 +805,6 @@ TEST_IMPL(fs_event_close_with_pending_event) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_KQUEUE) || defined(_AIX)
|
||||
|
||||
/* kqueue doesn't register fs events if you don't have an active watcher.
|
||||
* The file descriptor needs to be part of the kqueue set of interest and
|
||||
* that's not the case until we actually enter the event loop.
|
||||
* This is also observed on AIX with ahafs.
|
||||
*/
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !HAVE_KQUEUE || !_AIX */
|
||||
|
||||
static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
@ -724,52 +817,49 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
fs_event_unlink_files(NULL);
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
create_file("watch_dir/file2");
|
||||
create_file("watch_dir/file3");
|
||||
create_file("watch_dir/file4");
|
||||
create_file("watch_dir/file5");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Generate a couple of fs events. */
|
||||
touch_file("watch_dir/file1");
|
||||
touch_file("watch_dir/file2");
|
||||
touch_file("watch_dir/file3");
|
||||
touch_file("watch_dir/file4");
|
||||
touch_file("watch_dir/file5");
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
uv_close((uv_handle_t*)&timer, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_ONCE);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
ASSERT(fs_event_cb_called == 3);
|
||||
|
||||
/* Clean up */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file3");
|
||||
remove("watch_dir/file4");
|
||||
remove("watch_dir/file5");
|
||||
fs_event_unlink_files(NULL);
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_KQUEUE || _AIX */
|
||||
|
||||
TEST_IMPL(fs_event_start_and_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
uv_fs_event_t fs_event1;
|
||||
uv_fs_event_t fs_event2;
|
||||
|
@ -802,6 +892,9 @@ TEST_IMPL(fs_event_start_and_close) {
|
|||
}
|
||||
|
||||
TEST_IMPL(fs_event_getpath) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
char buf[1024];
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
/* FIXME we shouldn't need to branch in this file */
|
||||
#if defined(__unix__) || defined(__POSIX__) || \
|
||||
defined(__APPLE__) || defined(_AIX)
|
||||
defined(__APPLE__) || defined(_AIX) || defined(__MVS__)
|
||||
#include <unistd.h> /* unlink, rmdir, etc. */
|
||||
#else
|
||||
# include <direct.h>
|
||||
|
@ -662,8 +662,8 @@ static void check_utime(const char* path, double atime, double mtime) {
|
|||
ASSERT(req.result == 0);
|
||||
s = &req.statbuf;
|
||||
|
||||
ASSERT(s->st_atim.tv_sec == atime);
|
||||
ASSERT(s->st_mtim.tv_sec == mtime);
|
||||
ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime);
|
||||
ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime);
|
||||
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
|
@ -1134,7 +1134,15 @@ TEST_IMPL(fs_fstat) {
|
|||
ASSERT(s->st_mtim.tv_nsec == 0);
|
||||
ASSERT(s->st_ctim.tv_sec == t.st_ctime);
|
||||
ASSERT(s->st_ctim.tv_nsec == 0);
|
||||
#elif defined(__ANDROID__)
|
||||
ASSERT(s->st_atim.tv_sec == t.st_atime);
|
||||
ASSERT(s->st_atim.tv_nsec == t.st_atimensec);
|
||||
ASSERT(s->st_mtim.tv_sec == t.st_mtime);
|
||||
ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec);
|
||||
ASSERT(s->st_ctim.tv_sec == t.st_ctime);
|
||||
ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec);
|
||||
#elif defined(__sun) || \
|
||||
defined(_GNU_SOURCE) || \
|
||||
defined(_BSD_SOURCE) || \
|
||||
defined(_SVID_SOURCE) || \
|
||||
defined(_XOPEN_SOURCE) || \
|
||||
|
@ -1968,6 +1976,15 @@ TEST_IMPL(fs_utime) {
|
|||
|
||||
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
|
||||
|
||||
/*
|
||||
* Test sub-second timestamps only on Windows (assuming NTFS). Some other
|
||||
* platforms support sub-second timestamps, but that support is filesystem-
|
||||
* dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
mtime += 0.444; /* 1982-09-10 11:22:33.444 */
|
||||
#endif
|
||||
|
||||
r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(req.result == 0);
|
||||
|
@ -2055,6 +2072,15 @@ TEST_IMPL(fs_futime) {
|
|||
|
||||
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
|
||||
|
||||
/*
|
||||
* Test sub-second timestamps only on Windows (assuming NTFS). Some other
|
||||
* platforms support sub-second timestamps, but that support is filesystem-
|
||||
* dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
mtime += 0.444; /* 1982-09-10 11:22:33.444 */
|
||||
#endif
|
||||
|
||||
r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(req.result >= 0);
|
||||
|
@ -2605,7 +2631,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
|
|||
r = uv_fs_read(NULL, &read_req, open_req1.result,
|
||||
iovs, iovcount, offset, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(read_req.result == sizeof(test_buf) * iovcount);
|
||||
ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
|
||||
|
||||
for (index = 0; index < iovcount; ++index)
|
||||
ASSERT(strncmp(buffer + index * sizeof(test_buf),
|
||||
|
|
|
@ -68,8 +68,8 @@ static struct echo_ctx ctx2;
|
|||
/* Used in write2_cb to decide if we need to cleanup or not */
|
||||
static int is_child_process;
|
||||
static int is_in_process;
|
||||
static int read_cb_called;
|
||||
static int recv_cb_called;
|
||||
static int read_cb_count;
|
||||
static int recv_cb_count;
|
||||
static int write2_cb_called;
|
||||
|
||||
|
||||
|
@ -91,43 +91,46 @@ static void recv_cb(uv_stream_t* handle,
|
|||
int r;
|
||||
union handles* recv;
|
||||
|
||||
if (++recv_cb_called == 1) {
|
||||
recv = &ctx.recv;
|
||||
} else {
|
||||
recv = &ctx.recv2;
|
||||
}
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx.channel);
|
||||
|
||||
/* Depending on the OS, the final recv_cb can be called after the child
|
||||
* process has terminated which can result in nread being UV_EOF instead of
|
||||
* the number of bytes read. Since the other end of the pipe has closed this
|
||||
* UV_EOF is an acceptable value. */
|
||||
if (nread == UV_EOF) {
|
||||
/* UV_EOF is only acceptable for the final recv_cb call */
|
||||
ASSERT(recv_cb_called == 2);
|
||||
} else {
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
do {
|
||||
if (++recv_cb_count == 1) {
|
||||
recv = &ctx.recv;
|
||||
} else {
|
||||
recv = &ctx.recv2;
|
||||
}
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == ctx.expected_type);
|
||||
/* Depending on the OS, the final recv_cb can be called after
|
||||
* the child process has terminated which can result in nread
|
||||
* being UV_EOF instead of the number of bytes read. Since
|
||||
* the other end of the pipe has closed this UV_EOF is an
|
||||
* acceptable value. */
|
||||
if (nread == UV_EOF) {
|
||||
/* UV_EOF is only acceptable for the final recv_cb call */
|
||||
ASSERT(recv_cb_count == 2);
|
||||
} else {
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == ctx.expected_type);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
} while (uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
/* Close after two writes received */
|
||||
if (recv_cb_called == 2) {
|
||||
if (recv_cb_count == 2) {
|
||||
uv_close((uv_handle_t*)&ctx.channel, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +189,7 @@ static int run_test(int inprocess) {
|
|||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(recv_cb_called == 2);
|
||||
ASSERT(recv_cb_count == 2);
|
||||
|
||||
if (inprocess) {
|
||||
r = uv_thread_join(&tid);
|
||||
|
@ -293,41 +296,43 @@ static void read_cb(uv_stream_t* handle,
|
|||
return;
|
||||
}
|
||||
|
||||
if (++read_cb_called == 2) {
|
||||
recv = &ctx2.recv;
|
||||
write_req = &ctx2.write_req;
|
||||
} else {
|
||||
recv = &ctx2.recv2;
|
||||
write_req = &ctx2.write_req2;
|
||||
}
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx2.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
do {
|
||||
if (++read_cb_count == 2) {
|
||||
recv = &ctx2.recv;
|
||||
write_req = &ctx2.write_req;
|
||||
} else {
|
||||
recv = &ctx2.recv2;
|
||||
write_req = &ctx2.write_req2;
|
||||
}
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
|
||||
ASSERT(pipe == &ctx2.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
wrbuf = uv_buf_init(".", 1);
|
||||
r = uv_write2(write_req,
|
||||
(uv_stream_t*)&ctx2.channel,
|
||||
&wrbuf,
|
||||
1,
|
||||
&recv->stream,
|
||||
write2_cb);
|
||||
ASSERT(r == 0);
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
wrbuf = uv_buf_init(".", 1);
|
||||
r = uv_write2(write_req,
|
||||
(uv_stream_t*)&ctx2.channel,
|
||||
&wrbuf,
|
||||
1,
|
||||
&recv->stream,
|
||||
write2_cb);
|
||||
ASSERT(r == 0);
|
||||
} while (uv_pipe_pending_count(pipe) > 0);
|
||||
}
|
||||
|
||||
static void send_recv_start() {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
TEST_DECLARE (platform_output)
|
||||
TEST_DECLARE (callback_order)
|
||||
TEST_DECLARE (close_order)
|
||||
|
@ -59,6 +61,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess)
|
|||
TEST_DECLARE (ipc_send_recv_tcp)
|
||||
TEST_DECLARE (ipc_send_recv_tcp_inprocess)
|
||||
TEST_DECLARE (ipc_tcp_connection)
|
||||
TEST_DECLARE (tcp_alloc_cb_fail)
|
||||
TEST_DECLARE (tcp_ping_pong)
|
||||
TEST_DECLARE (tcp_ping_pong_v6)
|
||||
TEST_DECLARE (pipe_ping_pong)
|
||||
|
@ -104,6 +107,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail)
|
|||
TEST_DECLARE (tcp_bind6_error_fault)
|
||||
TEST_DECLARE (tcp_bind6_error_inval)
|
||||
TEST_DECLARE (tcp_bind6_localhost_ok)
|
||||
TEST_DECLARE (udp_alloc_cb_fail)
|
||||
TEST_DECLARE (udp_bind)
|
||||
TEST_DECLARE (udp_bind_reuseaddr)
|
||||
TEST_DECLARE (udp_create_early)
|
||||
|
@ -148,6 +152,7 @@ TEST_DECLARE (shutdown_eof)
|
|||
TEST_DECLARE (shutdown_twice)
|
||||
TEST_DECLARE (callback_stack)
|
||||
TEST_DECLARE (error_message)
|
||||
TEST_DECLARE (sys_error)
|
||||
TEST_DECLARE (timer)
|
||||
TEST_DECLARE (timer_init)
|
||||
TEST_DECLARE (timer_again)
|
||||
|
@ -273,6 +278,7 @@ TEST_DECLARE (fs_read_file_eof)
|
|||
TEST_DECLARE (fs_event_watch_dir)
|
||||
TEST_DECLARE (fs_event_watch_dir_recursive)
|
||||
TEST_DECLARE (fs_event_watch_file)
|
||||
TEST_DECLARE (fs_event_watch_file_exact_path)
|
||||
TEST_DECLARE (fs_event_watch_file_twice)
|
||||
TEST_DECLARE (fs_event_watch_file_current_dir)
|
||||
#ifdef _WIN32
|
||||
|
@ -314,13 +320,19 @@ TEST_DECLARE (poll_duplex)
|
|||
TEST_DECLARE (poll_unidirectional)
|
||||
TEST_DECLARE (poll_close)
|
||||
TEST_DECLARE (poll_bad_fdtype)
|
||||
#ifdef __linux__
|
||||
TEST_DECLARE (poll_nested_epoll)
|
||||
#endif
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
TEST_DECLARE (poll_nested_kqueue)
|
||||
#endif
|
||||
|
||||
TEST_DECLARE (ip4_addr)
|
||||
TEST_DECLARE (ip6_addr_link_local)
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
|
||||
TEST_DECLARE (poll_closesocket)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
|
||||
#if !defined(USING_UV_SHARED)
|
||||
TEST_DECLARE (argument_escaping)
|
||||
|
@ -407,6 +419,8 @@ TASK_LIST_START
|
|||
TEST_ENTRY (ipc_send_recv_tcp_inprocess)
|
||||
TEST_ENTRY (ipc_tcp_connection)
|
||||
|
||||
TEST_ENTRY (tcp_alloc_cb_fail)
|
||||
|
||||
TEST_ENTRY (tcp_ping_pong)
|
||||
TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
|
||||
|
||||
|
@ -474,6 +488,7 @@ TASK_LIST_START
|
|||
TEST_ENTRY (tcp_bind6_error_inval)
|
||||
TEST_ENTRY (tcp_bind6_localhost_ok)
|
||||
|
||||
TEST_ENTRY (udp_alloc_cb_fail)
|
||||
TEST_ENTRY (udp_bind)
|
||||
TEST_ENTRY (udp_bind_reuseaddr)
|
||||
TEST_ENTRY (udp_create_early)
|
||||
|
@ -528,6 +543,7 @@ TASK_LIST_START
|
|||
TEST_HELPER (callback_stack, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (error_message)
|
||||
TEST_ENTRY (sys_error)
|
||||
|
||||
TEST_ENTRY (timer)
|
||||
TEST_ENTRY (timer_init)
|
||||
|
@ -624,6 +640,12 @@ TASK_LIST_START
|
|||
TEST_ENTRY (poll_unidirectional)
|
||||
TEST_ENTRY (poll_close)
|
||||
TEST_ENTRY (poll_bad_fdtype)
|
||||
#ifdef __linux__
|
||||
TEST_ENTRY (poll_nested_epoll)
|
||||
#endif
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
TEST_ENTRY (poll_nested_kqueue)
|
||||
#endif
|
||||
|
||||
TEST_ENTRY (socket_buffer_size)
|
||||
|
||||
|
@ -655,9 +677,9 @@ TASK_LIST_START
|
|||
TEST_ENTRY (fs_poll_getpath)
|
||||
TEST_ENTRY (kill)
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
|
||||
TEST_ENTRY (poll_closesocket)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
|
||||
#if !defined(USING_UV_SHARED)
|
||||
TEST_ENTRY (argument_escaping)
|
||||
|
@ -710,6 +732,7 @@ TASK_LIST_START
|
|||
TEST_ENTRY (fs_event_watch_dir)
|
||||
TEST_ENTRY (fs_event_watch_dir_recursive)
|
||||
TEST_ENTRY (fs_event_watch_file)
|
||||
TEST_ENTRY (fs_event_watch_file_exact_path)
|
||||
TEST_ENTRY (fs_event_watch_file_twice)
|
||||
TEST_ENTRY (fs_event_watch_file_current_dir)
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -34,7 +34,9 @@ TEST_IMPL(loop_close) {
|
|||
int r;
|
||||
uv_loop_t loop;
|
||||
|
||||
loop.data = &loop;
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
|
||||
uv_timer_init(&loop, &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 100, 100);
|
||||
|
@ -47,7 +49,9 @@ TEST_IMPL(loop_close) {
|
|||
r = uv_run(&loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
ASSERT(0 == uv_loop_close(&loop));
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
|||
len1 = sizeof buf1;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf1[len1 - 1] != 0);
|
||||
ASSERT(len1 == 0); /* It's an annonymous pipe. */
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
@ -240,7 +240,7 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
|||
len2 = sizeof buf2;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf2[len2 - 1] != 0);
|
||||
ASSERT(len2 == 0); /* It's an annonymous pipe. */
|
||||
|
||||
r = uv_read_stop((uv_stream_t*)&pipe_client);
|
||||
ASSERT(r == 0);
|
||||
|
@ -255,7 +255,6 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
|||
|
||||
ASSERT(pipe_close_cb_called == 1);
|
||||
|
||||
_close(readfd);
|
||||
CloseHandle(writeh);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -61,8 +61,6 @@ TEST_IMPL(platform_output) {
|
|||
ASSERT(rusage.ru_utime.tv_usec >= 0);
|
||||
ASSERT(rusage.ru_stime.tv_sec >= 0);
|
||||
ASSERT(rusage.ru_stime.tv_usec >= 0);
|
||||
ASSERT(rusage.ru_majflt >= 0);
|
||||
ASSERT(rusage.ru_maxrss >= 0);
|
||||
printf("uv_getrusage:\n");
|
||||
printf(" user: %llu sec %llu microsec\n",
|
||||
(unsigned long long) rusage.ru_utime.tv_sec,
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -37,6 +35,7 @@
|
|||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
#ifdef _WIN32
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
|
@ -69,9 +68,13 @@ static void NO_INLINE close_socket_and_verify_stack() {
|
|||
for (i = 0; i < ARRAY_SIZE(data); i++)
|
||||
ASSERT(data[i] == MARKER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(poll_close_doesnt_corrupt_stack) {
|
||||
#ifndef _WIN32
|
||||
RETURN_SKIP("Test only relevant on Windows");
|
||||
#else
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
|
@ -109,6 +112,5 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) {
|
|||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -29,6 +28,7 @@
|
|||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
#ifdef _WIN32
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
|
@ -50,9 +50,13 @@ static void poll_cb(uv_poll_t* h, int status, int events) {
|
|||
uv_close((uv_handle_t*) &handle, close_cb);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(poll_closesocket) {
|
||||
#ifndef _WIN32
|
||||
RETURN_SKIP("Test only relevant on Windows");
|
||||
#else
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
|
@ -85,5 +89,5 @@ TEST_IMPL(poll_closesocket) {
|
|||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -31,6 +31,16 @@
|
|||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
# include <sys/types.h>
|
||||
# include <sys/event.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define NUM_CLIENTS 5
|
||||
#define TRANSFER_BYTES (1 << 16)
|
||||
|
@ -72,9 +82,9 @@ static int closed_connections = 0;
|
|||
static int valid_writable_wakeups = 0;
|
||||
static int spurious_writable_wakeups = 0;
|
||||
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
static int disconnects = 0;
|
||||
#endif /* !_AIX */
|
||||
#endif /* !_AIX && !__MVS__ */
|
||||
|
||||
static int got_eagain(void) {
|
||||
#ifdef _WIN32
|
||||
|
@ -378,7 +388,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
|
|||
new_events &= ~UV_WRITABLE;
|
||||
}
|
||||
}
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
if (events & UV_DISCONNECT) {
|
||||
context->got_disconnect = 1;
|
||||
++disconnects;
|
||||
|
@ -386,9 +396,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
|
|||
}
|
||||
|
||||
if (context->got_fin && context->sent_fin && context->got_disconnect) {
|
||||
#else /* _AIX */
|
||||
#else /* _AIX && __MVS__ */
|
||||
if (context->got_fin && context->sent_fin) {
|
||||
#endif /* !_AIx */
|
||||
#endif /* !_AIX && !__MVS__ */
|
||||
/* Sent and received FIN. Close and destroy context. */
|
||||
close_socket(context->sock);
|
||||
destroy_connection_context(context);
|
||||
|
@ -556,7 +566,7 @@ static void start_poll_test(void) {
|
|||
spurious_writable_wakeups > 20);
|
||||
|
||||
ASSERT(closed_connections == NUM_CLIENTS * 2);
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
ASSERT(disconnects == NUM_CLIENTS * 2);
|
||||
#endif
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
|
@ -584,7 +594,7 @@ TEST_IMPL(poll_unidirectional) {
|
|||
*/
|
||||
TEST_IMPL(poll_bad_fdtype) {
|
||||
#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \
|
||||
!defined(_AIX)
|
||||
!defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__)
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
|
@ -601,3 +611,47 @@ TEST_IMPL(poll_bad_fdtype) {
|
|||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
TEST_IMPL(poll_nested_epoll) {
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
fd = epoll_create(1);
|
||||
ASSERT(fd != -1);
|
||||
|
||||
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
|
||||
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
|
||||
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
|
||||
|
||||
uv_close((uv_handle_t*) &poll_handle, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(0 == close(fd));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
TEST_IMPL(poll_nested_kqueue) {
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
fd = kqueue();
|
||||
ASSERT(fd != -1);
|
||||
|
||||
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
|
||||
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
|
||||
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
|
||||
|
||||
uv_close((uv_handle_t*) &poll_handle, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(0 == close(fd));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif /* UV_HAVE_KQUEUE */
|
||||
|
|
|
@ -41,13 +41,35 @@ static void set_title(const char* title) {
|
|||
}
|
||||
|
||||
|
||||
static void uv_get_process_title_edge_cases() {
|
||||
char buffer[512];
|
||||
int r;
|
||||
|
||||
/* Test a NULL buffer */
|
||||
r = uv_get_process_title(NULL, 100);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* Test size of zero */
|
||||
r = uv_get_process_title(buffer, 0);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* Test for insufficient buffer size */
|
||||
r = uv_get_process_title(buffer, 1);
|
||||
ASSERT(r == UV_ENOBUFS);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(process_title) {
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
|
||||
#else
|
||||
/* Check for format string vulnerabilities. */
|
||||
set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
|
||||
set_title("new title");
|
||||
|
||||
/* Check uv_get_process_title() edge cases */
|
||||
uv_get_process_title_edge_cases();
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -194,6 +194,9 @@ TEST_IMPL(timer_ref2) {
|
|||
|
||||
|
||||
TEST_IMPL(fs_event_ref) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_fs_event_t h;
|
||||
uv_fs_event_init(uv_default_loop(), &h);
|
||||
uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0);
|
||||
|
|
|
@ -46,7 +46,7 @@ static uv_timer_t timer;
|
|||
static uv_process_options_t options;
|
||||
static char exepath[1024];
|
||||
static size_t exepath_size = 1024;
|
||||
static char* args[3];
|
||||
static char* args[5];
|
||||
static int no_term_signal;
|
||||
static int timer_counter;
|
||||
|
||||
|
@ -147,6 +147,8 @@ static void init_process_options(char* test, uv_exit_cb exit_cb) {
|
|||
args[0] = exepath;
|
||||
args[1] = test;
|
||||
args[2] = NULL;
|
||||
args[3] = NULL;
|
||||
args[4] = NULL;
|
||||
options.file = exepath;
|
||||
options.args = args;
|
||||
options.exit_cb = exit_cb;
|
||||
|
@ -1226,21 +1228,26 @@ TEST_IMPL(spawn_with_an_odd_path) {
|
|||
TEST_IMPL(spawn_setuid_setgid) {
|
||||
int r;
|
||||
struct passwd* pw;
|
||||
char uidstr[10];
|
||||
char gidstr[10];
|
||||
|
||||
/* if not root, then this will fail. */
|
||||
uv_uid_t uid = getuid();
|
||||
if (uid != 0) {
|
||||
fprintf(stderr, "spawn_setuid_setgid skipped: not root\n");
|
||||
return 0;
|
||||
RETURN_SKIP("It should be run as root user");
|
||||
}
|
||||
|
||||
init_process_options("spawn_helper1", exit_cb);
|
||||
init_process_options("spawn_helper_setuid_setgid", exit_cb);
|
||||
|
||||
/* become the "nobody" user. */
|
||||
pw = getpwnam("nobody");
|
||||
ASSERT(pw != NULL);
|
||||
options.uid = pw->pw_uid;
|
||||
options.gid = pw->pw_gid;
|
||||
snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid);
|
||||
snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid);
|
||||
options.args[2] = uidstr;
|
||||
options.args[3] = gidstr;
|
||||
options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &process, &options);
|
||||
|
@ -1431,6 +1438,9 @@ TEST_IMPL(spawn_fs_open) {
|
|||
|
||||
#ifndef _WIN32
|
||||
TEST_IMPL(closed_fd_events) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_stdio_container_t stdio[3];
|
||||
uv_pipe_t pipe_handle;
|
||||
int fd[2];
|
||||
|
@ -1500,6 +1510,8 @@ TEST_IMPL(spawn_reads_child_path) {
|
|||
*/
|
||||
#if defined(__APPLE__)
|
||||
static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
|
||||
#elif defined __MVS__
|
||||
static const char dyld_path_var[] = "LIBPATH";
|
||||
#else
|
||||
static const char dyld_path_var[] = "LD_LIBRARY_PATH";
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* Copyright libuv project and contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
static uv_tcp_t server;
|
||||
static uv_tcp_t client;
|
||||
static uv_tcp_t incoming;
|
||||
static int connect_cb_called;
|
||||
static int close_cb_called;
|
||||
static int connection_cb_called;
|
||||
static uv_write_t write_req;
|
||||
|
||||
static char hello[] = "HELLO!";
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
}
|
||||
|
||||
static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
/* Do nothing, read_cb should be called with UV_ENOBUFS. */
|
||||
}
|
||||
|
||||
static void conn_read_cb(uv_stream_t* stream,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
ASSERT(nread == UV_ENOBUFS);
|
||||
ASSERT(buf->base == NULL);
|
||||
ASSERT(buf->len == 0);
|
||||
|
||||
uv_close((uv_handle_t*) &incoming, close_cb);
|
||||
uv_close((uv_handle_t*) &client, close_cb);
|
||||
uv_close((uv_handle_t*) &server, close_cb);
|
||||
}
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(status == 0);
|
||||
connect_cb_called++;
|
||||
|
||||
buf = uv_buf_init(hello, sizeof(hello));
|
||||
r = uv_write(&write_req, req->handle, &buf, 1, write_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
|
||||
ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &incoming,
|
||||
conn_alloc_cb,
|
||||
conn_read_cb));
|
||||
|
||||
connection_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void start_server(void) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
|
||||
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_alloc_cb_fail) {
|
||||
uv_connect_t connect_req;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
start_server();
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
|
||||
ASSERT(0 == uv_tcp_connect(&connect_req,
|
||||
&client,
|
||||
(struct sockaddr*) &addr,
|
||||
connect_cb));
|
||||
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(connection_cb_called == 1);
|
||||
ASSERT(close_cb_called == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
|
@ -40,6 +40,7 @@ static unsigned int got_connections;
|
|||
static unsigned int close_cb_called;
|
||||
static unsigned int write_cb_called;
|
||||
static unsigned int read_cb_called;
|
||||
static unsigned int pending_incoming;
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
|
@ -58,8 +59,11 @@ static void connect_cb(uv_connect_t* req, int status) {
|
|||
if (req == &tcp_check_req) {
|
||||
ASSERT(status != 0);
|
||||
|
||||
/* Close check and incoming[0], time to finish test */
|
||||
uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
|
||||
/*
|
||||
* Time to finish the test: close both the check and pending incoming
|
||||
* connections
|
||||
*/
|
||||
uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], close_cb);
|
||||
uv_close((uv_handle_t*) &tcp_check, close_cb);
|
||||
return;
|
||||
}
|
||||
|
@ -84,8 +88,8 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
|||
uv_loop_t* loop;
|
||||
unsigned int i;
|
||||
|
||||
/* Only first stream should receive read events */
|
||||
ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
|
||||
pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0];
|
||||
ASSERT(pending_incoming < got_connections);
|
||||
ASSERT(0 == uv_read_stop(stream));
|
||||
ASSERT(1 == nread);
|
||||
|
||||
|
@ -93,8 +97,13 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
|||
read_cb_called++;
|
||||
|
||||
/* Close all active incomings, except current one */
|
||||
for (i = 1; i < got_connections; i++)
|
||||
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
|
||||
for (i = 0; i < got_connections; i++) {
|
||||
if (i != pending_incoming)
|
||||
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
|
||||
}
|
||||
|
||||
/* Close server, so no one will connect to it */
|
||||
uv_close((uv_handle_t*) &tcp_server, close_cb);
|
||||
|
||||
/* Create new fd that should be one of the closed incomings */
|
||||
ASSERT(0 == uv_tcp_init(loop, &tcp_check));
|
||||
|
@ -103,9 +112,6 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
|||
(const struct sockaddr*) &addr,
|
||||
connect_cb));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb));
|
||||
|
||||
/* Close server, so no one will connect to it */
|
||||
uv_close((uv_handle_t*) &tcp_server, close_cb);
|
||||
}
|
||||
|
||||
static void connection_cb(uv_stream_t* server, int status) {
|
||||
|
|
|
@ -29,6 +29,7 @@ static uv_tcp_t tcp_handle;
|
|||
static int connect_cb_called;
|
||||
static int timer1_cb_called;
|
||||
static int close_cb_called;
|
||||
static int netunreach_errors;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
|
@ -37,9 +38,15 @@ static void close_cb(uv_handle_t* handle) {
|
|||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT(status == UV_ECANCELED);
|
||||
/* The expected error is UV_ECANCELED but the test tries to connect to what
|
||||
* is basically an arbitrary address in the expectation that no network path
|
||||
* exists, so UV_ENETUNREACH is an equally plausible outcome.
|
||||
*/
|
||||
ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH);
|
||||
uv_timer_stop(&timer2_handle);
|
||||
connect_cb_called++;
|
||||
if (status == UV_ENETUNREACH)
|
||||
netunreach_errors++;
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,5 +89,9 @@ TEST_IMPL(tcp_close_while_connecting) {
|
|||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
|
||||
if (netunreach_errors > 0)
|
||||
RETURN_SKIP("Network unreachable.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
/* Copyright (c) 2015, Santiago Gimeno <santiago.gimeno@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static uv_tcp_t tcp_server;
|
||||
static uv_tcp_t tcp_client;
|
||||
static uv_tcp_t tcp_server_client;
|
||||
static uv_connect_t connect_req;
|
||||
static uv_write_t write_req;
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle,
|
||||
size_t size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = malloc(size);
|
||||
buf->len = size;
|
||||
}
|
||||
|
||||
static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
|
||||
free(buf->base);
|
||||
ASSERT(nread == UV_EOF);
|
||||
}
|
||||
|
||||
static void on_connect(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
uv_buf_t outbuf;
|
||||
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
|
||||
outbuf = uv_buf_init("ping", 4);
|
||||
r = uv_write(&write_req, (uv_stream_t*) req->handle, &outbuf, 1, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*) req->handle, alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*) &tcp_server_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*) &tcp_server_client, NULL);
|
||||
uv_close((uv_handle_t*) &tcp_server, NULL);
|
||||
}
|
||||
|
||||
static void start_server(void) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*) &tcp_server, SOMAXCONN, on_connection);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
static void start_client(void) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_connect(&connect_req,
|
||||
&tcp_client,
|
||||
(const struct sockaddr*) &addr,
|
||||
on_connect);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_squelch_connreset) {
|
||||
|
||||
start_server();
|
||||
|
||||
start_client();
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
|
@ -46,13 +46,13 @@ static void close_cb(uv_handle_t* handle) {
|
|||
close_cb_called++;
|
||||
}
|
||||
|
||||
void timer_cb(uv_timer_t* handle) {
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
uv_close((uv_handle_t*) &client, close_cb);
|
||||
uv_close((uv_handle_t*) &server, close_cb);
|
||||
uv_close((uv_handle_t*) &incoming, close_cb);
|
||||
}
|
||||
|
||||
void write_cb(uv_write_t* req, int status) {
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
if (status == 0)
|
||||
write_callbacks++;
|
||||
else if (status == UV_ECANCELED)
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
|
||||
|
||||
#define WRITES 3
|
||||
#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */
|
||||
#define CHUNKS_PER_WRITE 2048
|
||||
#else
|
||||
#define CHUNKS_PER_WRITE 4096
|
||||
#endif
|
||||
#define CHUNK_SIZE 10024 /* 10 kb */
|
||||
|
||||
#define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE)
|
||||
|
|
|
@ -37,77 +37,45 @@ struct cancel_info {
|
|||
uv_timer_t timer_handle;
|
||||
};
|
||||
|
||||
static uv_cond_t signal_cond;
|
||||
static uv_mutex_t signal_mutex;
|
||||
static uv_mutex_t wait_mutex;
|
||||
static unsigned num_threads;
|
||||
static unsigned fs_cb_called;
|
||||
static unsigned work_cb_called;
|
||||
static unsigned done_cb_called;
|
||||
static unsigned done2_cb_called;
|
||||
static unsigned timer_cb_called;
|
||||
static uv_work_t pause_reqs[4];
|
||||
static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)];
|
||||
|
||||
|
||||
static void work_cb(uv_work_t* req) {
|
||||
uv_mutex_lock(&signal_mutex);
|
||||
uv_cond_signal(&signal_cond);
|
||||
uv_mutex_unlock(&signal_mutex);
|
||||
|
||||
uv_mutex_lock(&wait_mutex);
|
||||
uv_mutex_unlock(&wait_mutex);
|
||||
|
||||
work_cb_called++;
|
||||
uv_sem_wait(pause_sems + (req - pause_reqs));
|
||||
}
|
||||
|
||||
|
||||
static void done_cb(uv_work_t* req, int status) {
|
||||
done_cb_called++;
|
||||
free(req);
|
||||
uv_sem_destroy(pause_sems + (req - pause_reqs));
|
||||
}
|
||||
|
||||
|
||||
static void saturate_threadpool(void) {
|
||||
uv_work_t* req;
|
||||
uv_loop_t* loop;
|
||||
char buf[64];
|
||||
size_t i;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&signal_cond));
|
||||
ASSERT(0 == uv_mutex_init(&signal_mutex));
|
||||
ASSERT(0 == uv_mutex_init(&wait_mutex));
|
||||
snprintf(buf, sizeof(buf), "UV_THREADPOOL_SIZE=%zu", ARRAY_SIZE(pause_reqs));
|
||||
putenv(buf);
|
||||
|
||||
uv_mutex_lock(&signal_mutex);
|
||||
uv_mutex_lock(&wait_mutex);
|
||||
|
||||
for (num_threads = 0; /* empty */; num_threads++) {
|
||||
req = malloc(sizeof(*req));
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb));
|
||||
|
||||
/* Expect to get signalled within 350 ms, otherwise assume that
|
||||
* the thread pool is saturated. As with any timing dependent test,
|
||||
* this is obviously not ideal.
|
||||
*/
|
||||
if (uv_cond_timedwait(&signal_cond,
|
||||
&signal_mutex,
|
||||
(uint64_t) (350 * 1e6))) {
|
||||
ASSERT(0 == uv_cancel((uv_req_t*) req));
|
||||
break;
|
||||
}
|
||||
loop = uv_default_loop();
|
||||
for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) {
|
||||
ASSERT(0 == uv_sem_init(pause_sems + i, 0));
|
||||
ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void unblock_threadpool(void) {
|
||||
uv_mutex_unlock(&signal_mutex);
|
||||
uv_mutex_unlock(&wait_mutex);
|
||||
}
|
||||
size_t i;
|
||||
|
||||
|
||||
static void cleanup_threadpool(void) {
|
||||
ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */
|
||||
ASSERT(work_cb_called == num_threads);
|
||||
|
||||
uv_cond_destroy(&signal_cond);
|
||||
uv_mutex_destroy(&signal_mutex);
|
||||
uv_mutex_destroy(&wait_mutex);
|
||||
for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1)
|
||||
uv_sem_post(pause_sems + i);
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,12 +134,9 @@ static void timer_cb(uv_timer_t* handle) {
|
|||
}
|
||||
|
||||
|
||||
static void nop_work_cb(uv_work_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static void nop_done_cb(uv_work_t* req, int status) {
|
||||
req->data = "OK";
|
||||
ASSERT(status == UV_ECANCELED);
|
||||
done_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,8 +168,6 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) {
|
|||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(1 == timer_cb_called);
|
||||
|
||||
cleanup_threadpool();
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
@ -241,8 +204,6 @@ TEST_IMPL(threadpool_cancel_getnameinfo) {
|
|||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(1 == timer_cb_called);
|
||||
|
||||
cleanup_threadpool();
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
@ -267,8 +228,6 @@ TEST_IMPL(threadpool_cancel_work) {
|
|||
ASSERT(1 == timer_cb_called);
|
||||
ASSERT(ARRAY_SIZE(reqs) == done2_cb_called);
|
||||
|
||||
cleanup_threadpool();
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
@ -322,7 +281,6 @@ TEST_IMPL(threadpool_cancel_fs) {
|
|||
ASSERT(n == fs_cb_called);
|
||||
ASSERT(1 == timer_cb_called);
|
||||
|
||||
cleanup_threadpool();
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
|
@ -332,30 +290,15 @@ TEST_IMPL(threadpool_cancel_fs) {
|
|||
TEST_IMPL(threadpool_cancel_single) {
|
||||
uv_loop_t* loop;
|
||||
uv_work_t req;
|
||||
int cancelled;
|
||||
int i;
|
||||
|
||||
saturate_threadpool();
|
||||
loop = uv_default_loop();
|
||||
for (i = 0; i < 5000; i++) {
|
||||
req.data = NULL;
|
||||
ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb));
|
||||
|
||||
cancelled = uv_cancel((uv_req_t*) &req);
|
||||
if (cancelled == 0)
|
||||
break;
|
||||
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
}
|
||||
|
||||
if (cancelled != 0) {
|
||||
fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n",
|
||||
stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASSERT(req.data == NULL);
|
||||
ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb));
|
||||
ASSERT(0 == uv_cancel((uv_req_t*) &req));
|
||||
ASSERT(0 == done_cb_called);
|
||||
unblock_threadpool();
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */
|
||||
ASSERT(1 == done_cb_called);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#else /* Unix */
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# if defined(__linux__)
|
||||
# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__)
|
||||
# include <pty.h>
|
||||
# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
# include <util.h>
|
||||
|
@ -260,16 +260,24 @@ TEST_IMPL(tty_file) {
|
|||
}
|
||||
|
||||
TEST_IMPL(tty_pty) {
|
||||
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
|
||||
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
int master_fd, slave_fd;
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
(defined(__linux__) && !defined(__ANDROID__)) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
int master_fd, slave_fd, r;
|
||||
struct winsize w;
|
||||
uv_loop_t loop;
|
||||
uv_tty_t master_tty, slave_tty;
|
||||
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
|
||||
ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w));
|
||||
r = openpty(&master_fd, &slave_fd, NULL, NULL, &w);
|
||||
if (r != 0)
|
||||
RETURN_SKIP("No pty available, skipping.");
|
||||
|
||||
ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0));
|
||||
ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0));
|
||||
/* Check if the file descriptor was reopened. If it is,
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/* Copyright libuv project and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK_HANDLE(handle) \
|
||||
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
|
||||
|
||||
static uv_udp_t server;
|
||||
static uv_udp_t client;
|
||||
|
||||
static int cl_send_cb_called;
|
||||
static int cl_recv_cb_called;
|
||||
|
||||
static int sv_send_cb_called;
|
||||
static int sv_recv_cb_called;
|
||||
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void sv_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[65536];
|
||||
CHECK_HANDLE(handle);
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void cl_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
/* Do nothing, recv_cb should be called with UV_ENOBUFS. */
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(1 == uv_is_closing(handle));
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void cl_recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(nread == UV_ENOBUFS);
|
||||
|
||||
cl_recv_cb_called++;
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void cl_send_cb(uv_udp_send_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
CHECK_HANDLE(req->handle);
|
||||
|
||||
r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
cl_send_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void sv_send_cb(uv_udp_send_t* req, int status) {
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
CHECK_HANDLE(req->handle);
|
||||
|
||||
uv_close((uv_handle_t*) req->handle, close_cb);
|
||||
free(req);
|
||||
|
||||
sv_send_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void sv_recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* rcvbuf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
uv_udp_send_t* req;
|
||||
uv_buf_t sndbuf;
|
||||
int r;
|
||||
|
||||
if (nread < 0) {
|
||||
ASSERT(0 && "unexpected error");
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
/* Returning unused buffer */
|
||||
/* Don't count towards sv_recv_cb_called */
|
||||
ASSERT(addr == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(flags == 0);
|
||||
|
||||
ASSERT(addr != NULL);
|
||||
ASSERT(nread == 4);
|
||||
ASSERT(!memcmp("PING", rcvbuf->base, nread));
|
||||
|
||||
r = uv_udp_recv_stop(handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
req = malloc(sizeof *req);
|
||||
ASSERT(req != NULL);
|
||||
|
||||
sndbuf = uv_buf_init("PONG", 4);
|
||||
r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
sv_recv_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_alloc_cb_fail) {
|
||||
struct sockaddr_in addr;
|
||||
uv_udp_send_t req;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_udp_init(uv_default_loop(), &server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_udp_init(uv_default_loop(), &client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
buf = uv_buf_init("PING", 4);
|
||||
r = uv_udp_send(&req,
|
||||
&client,
|
||||
&buf,
|
||||
1,
|
||||
(const struct sockaddr*) &addr,
|
||||
cl_send_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(close_cb_called == 0);
|
||||
ASSERT(cl_send_cb_called == 0);
|
||||
ASSERT(cl_recv_cb_called == 0);
|
||||
ASSERT(sv_send_cb_called == 0);
|
||||
ASSERT(sv_recv_cb_called == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(cl_send_cb_called == 1);
|
||||
ASSERT(cl_recv_cb_called == 1);
|
||||
ASSERT(sv_send_cb_called == 1);
|
||||
ASSERT(sv_recv_cb_called == 1);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
|
@ -47,7 +47,7 @@ static int send_cb_called;
|
|||
static int recv_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
static int can_ipv6_ipv4_dual() {
|
||||
int v6only;
|
||||
size_t size = sizeof(int);
|
||||
|
@ -166,7 +166,7 @@ TEST_IMPL(udp_dual_stack) {
|
|||
if (!can_ipv6())
|
||||
RETURN_SKIP("IPv6 not supported");
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
if (!can_ipv6_ipv4_dual())
|
||||
RETURN_SKIP("IPv6-IPv4 dual stack not supported");
|
||||
#endif
|
||||
|
|
|
@ -72,7 +72,7 @@ TEST_IMPL(udp_multicast_interface6) {
|
|||
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
r = uv_udp_set_multicast_interface(&server, "::1%lo0");
|
||||
#else
|
||||
r = uv_udp_set_multicast_interface(&server, NULL);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче