Update libuv

This commit is contained in:
KimLS 2017-02-25 14:30:35 -08:00
parent d402b25d69
commit 6033f48b47
115 changed files with 4304 additions and 893 deletions

View File

@ -185,6 +185,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend()
void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, uint64_t size)
{
Log.OutF(Logs::Detail, Logs::Netcode, "Recv {0:#x} from {1}:{2}.", data[1], endpoint, port);
if (m_options.simulated_in_packet_loss && m_options.simulated_in_packet_loss >= m_rand.Int(0, 100)) {
Log.OutF(Logs::Detail, Logs::Netcode, "Dropped a packet from {0}:{1} because of simulated packet loss", endpoint, port);
return;
@ -241,13 +242,15 @@ void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr,
{
DaybreakDisconnect header;
header.zero = 0;
header.opcode = OP_SessionDisconnect;
header.opcode = OP_OutOfSession;
header.connect_code = 0;
DynamicPacket out;
out.PutSerialize(0, header);
uv_udp_send_t *send_req = new uv_udp_send_t;
memset(send_req, 0, sizeof(*send_req));
sockaddr_in send_addr;
uv_ip4_addr(addr.c_str(), port, &send_addr);
uv_buf_t send_buffers[1];
@ -1229,6 +1232,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
uv_udp_send_t *send_req = new uv_udp_send_t;
memset(send_req, 0, sizeof(*send_req));
sockaddr_in send_addr;
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
@ -1251,6 +1255,8 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
}
uv_udp_send_t *send_req = new uv_udp_send_t;
memset(send_req, 0, sizeof(*send_req));
sockaddr_in send_addr;
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];

View File

@ -119,7 +119,16 @@ EQApplicationPacket *EQ::Net::EQStream::PopPacket() {
}
EmuOpcode emu_op = (*m_opcode_manager)->EQToEmu(opcode);
EQApplicationPacket *ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->m_options.opcode_size, p->Length() - m_owner->m_options.opcode_size);
auto sz = p->Length() - m_owner->m_options.opcode_size;
EQApplicationPacket *ret = nullptr;
if (sz > 0) {
ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->m_options.opcode_size, sz);
}
else {
ret = new EQApplicationPacket(emu_op);
}
ret->SetProtocolOpcode(opcode);
m_packet_queue.pop_front();
return ret;

View File

@ -1,6 +1,7 @@
Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
Bert Belder <bertbelder@gmail.com> <i@bertbelder.com>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org>

View File

@ -257,3 +257,30 @@ 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>
Hitesh Kanwathirtha <digitalinfinity@gmail.com>
Eric Sciple <ersciple@microsoft.com>
jBarz <jBarz@users.noreply.github.com>
muflub <admin@lodle.net>
Daniel Bevenius <daniel.bevenius@gmail.com>
Howard Hellyer <hhellyer@uk.ibm.com>
Chris Araman <chris.araman@fuze.com>

View File

@ -78,6 +78,7 @@ else()
list(APPEND libuv_sources
src/win/async.c
src/win/core.c
src/win/detect-wakeup.c
src/win/dl.c
src/win/error.c
src/win/fs-event.c

View File

@ -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

View File

@ -1,4 +1,310 @@
2016.05.17, Version 1.9.1 (Stable)
2017.02.02, Version 1.11.0 (Stable)
Changes since version 1.10.2:
* Now working on version 1.10.3 (cjihrig)
* win: added fcntl.h to uv-win.h (Michele Caini)
* unix: move function call out of assert (jBarz)
* fs: cleanup uv__fs_scandir (Santiago Gimeno)
* fs: fix crash in uv_fs_scandir_next (muflub)
* win,signal: fix potential deadlock (Bartosz Sosnowski)
* unix: use async-signal safe functions between fork and exec (jBarz)
* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis)
* zos: make platform functional (John Barboza)
* doc: add repitition qualifier to version regexs (Daniel Bevenius)
* zos: use gyp OS label "os390" on z/OS (John Barboza)
* aix: enable uv_get/set_process_title (Howard Hellyer)
* zos: use built-in proctitle implementation (John Barboza)
* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman)
* win,test: don't write uninitialized buffer to tty (Bert Belder)
* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau)
* aix: re-enable fs watch facility (Gireesh Punathil)
2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20
Changes since version 1.10.1:
* Now working on version 1.10.2 (cjihrig)
* darwin: fix fsync and fdatasync (Joran Dirk Greef)
* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511""
(Santiago Gimeno)
* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno)
* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts)
* win: fix comment in quote_cmd_arg (Eric Sciple)
* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé)
* win, tty: fix crash on restarting with pending data (Nicholas Vavilov)
* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno)
* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau)
* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis)
2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86
Changes since version 1.10.0:
* Now working on version 1.10.1 (cjihrig)
* win: fix anonymous union syntax (Brad King)
* unix: use uv__is_closing everywhere (Santiago Gimeno)
* win: add missing break statement (cjihrig)
* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini)
* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha)
* doc: add cjihrig alternative GPG ID (cjihrig)
* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis)
2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9
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:

View File

@ -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:
====

View File

@ -7,8 +7,14 @@ 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)
- GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb)
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
* **Imran Iqbal** ([@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 +40,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

View File

@ -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,13 +291,36 @@ 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
libuv_la_CFLAGS += -D_ALL_SOURCE \
-D_XOPEN_SOURCE=500 \
-D_LINUX_SOURCE_COMPAT \
-D_THREAD_SAFE \
-DHAVE_SYS_AHAFS_EVPRODS_H
include_HEADERS += include/uv-aix.h
libuv_la_SOURCES += src/unix/aix.c
endif
@ -312,6 +349,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 +388,30 @@ 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 \
src/unix/os390.c \
src/unix/os390-syscalls.c \
src/unix/proctitle.c
endif
if HAVE_PKG_CONFIG
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = @PACKAGE_NAME@.pc

View File

@ -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 \

View File

@ -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

View File

@ -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.

View File

@ -1,4 +1,4 @@
version: v1.9.1.build{build}
version: v1.11.0.build{build}
install:
- cinst -y nsis

View File

@ -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 != "os390"', {
'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 os390"', {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],

View File

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [1.9.1], [https://github.com/libuv/libuv/issues])
AC_INIT([libuv], [1.11.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*], [

View File

@ -21,11 +21,11 @@ def get_libuv_version():
with open('../../include/uv-version.h') as f:
data = f.read()
try:
m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE)
m = re.search(r"""^#define UV_VERSION_MAJOR (\d+)$""", data, re.MULTILINE)
major = int(m.group(1))
m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE)
m = re.search(r"""^#define UV_VERSION_MINOR (\d+)$""", data, re.MULTILINE)
minor = int(m.group(1))
m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE)
m = re.search(r"""^#define UV_VERSION_PATCH (\d+)$""", data, re.MULTILINE)
patch = int(m.group(1))
m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE)
is_release = int(m.group(1))

View File

@ -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.

View File

@ -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
@ -222,7 +223,7 @@ API
.. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
.. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively.
Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`lstat(2)` respectively.
.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
@ -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.

View File

@ -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
----------

View File

@ -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.

View File

@ -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,11 +186,17 @@ 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)
Sets the current process title.
Sets the current process title. On platforms with a fixed size buffer for the
process title the contents of `title` will be copied to the buffer and
truncated if larger than the available space. Other platforms will return
`UV_ENOMEM` if they cannot allocate enough space to duplicate the contents of
`title`.
.. c:function:: int uv_resident_set_memory(size_t* rss)
@ -203,6 +212,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)

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -18,7 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define _UV_PTHREAD_BARRIER_
#include <errno.h>
#include <pthread.h>
#if !defined(__MVS__)
#include <semaphore.h> /* sem_t */
#endif
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
@ -39,6 +41,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 {

View File

@ -408,6 +408,7 @@
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# define UV__EHOSTDOWN (-64)

View File

@ -0,0 +1,30 @@
/* 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
#define UV_PLATFORM_LOOP_FIELDS \
void* ep; \
#endif /* UV_MVS_H */

View File

@ -36,7 +36,9 @@
#include <termios.h>
#include <pwd.h>
#if !defined(__MVS__)
#include <semaphore.h>
#endif
#include <pthread.h>
#include <signal.h>
@ -44,15 +46,18 @@
#if defined(__linux__)
# include "uv-linux.h"
#elif defined (__MVS__)
# include "uv-os390.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun)
# 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

View File

@ -31,8 +31,8 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 9
#define UV_VERSION_PATCH 1
#define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

View File

@ -49,6 +49,7 @@ typedef struct pollfd {
#include <process.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
@ -116,7 +117,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 +127,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 +136,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 +146,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,

View File

@ -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);

View File

@ -1,5 +1,5 @@
prefix=@prefix@
exec_prefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=@includedir@

View File

@ -64,6 +64,11 @@
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
static void* args_mem = NULL;
static char** process_argv = NULL;
static int process_argc = 0;
static char* process_title_ptr = NULL;
int uv__platform_loop_init(uv_loop_t* loop) {
loop->fs_fd = -1;
@ -156,7 +161,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 +338,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 +365,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 +381,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 +457,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 +477,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 +552,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 +670,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
*
@ -753,6 +758,13 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
/* In file / directory move cases, AIX Event infrastructure
* produces a second event with no data.
* Ignore it and return gracefully.
*/
if(bytes == 0)
return;
/* Parse the data */
if(bytes > 0)
rc = uv__parse_data(result_data, &events, handle);
@ -881,23 +893,94 @@ void uv__fs_event_close(uv_fs_event_t* handle) {
char** uv_setup_args(int argc, char** argv) {
return argv;
char** new_argv;
size_t size;
char* s;
int i;
if (argc <= 0)
return argv;
/* Save the original pointer to argv.
* AIX uses argv to read the process name.
* (Not the memory pointed to by argv[0..n] as on Linux.)
*/
process_argv = argv;
process_argc = argc;
/* Calculate how much memory we need for the argv strings. */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
args_mem = new_argv;
/* Copy over the strings and set up the pointer table. */
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = strlen(argv[i]) + 1;
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
return new_argv;
}
int uv_set_process_title(const char* title) {
char* new_title;
/* We cannot free this pointer when libuv shuts down,
* the process may still be using it.
*/
new_title = uv__strdup(title);
if (new_title == NULL)
return -ENOMEM;
/* If this is the first time this is set,
* don't free and set argv[1] to NULL.
*/
if (process_title_ptr != NULL)
uv__free(process_title_ptr);
process_title_ptr = new_title;
process_argv[0] = process_title_ptr;
if (process_argc > 1)
process_argv[1] = NULL;
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
if (size > 0) {
buffer[0] = '\0';
}
size_t len;
len = strlen(process_argv[0]);
if (buffer == NULL || size == 0)
return -EINVAL;
else if (size <= len)
return -ENOBUFS;
memcpy(buffer, process_argv[0], len + 1);
return 0;
}
UV_DESTRUCTOR(static void free_args_mem(void)) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}
int uv_resident_set_memory(size_t* rss) {
char pp[64];
psinfo_t psinfo;

View File

@ -42,6 +42,13 @@ 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__)
unsigned int op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
return oldval;
else
return op4;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
@ -63,6 +70,19 @@ 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
unsigned long long op4;
if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
(unsigned long long*) ptr, *ptr, &op4))
#else
unsigned long op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
#endif
return oldval;
else
return op4;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif

View File

@ -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. */
@ -100,7 +98,7 @@ uint64_t uv_hrtime(void) {
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
handle->flags |= UV_CLOSING;
handle->close_cb = close_cb;
@ -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;
}
@ -519,14 +517,14 @@ int uv__close_nocheckstdio(int fd) {
int uv__close(int fd) {
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
#if defined(__MVS__)
epoll_file_close(fd);
#endif
return uv__close_nocheckstdio(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 +538,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 +551,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 +583,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 +613,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 +924,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 +939,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 +1239,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;
}

View File

@ -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;
}

View File

@ -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
@ -128,8 +129,23 @@
static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
return fdatasync(req->file);
#elif defined(__APPLE__) && defined(SYS_fdatasync)
return syscall(SYS_fdatasync, req->file);
#elif defined(__APPLE__)
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
* for flushing buffered data to permanent storage.
*/
return fcntl(req->file, F_FULLFSYNC);
#else
return fsync(req->file);
#endif
}
static ssize_t uv__fs_fsync(uv_fs_t* req) {
#if defined(__APPLE__)
/* See the comment in uv__fs_fdatasync. */
return fcntl(req->file, F_FULLFSYNC);
#else
return fsync(req->file);
#endif
@ -151,9 +167,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 +183,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 +209,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 +226,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 +276,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,49 +361,45 @@ 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;
if (n == 0)
goto out; /* osx still needs to deallocate some memory */
else if (n == -1)
if (n == 0) {
/* OS X still needs to deallocate some memory.
* Memory was allocated using the system allocator, so use free() here.
*/
free(dents);
dents = NULL;
} else if (n == -1) {
return n;
}
req->ptr = dents;
return n;
out:
saved_errno = errno;
if (dents != NULL) {
int i;
/* Memory was allocated using the system allocator, so use free() here. */
for (i = 0; i < n; i++)
free(dents[i]);
free(dents);
}
errno = saved_errno;
req->ptr = NULL;
return n;
}
@ -595,7 +616,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 +632,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 +801,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_flags = 0;
dst->st_gen = 0;
#elif !defined(_AIX) && ( \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__) || \
defined(_GNU_SOURCE) || \
defined(_BSD_SOURCE) || \
defined(_SVID_SOURCE) || \
defined(_XOPEN_SOURCE) || \
@ -778,9 +816,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
# if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
# if defined(__FreeBSD__) || \
defined(__NetBSD__)
dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
@ -810,8 +846,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 +858,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 +870,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;
}
@ -905,7 +950,7 @@ static void uv__fs_work(struct uv__work* w) {
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
X(FSYNC, fsync(req->file));
X(FSYNC, uv__fs_fsync(req));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));

View File

@ -38,6 +38,10 @@
# include "linux-syscalls.h"
#endif /* __linux__ */
#if defined(__MVS__)
# include "os390-syscalls.h"
#endif /* __MVS__ */
#if defined(__sun)
# include <sys/port.h>
# include <port.h>
@ -52,7 +56,7 @@
#endif /* _AIX */
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <CoreServices/CoreServices.h>
# include <AvailabilityMacros.h>
#endif
#if defined(__ANDROID__)
@ -132,7 +136,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 +157,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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,334 @@
/* 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 "os390-syscalls.h"
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include <search.h>
#define CW_CONDVAR 32
#pragma linkage(BPX4CTW, OS)
#pragma linkage(BPX1CTW, OS)
static int number_of_epolls;
static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT;
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent*),
int (*compar)(const struct dirent**,
const struct dirent **)) {
struct dirent** nl;
struct dirent* dirent;
unsigned count;
size_t allocated;
DIR* mdir;
nl = NULL;
count = 0;
allocated = 0;
mdir = opendir(maindir);
if (!mdir)
return -1;
while (1) {
dirent = readdir(mdir);
if (!dirent)
break;
if (!filter || filter(dirent)) {
struct dirent* copy;
copy = uv__malloc(sizeof(*copy));
if (!copy) {
while (count) {
dirent = nl[--count];
uv__free(dirent);
}
uv__free(nl);
closedir(mdir);
errno = ENOMEM;
return -1;
}
memcpy(copy, dirent, sizeof(*copy));
nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
nl[count++] = copy;
}
}
qsort(nl, count, sizeof(struct dirent *),
(int (*)(const void *, const void *)) compar);
closedir(mdir);
*namelist = nl;
return count;
}
static unsigned int next_power_of_two(unsigned int val) {
val -= 1;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val += 1;
return val;
}
static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
unsigned int newsize;
unsigned int i;
struct pollfd* newlst;
if (len <= lst->size)
return;
newsize = next_power_of_two(len);
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
if (newlst == NULL)
abort();
for (i = lst->size; i < newsize; ++i)
newlst[i].fd = -1;
lst->items = newlst;
lst->size = newsize;
}
static void epoll_init() {
QUEUE_INIT(&global_epoll_queue);
if (uv_mutex_init(&global_epoll_lock))
abort();
}
uv__os390_epoll* epoll_create1(int flags) {
uv__os390_epoll* lst;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
lst = uv__malloc(sizeof(*lst));
if (lst == -1)
return NULL;
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
uv_mutex_unlock(&global_epoll_lock);
/* initialize list */
lst->size = 0;
lst->items = NULL;
return lst;
}
int epoll_ctl(uv__os390_epoll* lst,
int op,
int fd,
struct epoll_event *event) {
if(op == EPOLL_CTL_DEL) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
errno = ENOENT;
return -1;
}
lst->items[fd].fd = -1;
} else if(op == EPOLL_CTL_ADD) {
maybe_resize(lst, fd + 1);
if (lst->items[fd].fd != -1) {
errno = EEXIST;
return -1;
}
lst->items[fd].fd = fd;
lst->items[fd].events = event->events;
} else if(op == EPOLL_CTL_MOD) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
errno = ENOENT;
return -1;
}
lst->items[fd].events = event->events;
} else
abort();
return 0;
}
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
size_t size;
struct pollfd* pfds;
int pollret;
int reventcount;
uv_mutex_lock(&global_epoll_lock);
uv_mutex_unlock(&global_epoll_lock);
size = lst->size;
pfds = lst->items;
pollret = poll(pfds, size, timeout);
if(pollret == -1)
return pollret;
reventcount = 0;
for (int i = 0; i < lst->size && i < maxevents; ++i) {
struct epoll_event ev;
ev.events = 0;
ev.fd = pfds[i].fd;
if(!pfds[i].revents)
continue;
if(pfds[i].revents & POLLRDNORM)
ev.events = ev.events | POLLIN;
if(pfds[i].revents & POLLWRNORM)
ev.events = ev.events | POLLOUT;
if(pfds[i].revents & POLLHUP)
ev.events = ev.events | POLLHUP;
pfds[i].revents = 0;
events[reventcount++] = ev;
}
return reventcount;
}
int epoll_file_close(int fd) {
QUEUE* q;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
QUEUE_FOREACH(q, &global_epoll_queue) {
uv__os390_epoll* lst;
lst = QUEUE_DATA(q, uv__os390_epoll, member);
if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
lst->items[fd].fd = -1;
}
uv_mutex_unlock(&global_epoll_lock);
return 0;
}
void epoll_queue_close(uv__os390_epoll* lst) {
uv_mutex_lock(&global_epoll_lock);
QUEUE_REMOVE(&lst->member);
uv_mutex_unlock(&global_epoll_lock);
uv__free(lst->items);
lst->items = NULL;
}
int nanosleep(const struct timespec* req, struct timespec* rem) {
unsigned nano;
unsigned seconds;
unsigned events;
unsigned secrem;
unsigned nanorem;
int rv;
int rc;
int rsn;
nano = (int)req->tv_nsec;
seconds = req->tv_sec;
events = CW_CONDVAR;
#if defined(_LP64)
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
#else
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
#endif
assert(rv == -1 && errno == EAGAIN);
if(rem != NULL) {
rem->tv_nsec = nanorem;
rem->tv_sec = secrem;
}
return 0;
}
char* mkdtemp(char* path) {
static const char* tempchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const size_t num_chars = 62;
static const size_t num_x = 6;
char *ep, *cp;
unsigned int tries, i;
size_t len;
uint64_t v;
int fd;
int retval;
int saved_errno;
len = strlen(path);
ep = path + len;
if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
errno = EINVAL;
return NULL;
}
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return NULL;
tries = TMP_MAX;
retval = -1;
do {
if (read(fd, &v, sizeof(v)) != sizeof(v))
break;
cp = ep - num_x;
for (i = 0; i < num_x; i++) {
*cp++ = tempchars[v % num_chars];
v /= num_chars;
}
if (mkdir(path, S_IRWXU) == 0) {
retval = 0;
break;
}
else if (errno != EEXIST)
break;
} while (--tries);
saved_errno = errno;
uv__close(fd);
if (tries == 0) {
errno = EEXIST;
return NULL;
}
if (retval == -1) {
errno = saved_errno;
return NULL;
}
return path;
}

View File

@ -0,0 +1,69 @@
/* 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_OS390_SYSCALL_H_
#define UV_OS390_SYSCALL_H_
#include "uv.h"
#include "internal.h"
#include <dirent.h>
#include <poll.h>
#include <pthread.h>
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
#define MAX_EPOLL_INSTANCES 256
#define MAX_ITEMS_PER_EPOLL 1024
#define UV__O_CLOEXEC 0x80000
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD
#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL
#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD
struct epoll_event {
int events;
int fd;
};
typedef struct {
QUEUE member;
struct pollfd* items;
unsigned long size;
} uv__os390_epoll;
/* epoll api */
uv__os390_epoll* epoll_create1(int flags);
int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event);
int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout);
int epoll_file_close(int fd);
/* utility functions */
int nanosleep(const struct timespec* req, struct timespec* rem);
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **,
const struct dirent **));
char *mkdtemp(char* path);
#endif /* UV_OS390_SYSCALL_H_ */

865
libs/libuv/src/unix/os390.c Normal file
View File

@ -0,0 +1,865 @@
/* 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"
#include <sys/ioctl.h>
#include <net/if.h>
#include <utmpx.h>
#include <unistd.h>
#include <sys/ps.h>
#if defined(__clang__)
#include "csrsic.h"
#else
#include "//'SYS1.SAMPLIB(CSRSIC)'"
#endif
#define CVT_PTR 0x10
#define CSD_OFFSET 0x294
/*
Long-term average CPU service used by this logical partition,
in millions of service units per hour. If this value is above
the partition's defined capacity, the partition will be capped.
It is calculated using the physical CPU adjustment factor
(RCTPCPUA) so it may not match other measures of service which
are based on the logical CPU adjustment factor. It is available
if the hardware supports LPAR cluster.
*/
#define RCTLACS_OFFSET 0xC4
/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
#define CSD_NUMBER_ONLINE_CPUS 0xD4
/* Address of system resources manager (SRM) control table */
#define CVTOPCTP_OFFSET 0x25C
/* Address of the RCT table */
#define RMCTRCT_OFFSET 0xE4
/* Address of the rsm control and enumeration area. */
#define CVTRCEP_OFFSET 0x490
/*
Number of frames currently available to system.
Excluded are frames backing perm storage, frames offline, and bad frames.
*/
#define RCEPOOL_OFFSET 0x004
/* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
/* Thread Entry constants */
#define PGTH_CURRENT 1
#define PGTH_LEN 26
#define PGTHAPATH 0x20
#pragma linkage(BPX4GTH, OS)
#pragma linkage(BPX1GTH, OS)
typedef unsigned data_area_ptr_assign_type;
typedef union {
struct {
#if defined(_LP64)
data_area_ptr_assign_type lower;
#endif
data_area_ptr_assign_type assign;
};
char* deref;
} data_area_ptr;
void uv_loadavg(double avg[3]) {
/* TODO: implement the following */
avg[0] = 0;
avg[1] = 0;
avg[2] = 0;
}
int uv__platform_loop_init(uv_loop_t* loop) {
uv__os390_epoll* ep;
ep = epoll_create1(UV__EPOLL_CLOEXEC);
loop->ep = ep;
if (ep == NULL)
return -errno;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->ep != NULL) {
epoll_queue_close(loop->ep);
loop->ep = NULL;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timeval time;
gettimeofday(&time, NULL);
return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
}
/*
Get the exe path using the thread entry information
in the address space.
*/
static int getexe(const int pid, char* buf, size_t len) {
struct {
int pid;
int thid[2];
char accesspid;
char accessthid;
char asid[2];
char loginname[8];
char flag;
char len;
} Input_data;
union {
struct {
char gthb[4];
int pid;
int thid[2];
char accesspid;
char accessthid[3];
int lenused;
int offsetProcess;
int offsetConTTY;
int offsetPath;
int offsetCommand;
int offsetFileData;
int offsetThread;
} Output_data;
char buf[2048];
} Output_buf;
struct Output_path_type {
char gthe[4];
short int len;
char path[1024];
};
int Input_length;
int Output_length;
void* Input_address;
void* Output_address;
struct Output_path_type* Output_path;
int rv;
int rc;
int rsn;
Input_length = PGTH_LEN;
Output_length = sizeof(Output_buf);
Output_address = &Output_buf;
Input_address = &Input_data;
memset(&Input_data, 0, sizeof Input_data);
Input_data.flag |= PGTHAPATH;
Input_data.pid = pid;
Input_data.accesspid = PGTH_CURRENT;
#ifdef _LP64
BPX4GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#else
BPX1GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#endif
if (rv == -1) {
errno = rc;
return -1;
}
/* Check highest byte to ensure data availability */
assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
/* Get the offset from the lowest 3 bytes */
Output_path = (char*)(&Output_buf) +
(Output_buf.Output_data.offsetPath & 0x00FFFFFF);
if (Output_path->len >= len) {
errno = ENOBUFS;
return -1;
}
strncpy(buf, Output_path->path, len);
return 0;
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
* There is no direct way of getting the exe path in zOS - either through /procfs
* or through some libc APIs. The below approach is to parse the argv[0]'s pattern
* and use it in conjunction with PATH environment variable to craft one.
*/
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[PATH_MAX];
char abspath[PATH_MAX];
size_t abspath_size;
int pid;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
pid = getpid();
res = getexe(pid, args, sizeof(args));
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
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(args, '/') != NULL) {
if (realpath(args, abspath) != abspath)
return -errno;
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
} else {
/* Case iii). Search PATH environment variable */
char trypath[PATH_MAX];
char* clonedpath = NULL;
char* token = NULL;
char* path = getenv("PATH");
if (path == NULL)
return -EINVAL;
clonedpath = uv__strdup(path);
if (clonedpath == NULL)
return -ENOMEM;
token = strtok(clonedpath, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
uv__free(clonedpath);
return 0;
}
}
token = strtok(NULL, ":");
}
uv__free(clonedpath);
/* Out of tokens (path entries), and no match found */
return -EINVAL;
}
}
uint64_t uv_get_free_memory(void) {
uint64_t freeram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
return freeram;
}
uint64_t uv_get_total_memory(void) {
uint64_t totalram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
return totalram;
}
int uv_resident_set_memory(size_t* rss) {
W_PSPROC buf;
memset(&buf, 0, sizeof(buf));
if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
return -EINVAL;
*rss = buf.ps_size;
return 0;
}
int uv_uptime(double* uptime) {
struct utmpx u ;
struct utmpx *v;
time64_t t;
u.ut_type = BOOT_TIME;
v = getutxid(&u);
if (v == NULL)
return -1;
*uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
int result;
int idx;
siv1v2 info;
data_area_ptr cvt = {0};
data_area_ptr csd = {0};
data_area_ptr rmctrct = {0};
data_area_ptr cvtopctp = {0};
int cpu_usage_avg;
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
*count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
*cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
if (!*cpu_infos)
return -ENOMEM;
cpu_info = *cpu_infos;
idx = 0;
while (idx < *count) {
cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
cpu_info->cpu_times.user = cpu_usage_avg;
/* TODO: implement the following */
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
cpu_info->cpu_times.nice = 0;
++cpu_info;
++idx;
}
return 0;
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
for (int i = 0; i < count; ++i)
uv__free(cpu_infos[i].model);
uv__free(cpu_infos);
}
static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
__net_ifconf6header_t ifc;
__net_ifconf6entry_t* ifr;
__net_ifconf6entry_t* p;
__net_ifconf6entry_t flg;
*count = 0;
/* Assume maximum buffer size allowable */
maxsize = 16384;
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
return -errno;
ifc.__nif6h_version = 1;
ifc.__nif6h_buflen = maxsize;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
uv__close(sockfd);
return -errno;
}
*count = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
++(*count);
}
/* Alloc the return interface structs */
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return -ENOMEM;
}
address = *addresses;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->__nif6e_name);
if (p->__nif6e_addr.sin6_family == AF_INET6)
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
else
address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
address++;
}
uv__close(sockfd);
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
struct ifconf ifc;
struct ifreq flg;
struct ifreq* ifr;
struct ifreq* p;
int count_v6;
/* get the ipv6 addresses first */
uv_interface_address_t* addresses_v6;
uv__interface_addresses_v6(&addresses_v6, &count_v6);
/* now get the ipv4 addresses */
*count = 0;
/* Assume maximum buffer size allowable */
maxsize = 16384;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (0 > sockfd)
return -errno;
ifc.ifc_req = uv__calloc(1, maxsize);
ifc.ifc_len = maxsize;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
uv__close(sockfd);
return -errno;
}
#define MAX(a,b) (((a)>(b))?(a):(b))
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
/* Count all up and running ipv4/ipv6 addresses */
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return -errno;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
(*count)++;
}
/* Alloc the return interface structs */
*addresses = uv__malloc((*count + count_v6) *
sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return -ENOMEM;
}
address = *addresses;
/* copy over the ipv6 addresses */
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
address += count_v6;
*count += count_v6;
uv__free(addresses_v6);
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return -ENOSYS;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->ifr_name);
if (p->ifr_addr.sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
address++;
}
#undef ADDR_SIZE
#undef MAX
uv__close(sockfd);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i)
uv__free(addresses[i].name);
uv__free(addresses);
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].fd == fd)
events[i].fd = -1;
/* Remove the file descriptor from the epoll. */
if (loop->ep != NULL)
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
}
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;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return -ENOSYS;
}
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
return -ENOSYS;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
return -ENOSYS;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
static const int max_safe_timeout = 1789569;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
uint64_t base;
int count;
int nfds;
int fd;
int op;
int i;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
uv_stream_t* stream;
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
stream= container_of(w, uv_stream_t, io_watcher);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.fd = w->fd;
if (w->events == 0)
op = UV__EPOLL_CTL_ADD;
else
op = UV__EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->ep, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == UV__EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
int nevents = 0;
nfds = 0;
for (;;) {
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
nfds = epoll_wait(loop->ep, events,
ARRAY_SIZE(events), timeout);
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
base = loop->time;
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
timeout = real_timeout - timeout;
if (timeout > 0)
continue;
return;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) {
w->cb(loop, w, pe->events);
nevents++;
}
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}
void uv__set_process_title(const char* title) {
/* do nothing */
}

View File

@ -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;

View File

@ -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;
@ -85,7 +92,7 @@ static void uv__poll_stop(uv_poll_t* handle) {
int uv_poll_stop(uv_poll_t* handle) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
return 0;
}
@ -95,7 +102,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__poll_stop(handle);

View File

@ -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;
@ -323,7 +323,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
}
if (fd == use_fd)
uv__cloexec(use_fd, 0);
uv__cloexec_fcntl(use_fd, 0);
else
fd = dup2(use_fd, fd);
@ -333,7 +333,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
}
if (fd <= 2)
uv__nonblock(fd, 0);
uv__nonblock_fcntl(fd, 0);
if (close_fd >= stdio_count)
uv__close(close_fd);

View File

@ -48,9 +48,15 @@ char** uv_setup_args(int argc, char** argv) {
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
#if defined(__MVS__)
/* argv is not adjacent. So just use argv[0] */
process_title.str = argv[0];
process_title.len = strlen(argv[0]);
#else
process_title.str = argv[0];
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
#endif
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
@ -87,10 +93,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;
}

View File

@ -73,7 +73,8 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) {
if (++b->in == b->threshold) {
b->in = 0;
b->out = b->threshold - 1;
assert(pthread_cond_signal(&b->cond) == 0);
rc = pthread_cond_signal(&b->cond);
assert(rc == 0);
pthread_mutex_unlock(&b->mutex);
return PTHREAD_BARRIER_SERIAL_THREAD;

View File

@ -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);
}
@ -290,7 +290,7 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
sigset_t saved_sigmask;
int err;
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
/* If the user supplies signum == 0, then return an error already. If the
* signum is otherwise invalid then uv__signal_register will find out
@ -434,7 +434,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
int uv_signal_stop(uv_signal_t* handle) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__signal_stop(handle);
return 0;
}

View File

@ -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)
@ -387,7 +390,7 @@ failed_malloc:
int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
#if defined(__APPLE__)
#if defined(__APPLE__) || defined(__MVS__)
int enable;
#endif
@ -406,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
return -errno;
}
#if defined(__APPLE__)
#if defined(__APPLE__) || defined(__MVS__)
enable = 1;
if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
errno != ENOTSOCK &&
@ -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;
@ -1189,6 +1194,30 @@ static void uv__read(uv_stream_t* stream) {
return;
}
}
#if defined(__MVS__)
if (is_ipc && msg.msg_controllen > 0) {
uv_buf_t blankbuf;
int nread;
struct iovec *old;
blankbuf.base = 0;
blankbuf.len = 0;
old = msg.msg_iov;
msg.msg_iov = (struct iovec*) &blankbuf;
nread = 0;
do {
nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
err = uv__stream_recv_cmsg(stream, &msg);
if (err != 0) {
stream->read_cb(stream, err, &buf);
msg.msg_iov = old;
return;
}
} while (nread == 0 && msg.msg_controllen > 0);
msg.msg_iov = old;
}
#endif
stream->read_cb(stream, nread, &buf);
/* Return if we didn't fill the buffer, there is no more data to read. */
@ -1216,8 +1245,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
if (!(stream->flags & UV_STREAM_WRITABLE) ||
stream->flags & UV_STREAM_SHUT ||
stream->flags & UV_STREAM_SHUTTING ||
stream->flags & UV_CLOSED ||
stream->flags & UV_CLOSING) {
uv__is_closing(stream)) {
return -ENOTCONN;
}

View File

@ -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,59 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
#ifdef SUNOS_NO_IFADDRS
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return -ENOSYS;
}
#else /* SUNOS_NO_IFADDRS */
/*
* 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,34 +800,15 @@ 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;
#endif /* SUNOS_NO_IFADDRS */
}
#endif /* SUNOS_NO_IFADDRS */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -512,8 +512,18 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) {
int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
uv__dirent_t** dents;
uv__dirent_t* dent;
unsigned int* nbufs;
unsigned int* nbufs = uv__get_nbufs(req);
/* Check to see if req passed */
if (req->result < 0)
return req->result;
/* Ptr will be null if req was canceled or no files found */
if (!req->ptr)
return UV_EOF;
nbufs = uv__get_nbufs(req);
assert(nbufs);
dents = req->ptr;
@ -613,6 +623,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 +639,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;

View File

@ -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,

View File

@ -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,
&registration_handle);
}

View File

@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;

View File

@ -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';

View File

@ -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));
}
@ -405,7 +403,6 @@ void fs__open(uv_fs_t* req) {
switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
case _O_RDONLY:
access = FILE_GENERIC_READ;
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
break;
case _O_WRONLY:
access = FILE_GENERIC_WRITE;
@ -420,7 +417,6 @@ void fs__open(uv_fs_t* req) {
if (flags & _O_APPEND) {
access &= ~FILE_WRITE_DATA;
access |= FILE_APPEND_DATA;
attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
}
/*
@ -1091,17 +1087,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 +1436,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 +1892,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;

View File

@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
int err;
if (req == NULL || (node == NULL && service == NULL)) {
err = WSAEINVAL;
goto error;
return UV_EINVAL;
}
uv_req_init(loop, (uv_req_t*)req);

View File

@ -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_ */

View File

@ -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;
}

View File

@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop,
case FILE_TYPE_PIPE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
case FILE_TYPE_CHAR:
case FILE_TYPE_REMOTE:

View File

@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
* input : hello\\"world
* output: "hello\\\\\"world"
* input : hello world\
* output: "hello world\"
* output: "hello world\\"
*/
*(target++) = L'"';

View File

@ -30,12 +30,14 @@
RB_HEAD(uv_signal_tree_s, uv_signal_s);
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
static ssize_t volatile uv__signal_control_handler_refs = 0;
static CRITICAL_SECTION uv__signal_lock;
static BOOL WINAPI uv__signal_control_handler(DWORD type);
void uv_signals_init() {
InitializeCriticalSection(&uv__signal_lock);
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
abort();
}
@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
}
static int uv__signal_register_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
/* If the console control handler has already been hooked, just add a */
/* reference. */
if (uv__signal_control_handler_refs > 0) {
uv__signal_control_handler_refs++;
return 0;
}
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
return GetLastError();
uv__signal_control_handler_refs++;
return 0;
}
static void uv__signal_unregister_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
BOOL r;
/* Don't unregister if the number of console control handlers exceeds one. */
/* Just remove a reference in that case. */
if (uv__signal_control_handler_refs > 1) {
uv__signal_control_handler_refs--;
return;
}
assert(uv__signal_control_handler_refs == 1);
r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
/* This should never fail; if it does it is probably a bug in libuv. */
assert(r);
uv__signal_control_handler_refs--;
}
static int uv__signal_register(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
return uv__signal_register_control_handler();
case SIGWINCH:
/* SIGWINCH is generated in tty.c. No need to register anything. */
return 0;
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Signal is never raised. */
return 0;
default:
/* Invalid signal. */
return ERROR_INVALID_PARAMETER;
}
}
static void uv__signal_unregister(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
uv__signal_unregister_control_handler();
return;
case SIGWINCH:
/* SIGWINCH is generated in tty.c. No need to unregister anything. */
return;
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Nothing is registered for this signal. */
return;
default:
/* Libuv bug. */
assert(0 && "Invalid signum");
return;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv_req_t* req;
@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) {
EnterCriticalSection(&uv__signal_lock);
uv__signal_unregister(handle->signum);
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) {
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
int err;
/* If the user supplies signum == 0, then return an error already. If the */
/* signum is otherwise invalid then uv__signal_register will find out */
/* eventually. */
if (signum == 0) {
/* Test for invalid signal values. */
if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
return UV_EINVAL;
}
/* Short circuit: if the signal watcher is already watching {signum} don't */
/* go through the process of deregistering and registering the handler. */
@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
EnterCriticalSection(&uv__signal_lock);
err = uv__signal_register(signum);
if (err) {
/* Uh-oh, didn't work. */
LeaveCriticalSection(&uv__signal_lock);
return uv_translate_sys_error(err);
}
handle->signum = signum;
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);

View File

@ -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;
}

View File

@ -40,6 +40,9 @@
#include "stream-inl.h"
#include "req-inl.h"
#ifndef InterlockedOr
# define InterlockedOr _InterlockedOr
#endif
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
@ -53,7 +56,11 @@
#define ANSI_BACKSLASH_SEEN 0x80
#define MAX_INPUT_BUFFER_LENGTH 8192
#define MAX_CONSOLE_CHAR 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 +112,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 +129,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 +178,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 +193,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 +317,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 +334,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 +371,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 +442,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 +472,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 +493,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 +539,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 +710,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 +865,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;
}
@ -966,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
if (handle->tty.rd.last_key_len > 0) {
SET_REQ_SUCCESS(&handle->read_req);
uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
/* Make sure no attempt is made to insert it again until it's handled. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
return 0;
}
@ -1013,11 +1054,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;
}
@ -1574,17 +1620,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
DWORD* error) {
/* We can only write 8k characters at a time. Windows can't handle */
/* much more characters in a single console write anyway. */
WCHAR utf16_buf[8192];
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
WCHAR* utf16_buffer;
DWORD utf16_buf_used = 0;
unsigned int i;
unsigned int i, len, max_len, pos;
int allocate = 0;
#define FLUSH_TEXT() \
do { \
if (utf16_buf_used > 0) { \
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
utf16_buf_used = 0; \
} \
} while (0)
#define FLUSH_TEXT() \
do { \
pos = 0; \
do { \
len = utf16_buf_used - pos; \
if (len > MAX_CONSOLE_CHAR) \
len = MAX_CONSOLE_CHAR; \
uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
pos += len; \
} while (pos < utf16_buf_used); \
if (allocate) { \
uv__free(utf16_buffer); \
allocate = 0; \
utf16_buffer = utf16_buf; \
} \
utf16_buf_used = 0; \
} while (0)
#define ENSURE_BUFFER_SPACE(wchars_needed) \
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
@ -1602,12 +1660,48 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
/* state. */
*error = ERROR_SUCCESS;
EnterCriticalSection(&uv_tty_output_lock);
utf16_buffer = utf16_buf;
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 && buf.len > 0) {
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
NULL,
0);
if (utf16_buf_used == 0) {
*error = GetLastError();
break;
}
max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
allocate = max_len > MAX_CONSOLE_CHAR;
if (allocate)
utf16_buffer = uv__malloc(max_len);
if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buffer,
utf16_buf_used)) {
if (allocate)
uv__free(utf16_buffer);
*error = GetLastError();
break;
}
FLUSH_TEXT();
continue;
}
for (j = 0; j < buf.len; j++) {
unsigned char c = buf.base[j];
@ -2012,7 +2106,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 +2259,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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#endif
@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
@ -4606,6 +4606,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
#endif
/* from winerror.h */
#ifndef ERROR_ELEVATION_REQUIRED
# define ERROR_ELEVATION_REQUIRED 740
#endif
#ifndef ERROR_SYMLINK_NOT_SUPPORTED
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
#endif
@ -4684,6 +4688,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 +4745,8 @@ extern sWakeConditionVariable pWakeConditionVariable;
extern sCancelSynchronousIo pCancelSynchronousIo;
extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
#endif /* UV_WIN_WINAPI_H_ */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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_ */

View File

@ -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); \

View File

@ -29,6 +29,7 @@
# if defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# define HAVE_KQUEUE 1

View File

@ -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;

View File

@ -21,6 +21,9 @@
#include "uv.h"
#include "task.h"
#if defined(_WIN32)
# include "../src/win/winapi.h"
#endif
#include <stdio.h>
#include <stdlib.h>
@ -48,3 +51,23 @@ 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(ERROR_ELEVATION_REQUIRED) == 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;
}

View File

@ -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];

View File

@ -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>
@ -510,6 +510,18 @@ static void empty_scandir_cb(uv_fs_t* req) {
scandir_cb_count++;
}
static void non_existent_scandir_cb(uv_fs_t* req) {
uv_dirent_t dent;
ASSERT(req == &scandir_req);
ASSERT(req->fs_type == UV_FS_SCANDIR);
ASSERT(req->result == UV_ENOENT);
ASSERT(req->ptr == NULL);
ASSERT(UV_ENOENT == uv_fs_scandir_next(req, &dent));
uv_fs_req_cleanup(req);
scandir_cb_count++;
}
static void file_scandir_cb(uv_fs_t* req) {
ASSERT(req == &scandir_req);
@ -662,8 +674,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,10 +1146,22 @@ 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(__sun) || \
defined(_BSD_SOURCE) || \
defined(_SVID_SOURCE) || \
defined(_XOPEN_SOURCE) || \
#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(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__) || \
defined(_GNU_SOURCE) || \
defined(_BSD_SOURCE) || \
defined(_SVID_SOURCE) || \
defined(_XOPEN_SOURCE) || \
defined(_DEFAULT_SOURCE)
ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec);
ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec);
@ -1145,10 +1169,8 @@ TEST_IMPL(fs_fstat) {
ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec);
ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec);
ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec);
# if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# if defined(__FreeBSD__) || \
defined(__NetBSD__)
ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec);
ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec);
ASSERT(s->st_flags == t.st_flags);
@ -1968,6 +1990,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 +2086,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);
@ -2147,6 +2187,39 @@ TEST_IMPL(fs_scandir_empty_dir) {
}
TEST_IMPL(fs_scandir_non_existent_dir) {
const char* path;
uv_fs_t req;
uv_dirent_t dent;
int r;
path = "./non_existent_dir/";
loop = uv_default_loop();
uv_fs_rmdir(NULL, &req, path, NULL);
uv_fs_req_cleanup(&req);
/* Fill the req to ensure that required fields are cleaned up */
memset(&req, 0xdb, sizeof(req));
r = uv_fs_scandir(NULL, &req, path, 0, NULL);
ASSERT(r == UV_ENOENT);
ASSERT(req.result == UV_ENOENT);
ASSERT(req.ptr == NULL);
ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent));
uv_fs_req_cleanup(&req);
r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb);
ASSERT(r == 0);
ASSERT(scandir_cb_count == 0);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(scandir_cb_count == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(fs_scandir_file) {
const char* path;
int r;
@ -2605,7 +2678,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),

View File

@ -83,6 +83,13 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle,
TEST_IMPL(getaddrinfo_fail) {
uv_getaddrinfo_t req;
ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(),
&req,
(uv_getaddrinfo_cb) abort,
NULL,
NULL,
NULL));
/* Use a FQDN by ending in a period */
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,

View File

@ -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() {

View File

@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
#include "uv.h"
TEST_DECLARE (platform_output)
TEST_DECLARE (callback_order)
TEST_DECLARE (close_order)
@ -45,6 +47,8 @@ TEST_DECLARE (semaphore_3)
TEST_DECLARE (tty)
#ifdef _WIN32
TEST_DECLARE (tty_raw)
TEST_DECLARE (tty_empty_write)
TEST_DECLARE (tty_large_write)
#endif
TEST_DECLARE (tty_file)
TEST_DECLARE (tty_pty)
@ -59,6 +63,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 +109,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 +154,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 +280,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
@ -287,6 +295,7 @@ TEST_DECLARE (fs_event_start_and_close)
TEST_DECLARE (fs_event_error_reporting)
TEST_DECLARE (fs_event_getpath)
TEST_DECLARE (fs_scandir_empty_dir)
TEST_DECLARE (fs_scandir_non_existent_dir)
TEST_DECLARE (fs_scandir_file)
TEST_DECLARE (fs_open_dir)
TEST_DECLARE (fs_rename_to_existing_file)
@ -314,13 +323,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)
@ -331,6 +346,7 @@ TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root)
TEST_DECLARE (spawn_with_an_odd_path)
TEST_DECLARE (ipc_listen_after_bind_twice)
TEST_DECLARE (win32_signum_number)
#else
TEST_DECLARE (emfile)
TEST_DECLARE (close_fd)
@ -392,6 +408,8 @@ TASK_LIST_START
TEST_ENTRY (tty)
#ifdef _WIN32
TEST_ENTRY (tty_raw)
TEST_ENTRY (tty_empty_write)
TEST_ENTRY (tty_large_write)
#endif
TEST_ENTRY (tty_file)
TEST_ENTRY (tty_pty)
@ -407,6 +425,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 +494,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 +549,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 +646,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 +683,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)
@ -668,6 +696,7 @@ TASK_LIST_START
TEST_ENTRY (fs_stat_root)
TEST_ENTRY (spawn_with_an_odd_path)
TEST_ENTRY (ipc_listen_after_bind_twice)
TEST_ENTRY (win32_signum_number)
#else
TEST_ENTRY (emfile)
TEST_ENTRY (close_fd)
@ -710,6 +739,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
@ -724,6 +754,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_error_reporting)
TEST_ENTRY (fs_event_getpath)
TEST_ENTRY (fs_scandir_empty_dir)
TEST_ENTRY (fs_scandir_non_existent_dir)
TEST_ENTRY (fs_scandir_file)
TEST_ENTRY (fs_open_dir)
TEST_ENTRY (fs_rename_to_existing_file)

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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 */

View File

@ -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
}

View File

@ -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 */

View File

@ -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)
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
}

View File

@ -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);

View File

@ -19,13 +19,40 @@
* IN THE SOFTWARE.
*/
/* This test does not pretend to be cross-platform. */
#ifndef _WIN32
#include "uv.h"
#include "task.h"
/* For Windows we test only signum handling */
#ifdef _WIN32
static void signum_test_cb(uv_signal_t* handle, int signum) {
FATAL("signum_test_cb should not be called");
}
TEST_IMPL(win32_signum_number) {
uv_signal_t signal;
uv_loop_t* loop;
loop = uv_default_loop();
uv_signal_init(loop, &signal);
ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0);
ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL);
ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL);
ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL);
MAKE_VALGRIND_HAPPY();
return 0;
}
#else
#include <errno.h>
#include <signal.h>
#include <stdarg.h>

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