mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Update libuv
This commit is contained in:
parent
d402b25d69
commit
6033f48b47
@ -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];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -165,5 +165,5 @@ not send out notifications when you add commits.
|
||||
[issue tracker]: https://github.com/libuv/libuv/issues
|
||||
[libuv mailing list]: http://groups.google.com/group/libuv
|
||||
[IRC]: http://webchat.freelibuv.net/?channels=libuv
|
||||
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
|
||||
[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html
|
||||
[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md
|
||||
|
||||
@ -1,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:
|
||||
|
||||
|
||||
@ -1,5 +1,29 @@
|
||||
libuv is part of the Node project: http://nodejs.org/
|
||||
libuv may be distributed alone under Node's license:
|
||||
libuv is licensed for use as follows:
|
||||
|
||||
====
|
||||
Copyright (c) 2015-present libuv project contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
====
|
||||
|
||||
This license applies to parts of libuv originating from the
|
||||
https://github.com/joyent/libuv repository:
|
||||
|
||||
====
|
||||
|
||||
|
||||
@ -7,8 +7,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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -48,6 +48,7 @@ OBJS = src/fs-poll.o \
|
||||
src/version.o \
|
||||
src/win/async.o \
|
||||
src/win/core.o \
|
||||
src/win/detect-wakeup.o \
|
||||
src/win/dl.o \
|
||||
src/win/error.o \
|
||||
src/win/fs-event.o \
|
||||
|
||||
@ -39,6 +39,12 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve
|
||||
scheme. The API change and backwards compatibility rules are those indicated by
|
||||
SemVer. libuv will keep a stable ABI across major releases.
|
||||
|
||||
The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/).
|
||||
|
||||
## Licensing
|
||||
|
||||
libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE).
|
||||
|
||||
## Community
|
||||
|
||||
* [Mailing list](http://groups.google.com/group/libuv)
|
||||
@ -220,18 +226,7 @@ Run:
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Microsoft Windows operating systems since Windows XP SP2. It can be built
|
||||
with either Visual Studio or MinGW. Consider using
|
||||
[Visual Studio Express 2010][] or later if you do not have a full Visual
|
||||
Studio license.
|
||||
|
||||
Linux using the GCC toolchain.
|
||||
|
||||
OS X using the GCC or XCode toolchain.
|
||||
|
||||
Solaris 121 and later using GCC toolchain.
|
||||
|
||||
AIX 6 and later using GCC toolchain (see notes).
|
||||
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
|
||||
|
||||
### AIX Notes
|
||||
|
||||
@ -250,7 +245,6 @@ See the [guidelines for contributing][].
|
||||
[node.js]: http://nodejs.org/
|
||||
[GYP]: http://code.google.com/p/gyp/
|
||||
[Python]: https://www.python.org/downloads/
|
||||
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
|
||||
[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
|
||||
[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
|
||||
[x32]: https://en.wikipedia.org/wiki/X32_ABI
|
||||
|
||||
70
libs/libuv/SUPPORTED_PLATFORMS.md
Normal file
70
libs/libuv/SUPPORTED_PLATFORMS.md
Normal 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.
|
||||
@ -1,4 +1,4 @@
|
||||
version: v1.9.1.build{build}
|
||||
version: v1.11.0.build{build}
|
||||
|
||||
install:
|
||||
- cinst -y nsis
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
'configurations': {
|
||||
'Debug': {
|
||||
'defines': [ 'DEBUG', '_DEBUG' ],
|
||||
'cflags': [ '-g', '-O0', '-fwrapv' ],
|
||||
'cflags': [ '-g' ],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'target_conditions': [
|
||||
@ -35,6 +35,9 @@
|
||||
'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ],
|
||||
},
|
||||
'conditions': [
|
||||
['OS != "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' ],
|
||||
}],
|
||||
|
||||
@ -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*], [
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -8,6 +8,9 @@ In libuv errors are negative numbered constants. As a rule of thumb, whenever
|
||||
there is a status parameter, or an API functions returns an integer, a negative
|
||||
number will imply an error.
|
||||
|
||||
When a function which takes a callback returns an error, the callback will never
|
||||
be called.
|
||||
|
||||
.. note::
|
||||
Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on
|
||||
Windows they are defined by libuv to arbitrary negative numbers.
|
||||
@ -329,3 +332,13 @@ API
|
||||
|
||||
Returns the error name for the given error code. Leaks a few bytes
|
||||
of memory when you call it with an unknown error code.
|
||||
|
||||
.. c:function:: int uv_translate_sys_error(int sys_errno)
|
||||
|
||||
Returns the libuv error code equivalent to the given platform dependent error
|
||||
code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error
|
||||
codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`).
|
||||
|
||||
If `sys_errno` is already a libuv error, it is simply returned.
|
||||
|
||||
.. versionchanged:: 1.10.0 function declared public.
|
||||
|
||||
@ -91,7 +91,8 @@ Data types
|
||||
UV_FS_SYMLINK,
|
||||
UV_FS_READLINK,
|
||||
UV_FS_CHOWN,
|
||||
UV_FS_FCHOWN
|
||||
UV_FS_FCHOWN,
|
||||
UV_FS_REALPATH
|
||||
} uv_fs_type;
|
||||
|
||||
.. c:type:: uv_dirent_t
|
||||
@ -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.
|
||||
|
||||
@ -8,6 +8,20 @@ FS Event handles allow the user to monitor a given path for changes, for example
|
||||
if the file was renamed or there was a generic change in it. This handle uses
|
||||
the best backend for the job on each platform.
|
||||
|
||||
.. note::
|
||||
For AIX, the non default IBM bos.ahafs package has to be installed.
|
||||
The AIX Event Infrastructure file system (ahafs) has some limitations:
|
||||
|
||||
- ahafs tracks monitoring per process and is not thread safe. A separate process
|
||||
must be spawned for each monitor for the same event.
|
||||
- Events for file modification (writing to a file) are not received if only the
|
||||
containing folder is watched.
|
||||
|
||||
See documentation_ for more details.
|
||||
|
||||
.. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/
|
||||
|
||||
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
||||
@ -17,6 +17,34 @@ Data types
|
||||
|
||||
The base libuv handle type.
|
||||
|
||||
.. c:type:: uv_handle_type
|
||||
|
||||
The kind of the libuv handle.
|
||||
|
||||
::
|
||||
|
||||
typedef enum {
|
||||
UV_UNKNOWN_HANDLE = 0,
|
||||
UV_ASYNC,
|
||||
UV_CHECK,
|
||||
UV_FS_EVENT,
|
||||
UV_FS_POLL,
|
||||
UV_HANDLE,
|
||||
UV_IDLE,
|
||||
UV_NAMED_PIPE,
|
||||
UV_POLL,
|
||||
UV_PREPARE,
|
||||
UV_PROCESS,
|
||||
UV_STREAM,
|
||||
UV_TCP,
|
||||
UV_TIMER,
|
||||
UV_TTY,
|
||||
UV_UDP,
|
||||
UV_SIGNAL,
|
||||
UV_FILE,
|
||||
UV_HANDLE_TYPE_MAX
|
||||
} uv_handle_type;
|
||||
|
||||
.. c:type:: uv_any_handle
|
||||
|
||||
Union of all handle types.
|
||||
@ -24,12 +52,28 @@ Data types
|
||||
.. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
|
||||
|
||||
Type definition for callback passed to :c:func:`uv_read_start` and
|
||||
:c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t`
|
||||
structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment)
|
||||
is provided, but it doesn't need to be honored. Setting the buffer's length to 0
|
||||
will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or
|
||||
:c:func:`uv_udp_recv_start`. The user must allocate memory and fill the supplied
|
||||
:c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length,
|
||||
a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the
|
||||
:c:type:`uv_read_cb` callback.
|
||||
|
||||
A suggested size (65536 at the moment in most cases) is provided, but it's just an indication,
|
||||
not related in any way to the pending data to be read. The user is free to allocate the amount
|
||||
of memory they decide.
|
||||
|
||||
As an example, applications with custom allocation schemes such as using freelists, allocation
|
||||
pools or slab based allocators may decide to use a different size which matches the memory
|
||||
chunks they already have.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
.. c:type:: void (*uv_close_cb)(uv_handle_t* handle)
|
||||
|
||||
Type definition for callback passed to :c:func:`uv_close`.
|
||||
@ -42,6 +86,10 @@ Public members
|
||||
|
||||
Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly.
|
||||
|
||||
.. c:member:: uv_loop_t* uv_handle_t.type
|
||||
|
||||
Pointer to the :c:type:`uv_handle_type`. Readonly.
|
||||
|
||||
.. c:member:: void* uv_handle_t.data
|
||||
|
||||
Space for user-defined arbitrary data. libuv does not use this field.
|
||||
|
||||
@ -17,11 +17,11 @@ Data types
|
||||
|
||||
.. c:member:: char* uv_buf_t.base
|
||||
|
||||
Pointer to the base of the buffer. Readonly.
|
||||
Pointer to the base of the buffer.
|
||||
|
||||
.. c:member:: size_t uv_buf_t.len
|
||||
|
||||
Total bytes in the buffer. Readonly.
|
||||
Total bytes in the buffer.
|
||||
|
||||
.. note::
|
||||
On Windows this field is ULONG.
|
||||
@ -69,21 +69,24 @@ Data types
|
||||
uv_timeval_t ru_utime; /* user CPU time used */
|
||||
uv_timeval_t ru_stime; /* system CPU time used */
|
||||
uint64_t ru_maxrss; /* maximum resident set size */
|
||||
uint64_t ru_ixrss; /* integral shared memory size */
|
||||
uint64_t ru_idrss; /* integral unshared data size */
|
||||
uint64_t ru_isrss; /* integral unshared stack size */
|
||||
uint64_t ru_minflt; /* page reclaims (soft page faults) */
|
||||
uint64_t ru_ixrss; /* integral shared memory size (X) */
|
||||
uint64_t ru_idrss; /* integral unshared data size (X) */
|
||||
uint64_t ru_isrss; /* integral unshared stack size (X) */
|
||||
uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */
|
||||
uint64_t ru_majflt; /* page faults (hard page faults) */
|
||||
uint64_t ru_nswap; /* swaps */
|
||||
uint64_t ru_nswap; /* swaps (X) */
|
||||
uint64_t ru_inblock; /* block input operations */
|
||||
uint64_t ru_oublock; /* block output operations */
|
||||
uint64_t ru_msgsnd; /* IPC messages sent */
|
||||
uint64_t ru_msgrcv; /* IPC messages received */
|
||||
uint64_t ru_nsignals; /* signals received */
|
||||
uint64_t ru_nvcsw; /* voluntary context switches */
|
||||
uint64_t ru_nivcsw; /* involuntary context switches */
|
||||
uint64_t ru_msgsnd; /* IPC messages sent (X) */
|
||||
uint64_t ru_msgrcv; /* IPC messages received (X) */
|
||||
uint64_t ru_nsignals; /* signals received (X) */
|
||||
uint64_t ru_nvcsw; /* voluntary context switches (X) */
|
||||
uint64_t ru_nivcsw; /* involuntary context switches (X) */
|
||||
} uv_rusage_t;
|
||||
|
||||
Members marked with `(X)` are unsupported on Windows.
|
||||
See :man:`getrusage(2)` for supported fields on Unix
|
||||
|
||||
.. c:type:: uv_cpu_info_t
|
||||
|
||||
Data type for CPU information.
|
||||
@ -183,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)
|
||||
|
||||
|
||||
@ -26,7 +26,11 @@ Data types
|
||||
|
||||
.. c:type:: uv_write_t
|
||||
|
||||
Write request type.
|
||||
Write request type. Careful attention must be paid when reusing objects of
|
||||
this type. When a stream is in non-blocking mode, write requests sent
|
||||
with ``uv_write`` will be queued. Reusing objects at this point is undefined
|
||||
behaviour. It is safe to reuse the ``uv_write_t`` object only after the
|
||||
callback passed to ``uv_write`` is fired.
|
||||
|
||||
.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
|
||||
@ -61,7 +65,7 @@ Data types
|
||||
|
||||
.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
|
||||
|
||||
Callback called after s shutdown request has been completed. `status` will
|
||||
Callback called after a shutdown request has been completed. `status` will
|
||||
be 0 in case of success, < 0 otherwise.
|
||||
|
||||
.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
|
||||
@ -92,7 +96,7 @@ Public members
|
||||
|
||||
.. c:member:: uv_stream_t* uv_write_t.send_handle
|
||||
|
||||
Pointer to the stream being sent using this write request..
|
||||
Pointer to the stream being sent using this write request.
|
||||
|
||||
.. seealso:: The :c:type:`uv_handle_t` members also apply.
|
||||
|
||||
@ -169,6 +173,10 @@ API
|
||||
uv_write(&req1, stream, a, 2, cb);
|
||||
uv_write(&req2, stream, b, 2, cb);
|
||||
|
||||
.. note::
|
||||
The memory pointed to by the buffers must remain valid until the callback gets called.
|
||||
This also holds for :c:func:`uv_write2`.
|
||||
|
||||
.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
|
||||
|
||||
Extended write function for sending handles over a pipe. The pipe must be
|
||||
|
||||
@ -53,7 +53,7 @@ API
|
||||
|
||||
.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
|
||||
|
||||
Enable / disable Nagle's algorithm.
|
||||
Enable `TCP_NODELAY`, which disables Nagle's algorithm.
|
||||
|
||||
.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
|
||||
|
||||
|
||||
@ -42,6 +42,9 @@ API
|
||||
If `repeat` is non-zero, the callback fires first after `timeout`
|
||||
milliseconds and then repeatedly after `repeat` milliseconds.
|
||||
|
||||
.. note::
|
||||
Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information.
|
||||
|
||||
.. c:function:: int uv_timer_stop(uv_timer_t* handle)
|
||||
|
||||
Stop the timer, the callback will not be called anymore.
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -408,6 +408,7 @@
|
||||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
# define UV__EHOSTDOWN (-64)
|
||||
|
||||
30
libs/libuv/include/uv-os390.h
Normal file
30
libs/libuv/include/uv-os390.h
Normal 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 */
|
||||
@ -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
|
||||
|
||||
@ -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 ""
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -363,6 +363,8 @@ typedef enum {
|
||||
} uv_membership;
|
||||
|
||||
|
||||
UV_EXTERN int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
UV_EXTERN const char* uv_strerror(int err);
|
||||
UV_EXTERN const char* uv_err_name(int err);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -196,14 +196,24 @@ int uv_set_process_title(const char* title) {
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,10 @@
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel_) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_PREADV 1
|
||||
#else
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
|
||||
timeout = real_timeout - timeout;
|
||||
if (timeout > 0)
|
||||
continue;
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
return;
|
||||
/* We may have been inside the system call for longer than |timeout|
|
||||
* milliseconds so we need to update the timestamp to avoid drift.
|
||||
*/
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
@ -484,12 +486,20 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -28,11 +28,15 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
void* saved_data;
|
||||
int err;
|
||||
|
||||
uv__signal_global_once_init();
|
||||
|
||||
saved_data = loop->data;
|
||||
memset(loop, 0, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
|
||||
heap_init((struct heap*) &loop->timer_heap);
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->active_reqs);
|
||||
|
||||
@ -147,14 +147,24 @@ int uv_set_process_title(const char* title) {
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -169,14 +169,24 @@ int uv_set_process_title(const char* title) {
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
334
libs/libuv/src/unix/os390-syscalls.c
Normal file
334
libs/libuv/src/unix/os390-syscalls.c
Normal 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;
|
||||
}
|
||||
69
libs/libuv/src/unix/os390-syscalls.h
Normal file
69
libs/libuv/src/unix/os390-syscalls.h
Normal 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
865
libs/libuv/src/unix/os390.c
Normal 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 */
|
||||
}
|
||||
@ -80,6 +80,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
||||
handle->io_watcher.fd = sockfd;
|
||||
return 0;
|
||||
@ -97,6 +98,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
if (uv__stream_fd(handle) == -1)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
/* On zOS, backlog=0 has undefined behaviour */
|
||||
if (backlog == 0)
|
||||
backlog = 1;
|
||||
else if (backlog < 0)
|
||||
backlog = SOMAXCONN;
|
||||
#endif
|
||||
|
||||
if (listen(uv__stream_fd(handle), backlog))
|
||||
return -errno;
|
||||
|
||||
|
||||
@ -59,7 +59,14 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err == -ENOTTY)
|
||||
if (uv__nonblock == uv__nonblock_ioctl)
|
||||
err = uv__nonblock_fcntl(fd, 1);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -115,6 +115,10 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
IPV6_V6ONLY,
|
||||
&on,
|
||||
sizeof on) == -1) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == EOPNOTSUPP)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
@ -130,6 +134,7 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
}
|
||||
tcp->delayed_error = -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
if (addr->sa_family == AF_INET6)
|
||||
tcp->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
@ -158,11 +163,17 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
|
||||
handle->delayed_error = 0;
|
||||
|
||||
do
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(uv__stream_fd(handle), addr, addrlen);
|
||||
while (r == -1 && errno == EINTR);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
/* We not only check the return value, but also check the errno != 0.
|
||||
* Because in rare cases connect() will return -1 but the errno
|
||||
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
|
||||
* and actually the tcp three-way handshake is completed.
|
||||
*/
|
||||
if (r == -1 && errno != 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED)
|
||||
@ -266,10 +277,32 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef __MVS__
|
||||
/* on zOS the listen call does not bind automatically
|
||||
if the socket is unbound. Hence the manual binding to
|
||||
an arbitrary port is required to be done manually
|
||||
*/
|
||||
|
||||
if (!(tcp->flags & UV_HANDLE_BOUND)) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
|
||||
if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
|
||||
return -errno;
|
||||
|
||||
if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
|
||||
return -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen(tcp->io_watcher.fd, backlog))
|
||||
return -errno;
|
||||
|
||||
tcp->connection_cb = cb;
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
/* Start listening for connections. */
|
||||
tcp->io_watcher.cb = uv__server_io;
|
||||
|
||||
@ -32,31 +32,16 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __MVS__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
struct thread_ctx {
|
||||
void (*entry)(void* arg);
|
||||
void* arg;
|
||||
};
|
||||
|
||||
|
||||
static void* uv__thread_start(void *arg)
|
||||
{
|
||||
struct thread_ctx *ctx_p;
|
||||
struct thread_ctx ctx;
|
||||
|
||||
ctx_p = arg;
|
||||
ctx = *ctx_p;
|
||||
uv__free(ctx_p);
|
||||
ctx.entry(ctx.arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
struct thread_ctx* ctx;
|
||||
int err;
|
||||
pthread_attr_t* attr;
|
||||
#if defined(__APPLE__)
|
||||
@ -64,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
struct rlimit lim;
|
||||
#endif
|
||||
|
||||
ctx = uv__malloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
ctx->entry = entry;
|
||||
ctx->arg = arg;
|
||||
|
||||
/* On OSX threads other than the main thread are created with a reduced stack
|
||||
* size by default, adjust it to RLIMIT_STACK.
|
||||
*/
|
||||
@ -94,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
attr = NULL;
|
||||
#endif
|
||||
|
||||
err = pthread_create(tid, attr, uv__thread_start, ctx);
|
||||
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
if (err)
|
||||
uv__free(ctx);
|
||||
|
||||
return -err;
|
||||
}
|
||||
|
||||
@ -302,6 +277,85 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
||||
return -EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
#elif defined(__MVS__)
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
uv_sem_t semid;
|
||||
struct sembuf buf;
|
||||
int err;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = value;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
|
||||
if (semid == -1)
|
||||
return -errno;
|
||||
|
||||
if (-1 == semop(semid, &buf, 1)) {
|
||||
err = errno;
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
return -err;
|
||||
}
|
||||
|
||||
*sem = semid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = 1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
if (-1 == semop(*sem, &buf, 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status)
|
||||
abort();
|
||||
}
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = IPC_NOWAIT;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status) {
|
||||
if (errno == EAGAIN)
|
||||
return -EAGAIN;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
@ -354,7 +408,7 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
return -pthread_cond_init(cond, NULL);
|
||||
|
||||
@ -31,8 +31,8 @@ static int timer_less_than(const struct heap_node* ha,
|
||||
const uv_timer_t* a;
|
||||
const uv_timer_t* b;
|
||||
|
||||
a = container_of(ha, const uv_timer_t, heap_node);
|
||||
b = container_of(hb, const uv_timer_t, heap_node);
|
||||
a = container_of(ha, uv_timer_t, heap_node);
|
||||
b = container_of(hb, uv_timer_t, heap_node);
|
||||
|
||||
if (a->timeout < b->timeout)
|
||||
return 1;
|
||||
@ -135,7 +135,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
handle = container_of(heap_node, const uv_timer_t, heap_node);
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
if (handle->timeout <= loop->time)
|
||||
return 0;
|
||||
|
||||
|
||||
@ -30,13 +30,17 @@
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__MVS__) && !defined(IMAXBEL)
|
||||
#define IMAXBEL 0
|
||||
#endif
|
||||
|
||||
static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int dummy;
|
||||
|
||||
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
|
||||
@ -57,6 +61,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
int saved_flags;
|
||||
char path[256];
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
@ -113,6 +118,22 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pacify the compiler. */
|
||||
(void) &saved_flags;
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
@ -120,13 +141,20 @@ skip:
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (r) {
|
||||
int rc = r;
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
QUEUE_REMOVE(&tty->handle_queue);
|
||||
return r;
|
||||
do
|
||||
r = fcntl(fd, F_SETFL, saved_flags);
|
||||
while (r == -1 && errno == EINTR);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -135,9 +163,6 @@ skip:
|
||||
else
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
@ -147,7 +172,7 @@ skip:
|
||||
static void uv__tty_make_raw(struct termios* tio) {
|
||||
assert(tio != NULL);
|
||||
|
||||
#ifdef __sun
|
||||
#if defined __sun || defined __MVS__
|
||||
/*
|
||||
* This implementation of cfmakeraw for Solaris and derivatives is taken from
|
||||
* http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
|
||||
@ -268,14 +293,14 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
return UV_UDP;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX)
|
||||
/* on AIX the getsockname call returns an empty sa structure
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
if (len == 0)
|
||||
return UV_NAMED_PIPE;
|
||||
#endif /* defined(_AIX) */
|
||||
#endif /* defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_TCP;
|
||||
|
||||
@ -27,6 +27,9 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__MVS__)
|
||||
#include <xti.h>
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
|
||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
@ -165,8 +168,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
@ -331,6 +335,8 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
if (addr->sa_family == AF_INET6)
|
||||
handle->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
@ -507,6 +513,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
@ -550,6 +560,10 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
@ -668,7 +682,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle,
|
||||
int option4,
|
||||
int option6,
|
||||
int val) {
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
char arg = val;
|
||||
#elif defined(__OpenBSD__)
|
||||
unsigned char arg = val;
|
||||
@ -700,19 +714,27 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
if (ttl < 1 || ttl > 255)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (!(handle->flags & UV_HANDLE_IPV6))
|
||||
return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Solaris and derivatives such as SmartOS, the length of socket options
|
||||
* is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
|
||||
* so hardcode the size of these options on this platform,
|
||||
* and use the general uv__setsockopt_maybe_char call on other platforms.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
|
||||
return uv__setsockopt(handle,
|
||||
IP_TTL,
|
||||
IPV6_UNICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_TTL,
|
||||
@ -728,14 +750,14 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
* IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
@ -751,14 +773,14 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
* IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
35
libs/libuv/src/win/detect-wakeup.c
Normal file
35
libs/libuv/src/win/detect-wakeup.c
Normal 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,
|
||||
®istration_handle);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
|
||||
int str_len;
|
||||
|
||||
str_len = wcslen(str);
|
||||
|
||||
/*
|
||||
Since we only care about equality, return early if the strings
|
||||
aren't the same length
|
||||
*/
|
||||
if (str_len != (file_name_len / sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
return _wcsnicmp(str, file_name, str_len);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
uv_fs_event_t* handle) {
|
||||
FILE_NOTIFY_INFORMATION* file_info;
|
||||
@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
* or if the filename filter matches.
|
||||
*/
|
||||
if (handle->dirw ||
|
||||
_wcsnicmp(handle->filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
|
||||
_wcsnicmp(handle->short_filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0) {
|
||||
file_info_cmp(handle->filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0 ||
|
||||
file_info_cmp(handle->short_filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0) {
|
||||
|
||||
if (handle->dirw) {
|
||||
/*
|
||||
@ -407,7 +425,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
|
||||
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
|
||||
file_info->FileNameLength / sizeof(WCHAR),
|
||||
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
|
||||
file_info->FileName);
|
||||
|
||||
filenamew[size - 1] = L'\0';
|
||||
|
||||
@ -94,7 +94,7 @@
|
||||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
|
||||
116444736000000000ULL; \
|
||||
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
|
||||
@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
||||
const char* new_path, const int copy_path) {
|
||||
char* buf;
|
||||
char* pos;
|
||||
ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
|
||||
ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
|
||||
|
||||
/* new_path can only be set if path is also set. */
|
||||
assert(new_path == NULL || path != NULL);
|
||||
@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
||||
req->fs.info.new_pathw = NULL;
|
||||
}
|
||||
|
||||
if (!copy_path) {
|
||||
req->path = path;
|
||||
} else if (path) {
|
||||
req->path = path;
|
||||
if (path != NULL && copy_path) {
|
||||
memcpy(pos, path, path_len);
|
||||
assert(path_len == buf_sz - (pos - buf));
|
||||
req->path = pos;
|
||||
} else {
|
||||
req->path = NULL;
|
||||
}
|
||||
|
||||
req->flags |= UV_FS_FREE_PATHS;
|
||||
@ -233,6 +230,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
|
||||
req->ptr = NULL;
|
||||
req->path = NULL;
|
||||
req->cb = cb;
|
||||
memset(&req->fs, 0, sizeof(req->fs));
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -381,4 +381,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
|
||||
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/*
|
||||
* Wake all loops with fake message
|
||||
*/
|
||||
void uv__wake_all_loops();
|
||||
|
||||
/*
|
||||
* Init system wake-up detection
|
||||
*/
|
||||
void uv__init_detect_system_wakeup();
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
|
||||
@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
|
||||
@ -1634,8 +1634,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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'"';
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -496,8 +496,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
*/
|
||||
if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
|
||||
if (handle->tcp.conn.read_buffer.len == 0) {
|
||||
if (handle->tcp.conn.read_buffer.base == NULL ||
|
||||
handle->tcp.conn.read_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
|
||||
return;
|
||||
}
|
||||
@ -1004,8 +1006,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -40,6 +40,9 @@
|
||||
#include "stream-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
#ifndef InterlockedOr
|
||||
# define InterlockedOr _InterlockedOr
|
||||
#endif
|
||||
|
||||
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -289,8 +289,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
|
||||
handle->recv_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
|
||||
if (handle->recv_buffer.len == 0) {
|
||||
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
|
||||
return;
|
||||
}
|
||||
@ -506,8 +507,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
|
||||
/* Do a nonblocking receive */
|
||||
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -54,6 +54,10 @@
|
||||
/* The number of nanoseconds in one second. */
|
||||
#define UV__NANOSEC 1000000000
|
||||
|
||||
/* Max user name length, from iphlpapi.h */
|
||||
#ifndef UNLEN
|
||||
# define UNLEN 256
|
||||
#endif
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
@ -416,6 +420,11 @@ static int uv__get_process_title() {
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
|
||||
EnterCriticalSection(&process_title_lock);
|
||||
@ -429,7 +438,14 @@ int uv_get_process_title(char* buffer, size_t size) {
|
||||
}
|
||||
|
||||
assert(process_title);
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
|
||||
return 0;
|
||||
@ -1062,6 +1078,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
FILETIME createTime, exitTime, kernelTime, userTime;
|
||||
SYSTEMTIME kernelSystemTime, userSystemTime;
|
||||
PROCESS_MEMORY_COUNTERS memCounters;
|
||||
IO_COUNTERS ioCounters;
|
||||
int ret;
|
||||
|
||||
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
|
||||
@ -1086,6 +1103,11 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
|
||||
if (ret == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
||||
|
||||
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
|
||||
@ -1101,6 +1123,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
|
||||
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
|
||||
|
||||
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
|
||||
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -49,9 +49,14 @@ sCancelSynchronousIo pCancelSynchronousIo;
|
||||
sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
|
||||
void uv_winapi_init() {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE powrprof_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@ -143,4 +148,12 @@ void uv_winapi_init() {
|
||||
|
||||
pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
|
||||
GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
|
||||
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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_ */
|
||||
|
||||
@ -56,6 +56,7 @@ int main(int argc, char **argv) {
|
||||
case 1: return run_tests(0);
|
||||
case 2: return maybe_run_test(argc, argv);
|
||||
case 3: return run_test_part(argv[1], argv[2]);
|
||||
case 4: return maybe_run_test(argc, argv);
|
||||
default:
|
||||
fprintf(stderr, "Too many arguments.\n");
|
||||
fflush(stderr);
|
||||
@ -177,5 +178,17 @@ static int maybe_run_test(int argc, char **argv) {
|
||||
return spawn_stdin_stdout();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) {
|
||||
uv_uid_t uid = atoi(argv[2]);
|
||||
uv_gid_t gid = atoi(argv[3]);
|
||||
|
||||
ASSERT(uid == getuid());
|
||||
ASSERT(gid == getgid());
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
return run_test(argv[1], 0, 1);
|
||||
}
|
||||
|
||||
@ -43,11 +43,6 @@
|
||||
|
||||
/* Do platform-specific initialization. */
|
||||
int platform_init(int argc, char **argv) {
|
||||
const char* tap;
|
||||
|
||||
tap = getenv("UV_TAP_OUTPUT");
|
||||
tap_output = (tap != NULL && atoi(tap) > 0);
|
||||
|
||||
/* Disable stdio output buffering. */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
@ -206,7 +201,11 @@ int process_wait(process_info_t* vec, int n, int timeout) {
|
||||
if (pthread_attr_init(&attr))
|
||||
abort();
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (pthread_attr_setstacksize(&attr, 1024 * 1024))
|
||||
#else
|
||||
if (pthread_attr_setstacksize(&attr, 256 * 1024))
|
||||
#endif
|
||||
abort();
|
||||
|
||||
r = pthread_create(&tid, &attr, dowait, &args);
|
||||
@ -294,8 +293,7 @@ long int process_output_size(process_info_t *p) {
|
||||
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
ssize_t nwritten;
|
||||
int process_copy_output(process_info_t* p, FILE* stream) {
|
||||
char buf[1024];
|
||||
int r;
|
||||
|
||||
@ -306,20 +304,8 @@ int process_copy_output(process_info_t *p, int fd) {
|
||||
}
|
||||
|
||||
/* TODO: what if the line is longer than buf */
|
||||
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
|
||||
/* TODO: what if write doesn't write the whole buffer... */
|
||||
nwritten = 0;
|
||||
|
||||
if (tap_output)
|
||||
nwritten += write(fd, "#", 1);
|
||||
|
||||
nwritten += write(fd, buf, strlen(buf));
|
||||
|
||||
if (nwritten < 0) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL)
|
||||
print_lines(buf, strlen(buf), stream);
|
||||
|
||||
if (ferror(p->stdout_file)) {
|
||||
perror("read");
|
||||
@ -390,11 +376,23 @@ void process_cleanup(process_info_t *p) {
|
||||
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
void rewind_cursor(void) {
|
||||
#if defined(__MVS__)
|
||||
fprintf(stderr, "\047[2K\r");
|
||||
#else
|
||||
fprintf(stderr, "\033[2K\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Pause the calling thread for a number of milliseconds. */
|
||||
void uv_sleep(int msec) {
|
||||
usleep(msec * 1000);
|
||||
int sec;
|
||||
int usec;
|
||||
|
||||
sec = msec / 1000;
|
||||
usec = (msec % 1000) * 1000;
|
||||
if (sec > 0)
|
||||
sleep(sec);
|
||||
if (usec > 0)
|
||||
usleep(usec);
|
||||
}
|
||||
|
||||
@ -44,11 +44,6 @@
|
||||
|
||||
/* Do platform-specific initialization. */
|
||||
int platform_init(int argc, char **argv) {
|
||||
const char* tap;
|
||||
|
||||
tap = getenv("UV_TAP_OUTPUT");
|
||||
tap_output = (tap != NULL && atoi(tap) > 0);
|
||||
|
||||
/* Disable the "application crashed" popup. */
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
@ -213,10 +208,9 @@ long int process_output_size(process_info_t *p) {
|
||||
}
|
||||
|
||||
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
int process_copy_output(process_info_t* p, FILE* stream) {
|
||||
DWORD read;
|
||||
char buf[1024];
|
||||
char *line, *start;
|
||||
|
||||
if (SetFilePointer(p->stdio_out,
|
||||
0,
|
||||
@ -225,29 +219,8 @@ int process_copy_output(process_info_t *p, int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
write(fd, "#", 1);
|
||||
|
||||
while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) &&
|
||||
read > 0) {
|
||||
if (tap_output) {
|
||||
start = buf;
|
||||
|
||||
while ((line = strchr(start, '\n')) != NULL) {
|
||||
write(fd, start, line - start + 1);
|
||||
write(fd, "#", 1);
|
||||
start = line + 1;
|
||||
}
|
||||
|
||||
if (start < buf + read)
|
||||
write(fd, start, buf + read - start);
|
||||
} else {
|
||||
write(fd, buf, read);
|
||||
}
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
write(fd, "\n", 1);
|
||||
while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0)
|
||||
print_lines(buf, read, stream);
|
||||
|
||||
if (GetLastError() != ERROR_HANDLE_EOF)
|
||||
return -1;
|
||||
|
||||
@ -28,31 +28,6 @@
|
||||
|
||||
char executable_path[sizeof(executable_path)];
|
||||
|
||||
int tap_output = 0;
|
||||
|
||||
|
||||
static void log_progress(int total,
|
||||
int passed,
|
||||
int failed,
|
||||
int todos,
|
||||
int skipped,
|
||||
const char* name) {
|
||||
int progress;
|
||||
|
||||
if (total == 0)
|
||||
total = 1;
|
||||
|
||||
progress = 100 * (passed + failed + skipped + todos) / total;
|
||||
fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
|
||||
progress,
|
||||
passed,
|
||||
failed,
|
||||
todos,
|
||||
skipped,
|
||||
name);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
const char* fmt(double d) {
|
||||
static char buf[1024];
|
||||
@ -95,7 +70,6 @@ int run_tests(int benchmark_output) {
|
||||
int total;
|
||||
int passed;
|
||||
int failed;
|
||||
int todos;
|
||||
int skipped;
|
||||
int current;
|
||||
int test_result;
|
||||
@ -109,15 +83,12 @@ int run_tests(int benchmark_output) {
|
||||
}
|
||||
}
|
||||
|
||||
if (tap_output) {
|
||||
fprintf(stderr, "1..%d\n", total);
|
||||
fflush(stderr);
|
||||
}
|
||||
fprintf(stderr, "1..%d\n", total);
|
||||
fflush(stderr);
|
||||
|
||||
/* Run all tests. */
|
||||
passed = 0;
|
||||
failed = 0;
|
||||
todos = 0;
|
||||
skipped = 0;
|
||||
current = 1;
|
||||
for (task = TASKS; task->main; task++) {
|
||||
@ -125,30 +96,15 @@ int run_tests(int benchmark_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tap_output)
|
||||
rewind_cursor();
|
||||
|
||||
if (!benchmark_output && !tap_output) {
|
||||
log_progress(total, passed, failed, todos, skipped, task->task_name);
|
||||
}
|
||||
|
||||
test_result = run_test(task->task_name, benchmark_output, current);
|
||||
switch (test_result) {
|
||||
case TEST_OK: passed++; break;
|
||||
case TEST_TODO: todos++; break;
|
||||
case TEST_SKIP: skipped++; break;
|
||||
default: failed++;
|
||||
}
|
||||
current++;
|
||||
}
|
||||
|
||||
if (!tap_output)
|
||||
rewind_cursor();
|
||||
|
||||
if (!benchmark_output && !tap_output) {
|
||||
log_progress(total, passed, failed, todos, skipped, "Done.\n");
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
@ -166,10 +122,6 @@ void log_tap_result(int test_count,
|
||||
result = "ok";
|
||||
directive = "";
|
||||
break;
|
||||
case TEST_TODO:
|
||||
result = "not ok";
|
||||
directive = " # TODO ";
|
||||
break;
|
||||
case TEST_SKIP:
|
||||
result = "ok";
|
||||
directive = " # SKIP ";
|
||||
@ -179,8 +131,7 @@ void log_tap_result(int test_count,
|
||||
directive = "";
|
||||
}
|
||||
|
||||
if ((status == TEST_SKIP || status == TEST_TODO) &&
|
||||
process_output_size(process) > 0) {
|
||||
if (status == TEST_SKIP && process_output_size(process) > 0) {
|
||||
process_read_last_line(process, reason, sizeof reason);
|
||||
} else {
|
||||
reason[0] = '\0';
|
||||
@ -194,7 +145,7 @@ void log_tap_result(int test_count,
|
||||
int run_test(const char* test,
|
||||
int benchmark_output,
|
||||
int test_count) {
|
||||
char errmsg[1024] = "no error";
|
||||
char errmsg[1024] = "";
|
||||
process_info_t processes[1024];
|
||||
process_info_t *main_proc;
|
||||
task_entry_t* task;
|
||||
@ -319,22 +270,13 @@ out:
|
||||
FATAL("process_wait failed");
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
log_tap_result(test_count, test, status, &processes[i]);
|
||||
log_tap_result(test_count, test, status, &processes[i]);
|
||||
|
||||
/* Show error and output from processes if the test failed. */
|
||||
if (status != 0 || task->show_output) {
|
||||
if (tap_output) {
|
||||
fprintf(stderr, "#");
|
||||
} else if (status == TEST_TODO) {
|
||||
fprintf(stderr, "\n`%s` todo\n", test);
|
||||
} else if (status == TEST_SKIP) {
|
||||
fprintf(stderr, "\n`%s` skipped\n", test);
|
||||
} else if (status != 0) {
|
||||
fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
|
||||
} else {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {
|
||||
if (strlen(errmsg) > 0)
|
||||
fprintf(stderr, "# %s\n", errmsg);
|
||||
fprintf(stderr, "# ");
|
||||
fflush(stderr);
|
||||
|
||||
for (i = 0; i < process_count; i++) {
|
||||
@ -354,15 +296,11 @@ out:
|
||||
default:
|
||||
fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
|
||||
fflush(stderr);
|
||||
process_copy_output(&processes[i], fileno(stderr));
|
||||
process_copy_output(&processes[i], stderr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tap_output) {
|
||||
fprintf(stderr, "=============================================================\n");
|
||||
}
|
||||
|
||||
/* In benchmark mode show concise output from the main process. */
|
||||
} else if (benchmark_output) {
|
||||
switch (process_output_size(main_proc)) {
|
||||
@ -378,7 +316,7 @@ out:
|
||||
|
||||
default:
|
||||
for (i = 0; i < process_count; i++) {
|
||||
process_copy_output(&processes[i], fileno(stderr));
|
||||
process_copy_output(&processes[i], stderr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -464,3 +402,21 @@ void print_tests(FILE* stream) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void print_lines(const char* buffer, size_t size, FILE* stream) {
|
||||
const char* start;
|
||||
const char* end;
|
||||
|
||||
start = buffer;
|
||||
while ((end = memchr(start, '\n', &buffer[size] - start))) {
|
||||
fprintf(stream, "# %.*s\n", (int) (end - start), start);
|
||||
fflush(stream);
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (start < &buffer[size]) {
|
||||
fprintf(stream, "# %s\n", start);
|
||||
fflush(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +126,8 @@ int run_test_part(const char* test, const char* part);
|
||||
*/
|
||||
void print_tests(FILE* stream);
|
||||
|
||||
/* Print lines in |buffer| as TAP diagnostics to |stream|. */
|
||||
void print_lines(const char* buffer, size_t size, FILE* stream);
|
||||
|
||||
/*
|
||||
* Stuff that should be implemented by test-runner-<platform>.h
|
||||
@ -148,8 +150,8 @@ int process_wait(process_info_t *vec, int n, int timeout);
|
||||
/* Returns the number of bytes in the stdio output buffer for process `p`. */
|
||||
long int process_output_size(process_info_t *p);
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd);
|
||||
/* Copy the contents of the stdio output buffer to `stream`. */
|
||||
int process_copy_output(process_info_t* p, FILE* stream);
|
||||
|
||||
/* Copy the last line of the stdio output buffer to `buffer` */
|
||||
int process_read_last_line(process_info_t *p,
|
||||
@ -172,7 +174,4 @@ void process_cleanup(process_info_t *p);
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
void rewind_cursor(void);
|
||||
|
||||
/* trigger output as tap */
|
||||
extern int tap_output;
|
||||
|
||||
#endif /* RUNNER_H_ */
|
||||
|
||||
@ -136,7 +136,6 @@ const char* fmt(double d);
|
||||
/* Reserved test exit codes. */
|
||||
enum test_status {
|
||||
TEST_OK = 0,
|
||||
TEST_TODO,
|
||||
TEST_SKIP
|
||||
};
|
||||
|
||||
@ -145,13 +144,6 @@ enum test_status {
|
||||
return TEST_OK; \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_TODO(explanation) \
|
||||
do { \
|
||||
fprintf(stderr, "%s\n", explanation); \
|
||||
fflush(stderr); \
|
||||
return TEST_TODO; \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_SKIP(explanation) \
|
||||
do { \
|
||||
fprintf(stderr, "%s\n", explanation); \
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
|
||||
@ -38,12 +38,12 @@ static uv_tcp_t client_handle;
|
||||
|
||||
|
||||
TEST_IMPL(emfile) {
|
||||
#ifdef _AIX
|
||||
#if defined(_AIX) || defined(__MVS__)
|
||||
/* On AIX, if a 'accept' call fails ECONNRESET is set on the socket
|
||||
* which causes uv__emfile_trick to not work as intended and this test
|
||||
* to fail.
|
||||
*/
|
||||
RETURN_SKIP("uv__emfile_trick does not work on AIX");
|
||||
RETURN_SKIP("uv__emfile_trick does not work on this OS");
|
||||
#endif
|
||||
struct sockaddr_in addr;
|
||||
struct rlimit limits;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -29,12 +29,19 @@
|
||||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */
|
||||
# define CREATE_TIMEOUT 100
|
||||
#else
|
||||
# define CREATE_TIMEOUT 1
|
||||
#endif
|
||||
|
||||
static uv_fs_event_t fs_event;
|
||||
static const char file_prefix[] = "fsevent-";
|
||||
static const int fs_event_file_count = 16;
|
||||
@ -53,6 +60,14 @@ static char fs_event_filename[PATH_MAX];
|
||||
static char fs_event_filename[1024];
|
||||
#endif /* defined(PATH_MAX) */
|
||||
static int timer_cb_touch_called;
|
||||
static int timer_cb_exact_called;
|
||||
|
||||
static void fs_event_fail(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
ASSERT(0 && "should never be called");
|
||||
}
|
||||
|
||||
static void create_dir(const char* name) {
|
||||
int r;
|
||||
@ -143,7 +158,10 @@ static void fs_event_create_files(uv_timer_t* handle) {
|
||||
if (++fs_event_created < fs_event_file_count) {
|
||||
/* Create another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
|
||||
ASSERT(0 == uv_timer_start(&timer,
|
||||
fs_event_create_files,
|
||||
CREATE_TIMEOUT,
|
||||
0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +272,14 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
#ifdef _WIN32
|
||||
/* Each file created (or deleted) will cause this callback to be called twice
|
||||
* under Windows: once with the name of the file, and second time with the
|
||||
* name of the directory. We will ignore the callback for the directory
|
||||
* itself. */
|
||||
if (filename && strcmp(filename, file_prefix_in_subdir) == 0)
|
||||
return;
|
||||
#endif
|
||||
fs_event_cb_called++;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
@ -345,6 +371,21 @@ static void timer_cb_touch(uv_timer_t* timer) {
|
||||
timer_cb_touch_called++;
|
||||
}
|
||||
|
||||
static void timer_cb_exact(uv_timer_t* handle) {
|
||||
int r;
|
||||
|
||||
if (timer_cb_exact_called == 0) {
|
||||
touch_file("watch_dir/file.js");
|
||||
} else {
|
||||
uv_close((uv_handle_t*)handle, NULL);
|
||||
r = uv_fs_event_stop(&fs_event);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &fs_event, NULL);
|
||||
}
|
||||
|
||||
++timer_cb_exact_called;
|
||||
}
|
||||
|
||||
static void timer_cb_watch_twice(uv_timer_t* handle) {
|
||||
uv_fs_event_t* handles = handle->data;
|
||||
uv_close((uv_handle_t*) (handles + 0), NULL);
|
||||
@ -353,6 +394,10 @@ static void timer_cb_watch_twice(uv_timer_t* handle) {
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_dir) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
@ -432,6 +477,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) {
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_watch_file) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
@ -467,7 +516,54 @@ TEST_IMPL(fs_event_watch_file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_exact_path) {
|
||||
/*
|
||||
This test watches a file named "file.jsx" and modifies a file named
|
||||
"file.js". The test verifies that no events occur for file.jsx.
|
||||
*/
|
||||
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Setup */
|
||||
remove("watch_dir/file.js");
|
||||
remove("watch_dir/file.jsx");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file.js");
|
||||
create_file("watch_dir/file.jsx");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
|
||||
ASSERT(r == 0);
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(timer_cb_exact_called == 2);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_dir/file.js");
|
||||
remove("watch_dir/file.jsx");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_twice) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
const char path[] = "test/fixtures/empty_file";
|
||||
uv_fs_event_t watchers[2];
|
||||
uv_timer_t timer;
|
||||
@ -489,6 +585,9 @@ TEST_IMPL(fs_event_watch_file_twice) {
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_current_dir) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
@ -559,6 +658,10 @@ TEST_IMPL(fs_event_watch_file_root_dir) {
|
||||
#endif
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_after_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
@ -593,6 +696,10 @@ TEST_IMPL(fs_event_no_callback_after_close) {
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_on_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
@ -626,12 +733,6 @@ TEST_IMPL(fs_event_no_callback_on_close) {
|
||||
}
|
||||
|
||||
|
||||
static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
ASSERT(0 && "should never be called");
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
int r;
|
||||
|
||||
@ -646,6 +747,9 @@ static void timer_cb(uv_timer_t* handle) {
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_immediate_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
@ -668,6 +772,9 @@ TEST_IMPL(fs_event_immediate_close) {
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_close_with_pending_event) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
@ -698,20 +805,6 @@ TEST_IMPL(fs_event_close_with_pending_event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_KQUEUE) || defined(_AIX)
|
||||
|
||||
/* kqueue doesn't register fs events if you don't have an active watcher.
|
||||
* The file descriptor needs to be part of the kqueue set of interest and
|
||||
* that's not the case until we actually enter the event loop.
|
||||
* This is also observed on AIX with ahafs.
|
||||
*/
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !HAVE_KQUEUE || !_AIX */
|
||||
|
||||
static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
ASSERT(status == 0);
|
||||
@ -724,52 +817,49 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
fs_event_unlink_files(NULL);
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
create_file("watch_dir/file2");
|
||||
create_file("watch_dir/file3");
|
||||
create_file("watch_dir/file4");
|
||||
create_file("watch_dir/file5");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Generate a couple of fs events. */
|
||||
touch_file("watch_dir/file1");
|
||||
touch_file("watch_dir/file2");
|
||||
touch_file("watch_dir/file3");
|
||||
touch_file("watch_dir/file4");
|
||||
touch_file("watch_dir/file5");
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
uv_close((uv_handle_t*)&timer, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_ONCE);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
ASSERT(fs_event_cb_called == 3);
|
||||
|
||||
/* Clean up */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file3");
|
||||
remove("watch_dir/file4");
|
||||
remove("watch_dir/file5");
|
||||
fs_event_unlink_files(NULL);
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_KQUEUE || _AIX */
|
||||
|
||||
TEST_IMPL(fs_event_start_and_close) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop;
|
||||
uv_fs_event_t fs_event1;
|
||||
uv_fs_event_t fs_event2;
|
||||
@ -802,6 +892,9 @@ TEST_IMPL(fs_event_start_and_close) {
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_getpath) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
char buf[1024];
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
/* FIXME we shouldn't need to branch in this file */
|
||||
#if defined(__unix__) || defined(__POSIX__) || \
|
||||
defined(__APPLE__) || defined(_AIX)
|
||||
defined(__APPLE__) || defined(_AIX) || defined(__MVS__)
|
||||
#include <unistd.h> /* unlink, rmdir, etc. */
|
||||
#else
|
||||
# include <direct.h>
|
||||
@ -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),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -68,8 +68,8 @@ static struct echo_ctx ctx2;
|
||||
/* Used in write2_cb to decide if we need to cleanup or not */
|
||||
static int is_child_process;
|
||||
static int is_in_process;
|
||||
static int read_cb_called;
|
||||
static int recv_cb_called;
|
||||
static int read_cb_count;
|
||||
static int recv_cb_count;
|
||||
static int write2_cb_called;
|
||||
|
||||
|
||||
@ -91,43 +91,46 @@ static void recv_cb(uv_stream_t* handle,
|
||||
int r;
|
||||
union handles* recv;
|
||||
|
||||
if (++recv_cb_called == 1) {
|
||||
recv = &ctx.recv;
|
||||
} else {
|
||||
recv = &ctx.recv2;
|
||||
}
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx.channel);
|
||||
|
||||
/* Depending on the OS, the final recv_cb can be called after the child
|
||||
* process has terminated which can result in nread being UV_EOF instead of
|
||||
* the number of bytes read. Since the other end of the pipe has closed this
|
||||
* UV_EOF is an acceptable value. */
|
||||
if (nread == UV_EOF) {
|
||||
/* UV_EOF is only acceptable for the final recv_cb call */
|
||||
ASSERT(recv_cb_called == 2);
|
||||
} else {
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
do {
|
||||
if (++recv_cb_count == 1) {
|
||||
recv = &ctx.recv;
|
||||
} else {
|
||||
recv = &ctx.recv2;
|
||||
}
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == ctx.expected_type);
|
||||
/* Depending on the OS, the final recv_cb can be called after
|
||||
* the child process has terminated which can result in nread
|
||||
* being UV_EOF instead of the number of bytes read. Since
|
||||
* the other end of the pipe has closed this UV_EOF is an
|
||||
* acceptable value. */
|
||||
if (nread == UV_EOF) {
|
||||
/* UV_EOF is only acceptable for the final recv_cb call */
|
||||
ASSERT(recv_cb_count == 2);
|
||||
} else {
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == ctx.expected_type);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
} while (uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
/* Close after two writes received */
|
||||
if (recv_cb_called == 2) {
|
||||
if (recv_cb_count == 2) {
|
||||
uv_close((uv_handle_t*)&ctx.channel, NULL);
|
||||
}
|
||||
}
|
||||
@ -186,7 +189,7 @@ static int run_test(int inprocess) {
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(recv_cb_called == 2);
|
||||
ASSERT(recv_cb_count == 2);
|
||||
|
||||
if (inprocess) {
|
||||
r = uv_thread_join(&tid);
|
||||
@ -293,41 +296,43 @@ static void read_cb(uv_stream_t* handle,
|
||||
return;
|
||||
}
|
||||
|
||||
if (++read_cb_called == 2) {
|
||||
recv = &ctx2.recv;
|
||||
write_req = &ctx2.write_req;
|
||||
} else {
|
||||
recv = &ctx2.recv2;
|
||||
write_req = &ctx2.write_req2;
|
||||
}
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx2.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
do {
|
||||
if (++read_cb_count == 2) {
|
||||
recv = &ctx2.recv;
|
||||
write_req = &ctx2.write_req;
|
||||
} else {
|
||||
recv = &ctx2.recv2;
|
||||
write_req = &ctx2.write_req2;
|
||||
}
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
|
||||
ASSERT(pipe == &ctx2.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(uv_pipe_pending_count(pipe) > 0);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
|
||||
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
wrbuf = uv_buf_init(".", 1);
|
||||
r = uv_write2(write_req,
|
||||
(uv_stream_t*)&ctx2.channel,
|
||||
&wrbuf,
|
||||
1,
|
||||
&recv->stream,
|
||||
write2_cb);
|
||||
ASSERT(r == 0);
|
||||
r = uv_accept(handle, &recv->stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
wrbuf = uv_buf_init(".", 1);
|
||||
r = uv_write2(write_req,
|
||||
(uv_stream_t*)&ctx2.channel,
|
||||
&wrbuf,
|
||||
1,
|
||||
&recv->stream,
|
||||
write2_cb);
|
||||
ASSERT(r == 0);
|
||||
} while (uv_pipe_pending_count(pipe) > 0);
|
||||
}
|
||||
|
||||
static void send_recv_start() {
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
TEST_DECLARE (platform_output)
|
||||
TEST_DECLARE (callback_order)
|
||||
TEST_DECLARE (close_order)
|
||||
@ -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)
|
||||
|
||||
@ -34,7 +34,9 @@ TEST_IMPL(loop_close) {
|
||||
int r;
|
||||
uv_loop_t loop;
|
||||
|
||||
loop.data = &loop;
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
|
||||
uv_timer_init(&loop, &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 100, 100);
|
||||
@ -47,7 +49,9 @@ TEST_IMPL(loop_close) {
|
||||
r = uv_run(&loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
ASSERT(0 == uv_loop_close(&loop));
|
||||
ASSERT(loop.data == (void*) &loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -231,7 +231,7 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
||||
len1 = sizeof buf1;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf1[len1 - 1] != 0);
|
||||
ASSERT(len1 == 0); /* It's an annonymous pipe. */
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
|
||||
ASSERT(r == 0);
|
||||
@ -240,7 +240,7 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
||||
len2 = sizeof buf2;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf2[len2 - 1] != 0);
|
||||
ASSERT(len2 == 0); /* It's an annonymous pipe. */
|
||||
|
||||
r = uv_read_stop((uv_stream_t*)&pipe_client);
|
||||
ASSERT(r == 0);
|
||||
@ -255,7 +255,6 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
||||
|
||||
ASSERT(pipe_close_cb_called == 1);
|
||||
|
||||
_close(readfd);
|
||||
CloseHandle(writeh);
|
||||
#endif
|
||||
|
||||
|
||||
@ -61,8 +61,6 @@ TEST_IMPL(platform_output) {
|
||||
ASSERT(rusage.ru_utime.tv_usec >= 0);
|
||||
ASSERT(rusage.ru_stime.tv_sec >= 0);
|
||||
ASSERT(rusage.ru_stime.tv_usec >= 0);
|
||||
ASSERT(rusage.ru_majflt >= 0);
|
||||
ASSERT(rusage.ru_maxrss >= 0);
|
||||
printf("uv_getrusage:\n");
|
||||
printf(" user: %llu sec %llu microsec\n",
|
||||
(unsigned long long) rusage.ru_utime.tv_sec,
|
||||
|
||||
@ -19,8 +19,6 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -37,6 +35,7 @@
|
||||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
#ifdef _WIN32
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
@ -69,9 +68,13 @@ static void NO_INLINE close_socket_and_verify_stack() {
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++)
|
||||
ASSERT(data[i] == MARKER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(poll_close_doesnt_corrupt_stack) {
|
||||
#ifndef _WIN32
|
||||
RETURN_SKIP("Test only relevant on Windows");
|
||||
#else
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
@ -109,6 +112,5 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) {
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
@ -29,6 +28,7 @@
|
||||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
#ifdef _WIN32
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
@ -50,9 +50,13 @@ static void poll_cb(uv_poll_t* h, int status, int events) {
|
||||
uv_close((uv_handle_t*) &handle, close_cb);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(poll_closesocket) {
|
||||
#ifndef _WIN32
|
||||
RETURN_SKIP("Test only relevant on Windows");
|
||||
#else
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
@ -85,5 +89,5 @@ TEST_IMPL(poll_closesocket) {
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -31,6 +31,16 @@
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
# include <sys/types.h>
|
||||
# include <sys/event.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define NUM_CLIENTS 5
|
||||
#define TRANSFER_BYTES (1 << 16)
|
||||
@ -72,9 +82,9 @@ static int closed_connections = 0;
|
||||
static int valid_writable_wakeups = 0;
|
||||
static int spurious_writable_wakeups = 0;
|
||||
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
static int disconnects = 0;
|
||||
#endif /* !_AIX */
|
||||
#endif /* !_AIX && !__MVS__ */
|
||||
|
||||
static int got_eagain(void) {
|
||||
#ifdef _WIN32
|
||||
@ -378,7 +388,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
|
||||
new_events &= ~UV_WRITABLE;
|
||||
}
|
||||
}
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
if (events & UV_DISCONNECT) {
|
||||
context->got_disconnect = 1;
|
||||
++disconnects;
|
||||
@ -386,9 +396,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
|
||||
}
|
||||
|
||||
if (context->got_fin && context->sent_fin && context->got_disconnect) {
|
||||
#else /* _AIX */
|
||||
#else /* _AIX && __MVS__ */
|
||||
if (context->got_fin && context->sent_fin) {
|
||||
#endif /* !_AIx */
|
||||
#endif /* !_AIX && !__MVS__ */
|
||||
/* Sent and received FIN. Close and destroy context. */
|
||||
close_socket(context->sock);
|
||||
destroy_connection_context(context);
|
||||
@ -556,7 +566,7 @@ static void start_poll_test(void) {
|
||||
spurious_writable_wakeups > 20);
|
||||
|
||||
ASSERT(closed_connections == NUM_CLIENTS * 2);
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
ASSERT(disconnects == NUM_CLIENTS * 2);
|
||||
#endif
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
@ -584,7 +594,7 @@ TEST_IMPL(poll_unidirectional) {
|
||||
*/
|
||||
TEST_IMPL(poll_bad_fdtype) {
|
||||
#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \
|
||||
!defined(_AIX)
|
||||
!defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__)
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
@ -601,3 +611,47 @@ TEST_IMPL(poll_bad_fdtype) {
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
TEST_IMPL(poll_nested_epoll) {
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
fd = epoll_create(1);
|
||||
ASSERT(fd != -1);
|
||||
|
||||
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
|
||||
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
|
||||
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
|
||||
|
||||
uv_close((uv_handle_t*) &poll_handle, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(0 == close(fd));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
TEST_IMPL(poll_nested_kqueue) {
|
||||
uv_poll_t poll_handle;
|
||||
int fd;
|
||||
|
||||
fd = kqueue();
|
||||
ASSERT(fd != -1);
|
||||
|
||||
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
|
||||
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
|
||||
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
|
||||
|
||||
uv_close((uv_handle_t*) &poll_handle, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(0 == close(fd));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif /* UV_HAVE_KQUEUE */
|
||||
|
||||
@ -41,13 +41,35 @@ static void set_title(const char* title) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_get_process_title_edge_cases() {
|
||||
char buffer[512];
|
||||
int r;
|
||||
|
||||
/* Test a NULL buffer */
|
||||
r = uv_get_process_title(NULL, 100);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* Test size of zero */
|
||||
r = uv_get_process_title(buffer, 0);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* Test for insufficient buffer size */
|
||||
r = uv_get_process_title(buffer, 1);
|
||||
ASSERT(r == UV_ENOBUFS);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(process_title) {
|
||||
#if defined(__sun) || defined(_AIX)
|
||||
#if defined(__sun)
|
||||
RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
|
||||
#else
|
||||
/* Check for format string vulnerabilities. */
|
||||
set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
|
||||
set_title("new title");
|
||||
|
||||
/* Check uv_get_process_title() edge cases */
|
||||
uv_get_process_title_edge_cases();
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -194,6 +194,9 @@ TEST_IMPL(timer_ref2) {
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_ref) {
|
||||
#if defined(__MVS__)
|
||||
RETURN_SKIP("Filesystem watching not supported on this platform.");
|
||||
#endif
|
||||
uv_fs_event_t h;
|
||||
uv_fs_event_init(uv_default_loop(), &h);
|
||||
uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0);
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user