Browse Source

deps: update libuv to v0.11.28

archived-io.js-v0.10
Fedor Indutny 11 years ago
parent
commit
e49429ebd2
  1. 4
      deps/uv/.mailmap
  2. 9
      deps/uv/AUTHORS
  3. 91
      deps/uv/ChangeLog
  4. 12
      deps/uv/Makefile.am
  5. 3
      deps/uv/Makefile.mingw
  6. 7
      deps/uv/README.md
  7. 2
      deps/uv/configure.ac
  8. 12
      deps/uv/gyp_uv.py
  9. BIN
      deps/uv/img/banner.png
  10. 152
      deps/uv/img/logos.svg
  11. 32
      deps/uv/include/uv-aix.h
  12. 37
      deps/uv/include/uv-threadpool.h
  13. 13
      deps/uv/include/uv-unix.h
  14. 2
      deps/uv/include/uv-version.h
  15. 22
      deps/uv/include/uv-win.h
  16. 400
      deps/uv/include/uv.h
  17. 77
      deps/uv/src/threadpool.c
  18. 874
      deps/uv/src/unix/aix.c
  19. 7
      deps/uv/src/unix/core.c
  20. 30
      deps/uv/src/unix/fs.c
  21. 15
      deps/uv/src/unix/internal.h
  22. 4
      deps/uv/src/unix/loop.c
  23. 30
      deps/uv/src/unix/openbsd.c
  24. 63
      deps/uv/src/unix/stream.c
  25. 213
      deps/uv/src/unix/udp.c
  26. 33
      deps/uv/src/uv-common.c
  27. 15
      deps/uv/src/uv-common.h
  28. 159
      deps/uv/src/win/core.c
  29. 1
      deps/uv/src/win/error.c
  30. 175
      deps/uv/src/win/fs.c
  31. 63
      deps/uv/src/win/getaddrinfo.c
  32. 61
      deps/uv/src/win/getnameinfo.c
  33. 35
      deps/uv/src/win/internal.h
  34. 64
      deps/uv/src/win/pipe.c
  35. 252
      deps/uv/src/win/process.c
  36. 16
      deps/uv/src/win/req-inl.h
  37. 11
      deps/uv/src/win/stream-inl.h
  38. 63
      deps/uv/src/win/tcp.c
  39. 81
      deps/uv/src/win/threadpool.c
  40. 50
      deps/uv/src/win/timer.c
  41. 4
      deps/uv/src/win/tty.c
  42. 25
      deps/uv/src/win/udp.c
  43. 5
      deps/uv/test/run-tests.c
  44. 29
      deps/uv/test/test-barrier.c
  45. 67
      deps/uv/test/test-fs.c
  46. 3
      deps/uv/test/test-getsockname.c
  47. 125
      deps/uv/test/test-ipc.c
  48. 19
      deps/uv/test/test-list.h
  49. 29
      deps/uv/test/test-loop-time.c
  50. 151
      deps/uv/test/test-spawn.c
  51. 5
      deps/uv/test/test-tcp-close-accept.c
  52. 10
      deps/uv/test/test-tcp-try-write.c
  53. 137
      deps/uv/test/test-tcp-write-queue-order.c
  54. 3
      deps/uv/test/test-udp-multicast-interface.c
  55. 2
      deps/uv/test/test-udp-open.c
  56. 3
      deps/uv/test/test-udp-send-and-recv.c
  57. 148
      deps/uv/test/test-udp-send-immediate.c
  58. 133
      deps/uv/test/test-udp-try-send.c
  59. 2
      deps/uv/test/test-watcher-cross-stop.c
  60. 23
      deps/uv/uv.gyp

4
deps/uv/.mailmap

@ -1,3 +1,4 @@
Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com> Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com> Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl> Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
@ -5,6 +6,7 @@ Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org> Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org>
Brian White <mscdex@mscdex.net> Brian White <mscdex@mscdex.net>
Brian White <mscdex@mscdex.net> <mscdex@gmail.com> Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr>
Christoph Iserlohn <christoph.iserlohn@innoq.com> Christoph Iserlohn <christoph.iserlohn@innoq.com>
Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com> Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
Frank Denis <github@pureftpd.org> Frank Denis <github@pureftpd.org>
@ -15,6 +17,8 @@ Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu>
Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com> Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com> Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Rasmus Christian Pedersen <ruysch@outlook.com> Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com> Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
Rasmus Pedersen <ruysch@outlook.com> <zerhacken@yahoo.com> Rasmus Pedersen <ruysch@outlook.com> <zerhacken@yahoo.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org> Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>

9
deps/uv/AUTHORS

@ -146,3 +146,12 @@ HungMingWu <u9089000@gmail.com>
Jay Satiro <raysatiro@yahoo.com> Jay Satiro <raysatiro@yahoo.com>
Leith Bade <leith@leithalweapon.geek.nz> Leith Bade <leith@leithalweapon.geek.nz>
Peter Atashian <retep998@gmail.com> Peter Atashian <retep998@gmail.com>
Tim Cooper <tim.cooper@layeh.com>
Caleb James DeLisle <cjd@hyperboria.ca>
Jameson Nash <vtjnash@gmail.com>
Graham Lee <ghmlee@ghmlee.com>
Andrew Low <Andrew_Low@ca.ibm.com>
Pavel Platto <hinidu@gmail.com>
Tony Kelman <tony@kelman.net>
John Firebaugh <john.firebaugh@gmail.com>
lilohuang <lilohuang@hotmail.com>

91
deps/uv/ChangeLog

@ -1,4 +1,93 @@
2014.06.28, Version 0.11.26 (Unstable) 2014.08.08, Version 0.11.28 (Unstable)
Changes since version 0.11.27:
* unix, windows: const-ify handle in uv_udp_getsockname (Rasmus Pedersen)
* windows: use UV_ECANCELED for aborted TCP writes (Saúl Ibarra Corretgé)
* windows: add more required environment variables (Jameson Nash)
* windows: sort environment variables before calling CreateProcess (Jameson
Nash)
* unix, windows: move uv_loop_close out of assert (John Firebaugh)
* windows: fix buffer overflow on uv__getnameinfo_work() (lilohuang)
* windows: add uv_backend_timeout (Jameson Nash)
* test: disable tcp_close_accept on Windows (Saúl Ibarra Corretgé)
* windows: read the PATH env var of the child (Alex Crichton)
* include: avoid using C++ 'template' reserved word (Iñaki Baz Castillo)
* include: fix version number (Saúl Ibarra Corretgé)
2014.07.32, Version 0.11.27 (Unstable), ffe24f955032d060968ea0289af365006afed55e
Changes since version 0.11.26:
* unix, windows: use the same threadpool implementation (Saúl Ibarra Corretgé)
* unix: use struct sockaddr_storage for target UDP addr (Saúl Ibarra Corretgé)
* doc: add documentation to uv_udp_start_recv (Andrius Bentkus)
* common: use common uv__count_bufs code (Andrius Bentkus)
* unix, win: add send_queue_size and send_queue_count to uv_udp_t (Andrius
Bentkus)
* unix, win: add uv_udp_try_send (Andrius Bentkus)
* unix: return UV_EAGAIN if uv_try_write cannot write any data (Saúl Ibarra
Corretgé)
* windows: fix compatibility with cygwin pipes (Jameson Nash)
* windows: count queued bytes even if request completed immediately (Saúl
Ibarra Corretgé)
* windows: disable CRT debug handler on MinGW32 (Saúl Ibarra Corretgé)
* windows: map ERROR_INVALID_DRIVE to UV_ENOENT (Saúl Ibarra Corretgé)
* unix: try to write immediately in uv_udp_send (Saúl Ibarra Corretgé)
* unix: remove incorrect assert (Saúl Ibarra Corretgé)
* openbsd: avoid requiring privileges for uv_resident_set_memory (Aaron Bieber)
* unix: guarantee write queue cb execution order in streams (Andrius Bentkus)
* img: add logo files (Saúl Ibarra Corretgé)
* aix: improve AIX compatibility (Andrew Low)
* windows: return bind error immediately when implicitly binding (Saúl Ibarra
Corretgé)
* windows: don't use atexit for cleaning up the threadpool (Saúl Ibarra
Corretgé)
* windows: destroy work queue elements when colsing a loop (Saúl Ibarra
Corretgé)
* unix, windows: add uv_fs_mkdtemp (Pavel Platto)
* build: handle platforms without multiprocessing.synchronize (Saúl Ibarra
Corretgé)
* windows: change GENERIC_ALL to GENERIC_WRITE in fs__create_junction (Tony
Kelman)
* windows: relay TCP bind errors via ipc (Alexis Campailla)
2014.06.28, Version 0.11.26 (Unstable), 115281a1058c4034d5c5ccedacb667fe3f6327ea
Changes since version 0.11.25: Changes since version 0.11.25:

12
deps/uv/Makefile.am

@ -17,7 +17,7 @@ ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -I$(top_srcdir)/include \ AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_srcdir)/src -I$(top_srcdir)/src
include_HEADERS=include/uv.h include/uv-errno.h include/uv-version.h include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h
CLEANFILES = CLEANFILES =
@ -28,6 +28,7 @@ libuv_la_SOURCES = src/fs-poll.c \
src/heap-inl.h \ src/heap-inl.h \
src/inet.c \ src/inet.c \
src/queue.h \ src/queue.h \
src/threadpool.c \
src/uv-common.c \ src/uv-common.c \
src/uv-common.h \ src/uv-common.h \
src/version.c src/version.c
@ -67,7 +68,6 @@ libuv_la_SOURCES += src/win/async.c \
src/win/stream-inl.h \ src/win/stream-inl.h \
src/win/tcp.c \ src/win/tcp.c \
src/win/thread.c \ src/win/thread.c \
src/win/threadpool.c \
src/win/timer.c \ src/win/timer.c \
src/win/tty.c \ src/win/tty.c \
src/win/udp.c \ src/win/udp.c \
@ -99,7 +99,6 @@ libuv_la_SOURCES += src/unix/async.c \
src/unix/stream.c \ src/unix/stream.c \
src/unix/tcp.c \ src/unix/tcp.c \
src/unix/thread.c \ src/unix/thread.c \
src/unix/threadpool.c \
src/unix/timer.c \ src/unix/timer.c \
src/unix/tty.c \ src/unix/tty.c \
src/unix/udp.c src/unix/udp.c
@ -197,6 +196,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-tcp-write-to-half-open-connection.c \ test/test-tcp-write-to-half-open-connection.c \
test/test-tcp-writealot.c \ test/test-tcp-writealot.c \
test/test-tcp-try-write.c \ test/test-tcp-try-write.c \
test/test-tcp-write-queue-order.c \
test/test-thread.c \ test/test-thread.c \
test/test-threadpool-cancel.c \ test/test-threadpool-cancel.c \
test/test-threadpool.c \ test/test-threadpool.c \
@ -215,6 +215,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-udp-open.c \ test/test-udp-open.c \
test/test-udp-options.c \ test/test-udp-options.c \
test/test-udp-send-and-recv.c \ test/test-udp-send-and-recv.c \
test/test-udp-send-immediate.c \
test/test-udp-try-send.c \
test/test-walk-handles.c \ test/test-walk-handles.c \
test/test-watcher-cross-stop.c test/test-watcher-cross-stop.c
test_run_tests_LDADD = libuv.la test_run_tests_LDADD = libuv.la
@ -228,7 +230,7 @@ test_run_tests_SOURCES += test/runner-unix.c \
endif endif
if AIX if AIX
test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
endif endif
if SUNOS if SUNOS
@ -237,7 +239,7 @@ endif
if AIX if AIX
libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
libuv_la_SOURCES += src/unix/aix.c libuv_la_SOURCES += src/unix/aix.c
endif endif

3
deps/uv/Makefile.mingw

@ -26,6 +26,7 @@ CFLAGS += -Wall \
INCLUDES = include/stdint-msvc2008.h \ INCLUDES = include/stdint-msvc2008.h \
include/tree.h \ include/tree.h \
include/uv-errno.h \ include/uv-errno.h \
include/uv-threadpool.h \
include/uv-version.h \ include/uv-version.h \
include/uv-win.h \ include/uv-win.h \
include/uv.h \ include/uv.h \
@ -42,6 +43,7 @@ INCLUDES = include/stdint-msvc2008.h \
OBJS = src/fs-poll.o \ OBJS = src/fs-poll.o \
src/inet.o \ src/inet.o \
src/threadpool.o \
src/uv-common.o \ src/uv-common.o \
src/version.o \ src/version.o \
src/win/async.o \ src/win/async.o \
@ -63,7 +65,6 @@ OBJS = src/fs-poll.o \
src/win/stream.o \ src/win/stream.o \
src/win/tcp.o \ src/win/tcp.o \
src/win/thread.o \ src/win/thread.o \
src/win/threadpool.o \
src/win/timer.o \ src/win/timer.o \
src/win/tty.o \ src/win/tty.o \
src/win/udp.o \ src/win/udp.o \

7
deps/uv/README.md

@ -1,10 +1,12 @@
# libuv ![libuv][libuv_banner]
## Overview
libuv is a multi-platform support library with a focus on asynchronous I/O. It libuv is a multi-platform support library with a focus on asynchronous I/O. It
was primarily developed for use by [Node.js](http://nodejs.org), but it's also was primarily developed for use by [Node.js](http://nodejs.org), but it's also
used by Mozilla's [Rust language](http://www.rust-lang.org/), used by Mozilla's [Rust language](http://www.rust-lang.org/),
[Luvit](http://luvit.io/), [Julia](http://julialang.org/), [Luvit](http://luvit.io/), [Julia](http://julialang.org/),
[pyuv](https://crate.io/packages/pyuv/), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). [pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv).
## Feature highlights ## Feature highlights
@ -141,3 +143,4 @@ See the [guidelines for contributing][].
[Python]: https://www.python.org/downloads/ [Python]: https://www.python.org/downloads/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md [guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md
[libuv_banner]: https://raw.githubusercontent.com/joyent/libuv/master/img/banner.png

2
deps/uv/configure.ac

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT([libuv], [0.11.26], [https://github.com/joyent/libuv/issues]) AC_INIT([libuv], [0.11.28], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4]) m4_include([m4/as_case.m4])

12
deps/uv/gyp_uv.py

@ -6,6 +6,13 @@ import os
import subprocess import subprocess
import sys import sys
try:
import multiprocessing.synchronize
gyp_parallel_support = True
except ImportError:
gyp_parallel_support = False
CC = os.environ.get('CC', 'cc') CC = os.environ.get('CC', 'cc')
script_dir = os.path.dirname(__file__) script_dir = os.path.dirname(__file__)
uv_root = os.path.normpath(script_dir) uv_root = os.path.normpath(script_dir)
@ -94,6 +101,11 @@ if __name__ == '__main__':
if not any(a.startswith('-Dcomponent=') for a in args): if not any(a.startswith('-Dcomponent=') for a in args):
args.append('-Dcomponent=static_library') args.append('-Dcomponent=static_library')
# Some platforms (OpenBSD for example) don't have multiprocessing.synchronize
# so gyp must be run with --no-parallel
if not gyp_parallel_support:
args.append('--no-parallel')
gyp_args = list(args) gyp_args = list(args)
print gyp_args print gyp_args
run_gyp(gyp_args) run_gyp(gyp_args)

BIN
deps/uv/img/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

152
deps/uv/img/logos.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 64 KiB

32
deps/uv/include/uv-aix.h

@ -0,0 +1,32 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_AIX_H
#define UV_AIX_H
#define UV_PLATFORM_LOOP_FIELDS \
int fs_fd; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
uv__io_t event_watcher; \
char *dir_filename; \
#endif /* UV_AIX_H */

37
deps/uv/include/uv-threadpool.h

@ -0,0 +1,37 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* This file is private to libuv. It provides common functionality to both
* Windows and Unix backends.
*/
#ifndef UV_THREADPOOL_H_
#define UV_THREADPOOL_H_
struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
struct uv_loop_s* loop;
void* wq[2];
};
#endif /* UV_THREADPOOL_H_ */

13
deps/uv/include/uv-unix.h

@ -42,8 +42,12 @@
#endif #endif
#include <signal.h> #include <signal.h>
#include "uv-threadpool.h"
#if defined(__linux__) #if defined(__linux__)
# include "uv-linux.h" # include "uv-linux.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun) #elif defined(__sun)
# include "uv-sunos.h" # include "uv-sunos.h"
#elif defined(__APPLE__) #elif defined(__APPLE__)
@ -96,13 +100,6 @@ struct uv__async {
int wfd; int wfd;
}; };
struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
struct uv_loop_s* loop;
void* wq[2];
};
#ifndef UV_PLATFORM_SEM_T #ifndef UV_PLATFORM_SEM_T
# define UV_PLATFORM_SEM_T sem_t # define UV_PLATFORM_SEM_T sem_t
#endif #endif
@ -218,7 +215,7 @@ typedef struct {
#define UV_UDP_SEND_PRIVATE_FIELDS \ #define UV_UDP_SEND_PRIVATE_FIELDS \
void* queue[2]; \ void* queue[2]; \
struct sockaddr_in6 addr; \ struct sockaddr_storage addr; \
unsigned int nbufs; \ unsigned int nbufs; \
uv_buf_t* bufs; \ uv_buf_t* bufs; \
ssize_t status; \ ssize_t status; \

2
deps/uv/include/uv-version.h

@ -32,7 +32,7 @@
#define UV_VERSION_MAJOR 0 #define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11 #define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 26 #define UV_VERSION_PATCH 28
#define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_IS_RELEASE 1
#endif /* UV_VERSION_H */ #endif /* UV_VERSION_H */

22
deps/uv/include/uv-win.h

@ -30,6 +30,15 @@ typedef intptr_t ssize_t;
#endif #endif
#include <winsock2.h> #include <winsock2.h>
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct pollfd {
SOCKET fd;
short events;
short revents;
} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
#endif
#include <mswsock.h> #include <mswsock.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <windows.h> #include <windows.h>
@ -45,6 +54,7 @@ typedef intptr_t ssize_t;
#endif #endif
#include "tree.h" #include "tree.h"
#include "uv-threadpool.h"
#define MAX_PIPENAME_LEN 256 #define MAX_PIPENAME_LEN 256
@ -307,7 +317,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* Counter to keep track of active udp streams */ \ /* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams; \ unsigned int active_udp_streams; \
/* Counter to started timer */ \ /* Counter to started timer */ \
uint64_t timer_counter; uint64_t timer_counter; \
/* Threadpool */ \
void* wq[2]; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async;
#define UV_REQ_TYPE_PRIVATE \ #define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \ /* TODO: remove the req suffix */ \
@ -395,7 +409,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define UV_TCP_PRIVATE_FIELDS \ #define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \ SOCKET socket; \
int bind_error; \ int delayed_error; \
union { \ union { \
struct { uv_tcp_server_fields }; \ struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \ struct { uv_tcp_connection_fields }; \
@ -520,6 +534,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
unsigned int flags; unsigned int flags;
#define UV_GETADDRINFO_PRIVATE_FIELDS \ #define UV_GETADDRINFO_PRIVATE_FIELDS \
struct uv__work work_req; \
uv_getaddrinfo_cb getaddrinfo_cb; \ uv_getaddrinfo_cb getaddrinfo_cb; \
void* alloc; \ void* alloc; \
WCHAR* node; \ WCHAR* node; \
@ -529,6 +544,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
int retcode; int retcode;
#define UV_GETNAMEINFO_PRIVATE_FIELDS \ #define UV_GETNAMEINFO_PRIVATE_FIELDS \
struct uv__work work_req; \
uv_getnameinfo_cb getnameinfo_cb; \ uv_getnameinfo_cb getnameinfo_cb; \
struct sockaddr_storage storage; \ struct sockaddr_storage storage; \
int flags; \ int flags; \
@ -547,6 +563,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
volatile char exit_cb_pending; volatile char exit_cb_pending;
#define UV_FS_PRIVATE_FIELDS \ #define UV_FS_PRIVATE_FIELDS \
struct uv__work work_req; \
int flags; \ int flags; \
DWORD sys_errno_; \ DWORD sys_errno_; \
union { \ union { \
@ -572,6 +589,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
}; };
#define UV_WORK_PRIVATE_FIELDS \ #define UV_WORK_PRIVATE_FIELDS \
struct uv__work work_req;
#define UV_FS_EVENT_PRIVATE_FIELDS \ #define UV_FS_EVENT_PRIVATE_FIELDS \
struct uv_fs_event_req_s { \ struct uv_fs_event_req_s { \

400
deps/uv/include/uv.h

@ -258,7 +258,8 @@ UV_EXTERN const char* uv_version_string(void);
*/ */
/* /*
* Returns the default loop. * Returns the initialized default loop. It may return NULL in case of
* allocation failture.
*/ */
UV_EXTERN uv_loop_t* uv_default_loop(void); UV_EXTERN uv_loop_t* uv_default_loop(void);
@ -276,20 +277,24 @@ UV_EXTERN int uv_loop_close(uv_loop_t* loop);
/* /*
* Allocates and initializes a new loop. * Allocates and initializes a new loop.
* NOTE: This function is DEPRECATED (to be removed after 0.12), users should *
* NOTE:
* This function is DEPRECATED (to be removed after 0.12), users should
* allocate the loop manually and use uv_loop_init instead. * allocate the loop manually and use uv_loop_init instead.
*/ */
UV_EXTERN uv_loop_t* uv_loop_new(void); UV_EXTERN uv_loop_t* uv_loop_new(void);
/* /*
* Cleans up a loop once it has finished executio and frees its memory. * Cleans up a loop once it has finished executio and frees its memory.
* NOTE: This function is DEPRECATED (to be removed after 0.12). Users should use *
* NOTE:
* This function is DEPRECATED (to be removed after 0.12). Users should use
* uv_loop_close and free the memory manually instead. * uv_loop_close and free the memory manually instead.
*/ */
UV_EXTERN void uv_loop_delete(uv_loop_t*); UV_EXTERN void uv_loop_delete(uv_loop_t*);
/* /*
* Returns size of the loop struct, useful for dynamic lookup with FFI * Returns size of the loop struct, useful for dynamic lookup with FFI.
*/ */
UV_EXTERN size_t uv_loop_size(void); UV_EXTERN size_t uv_loop_size(void);
@ -316,10 +321,10 @@ UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
/* /*
* This function will stop the event loop by forcing uv_run to end * This function will stop the event loop by forcing uv_run to end as soon as
* as soon as possible, but not sooner than the next loop iteration. * possible, but not sooner than the next loop iteration.
* If this function was called before blocking for i/o, the loop won't * If this function was called before blocking for i/o, the loop won't block
* block for i/o on this iteration. * for i/o on this iteration.
*/ */
UV_EXTERN void uv_stop(uv_loop_t*); UV_EXTERN void uv_stop(uv_loop_t*);
@ -398,12 +403,12 @@ typedef void (*uv_alloc_cb)(uv_handle_t* handle,
* `nread` is > 0 if there is data available, 0 if libuv is done reading for * `nread` is > 0 if there is data available, 0 if libuv is done reading for
* now, or < 0 on error. * now, or < 0 on error.
* *
* The callee is responsible for closing the stream when an error happens. * The callee is responsible for closing the stream when an error happens
* Trying to read from the stream again is undefined. * by calling uv_close(). Trying to read from the stream again is undefined.
* *
* The callee is responsible for freeing the buffer, libuv does not reuse it. * The callee is responsible for freeing the buffer, libuv does not reuse it.
* The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on * The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on
* EOF or error. * error.
*/ */
typedef void (*uv_read_cb)(uv_stream_t* stream, typedef void (*uv_read_cb)(uv_stream_t* stream,
ssize_t nread, ssize_t nread,
@ -505,17 +510,17 @@ struct uv_req_s {
}; };
/* Platform-specific request types */ /* Platform-specific request types. */
UV_PRIVATE_REQ_TYPES UV_PRIVATE_REQ_TYPES
/* /*
* uv_shutdown_t is a subclass of uv_req_t * uv_shutdown_t is a subclass of uv_req_t.
* *
* Shutdown the outgoing (write) side of a duplex stream. It waits for * Shutdown the outgoing (write) side of a duplex stream. It waits for pending
* pending write requests to complete. The handle should refer to a * write requests to complete. The handle should refer to a initialized stream.
* initialized stream. req should be an uninitialized shutdown request * req should be an uninitialized shutdown request struct. The cb is called
* struct. The cb is called after shutdown is complete. * after shutdown is complete.
*/ */
UV_EXTERN int uv_shutdown(uv_shutdown_t* req, UV_EXTERN int uv_shutdown(uv_shutdown_t* req,
uv_stream_t* handle, uv_stream_t* handle,
@ -546,14 +551,13 @@ struct uv_handle_s {
}; };
/* /*
* Returns size of various handle types, useful for FFI * Returns size of various handle types, useful for FFI bindings to allocate
* bindings to allocate correct memory without copying struct * correct memory without copying struct definitions.
* definitions
*/ */
UV_EXTERN size_t uv_handle_size(uv_handle_type type); UV_EXTERN size_t uv_handle_size(uv_handle_type type);
/* /*
* Returns size of request types, useful for dynamic lookup with FFI * Returns size of request types, useful for dynamic lookup with FFI.
*/ */
UV_EXTERN size_t uv_req_size(uv_req_type type); UV_EXTERN size_t uv_req_size(uv_req_type type);
@ -566,7 +570,7 @@ UV_EXTERN size_t uv_req_size(uv_req_type type);
* by closing it with uv_close(). * by closing it with uv_close().
* *
* - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that * - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that
* deals with I/O - is active when it is doing something that involves I/O, * deals with i/o - is active when it is doing something that involves i/o,
* like reading, writing, connecting, accepting new connections, etc. * like reading, writing, connecting, accepting new connections, etc.
* *
* - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has * - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has
@ -601,6 +605,7 @@ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
/* /*
* Constructor for uv_buf_t. * Constructor for uv_buf_t.
*
* Due to platform differences the user cannot rely on the ordering of the * Due to platform differences the user cannot rely on the ordering of the
* base and len members of the uv_buf_t struct. The user is responsible for * base and len members of the uv_buf_t struct. The user is responsible for
* freeing base after the uv_buf_t is done. Return struct passed by value. * freeing base after the uv_buf_t is done. Return struct passed by value.
@ -617,7 +622,7 @@ UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
UV_STREAM_PRIVATE_FIELDS UV_STREAM_PRIVATE_FIELDS
/* /*
* uv_stream_t is a subclass of uv_handle_t * uv_stream_t is a subclass of uv_handle_t.
* *
* uv_stream is an abstract class. * uv_stream is an abstract class.
* *
@ -636,16 +641,16 @@ UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
* the connection. Before calling uv_accept use uv_*_init() must be * the connection. Before calling uv_accept use uv_*_init() must be
* called on the client. Non-zero return value indicates an error. * called on the client. Non-zero return value indicates an error.
* *
* When the uv_connection_cb is called it is guaranteed that uv_accept will * When the uv_connection_cb is called it is guaranteed that uv_accept() will
* complete successfully the first time. If you attempt to use it more than * complete successfully the first time. If you attempt to use it more than
* once, it may fail. It is suggested to only call uv_accept once per * once, it may fail. It is suggested to only call uv_accept() once per
* uv_connection_cb call. * uv_connection_cb call.
*/ */
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
/* /*
* Read data from an incoming stream. The callback will be made several * Read data from an incoming stream. The callback will be made several
* times until there is no more data to read or uv_read_stop is called. * times until there is no more data to read or uv_read_stop() is called.
* When we've reached EOF nread will be set to UV_EOF. * When we've reached EOF nread will be set to UV_EOF.
* *
* When nread < 0, the buf parameter might not point to a valid buffer; * When nread < 0, the buf parameter might not point to a valid buffer;
@ -704,17 +709,19 @@ UV_EXTERN int uv_write2(uv_write_t* req,
uv_write_cb cb); uv_write_cb cb);
/* /*
* Same as `uv_write()`, but won't queue write request if it can't be completed * Same as uv_write(), but won't queue write request if it can't be completed
* immediately. * immediately.
*
* Will return either: * Will return either:
* - >= 0: number of bytes written (can be less than the supplied buffer size) * - > 0: number of bytes written (can be less than the supplied buffer size).
* - < 0: negative error code * - < 0: negative error code (UV_EAGAIN is returned if no data can be sent
* immediately).
*/ */
UV_EXTERN int uv_try_write(uv_stream_t* handle, UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[], const uv_buf_t bufs[],
unsigned int nbufs); unsigned int nbufs);
/* uv_write_t is a subclass of uv_req_t */ /* uv_write_t is a subclass of uv_req_t. */
struct uv_write_s { struct uv_write_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_write_cb cb; uv_write_cb cb;
@ -755,15 +762,14 @@ UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking);
/* /*
* Used to determine whether a stream is closing or closed. * Used to determine whether a stream is closing or closed.
* *
* N.B. is only valid between the initialization of the handle * N.B. is only valid between the initialization of the handle and the arrival
* and the arrival of the close callback, and cannot be used * of the close callback, and cannot be used to validate the handle.
* to validate the handle.
*/ */
UV_EXTERN int uv_is_closing(const uv_handle_t* handle); UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
/* /*
* uv_tcp_t is a subclass of uv_stream_t * uv_tcp_t is a subclass of uv_stream_t.
* *
* Represents a TCP stream or TCP server. * Represents a TCP stream or TCP server.
*/ */
@ -795,15 +801,16 @@ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
/* /*
* Enable/disable simultaneous asynchronous accept requests that are * Enable/disable simultaneous asynchronous accept requests that are
* queued by the operating system when listening for new tcp connections. * queued by the operating system when listening for new tcp connections.
*
* This setting is used to tune a tcp server for the desired performance. * This setting is used to tune a tcp server for the desired performance.
* Having simultaneous accepts can significantly improve the rate of * Having simultaneous accepts can significantly improve the rate of accepting
* accepting connections (which is why it is enabled by default) but * connections (which is why it is enabled by default) but may lead to uneven
* may lead to uneven load distribution in multi-process setups. * load distribution in multi-process setups.
*/ */
UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
enum uv_tcp_flags { enum uv_tcp_flags {
/* Used with uv_tcp_bind, when an IPv6 address is used */ /* Used with uv_tcp_bind, when an IPv6 address is used. */
UV_TCP_IPV6ONLY = 1 UV_TCP_IPV6ONLY = 1
}; };
@ -811,11 +818,11 @@ enum uv_tcp_flags {
* Bind the handle to an address and port. `addr` should point to an * Bind the handle to an address and port. `addr` should point to an
* initialized struct sockaddr_in or struct sockaddr_in6. * initialized struct sockaddr_in or struct sockaddr_in6.
* *
* When the port is already taken, you can expect to see an UV_EADDRINUSE * When the port is already taken, you can expect to see an UV_EADDRINUSE error
* error from either uv_tcp_bind(), uv_listen() or uv_tcp_connect(). * from either uv_tcp_bind(), uv_listen() or uv_tcp_connect().
* *
* That is, a successful call to uv_tcp_bind() does not guarantee that * That is, a successful call to uv_tcp_bind() does not guarantee that the call
* the call to uv_listen() or uv_tcp_connect() will succeed as well. * to uv_listen() or uv_tcp_connect() will succeed as well.
*/ */
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
@ -840,7 +847,7 @@ UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
const struct sockaddr* addr, const struct sockaddr* addr,
uv_connect_cb cb); uv_connect_cb cb);
/* uv_connect_t is a subclass of uv_req_t */ /* uv_connect_t is a subclass of uv_req_t. */
struct uv_connect_s { struct uv_connect_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_connect_cb cb; uv_connect_cb cb;
@ -861,9 +868,10 @@ enum uv_udp_flags {
* remainder was discarded by the OS. Used in uv_udp_recv_cb. * remainder was discarded by the OS. Used in uv_udp_recv_cb.
*/ */
UV_UDP_PARTIAL = 2, UV_UDP_PARTIAL = 2,
/* Indicates if SO_REUSEADDR will be set when binding the handle. /*
* Indicates if SO_REUSEADDR will be set when binding the handle.
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
* UNIX platforms, it sets the SO_REUSEADDR flag. What that means is that * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
* multiple threads or processes can bind to the same address without error * multiple threads or processes can bind to the same address without error
* (provided they all set the flag) but only the last one to bind will receive * (provided they all set the flag) but only the last one to bind will receive
* any traffic, in effect "stealing" the port from the previous listener. * any traffic, in effect "stealing" the port from the previous listener.
@ -872,8 +880,7 @@ enum uv_udp_flags {
}; };
/* /*
* Called after uv_udp_send(). status 0 indicates * Called after uv_udp_send(). status 0 indicates success otherwise error.
* success otherwise error.
*/ */
typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
@ -882,14 +889,20 @@ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
* *
* handle UDP handle. * handle UDP handle.
* nread Number of bytes that have been received. * nread Number of bytes that have been received.
* 0 if there is no more data to read. You may * - 0 if there is no more data to read. You may discard or repurpose
* discard or repurpose the read buffer. * the read buffer. Note that 0 may also mean that an empty datagram
* < 0 if a transmission error was detected. * was received (in this case `addr` is not NULL).
* - < 0 if a transmission error was detected.
* buf uv_buf_t with the received data. * buf uv_buf_t with the received data.
* addr struct sockaddr* containing the address of the sender. * addr struct sockaddr* containing the address of the sender. Can be NULL.
* Can be NULL. Valid for the duration of the callback only. * Valid for the duration of the callback only.
* flags One or more OR'ed UV_UDP_* constants. * flags One or more OR'ed UV_UDP_* constants. Right now only UV_UDP_PARTIAL
* Right now only UV_UDP_PARTIAL is used. * is used.
*
* NOTE:
* The receive callback will be called with nread == 0 and addr == NULL when
* there is nothing to read, and with nread == 0 and addr != NULL when an empty
* UDP packet is received.
*/ */
typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
ssize_t nread, ssize_t nread,
@ -897,13 +910,23 @@ typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned flags); unsigned flags);
/* uv_udp_t is a subclass of uv_handle_t */ /* uv_udp_t is a subclass of uv_handle_t. */
struct uv_udp_s { struct uv_udp_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
/* read-only */
/*
* Number of bytes queued for sending. This field strictly shows how much
* information is currently queued.
*/
size_t send_queue_size;
/*
* Number of send requests currently in the queue awaiting to be processed.
*/
size_t send_queue_count;
UV_UDP_PRIVATE_FIELDS UV_UDP_PRIVATE_FIELDS
}; };
/* uv_udp_send_t is a subclass of uv_req_t */ /* uv_udp_send_t is a subclass of uv_req_t. */
struct uv_udp_send_s { struct uv_udp_send_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_udp_t* handle; uv_udp_t* handle;
@ -921,16 +944,16 @@ UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
* Opens an existing file descriptor or SOCKET as a udp handle. * Opens an existing file descriptor or SOCKET as a udp handle.
* *
* Unix only: * Unix only:
* The only requirement of the sock argument is that it follows the * The only requirement of the sock argument is that it follows the datagram
* datagram contract (works in unconnected mode, supports sendmsg()/recvmsg(), * contract (works in unconnected mode, supports sendmsg()/recvmsg(), etc).
* etc.). In other words, other datagram-type sockets like raw sockets or * In other words, other datagram-type sockets like raw sockets or netlink
* netlink sockets can also be passed to this function. * sockets can also be passed to this function.
* *
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other Unix
* UNIX platforms, it sets the SO_REUSEADDR flag. What that means is that * platforms, it sets the SO_REUSEADDR flag. What that means is that multiple
* multiple threads or processes can bind to the same address without error * threads or processes can bind to the same address without error (provided
* (provided they all set the flag) but only the last one to bind will receive * they all set the flag) but only the last one to bind will receive any
* any traffic, in effect "stealing" the port from the previous listener. * traffic, in effect "stealing" the port from the previous listener.
* This behavior is something of an anomaly and may be replaced by an explicit * This behavior is something of an anomaly and may be replaced by an explicit
* opt-in mechanism in future versions of libuv. * opt-in mechanism in future versions of libuv.
*/ */
@ -940,7 +963,7 @@ UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
* Bind to an IP address and port. * Bind to an IP address and port.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with `uv_udp_init`. * handle UDP handle. Should have been initialized with uv_udp_init().
* addr struct sockaddr_in or struct sockaddr_in6 with the address and * addr struct sockaddr_in or struct sockaddr_in6 with the address and
* port to bind to. * port to bind to.
* flags Indicate how the socket will be bound, UV_UDP_IPV6ONLY and * flags Indicate how the socket will be bound, UV_UDP_IPV6ONLY and
@ -953,7 +976,7 @@ UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int flags); unsigned int flags);
UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
struct sockaddr* name, struct sockaddr* name,
int* namelen); int* namelen);
@ -962,10 +985,10 @@ UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle,
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* multicast_addr multicast address to set membership for * multicast_addr multicast address to set membership for.
* interface_addr interface address * interface_addr interface address.
* membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP * membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -981,8 +1004,8 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* on 1 for on, 0 for off * on 1 for on, 0 for off.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -990,12 +1013,12 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
/* /*
* Set the multicast ttl * Set the multicast ttl.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* ttl 1 through 255 * ttl 1 through 255.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -1004,12 +1027,12 @@ UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
/* /*
* Set the multicast interface to send on * Set the multicast interface to send on.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* interface_addr interface address * interface_addr interface address.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -1018,12 +1041,12 @@ UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
const char* interface_addr); const char* interface_addr);
/* /*
* Set broadcast on or off * Set broadcast on or off.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* on 1 for on, 0 for off * on 1 for on, 0 for off.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -1031,12 +1054,12 @@ UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
/* /*
* Set the time to live * Set the time to live.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with * handle UDP handle. Should have been initialized with
* `uv_udp_init`. * uv_udp_init().
* ttl 1 through 255 * ttl 1 through 255.
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -1044,13 +1067,12 @@ UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl);
/* /*
* Send data. If the socket has not previously been bound with `uv_udp_bind,` * Send data. If the socket has not previously been bound with uv_udp_bind() it
* it is bound to 0.0.0.0 (the "all interfaces" address) and a random * is bound to 0.0.0.0 (the "all interfaces" address) and a random port number.
* port number.
* *
* Arguments: * Arguments:
* req UDP request handle. Need not be initialized. * req UDP request handle. Need not be initialized.
* handle UDP handle. Should have been initialized with `uv_udp_init`. * handle UDP handle. Should have been initialized with uv_udp_init().
* bufs List of buffers to send. * bufs List of buffers to send.
* nbufs Number of buffers in `bufs`. * nbufs Number of buffers in `bufs`.
* addr struct sockaddr_in or struct sockaddr_in6 with the address and * addr struct sockaddr_in or struct sockaddr_in6 with the address and
@ -1068,12 +1090,25 @@ UV_EXTERN int uv_udp_send(uv_udp_send_t* req,
uv_udp_send_cb send_cb); uv_udp_send_cb send_cb);
/* /*
* Receive data. If the socket has not previously been bound with `uv_udp_bind` * Same as uv_udp_send(), but won't queue a send request if it can't be completed
* it is bound to 0.0.0.0 (the "all interfaces" address) and a random * immediately.
* port number. *
* Will return either:
* - >= 0: number of bytes sent (it matches the given buffer size).
* - < 0: negative error code (UV_EAGAIN is returned when the message can't be
* sent immediately).
*/
UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr);
/*
* Receive data. If the socket has not previously been bound with uv_udp_bind()
* it is bound to 0.0.0.0 (the "all interfaces" address) and a random port
* number.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with `uv_udp_init`. * handle UDP handle. Should have been initialized with uv_udp_init().
* alloc_cb Callback to invoke when temporary storage is needed. * alloc_cb Callback to invoke when temporary storage is needed.
* recv_cb Callback to invoke with received data. * recv_cb Callback to invoke with received data.
* *
@ -1088,7 +1123,7 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
* Stop listening for incoming datagrams. * Stop listening for incoming datagrams.
* *
* Arguments: * Arguments:
* handle UDP handle. Should have been initialized with `uv_udp_init`. * handle UDP handle. Should have been initialized with uv_udp_init().
* *
* Returns: * Returns:
* 0 on success, or an error code < 0 on failure. * 0 on success, or an error code < 0 on failure.
@ -1097,7 +1132,7 @@ UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
/* /*
* uv_tty_t is a subclass of uv_stream_t * uv_tty_t is a subclass of uv_stream_t.
* *
* Representing a stream for the console. * Representing a stream for the console.
*/ */
@ -1109,12 +1144,12 @@ struct uv_tty_s {
/* /*
* Initialize a new TTY stream with the given file descriptor. Usually the * Initialize a new TTY stream with the given file descriptor. Usually the
* file descriptor will be * file descriptor will be:
* 0 = stdin * 0 = stdin
* 1 = stdout * 1 = stdout
* 2 = stderr * 2 = stderr
* The last argument, readable, specifies if you plan on calling * The last argument, readable, specifies if you plan on calling
* uv_read_start with this stream. stdin is readable, stdout is not. * uv_read_start() with this stream. stdin is readable, stdout is not.
* *
* TTY streams which are not readable have blocking writes. * TTY streams which are not readable have blocking writes.
*/ */
@ -1129,7 +1164,7 @@ UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode);
* To be called when the program exits. Resets TTY settings to default * To be called when the program exits. Resets TTY settings to default
* values for the next process to take over. * values for the next process to take over.
* *
* This function is async signal-safe on UNIX platforms but can fail with error * This function is async signal-safe on Unix platforms but can fail with error
* code UV_EBUSY if you call it when execution is inside uv_tty_set_mode(). * code UV_EBUSY if you call it when execution is inside uv_tty_set_mode().
*/ */
UV_EXTERN int uv_tty_reset_mode(void); UV_EXTERN int uv_tty_reset_mode(void);
@ -1143,15 +1178,16 @@ UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
* Used to detect what type of stream should be used with a given file * Used to detect what type of stream should be used with a given file
* descriptor. Usually this will be used during initialization to guess the * descriptor. Usually this will be used during initialization to guess the
* type of the stdio streams. * type of the stdio streams.
*
* For isatty() functionality use this function and test for UV_TTY. * For isatty() functionality use this function and test for UV_TTY.
*/ */
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
/* /*
* uv_pipe_t is a subclass of uv_stream_t * uv_pipe_t is a subclass of uv_stream_t.
* *
* Representing a pipe stream or pipe server. On Windows this is a Named * Representing a pipe stream or pipe server. On Windows this is a Named
* Pipe. On Unix this is a UNIX domain socket. * Pipe. On Unix this is a Unix domain socket.
*/ */
struct uv_pipe_s { struct uv_pipe_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
@ -1172,17 +1208,17 @@ UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
/* /*
* Bind the pipe to a file path (UNIX) or a name (Windows.) * Bind the pipe to a file path (Unix) or a name (Windows).
* *
* Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, * Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
* typically between 92 and 108 bytes. * typically between 92 and 108 bytes.
*/ */
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
/* /*
* Connect to the UNIX domain socket or the named pipe. * Connect to the Unix domain socket or the named pipe.
* *
* Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, * Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
* typically between 92 and 108 bytes. * typically between 92 and 108 bytes.
*/ */
UV_EXTERN void uv_pipe_connect(uv_connect_t* req, UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
@ -1191,12 +1227,12 @@ UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
uv_connect_cb cb); uv_connect_cb cb);
/* /*
* Get the name of the UNIX domain socket or the named pipe. * Get the name of the Unix domain socket or the named pipe.
* *
* A preallocated buffer must be provided. The len parameter holds the * A preallocated buffer must be provided. The len parameter holds the length
* length of the buffer and it's set to the number of bytes written to the * of the buffer and it's set to the number of bytes written to the buffer on
* buffer on output. If the buffer is not big enough UV_ENOBUFS will be * output. If the buffer is not big enough UV_ENOBUFS will be returned and len
* returned and len will contain the required size. * will contain the required size.
*/ */
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
char* buf, char* buf,
@ -1204,17 +1240,18 @@ UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
/* /*
* This setting applies to Windows only. * This setting applies to Windows only.
* Set the number of pending pipe instance handles when the pipe server *
* is waiting for connections. * Set the number of pending pipe instance handles when the pipe server is
* waiting for connections.
*/ */
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
/* /*
* Used to receive handles over ipc pipes. * Used to receive handles over ipc pipes.
* *
* First - call `uv_pipe_pending_count`, if it is > 0 - initialize handle * First - call uv_pipe_pending_count(), if it is > 0 - initialize handle
* using type, returned by `uv_pipe_pending_type` and call * using type, returned by uv_pipe_pending_type() and call
* `uv_accept(pipe, handle)`. * uv_accept(pipe, handle).
*/ */
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
@ -1227,10 +1264,10 @@ UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
* *
* The purpose of uv_poll is to enable integrating external libraries that * The purpose of uv_poll is to enable integrating external libraries that
* rely on the event loop to signal it about the socket status changes, like * rely on the event loop to signal it about the socket status changes, like
* c-ares or libssh2. Using uv_poll_t for any other other purpose is not * c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended;
* recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is * uv_tcp_t, uv_udp_t, etc. provide an implementation that is much faster and
* much faster and more scalable than what can be achieved with uv_poll_t, * more scalable than what can be achieved with uv_poll_t, especially on
* especially on Windows. * Windows.
* *
* It is possible that uv_poll occasionally signals that a file descriptor is * It is possible that uv_poll occasionally signals that a file descriptor is
* readable or writable even when it isn't. The user should therefore always * readable or writable even when it isn't. The user should therefore always
@ -1245,7 +1282,7 @@ UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
* but it might also start polling another socket. However the fd can be safely * but it might also start polling another socket. However the fd can be safely
* closed immediately after a call to uv_poll_stop() or uv_close(). * closed immediately after a call to uv_poll_stop() or uv_close().
* *
* On windows only sockets can be polled with uv_poll. On unix any file * On windows only sockets can be polled with uv_poll. On Unix any file
* descriptor that would be accepted by poll(2) can be used with uv_poll. * descriptor that would be accepted by poll(2) can be used with uv_poll.
*/ */
struct uv_poll_s { struct uv_poll_s {
@ -1262,8 +1299,10 @@ enum uv_poll_event {
/* Initialize the poll watcher using a file descriptor. */ /* Initialize the poll watcher using a file descriptor. */
UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
/* Initialize the poll watcher using a socket descriptor. On unix this is */ /*
/* identical to uv_poll_init. On windows it takes a SOCKET handle. */ * Initialize the poll watcher using a socket descriptor. On Unix this is
* identical to uv_poll_init. On windows it takes a SOCKET handle.
*/
UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop,
uv_poll_t* handle, uv_poll_t* handle,
uv_os_sock_t socket); uv_os_sock_t socket);
@ -1347,11 +1386,15 @@ UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
/* /*
* uv_async_t is a subclass of uv_handle_t. * uv_async_t is a subclass of uv_handle_t.
* *
* uv_async_send wakes up the event loop and calls the async handle's callback. * uv_async_send() wakes up the event loop and calls the async handle's callback.
* There is no guarantee that every uv_async_send call leads to exactly one *
* invocation of the callback; the only guarantee is that the callback function * Unlike all other libuv functions, uv_async_send() can be called from another
* is called at least once after the call to async_send. Unlike all other * thread.
* libuv functions, uv_async_send can be called from another thread. *
* NOTE:
* There is no guarantee that every uv_async_send() call leads to exactly one
* invocation of the callback; the only guarantee is that the callback
* function is called at least once after the call to async_send.
*/ */
struct uv_async_s { struct uv_async_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
@ -1420,7 +1463,7 @@ UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
/* /*
* uv_getaddrinfo_t is a subclass of uv_req_t * uv_getaddrinfo_t is a subclass of uv_req_t.
* *
* Request object for uv_getaddrinfo. * Request object for uv_getaddrinfo.
*/ */
@ -1464,7 +1507,7 @@ UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
/* /*
* uv_getnameinfo_t is a subclass of uv_req_t * uv_getnameinfo_t is a subclass of uv_req_t.
* *
* Request object for uv_getnameinfo. * Request object for uv_getnameinfo.
*/ */
@ -1490,14 +1533,15 @@ UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
int flags); int flags);
/* uv_spawn() options */ /* uv_spawn() options. */
typedef enum { typedef enum {
UV_IGNORE = 0x00, UV_IGNORE = 0x00,
UV_CREATE_PIPE = 0x01, UV_CREATE_PIPE = 0x01,
UV_INHERIT_FD = 0x02, UV_INHERIT_FD = 0x02,
UV_INHERIT_STREAM = 0x04, UV_INHERIT_STREAM = 0x04,
/* When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE /*
* When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
* determine the direction of flow, from the child process' perspective. Both * determine the direction of flow, from the child process' perspective. Both
* flags may be specified to create a duplex data stream. * flags may be specified to create a duplex data stream.
*/ */
@ -1578,7 +1622,7 @@ enum uv_process_flags {
/* /*
* Do not wrap any arguments in quotes, or perform any other escaping, when * Do not wrap any arguments in quotes, or perform any other escaping, when
* converting the argument list into a command line string. This option is * converting the argument list into a command line string. This option is
* only meaningful on Windows systems. On unix it is silently ignored. * only meaningful on Windows systems. On Unix it is silently ignored.
*/ */
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
/* /*
@ -1591,14 +1635,14 @@ enum uv_process_flags {
UV_PROCESS_DETACHED = (1 << 3), UV_PROCESS_DETACHED = (1 << 3),
/* /*
* Hide the subprocess console window that would normally be created. This * Hide the subprocess console window that would normally be created. This
* option is only meaningful on Windows systems. On unix it is silently * option is only meaningful on Windows systems. On Unix it is silently
* ignored. * ignored.
*/ */
UV_PROCESS_WINDOWS_HIDE = (1 << 4) UV_PROCESS_WINDOWS_HIDE = (1 << 4)
}; };
/* /*
* uv_process_t is a subclass of uv_handle_t * uv_process_t is a subclass of uv_handle_t.
*/ */
struct uv_process_s { struct uv_process_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
@ -1625,7 +1669,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop,
/* /*
* Kills the process with the specified signal. The user must still * Kills the process with the specified signal. The user must still
* call uv_close on the process. * call uv_close() on the process.
* *
* Emulates some aspects of Unix exit status on Windows, in that while the * Emulates some aspects of Unix exit status on Windows, in that while the
* underlying process will be terminated with a status of `1`, * underlying process will be terminated with a status of `1`,
@ -1651,7 +1695,7 @@ UV_EXTERN int uv_kill(int pid, int signum);
/* /*
* uv_work_t is a subclass of uv_req_t * uv_work_t is a subclass of uv_req_t.
*/ */
struct uv_work_s { struct uv_work_s {
UV_REQ_FIELDS UV_REQ_FIELDS
@ -1686,7 +1730,7 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop,
* - A uv_work_t or uv_getaddrinfo_t request has its callback invoked with * - A uv_work_t or uv_getaddrinfo_t request has its callback invoked with
* status == UV_ECANCELED. * status == UV_ECANCELED.
* *
* This function is currently only implemented on UNIX platforms. On Windows, * This function is currently only implemented on Unix platforms. On Windows,
* it always returns UV_ENOSYS. * it always returns UV_ENOSYS.
*/ */
UV_EXTERN int uv_cancel(uv_req_t* req); UV_EXTERN int uv_cancel(uv_req_t* req);
@ -1755,15 +1799,15 @@ typedef struct {
UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
/* /*
* This allocates cpu_infos array, and sets count. The array * This allocates cpu_infos array, and sets count. The array is freed
* is freed using uv_free_cpu_info(). * using uv_free_cpu_info().
*/ */
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
/* /*
* This allocates addresses array, and sets count. The array * This allocates addresses array, and sets count. The array is freed
* is freed using uv_free_interface_addresses(). * using uv_free_interface_addresses().
*/ */
UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
int* count); int* count);
@ -1805,6 +1849,7 @@ typedef enum {
UV_FS_UNLINK, UV_FS_UNLINK,
UV_FS_RMDIR, UV_FS_RMDIR,
UV_FS_MKDIR, UV_FS_MKDIR,
UV_FS_MKDTEMP,
UV_FS_RENAME, UV_FS_RENAME,
UV_FS_READDIR, UV_FS_READDIR,
UV_FS_LINK, UV_FS_LINK,
@ -1814,7 +1859,7 @@ typedef enum {
UV_FS_FCHOWN UV_FS_FCHOWN
} uv_fs_type; } uv_fs_type;
/* uv_fs_t is a subclass of uv_req_t */ /* uv_fs_t is a subclass of uv_req_t. */
struct uv_fs_s { struct uv_fs_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_fs_type fs_type; uv_fs_type fs_type;
@ -1823,7 +1868,7 @@ struct uv_fs_s {
ssize_t result; ssize_t result;
void* ptr; void* ptr;
const char* path; const char* path;
uv_stat_t statbuf; /* Stores the result of uv_fs_stat and uv_fs_fstat. */ uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */
UV_FS_PRIVATE_FIELDS UV_FS_PRIVATE_FIELDS
}; };
@ -1847,6 +1892,9 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file,
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
int mode, uv_fs_cb cb); int mode, uv_fs_cb cb);
UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
uv_fs_cb cb);
UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb); uv_fs_cb cb);
@ -1890,14 +1938,14 @@ UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb); const char* new_path, uv_fs_cb cb);
/* /*
* This flag can be used with uv_fs_symlink on Windows * This flag can be used with uv_fs_symlink() on Windows to specify whether
* to specify whether path argument points to a directory. * path argument points to a directory.
*/ */
#define UV_FS_SYMLINK_DIR 0x0001 #define UV_FS_SYMLINK_DIR 0x0001
/* /*
* This flag can be used with uv_fs_symlink on Windows * This flag can be used with uv_fs_symlink() on Windows to specify whether
* to specify whether the symlink is to be created using junction points. * the symlink is to be created using junction points.
*/ */
#define UV_FS_SYMLINK_JUNCTION 0x0002 #define UV_FS_SYMLINK_JUNCTION 0x0002
@ -1975,7 +2023,7 @@ UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len);
/* /*
* UNIX signal handling on a per-event loop basis. The implementation is not * Unix signal handling on a per-event loop basis. The implementation is not
* ultra efficient so don't go creating a million event loops with a million * ultra efficient so don't go creating a million event loops with a million
* signal watchers. * signal watchers.
* *
@ -2030,14 +2078,16 @@ UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
/* /*
* Gets load average. * Gets load average.
*
* See: http://en.wikipedia.org/wiki/Load_(computing) * See: http://en.wikipedia.org/wiki/Load_(computing)
*
* Returns [0,0,0] on Windows. * Returns [0,0,0] on Windows.
*/ */
UV_EXTERN void uv_loadavg(double avg[3]); UV_EXTERN void uv_loadavg(double avg[3]);
/* /*
* Flags to be passed to uv_fs_event_start. * Flags to be passed to uv_fs_event_start().
*/ */
enum uv_fs_event_flags { enum uv_fs_event_flags {
/* /*
@ -2088,32 +2138,34 @@ UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle,
size_t* len); size_t* len);
/* Utility */ /* Utilities. */
/* Convert string ip addresses to binary structures */ /* Convert string ip addresses to binary structures. */
UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr); UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr); UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
/* Convert binary addresses to strings */ /* Convert binary addresses to strings. */
UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size); UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size); UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
/* Cross-platform IPv6-capable implementation of the 'standard' inet_ntop */ /*
/* and inet_pton functions. On success they return 0. If an error */ * Cross-platform IPv6-capable implementation of the 'standard' inet_ntop() and
/* the target of the `dst` pointer is unmodified. */ * inet_pton() functions. On success they return 0. If an error the target of
* the `dst` pointer is unmodified.
*/
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
/* Gets the executable path */ /* Gets the executable path. */
UV_EXTERN int uv_exepath(char* buffer, size_t* size); UV_EXTERN int uv_exepath(char* buffer, size_t* size);
/* Gets the current working directory */ /* Gets the current working directory. */
UV_EXTERN int uv_cwd(char* buffer, size_t* size); UV_EXTERN int uv_cwd(char* buffer, size_t* size);
/* Changes the current working directory */ /* Changes the current working directory. */
UV_EXTERN int uv_chdir(const char* dir); UV_EXTERN int uv_chdir(const char* dir);
/* Gets memory info in bytes */ /* Gets memory info in bytes. */
UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_free_memory(void);
UV_EXTERN uint64_t uv_get_total_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void);
@ -2139,13 +2191,13 @@ UV_EXTERN extern uint64_t uv_hrtime(void);
* *
* Note that this function works on a best-effort basis: there is no guarantee * Note that this function works on a best-effort basis: there is no guarantee
* that libuv can discover all file descriptors that were inherited. In general * that libuv can discover all file descriptors that were inherited. In general
* it does a better job on Windows than it does on unix. * it does a better job on Windows than it does on Unix.
*/ */
UV_EXTERN void uv_disable_stdio_inheritance(void); UV_EXTERN void uv_disable_stdio_inheritance(void);
/* /*
* Opens a shared library. The filename is in utf-8. Returns 0 on success and * Opens a shared library. The filename is in utf-8. Returns 0 on success and
* -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message. * -1 on error. Call uv_dlerror(uv_lib_t*) to get the error message.
*/ */
UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
@ -2166,8 +2218,8 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib); UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
/* /*
* The mutex functions return 0 on success or an error code < 0 * The mutex functions return 0 on success or an error code < 0 (unless the
* (unless the return type is void, of course). * return type is void, of course).
*/ */
UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
@ -2216,31 +2268,35 @@ UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier); UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier); UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
/* Waits on a condition variable without a timeout. /*
* Waits on a condition variable without a timeout.
* *
* Note: * NOTE:
* 1. callers should be prepared to deal with spurious wakeups. * 1. callers should be prepared to deal with spurious wakeups.
*/ */
UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex); UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
/* Waits on a condition variable with a timeout in nano seconds. /*
* Waits on a condition variable with a timeout in nano seconds.
* Returns 0 for success or UV_ETIMEDOUT on timeout, It aborts when other * Returns 0 for success or UV_ETIMEDOUT on timeout, It aborts when other
* errors happen. * errors happen.
* *
* Note: * NOTE:
* 1. callers should be prepared to deal with spurious wakeups. * 1. callers should be prepared to deal with spurious wakeups.
* 2. the granularity of timeout on Windows is never less than one millisecond. * 2. the granularity of timeout on Windows is never less than one millisecond.
* 3. uv_cond_timedwait takes a relative timeout, not an absolute time. * 3. uv_cond_timedwait() takes a relative timeout, not an absolute time.
*/ */
UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
uint64_t timeout); uint64_t timeout);
/* Runs a function once and only once. Concurrent calls to uv_once() with the /*
* Runs a function once and only once. Concurrent calls to uv_once() with the
* same guard will block all callers except one (it's unspecified which one). * same guard will block all callers except one (it's unspecified which one).
* The guard should be initialized statically with the UV_ONCE_INIT macro. * The guard should be initialized statically with the UV_ONCE_INIT macro.
*/ */
UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
/* Thread-local storage. These functions largely follow the semantics of /*
* Thread-local storage. These functions largely follow the semantics of
* pthread_key_create(), pthread_key_delete(), pthread_getspecific() and * pthread_key_create(), pthread_key_delete(), pthread_getspecific() and
* pthread_setspecific(). * pthread_setspecific().
* *
@ -2278,11 +2334,11 @@ union uv_any_req {
struct uv_loop_s { struct uv_loop_s {
/* User data - use this for whatever. */ /* User data - use this for whatever. */
void* data; void* data;
/* Loop reference counting */ /* Loop reference counting. */
unsigned int active_handles; unsigned int active_handles;
void* handle_queue[2]; void* handle_queue[2];
void* active_reqs[2]; void* active_reqs[2];
/* Internal flag to signal loop stop */ /* Internal flag to signal loop stop. */
unsigned int stop_flag; unsigned int stop_flag;
UV_LOOP_PRIVATE_FIELDS UV_LOOP_PRIVATE_FIELDS
}; };

77
deps/uv/src/unix/threadpool.c → deps/uv/src/threadpool.c

@ -19,7 +19,24 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
#include "internal.h" #include "uv-common.h"
#if !defined(_WIN32)
# include "unix/internal.h"
#else
# include "win/req-inl.h"
/* TODO(saghul): unify internal req functions */
static void uv__req_init(uv_loop_t* loop,
uv_req_t* req,
uv_req_type type) {
uv_req_init(loop, req);
req->type = type;
uv__req_register(loop, req);
}
# define uv__req_init(loop, req, type) \
uv__req_init((loop), (uv_req_t*)(req), (type))
#endif
#include <stdlib.h> #include <stdlib.h>
#define MAX_THREADPOOL_SIZE 128 #define MAX_THREADPOOL_SIZE 128
@ -91,6 +108,32 @@ static void post(QUEUE* q) {
} }
#ifndef _WIN32
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
if (initialized == 0)
return;
post(&exit_message);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
abort();
if (threads != default_threads)
free(threads);
uv_mutex_destroy(&mutex);
uv_cond_destroy(&cond);
threads = NULL;
nthreads = 0;
initialized = 0;
}
#endif
static void init_once(void) { static void init_once(void) {
unsigned int i; unsigned int i;
const char* val; const char* val;
@ -129,30 +172,6 @@ static void init_once(void) {
} }
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
if (initialized == 0)
return;
post(&exit_message);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
abort();
if (threads != default_threads)
free(threads);
uv_mutex_destroy(&mutex);
uv_cond_destroy(&cond);
threads = NULL;
nthreads = 0;
initialized = 0;
}
void uv__work_submit(uv_loop_t* loop, void uv__work_submit(uv_loop_t* loop,
struct uv__work* w, struct uv__work* w,
void (*work)(struct uv__work* w), void (*work)(struct uv__work* w),
@ -179,7 +198,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
uv_mutex_unlock(&mutex); uv_mutex_unlock(&mutex);
if (!cancelled) if (!cancelled)
return -EBUSY; return UV_EBUSY;
w->work = uv__cancelled; w->work = uv__cancelled;
uv_mutex_lock(&loop->wq_mutex); uv_mutex_lock(&loop->wq_mutex);
@ -213,7 +232,7 @@ void uv__work_done(uv_async_t* handle) {
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
w = container_of(q, struct uv__work, wq); w = container_of(q, struct uv__work, wq);
err = (w->work == uv__cancelled) ? -ECANCELED : 0; err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
w->done(w, err); w->done(w, err);
} }
} }
@ -244,7 +263,7 @@ int uv_queue_work(uv_loop_t* loop,
uv_work_cb work_cb, uv_work_cb work_cb,
uv_after_work_cb after_work_cb) { uv_after_work_cb after_work_cb) {
if (work_cb == NULL) if (work_cb == NULL)
return -EINVAL; return UV_EINVAL;
uv__req_init(loop, req, UV_WORK); uv__req_init(loop, req, UV_WORK);
req->loop = loop; req->loop = loop;
@ -277,7 +296,7 @@ int uv_cancel(uv_req_t* req) {
wreq = &((uv_work_t*) req)->work_req; wreq = &((uv_work_t*) req)->work_req;
break; break;
default: default:
return -EINVAL; return UV_EINVAL;
} }
return uv__work_cancel(loop, req, wreq); return uv__work_cancel(loop, req, wreq);

874
deps/uv/src/unix/aix.c

@ -39,12 +39,235 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <utmp.h> #include <utmp.h>
#include <libgen.h>
#include <sys/protosw.h> #include <sys/protosw.h>
#include <libperfstat.h> #include <libperfstat.h>
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/procfs.h> #include <sys/procfs.h>
#include <sys/poll.h>
#include <sys/pollset.h>
#include <ctype.h>
#include <sys/ahafs_evProds.h>
#include <sys/mntctl.h>
#include <sys/vmount.h>
#include <limits.h>
#include <strings.h>
#include <sys/vnode.h>
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
loop->fs_fd = -1;
/* Passing maxfd of -1 should mean the limit is determined
* by the user's ulimit or the global limit as per the doc */
loop->backend_fd = pollset_create(-1);
if (loop->backend_fd == -1)
return -1;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->fs_fd != -1) {
uv__close(loop->fs_fd);
loop->fs_fd = -1;
}
if (loop->backend_fd != -1) {
pollset_destroy(loop->backend_fd);
loop->backend_fd = -1;
}
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct pollfd events[1024];
struct pollfd pqry;
struct pollfd* pe;
struct poll_ctl pc;
QUEUE* q;
uv__io_t* w;
uint64_t base;
uint64_t diff;
int nevents;
int count;
int nfds;
int i;
int rc;
int add_failed;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
pc.events = w->pevents;
pc.fd = w->fd;
add_failed = 0;
if (w->events == 0) {
pc.cmd = PS_ADD;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
if (errno != EINVAL) {
assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
abort();
}
/* Check if the fd is already in the pollset */
pqry.fd = pc.fd;
rc = pollset_query(loop->backend_fd, &pqry);
switch (rc) {
case -1:
assert(0 && "Failed to query pollset for file descriptor");
abort();
case 0:
assert(0 && "Pollset does not contain file descriptor");
abort();
}
/* If we got here then the pollset already contained the file descriptor even though
* we didn't think it should. This probably shouldn't happen, but we can continue. */
add_failed = 1;
}
}
if (w->events != 0 || add_failed) {
/* Modify, potentially removing events -- need to delete then add.
* Could maybe mod if we knew for sure no events are removed, but
* content of w->events is handled above as not reliable (falls back)
* so may require a pollset_query() which would have to be pretty cheap
* compared to a PS_DELETE to be worth optimising. Alternatively, could
* lazily remove events, squelching them in the mean time. */
pc.cmd = PS_DELETE;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
abort();
}
pc.cmd = PS_ADD;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
abort();
}
}
w->events = w->pevents;
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
for (;;) {
nfds = pollset_poll(loop->backend_fd,
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.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
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;
}
nevents = 0;
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;
pc.cmd = PS_DELETE;
pc.fd = pe->fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (pc.fd == -1)
continue;
assert(pc.fd >= 0);
assert((unsigned) pc.fd < loop->nwatchers);
w = loop->watchers[pc.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.
*/
pollset_ctl(loop->backend_fd, &pc, 1);
continue;
}
w->cb(loop, w, pe->revents);
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);
diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
timeout -= diff;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) { uint64_t uv__hrtime(uv_clocktype_t type) {
uint64_t G = 1000000000; uint64_t G = 1000000000;
timebasestruct_t t; timebasestruct_t t;
@ -58,28 +281,24 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
* We could use a static buffer for the path manipulations that we need outside * 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 * 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. * 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 AIX - 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 uv_exepath(char* buffer, size_t* size) {
ssize_t res; ssize_t res;
char pp[64], cwdl[PATH_MAX]; char cwd[PATH_MAX], cwdl[PATH_MAX];
char symlink[PATH_MAX], temp_buffer[PATH_MAX];
char pp[64];
struct psinfo ps; struct psinfo ps;
int fd; int fd;
char **argv;
if (buffer == NULL) if ((buffer == NULL) || (size == NULL))
return (-1); return -EINVAL;
if (size == NULL)
return (-1);
(void) snprintf(pp, sizeof(pp), "/proc/%lu/cwd", (unsigned long) getpid()); snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
res = readlink(pp, cwdl, sizeof(cwdl) - 1);
if (res < 0)
return res;
cwdl[res] = '\0';
(void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
fd = open(pp, O_RDONLY); fd = open(pp, O_RDONLY);
if (fd < 0) if (fd < 0)
return fd; return fd;
@ -89,9 +308,163 @@ int uv_exepath(char* buffer, size_t* size) {
if (res < 0) if (res < 0)
return res; return res;
(void) snprintf(buffer, *size, "%s%s", cwdl, ps.pr_fname); if (ps.pr_argv == 0)
return -EINVAL;
argv = (char **) *((char ***) (intptr_t) ps.pr_argv);
if ((argv == NULL) || (argv[0] == NULL))
return -EINVAL;
/*
* Three possibilities for argv[0]:
* 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 #1, absolute path. */
if (argv[0][0] == '/') {
snprintf(symlink, PATH_MAX-1, "%s", argv[0]);
/* This could or could not be a symlink. */
res = readlink(symlink, temp_buffer, PATH_MAX-1);
/* if readlink fails, it is a normal file just copy symlink to the
* outbut buffer.
*/
if (res < 0) {
assert(*size > strlen(symlink));
strcpy(buffer, symlink);
/* If it is a link, the resolved filename is again a relative path,
* make it absolute.
*/
} else {
assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
}
*size = strlen(buffer); *size = strlen(buffer);
return 0; return 0;
/* case #2, relative path with usage of '.' */
} else if (argv[0][0] == '.') {
char *relative = strchr(argv[0], '/');
if (relative == NULL)
return -EINVAL;
/* Get the current working directory to resolve the relative path. */
snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
/* This is always a symlink, resolve it. */
res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
if (res < 0)
return -errno;
snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1);
res = readlink(symlink, temp_buffer, PATH_MAX-1);
if (res < 0) {
assert(*size > strlen(symlink));
strcpy(buffer, symlink);
} else {
assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
}
*size = strlen(buffer);
return 0;
/* case #3, relative path without usage of '.', such as invocations in Node test suite. */
} else if (strchr(argv[0], '/') != NULL) {
/* Get the current working directory to resolve the relative path. */
snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
/* This is always a symlink, resolve it. */
res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
if (res < 0)
return -errno;
snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]);
res = readlink(symlink, temp_buffer, PATH_MAX-1);
if (res < 0) {
assert(*size > strlen(symlink));
strcpy(buffer, symlink);
} else {
assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
}
*size = strlen(buffer);
return 0;
/* Usage of absolute filename with location exported in PATH */
} else {
char clonedpath[8192]; /* assume 8k buffer will fit PATH */
char *token = NULL;
struct stat statstruct;
/* Get the paths. */
char *path = getenv("PATH");
if(sizeof(clonedpath) <= strlen(path))
return -EINVAL;
/* Get a local copy. */
strcpy(clonedpath, path);
/* Tokenize. */
token = strtok(clonedpath, ":");
/* Get current working directory. (may be required in the loop). */
snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
if (res < 0)
return -errno;
/* Run through the tokens, append our executable file name with each,
* and see which one succeeds. Exit on first match. */
while(token != NULL) {
if (token[0] == '.') {
/* Path contains a token relative to current directory. */
char *relative = strchr(token, '/');
if (relative != NULL)
/* A path which is not current directory. */
snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname);
else
snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname);
if (stat(symlink, &statstruct) != -1) {
/* File exists. Resolve if it is a link. */
res = readlink(symlink, temp_buffer, PATH_MAX-1);
if (res < 0) {
assert(*size > strlen(symlink));
strcpy(buffer, symlink);
} else {
assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
}
*size = strlen(buffer);
return 0;
}
/* Absolute path names. */
} else {
snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname);
if (stat(symlink, &statstruct) != -1) {
res = readlink(symlink, temp_buffer, PATH_MAX-1);
if (res < 0) {
assert(*size > strlen(symlink));
strcpy(buffer, symlink);
} else {
assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
}
*size = strlen(buffer);
return 0;
}
}
token = strtok(NULL, ":");
}
/* Out of tokens (path entries), and no match found */
return -EINVAL;
}
} }
@ -128,8 +501,369 @@ void uv_loadavg(double avg[3]) {
} }
static char *uv__rawname(char *cp) {
static char rawbuf[FILENAME_MAX+1];
char *dp = rindex(cp, '/');
if (dp == 0)
return 0;
*dp = 0;
strcpy(rawbuf, cp);
*dp = '/';
strcat(rawbuf, "/r");
strcat(rawbuf, dp+1);
return rawbuf;
}
/*
* Determine whether given pathname is a directory
* Returns 0 if the path is a directory, -1 if not
*
* Note: Opportunity here for more detailed error information but
* that requires changing callers of this function as well
*/
static int uv__path_is_a_directory(char* filename) {
struct stat statbuf;
if (stat(filename, &statbuf) < 0)
return -1; /* failed: not a directory, assume it is a file */
if (statbuf.st_type == VDIR)
return 0;
return -1;
}
/*
* Check whether AHAFS is mounted.
* Returns 0 if AHAFS is mounted, or an error code < 0 on failure
*/
static int uv__is_ahafs_mounted(void){
int rv, i = 2;
struct vmount *p;
int size_multiplier = 10;
size_t siz = sizeof(struct vmount)*size_multiplier;
struct vmount *vmt;
const char *dev = "/aha";
char *obj, *stub;
p = malloc(siz);
if (p == NULL)
return -errno;
/* Retrieve all mounted filesystems */
rv = mntctl(MCTL_QUERY, siz, (char*)p);
if (rv < 0)
return -errno;
if (rv == 0) {
/* buffer was not large enough, reallocate to correct size */
siz = *(int*)p;
free(p);
p = malloc(siz);
if (p == NULL)
return -errno;
rv = mntctl(MCTL_QUERY, siz, (char*)p);
if (rv < 0)
return -errno;
}
/* Look for dev in filesystems mount info */
for(vmt = p, i = 0; i < rv; i++) {
obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
free(p); /* Found a match */
return 0;
}
vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
}
/* /aha is required for monitoring filesystem changes */
return -1;
}
/*
* Recursive call to mkdir() to create intermediate folders, if any
* Returns code from mkdir call
*/
static int uv__makedir_p(const char *dir) {
char tmp[256];
char *p = NULL;
size_t len;
int err;
snprintf(tmp, sizeof(tmp),"%s",dir);
len = strlen(tmp);
if (tmp[len - 1] == '/')
tmp[len - 1] = 0;
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0;
err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if(err != 0)
return err;
*p = '/';
}
}
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
*/
static int uv__make_subdirs_p(const char *filename) {
char cmd[2048];
char *p;
int rc = 0;
/* Strip off the monitor file name */
p = strrchr(filename, '/');
if (p == NULL)
return 0;
if (uv__path_is_a_directory((char*)filename) == 0) {
sprintf(cmd, "/aha/fs/modDir.monFactory");
} else {
sprintf(cmd, "/aha/fs/modFile.monFactory");
}
strncat(cmd, filename, (p - filename));
rc = uv__makedir_p(cmd);
if (rc == -1 && errno != EEXIST){
return -errno;
}
return rc;
}
/*
* Checks if /aha is mounted, then proceeds to set up the monitoring
* objects for the specified file.
* Returns 0 on success, or an error code < 0 on failure
*/
static int uv__setup_ahafs(const char* filename, int *fd) {
int rc = 0;
char mon_file_write_string[RDWR_BUF_SIZE];
char mon_file[PATH_MAX];
int file_is_directory = 0; /* -1 == NO, 0 == YES */
/* Create monitor file name for object */
file_is_directory = uv__path_is_a_directory((char*)filename);
if (file_is_directory == 0)
sprintf(mon_file, "/aha/fs/modDir.monFactory");
else
sprintf(mon_file, "/aha/fs/modFile.monFactory");
if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
return -ENAMETOOLONG;
/* Make the necessary subdirectories for the monitor file */
rc = uv__make_subdirs_p(filename);
if (rc == -1 && errno != EEXIST)
return rc;
strcat(mon_file, filename);
strcat(mon_file, ".mon");
*fd = 0; errno = 0;
/* Open the monitor file, creating it if necessary */
*fd = open(mon_file, O_CREAT|O_RDWR);
if (*fd < 0)
return -errno;
/* Write out the monitoring specifications.
* In this case, we are monitoring for a state change event type
* CHANGED=YES
* We will be waiting in select call, rather than a read:
* WAIT_TYPE=WAIT_IN_SELECT
* We only want minimal information for files:
* INFO_LVL=1
* For directories, we want more information to track what file
* caused the change
* INFO_LVL=2
*/
if (file_is_directory == 0)
sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
else
sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
if (rc < 0)
return -errno;
return 0;
}
/*
* Skips a specified number of lines in the buffer passed in.
* Walks the buffer pointed to by p and attempts to skip n lines.
* Returns the total number of lines skipped
*/
static int uv__skip_lines(char **p, int n) {
int lines = 0;
while(n > 0) {
*p = strchr(*p, '\n');
if (!p)
return lines;
(*p)++;
n--;
lines++;
}
return lines;
}
/*
* 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
*
*/
static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
int evp_rc, i;
char *p;
char filename[PATH_MAX]; /* To be used when handling directories */
p = buf;
*events = 0;
/* Clean the filename buffer*/
for(i = 0; i < PATH_MAX; i++) {
filename[i] = 0;
}
i = 0;
/* Check for BUF_WRAP */
if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
assert(0 && "Buffer wrap detected, Some event occurrences lost!");
return 0;
}
/* Since we are using the default buffer size (4K), and have specified
* INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
* should check for this keyword if they are using an INFO_LVL of 2 or
* higher, and have a buffer size of <= 4K
*/
/* Skip to RC_FROM_EVPROD */
if (uv__skip_lines(&p, 9) != 9)
return -1;
if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
/* The directory is no longer available for monitoring */
*events = UV_RENAME;
handle->dir_filename = NULL;
} else {
/* A file was added/removed inside the directory */
*events = UV_CHANGE;
/* Get the EVPROD_INFO */
if (uv__skip_lines(&p, 1) != 1)
return -1;
/* Scan out the name of the file that triggered the event*/
if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
handle->dir_filename = strdup((const char*)&filename);
} else
return -1;
}
} else { /* Regular File */
if (evp_rc == AHAFS_MODFILE_RENAME)
*events = UV_RENAME;
else
*events = UV_CHANGE;
}
}
else
return -1;
return 0;
}
/* This is the internal callback */
static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
char result_data[RDWR_BUF_SIZE];
int bytes, rc = 0;
uv_fs_event_t* handle;
int events = 0;
int i = 0;
char fname[PATH_MAX];
char *p;
handle = container_of(event_watch, uv_fs_event_t, event_watcher);
/* Clean all the buffers*/
for(i = 0; i < PATH_MAX; i++) {
fname[i] = 0;
}
i = 0;
/* At this point, we assume that polling has been done on the
* file descriptor, so we can just read the AHAFS event occurrence
* data and parse its results without having to block anything
*/
bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
/* Parse the data */
if(bytes > 0)
rc = uv__parse_data(result_data, &events, handle);
/* For directory changes, the name of the files that triggered the change
* are never absolute pathnames
*/
if (uv__path_is_a_directory(handle->path) == 0) {
p = handle->dir_filename;
while(*p != NULL){
fname[i]= *p;
i++;
p++;
}
} else {
/* For file changes, figure out whether filename is absolute or not */
if (handle->path[0] == '/') {
p = strrchr(handle->path, '/');
p++;
while(*p != NULL) {
fname[i]= *p;
i++;
p++;
}
}
}
/* Unrecoverable error */
if (rc == -1)
return;
else /* Call the actual JavaScript callback function */
handle->cb(handle, (const char*)&fname, events, 0);
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return -ENOSYS; uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
} }
@ -137,17 +871,99 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb, uv_fs_event_cb cb,
const char* filename, const char* filename,
unsigned int flags) { unsigned int flags) {
return -ENOSYS; int fd, rc, i = 0, res = 0;
char cwd[PATH_MAX];
char absolute_path[PATH_MAX];
char fname[PATH_MAX];
char *p;
/* Clean all the buffers*/
for(i = 0; i < PATH_MAX; i++) {
cwd[i] = 0;
absolute_path[i] = 0;
fname[i] = 0;
}
i = 0;
/* Figure out whether filename is absolute or not */
if (filename[0] == '/') {
/* We have absolute pathname, create the relative pathname*/
sprintf(absolute_path, filename);
p = strrchr(filename, '/');
p++;
} else {
if (filename[0] == '.' && filename[1] == '/') {
/* We have a relative pathname, compose the absolute pathname */
sprintf(fname, filename);
snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
if (res < 0)
return res;
p = strrchr(absolute_path, '/');
p++;
p++;
} else {
/* We have a relative pathname, compose the absolute pathname */
sprintf(fname, filename);
snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
if (res < 0)
return res;
p = strrchr(absolute_path, '/');
p++;
}
/* Copy to filename buffer */
while(filename[i] != NULL) {
*p = filename[i];
i++;
p++;
}
}
if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
return UV_ENOSYS;
/* Setup ahafs */
rc = uv__setup_ahafs((const char *)absolute_path, &fd);
if (rc != 0)
return rc;
/* Setup/Initialize all the libuv routines */
uv__handle_start(handle);
uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
handle->path = strdup((const char*)&absolute_path);
handle->cb = cb;
uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
return 0;
} }
int uv_fs_event_stop(uv_fs_event_t* handle) { int uv_fs_event_stop(uv_fs_event_t* handle) {
return -ENOSYS;
if (!uv__is_active(handle))
return 0;
uv__io_close(handle->loop, &handle->event_watcher);
uv__handle_stop(handle);
if (uv__path_is_a_directory(handle->path) == 0) {
free(handle->dir_filename);
handle->dir_filename = NULL;
}
free(handle->path);
handle->path = NULL;
uv__close(handle->event_watcher.fd);
handle->event_watcher.fd = -1;
return 0;
} }
void uv__fs_event_close(uv_fs_event_t* handle) { void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE(); uv_fs_event_stop(handle);
} }
@ -175,7 +991,7 @@ int uv_resident_set_memory(size_t* rss) {
int err; int err;
int fd; int fd;
(void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
fd = open(pp, O_RDONLY); fd = open(pp, O_RDONLY);
if (fd == -1) if (fd == -1)
@ -397,3 +1213,21 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
free(addresses); free(addresses);
} }
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct pollfd* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct pollfd*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].fd == fd)
events[i].fd = -1;
}

7
deps/uv/src/unix/core.c

@ -70,6 +70,10 @@
# endif # endif
#endif #endif
#ifdef _AIX
#include <sys/ioctl.h>
#endif
static void uv__run_pending(uv_loop_t* loop); static void uv__run_pending(uv_loop_t* loop);
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */ /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
@ -444,7 +448,8 @@ int uv__close(int fd) {
} }
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX)
int uv__nonblock(int fd, int set) { int uv__nonblock(int fd, int set) {
int r; int r;

30
deps/uv/src/unix/fs.c

@ -214,9 +214,23 @@ skip:
} }
static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
return mkdtemp((char*) req->path) ? 0 : -1;
}
static ssize_t uv__fs_read(uv_fs_t* req) { static ssize_t uv__fs_read(uv_fs_t* req) {
ssize_t result; ssize_t result;
#if defined(_AIX)
struct stat buf;
if(fstat(req->file, &buf))
return -1;
if(S_ISDIR(buf.st_mode)) {
errno = EISDIR;
return -1;
}
#endif /* defined(_AIX) */
if (req->off < 0) { if (req->off < 0) {
if (req->nbufs == 1) if (req->nbufs == 1)
result = read(req->file, req->bufs[0].base, req->bufs[0].len); result = read(req->file, req->bufs[0].base, req->bufs[0].len);
@ -683,7 +697,8 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec; dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
dst->st_flags = src->st_flags; dst->st_flags = src->st_flags;
dst->st_gen = src->st_gen; dst->st_gen = src->st_gen;
#elif defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) #elif !defined(_AIX) && \
(defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE))
dst->st_atim.tv_sec = src->st_atim.tv_sec; dst->st_atim.tv_sec = src->st_atim.tv_sec;
dst->st_atim.tv_nsec = src->st_atim.tv_nsec; dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
dst->st_mtim.tv_sec = src->st_mtim.tv_sec; dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
@ -779,6 +794,7 @@ static void uv__fs_work(struct uv__work* w) {
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
X(LINK, link(req->path, req->new_path)); X(LINK, link(req->path, req->new_path));
X(MKDIR, mkdir(req->path, req->mode)); X(MKDIR, mkdir(req->path, req->mode));
X(MKDTEMP, uv__fs_mkdtemp(req));
X(READ, uv__fs_read(req)); X(READ, uv__fs_read(req));
X(READDIR, uv__fs_readdir(req)); X(READDIR, uv__fs_readdir(req));
X(READLINK, uv__fs_readlink(req)); X(READLINK, uv__fs_readlink(req));
@ -991,6 +1007,18 @@ int uv_fs_mkdir(uv_loop_t* loop,
} }
int uv_fs_mkdtemp(uv_loop_t* loop,
uv_fs_t* req,
const char* tpl,
uv_fs_cb cb) {
INIT(MKDTEMP);
req->path = strdup(tpl);
if (req->path == NULL)
return -ENOMEM;
POST;
}
int uv_fs_open(uv_loop_t* loop, int uv_fs_open(uv_loop_t* loop,
uv_fs_t* req, uv_fs_t* req,
const char* path, const char* path,

15
deps/uv/src/unix/internal.h

@ -42,6 +42,12 @@
# include <port.h> # include <port.h>
#endif /* __sun */ #endif /* __sun */
#if defined(_AIX)
#define reqevents events
#define rtnevents revents
#include <sys/poll.h>
#endif /* _AIX */
#if defined(__APPLE__) && !TARGET_OS_IPHONE #if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <CoreServices/CoreServices.h> # include <CoreServices/CoreServices.h>
#endif #endif
@ -89,7 +95,7 @@
# define UV__POLLHUP UV__EPOLLHUP # define UV__POLLHUP UV__EPOLLHUP
#endif #endif
#if defined(__sun) #if defined(__sun) || defined(_AIX)
# define UV__POLLIN POLLIN # define UV__POLLIN POLLIN
# define UV__POLLOUT POLLOUT # define UV__POLLOUT POLLOUT
# define UV__POLLERR POLLERR # define UV__POLLERR POLLERR
@ -210,13 +216,6 @@ void uv__signal_close(uv_signal_t* handle);
void uv__signal_global_once_init(void); void uv__signal_global_once_init(void);
void uv__signal_loop_cleanup(uv_loop_t* loop); void uv__signal_loop_cleanup(uv_loop_t* loop);
/* thread pool */
void uv__work_submit(uv_loop_t* loop,
struct uv__work *w,
void (*work)(struct uv__work *w),
void (*done)(struct uv__work *w, int status));
void uv__work_done(uv_async_t* handle);
/* platform specific */ /* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type); uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop); int uv__kqueue_init(uv_loop_t* loop);

4
deps/uv/src/unix/loop.c

@ -89,8 +89,10 @@ uv_loop_t* uv_loop_new(void) {
void uv_loop_delete(uv_loop_t* loop) { void uv_loop_delete(uv_loop_t* loop) {
uv_loop_t* default_loop; uv_loop_t* default_loop;
int err;
default_loop = default_loop_ptr; default_loop = default_loop_ptr;
assert(uv_loop_close(loop) == 0); err = uv_loop_close(loop);
assert(err == 0);
if (loop != default_loop) if (loop != default_loop)
free(loop); free(loop);
} }

30
deps/uv/src/unix/openbsd.c

@ -180,29 +180,23 @@ int uv_get_process_title(char* buffer, size_t size) {
int uv_resident_set_memory(size_t* rss) { int uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL; struct kinfo_proc kinfo;
struct kinfo_proc *kinfo = NULL;
pid_t pid;
int nprocs, max_size = sizeof(struct kinfo_proc);
size_t page_size = getpagesize(); size_t page_size = getpagesize();
size_t size = sizeof(struct kinfo_proc);
int mib[6];
pid = getpid(); mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open"); mib[2] = KERN_PROC_PID;
if (kd == NULL) goto error; mib[3] = getpid();
mib[4] = sizeof(struct kinfo_proc);
kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, max_size, &nprocs); mib[5] = 1;
if (kinfo == NULL) goto error;
*rss = kinfo->p_vm_rssize * page_size;
kvm_close(kd); if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
return -errno;
*rss = kinfo.p_vm_rssize * page_size;
return 0; return 0;
error:
if (kd) kvm_close(kd);
return -EPERM;
} }

63
deps/uv/src/unix/stream.c

@ -60,21 +60,10 @@ static void uv__stream_connect(uv_stream_t*);
static void uv__write(uv_stream_t* stream); static void uv__write(uv_stream_t* stream);
static void uv__read(uv_stream_t* stream); static void uv__read(uv_stream_t* stream);
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
static void uv__write_callbacks(uv_stream_t* stream);
static size_t uv__write_req_size(uv_write_t* req); static size_t uv__write_req_size(uv_write_t* req);
static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
unsigned int i;
size_t bytes;
bytes = 0;
for (i = 0; i < nbufs; i++)
bytes += bufs[i].len;
return bytes;
}
void uv__stream_init(uv_loop_t* loop, void uv__stream_init(uv_loop_t* loop,
uv_stream_t* stream, uv_stream_t* stream,
uv_handle_type type) { uv_handle_type type) {
@ -390,33 +379,12 @@ void uv__stream_destroy(uv_stream_t* stream) {
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
req = QUEUE_DATA(q, uv_write_t, queue); req = QUEUE_DATA(q, uv_write_t, queue);
uv__req_unregister(stream->loop, req); req->error = -ECANCELED;
if (req->bufs != req->bufsml)
free(req->bufs);
req->bufs = NULL;
if (req->cb != NULL)
req->cb(req, -ECANCELED);
}
while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
q = QUEUE_HEAD(&stream->write_completed_queue);
QUEUE_REMOVE(q);
req = QUEUE_DATA(q, uv_write_t, queue);
uv__req_unregister(stream->loop, req);
if (req->bufs != NULL) { QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
stream->write_queue_size -= uv__write_req_size(req);
if (req->bufs != req->bufsml)
free(req->bufs);
req->bufs = NULL;
} }
if (req->cb) uv__write_callbacks(stream);
req->cb(req, req->error);
}
if (stream->shutdown_req) { if (stream->shutdown_req) {
/* The ECANCELED error code is a lie, the shutdown(2) syscall is a /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
@ -428,6 +396,8 @@ void uv__stream_destroy(uv_stream_t* stream) {
stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED);
stream->shutdown_req = NULL; stream->shutdown_req = NULL;
} }
assert(stream->write_queue_size == 0);
} }
@ -660,7 +630,7 @@ static size_t uv__write_req_size(uv_write_t* req) {
size_t size; size_t size;
assert(req->bufs != NULL); assert(req->bufs != NULL);
size = uv_count_bufs(req->bufs + req->write_index, size = uv__count_bufs(req->bufs + req->write_index,
req->nbufs - req->write_index); req->nbufs - req->write_index);
assert(req->handle->write_queue_size >= size); assert(req->handle->write_queue_size >= size);
@ -903,10 +873,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
} }
assert(QUEUE_EMPTY(&stream->write_completed_queue)); assert(QUEUE_EMPTY(&stream->write_completed_queue));
/* Write queue drained. */
if (QUEUE_EMPTY(&stream->write_queue))
uv__drain(stream);
} }
@ -1223,6 +1189,10 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) {
uv__write(stream); uv__write(stream);
uv__write_callbacks(stream); uv__write_callbacks(stream);
/* Write queue drained. */
if (QUEUE_EMPTY(&stream->write_queue))
uv__drain(stream);
} }
} }
@ -1327,7 +1297,7 @@ int uv_write2(uv_write_t* req,
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
req->nbufs = nbufs; req->nbufs = nbufs;
req->write_index = 0; req->write_index = 0;
stream->write_queue_size += uv_count_bufs(bufs, nbufs); stream->write_queue_size += uv__count_bufs(bufs, nbufs);
/* Append the request to write_queue. */ /* Append the request to write_queue. */
QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
@ -1386,7 +1356,7 @@ int uv_try_write(uv_stream_t* stream,
/* Connecting or already writing some data */ /* Connecting or already writing some data */
if (stream->connect_req != NULL || stream->write_queue_size != 0) if (stream->connect_req != NULL || stream->write_queue_size != 0)
return 0; return -EAGAIN;
has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT);
@ -1395,7 +1365,7 @@ int uv_try_write(uv_stream_t* stream,
return r; return r;
/* Remove not written bytes from write queue size */ /* Remove not written bytes from write queue size */
written = uv_count_bufs(bufs, nbufs); written = uv__count_bufs(bufs, nbufs);
if (req.bufs != NULL) if (req.bufs != NULL)
req_size = uv__write_req_size(&req); req_size = uv__write_req_size(&req);
else else
@ -1416,7 +1386,10 @@ int uv_try_write(uv_stream_t* stream,
uv__stream_osx_interrupt_select(stream); uv__stream_osx_interrupt_select(stream);
} }
return (int) written; if (written == 0)
return -EAGAIN;
else
return written;
} }

213
deps/uv/src/unix/udp.c

@ -38,10 +38,9 @@
static void uv__udp_run_completed(uv_udp_t* handle); static void uv__udp_run_completed(uv_udp_t* handle);
static void uv__udp_run_pending(uv_udp_t* handle);
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_recvmsg(uv_udp_t* handle);
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_sendmsg(uv_udp_t* handle);
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
int domain, int domain,
unsigned int flags); unsigned int flags);
@ -65,22 +64,19 @@ void uv__udp_finish_close(uv_udp_t* handle) {
assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
assert(handle->io_watcher.fd == -1); assert(handle->io_watcher.fd == -1);
uv__udp_run_completed(handle);
while (!QUEUE_EMPTY(&handle->write_queue)) { while (!QUEUE_EMPTY(&handle->write_queue)) {
q = QUEUE_HEAD(&handle->write_queue); q = QUEUE_HEAD(&handle->write_queue);
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
req = QUEUE_DATA(q, uv_udp_send_t, queue); req = QUEUE_DATA(q, uv_udp_send_t, queue);
uv__req_unregister(handle->loop, req); req->status = -ECANCELED;
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
}
if (req->bufs != req->bufsml) uv__udp_run_completed(handle);
free(req->bufs);
req->bufs = NULL;
if (req->send_cb != NULL) assert(handle->send_queue_size == 0);
req->send_cb(req, -ECANCELED); assert(handle->send_queue_count == 0);
}
/* Now tear down the handle. */ /* Now tear down the handle. */
handle->recv_cb = NULL; handle->recv_cb = NULL;
@ -89,50 +85,6 @@ void uv__udp_finish_close(uv_udp_t* handle) {
} }
static void uv__udp_run_pending(uv_udp_t* handle) {
uv_udp_send_t* req;
QUEUE* q;
struct msghdr h;
ssize_t size;
while (!QUEUE_EMPTY(&handle->write_queue)) {
q = QUEUE_HEAD(&handle->write_queue);
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
assert(req != NULL);
memset(&h, 0, sizeof h);
h.msg_name = &req->addr;
h.msg_namelen = (req->addr.sin6_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
h.msg_iov = (struct iovec*) req->bufs;
h.msg_iovlen = req->nbufs;
do {
size = sendmsg(handle->io_watcher.fd, &h, 0);
}
while (size == -1 && errno == EINTR);
/* TODO try to write once or twice more in the
* hope that the socket becomes readable again?
*/
if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
break;
req->status = (size == -1 ? -errno : size);
/* Sending a datagram is an atomic operation: either all data
* is written or nothing is (and EMSGSIZE is raised). That is
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
}
}
static void uv__udp_run_completed(uv_udp_t* handle) { static void uv__udp_run_completed(uv_udp_t* handle) {
uv_udp_send_t* req; uv_udp_send_t* req;
QUEUE* q; QUEUE* q;
@ -144,6 +96,9 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
req = QUEUE_DATA(q, uv_udp_send_t, queue); req = QUEUE_DATA(q, uv_udp_send_t, queue);
uv__req_unregister(handle->loop, req); uv__req_unregister(handle->loop, req);
handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
handle->send_queue_count--;
if (req->bufs != req->bufsml) if (req->bufs != req->bufsml)
free(req->bufs); free(req->bufs);
req->bufs = NULL; req->bufs = NULL;
@ -159,33 +114,40 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
else else
req->send_cb(req, req->status); req->send_cb(req, req->status);
} }
if (QUEUE_EMPTY(&handle->write_queue)) {
/* Pending queue and completion queue empty, stop watcher. */
uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT);
if (!uv__io_active(&handle->io_watcher, UV__POLLIN))
uv__handle_stop(handle);
}
} }
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
uv_udp_t* handle;
handle = container_of(w, uv_udp_t, io_watcher);
assert(handle->type == UV_UDP);
if (revents & UV__POLLIN) if (revents & UV__POLLIN)
uv__udp_recvmsg(loop, w, revents); uv__udp_recvmsg(handle);
if (revents & UV__POLLOUT) if (revents & UV__POLLOUT) {
uv__udp_sendmsg(loop, w, revents); uv__udp_sendmsg(handle);
uv__udp_run_completed(handle);
}
} }
static void uv__udp_recvmsg(uv_loop_t* loop, static void uv__udp_recvmsg(uv_udp_t* handle) {
uv__io_t* w,
unsigned int revents) {
struct sockaddr_storage peer; struct sockaddr_storage peer;
struct msghdr h; struct msghdr h;
uv_udp_t* handle;
ssize_t nread; ssize_t nread;
uv_buf_t buf; uv_buf_t buf;
int flags; int flags;
int count; int count;
handle = container_of(w, uv_udp_t, io_watcher);
assert(handle->type == UV_UDP);
assert(revents & UV__POLLIN);
assert(handle->recv_cb != NULL); assert(handle->recv_cb != NULL);
assert(handle->alloc_cb != NULL); assert(handle->alloc_cb != NULL);
@ -242,34 +204,43 @@ static void uv__udp_recvmsg(uv_loop_t* loop,
} }
static void uv__udp_sendmsg(uv_loop_t* loop, static void uv__udp_sendmsg(uv_udp_t* handle) {
uv__io_t* w, uv_udp_send_t* req;
unsigned int revents) { QUEUE* q;
uv_udp_t* handle; struct msghdr h;
ssize_t size;
handle = container_of(w, uv_udp_t, io_watcher); while (!QUEUE_EMPTY(&handle->write_queue)) {
assert(handle->type == UV_UDP); q = QUEUE_HEAD(&handle->write_queue);
assert(revents & UV__POLLOUT); assert(q != NULL);
assert(!QUEUE_EMPTY(&handle->write_queue) req = QUEUE_DATA(q, uv_udp_send_t, queue);
|| !QUEUE_EMPTY(&handle->write_completed_queue)); assert(req != NULL);
/* Write out pending data first. */ memset(&h, 0, sizeof h);
uv__udp_run_pending(handle); h.msg_name = &req->addr;
h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
h.msg_iov = (struct iovec*) req->bufs;
h.msg_iovlen = req->nbufs;
/* Drain 'request completed' queue. */ do {
uv__udp_run_completed(handle); size = sendmsg(handle->io_watcher.fd, &h, 0);
} while (size == -1 && errno == EINTR);
if (!QUEUE_EMPTY(&handle->write_completed_queue)) { if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
/* Schedule completion callbacks. */ break;
uv__io_feed(handle->loop, &handle->io_watcher);
}
else if (QUEUE_EMPTY(&handle->write_queue)) {
/* Pending queue and completion queue empty, stop watcher. */
uv__io_stop(loop, &handle->io_watcher, UV__POLLOUT);
if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) req->status = (size == -1 ? -errno : size);
uv__handle_stop(handle);
/* Sending a datagram is an atomic operation: either all data
* is written or nothing is (and EMSGSIZE is raised). That is
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
uv__io_feed(handle->loop, &handle->io_watcher);
} }
} }
@ -410,6 +381,7 @@ int uv__udp_send(uv_udp_send_t* req,
unsigned int addrlen, unsigned int addrlen,
uv_udp_send_cb send_cb) { uv_udp_send_cb send_cb) {
int err; int err;
int empty_queue;
assert(nbufs > 0); assert(nbufs > 0);
@ -417,8 +389,13 @@ int uv__udp_send(uv_udp_send_t* req,
if (err) if (err)
return err; return err;
uv__req_init(handle->loop, req, UV_UDP_SEND); /* It's legal for send_queue_count > 0 even when the write_queue is empty;
* it means there are error-state requests in the write_completed_queue that
* will touch up send_queue_size/count later.
*/
empty_queue = (handle->send_queue_count == 0);
uv__req_init(handle->loop, req, UV_UDP_SEND);
assert(addrlen <= sizeof(req->addr)); assert(addrlen <= sizeof(req->addr));
memcpy(&req->addr, addr, addrlen); memcpy(&req->addr, addr, addrlen);
req->send_cb = send_cb; req->send_cb = send_cb;
@ -433,14 +410,60 @@ int uv__udp_send(uv_udp_send_t* req,
return -ENOMEM; return -ENOMEM;
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
handle->send_queue_count++;
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
uv__handle_start(handle); uv__handle_start(handle);
if (empty_queue)
uv__udp_sendmsg(handle);
else
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
return 0; return 0;
} }
int uv__udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen) {
int err;
struct msghdr h;
ssize_t size;
assert(nbufs > 0);
/* already sending a message */
if (handle->send_queue_count != 0)
return -EAGAIN;
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
if (err)
return err;
memset(&h, 0, sizeof h);
h.msg_name = (struct sockaddr*) addr;
h.msg_namelen = addrlen;
h.msg_iov = (struct iovec*) bufs;
h.msg_iovlen = nbufs;
do {
size = sendmsg(handle->io_watcher.fd, &h, 0);
} while (size == -1 && errno == EINTR);
if (size == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return -EAGAIN;
else
return -errno;
}
return size;
}
static int uv__udp_set_membership4(uv_udp_t* handle, static int uv__udp_set_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr, const struct sockaddr_in* multicast_addr,
const char* interface_addr, const char* interface_addr,
@ -531,6 +554,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
handle->alloc_cb = NULL; handle->alloc_cb = NULL;
handle->recv_cb = NULL; handle->recv_cb = NULL;
handle->send_queue_size = 0;
handle->send_queue_count = 0;
uv__io_init(&handle->io_watcher, uv__udp_io, -1); uv__io_init(&handle->io_watcher, uv__udp_io, -1);
QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_queue);
QUEUE_INIT(&handle->write_completed_queue); QUEUE_INIT(&handle->write_completed_queue);
@ -579,7 +604,7 @@ int uv_udp_set_membership(uv_udp_t* handle,
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) {
#if defined(__sun) #if defined(__sun) || defined(_AIX)
char arg = val; char arg = val;
#else #else
int arg = val; int arg = val;
@ -678,7 +703,9 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
} }
int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { int uv_udp_getsockname(const uv_udp_t* handle,
struct sockaddr* name,
int* namelen) {
socklen_t socklen; socklen_t socklen;
if (handle->io_watcher.fd == -1) if (handle->io_watcher.fd == -1)

33
deps/uv/src/uv-common.c

@ -233,6 +233,26 @@ int uv_udp_send(uv_udp_send_t* req,
} }
int uv_udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr) {
unsigned int addrlen;
if (handle->type != UV_UDP)
return UV_EINVAL;
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
else
return UV_EINVAL;
return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
}
int uv_udp_recv_start(uv_udp_t* handle, int uv_udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb, uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb) { uv_udp_recv_cb recv_cb) {
@ -446,6 +466,19 @@ int uv__getaddrinfo_translate_error(int sys_err) {
return 0; /* Pacify compiler. */ return 0; /* Pacify compiler. */
} }
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
unsigned int i;
size_t bytes;
bytes = 0;
for (i = 0; i < nbufs; i++)
bytes += (size_t) bufs[i].len;
return bytes;
}
int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) { int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) {
size_t required_len; size_t required_len;

15
deps/uv/src/uv-common.h

@ -83,6 +83,12 @@ int uv__udp_send(uv_udp_send_t* req,
unsigned int addrlen, unsigned int addrlen,
uv_udp_send_cb send_cb); uv_udp_send_cb send_cb);
int uv__udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen);
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
uv_udp_recv_cb recv_cb); uv_udp_recv_cb recv_cb);
@ -92,6 +98,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
void uv__work_submit(uv_loop_t* loop,
struct uv__work *w,
void (*work)(struct uv__work *w),
void (*done)(struct uv__work *w, int status));
void uv__work_done(uv_async_t* handle);
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
#define uv__has_active_reqs(loop) \ #define uv__has_active_reqs(loop) \
(QUEUE_EMPTY(&(loop)->active_reqs) == 0) (QUEUE_EMPTY(&(loop)->active_reqs) == 0)

159
deps/uv/src/win/core.c

@ -26,7 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if !defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
#include <crtdbg.h> #include <crtdbg.h>
#endif #endif
@ -44,19 +44,21 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT; static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
#if defined(_DEBUG) && !defined(__MINGW32__) #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
/* Our crt debug report handler allows us to temporarily disable asserts */ /* Our crt debug report handler allows us to temporarily disable asserts
/* just for the current thread. */ * just for the current thread.
*/
__declspec( thread ) int uv__crt_assert_enabled = TRUE; UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) { static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT) if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
return FALSE; return FALSE;
if (ret_val) { if (ret_val) {
/* Set ret_val to 0 to continue with normal execution. */ /* Set ret_val to 0 to continue with normal execution.
/* Set ret_val to 1 to trigger a breakpoint. */ * Set ret_val to 1 to trigger a breakpoint.
*/
if(IsDebuggerPresent()) if(IsDebuggerPresent())
*ret_val = 1; *ret_val = 1;
@ -67,6 +69,8 @@ static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_v
/* Don't call _CrtDbgReport. */ /* Don't call _CrtDbgReport. */
return TRUE; return TRUE;
} }
#else
UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
#endif #endif
@ -84,21 +88,24 @@ static void uv_init(void) {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX); SEM_NOOPENFILEERRORBOX);
/* Tell the CRT to not exit the application when an invalid parameter is */ /* Tell the CRT to not exit the application when an invalid parameter is
/* passed. The main issue is that invalid FDs will trigger this behavior. */ * passed. The main issue is that invalid FDs will trigger this behavior.
*/
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
#endif #endif
/* We also need to setup our debug report handler because some CRT */ /* We also need to setup our debug report handler because some CRT
/* functions (eg _get_osfhandle) raise an assert when called with invalid */ * functions (eg _get_osfhandle) raise an assert when called with invalid
/* FDs even though they return the proper error code in the release build. */ * FDs even though they return the proper error code in the release build.
#if defined(_DEBUG) && !defined(__MINGW32__) */
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
_CrtSetReportHook(uv__crt_dbg_report_handler); _CrtSetReportHook(uv__crt_dbg_report_handler);
#endif #endif
/* Fetch winapi function pointers. This must be done first because other */ /* Fetch winapi function pointers. This must be done first because other
/* intialization code might need these function pointers to be loaded. */ * intialization code might need these function pointers to be loaded.
*/
uv_winapi_init(); uv_winapi_init();
/* Initialize winsock */ /* Initialize winsock */
@ -127,12 +134,14 @@ int uv_loop_init(uv_loop_t* loop) {
if (loop->iocp == NULL) if (loop->iocp == NULL)
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
/* To prevent uninitialized memory access, loop->time must be intialized */ /* To prevent uninitialized memory access, loop->time must be intialized
/* to zero before calling uv_update_time for the first time. */ * to zero before calling uv_update_time for the first time.
*/
loop->time = 0; loop->time = 0;
loop->last_tick_count = 0; loop->last_tick_count = 0;
uv_update_time(loop); uv_update_time(loop);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue); QUEUE_INIT(&loop->handle_queue);
QUEUE_INIT(&loop->active_reqs); QUEUE_INIT(&loop->active_reqs);
loop->active_handles = 0; loop->active_handles = 0;
@ -159,6 +168,15 @@ int uv_loop_init(uv_loop_t* loop) {
loop->timer_counter = 0; loop->timer_counter = 0;
loop->stop_flag = 0; loop->stop_flag = 0;
if (uv_mutex_init(&loop->wq_mutex))
abort();
if (uv_async_init(loop, &loop->wq_async, uv__work_done))
abort();
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
return 0; return 0;
} }
@ -183,6 +201,31 @@ uv_loop_t* uv_default_loop(void) {
} }
static void uv__loop_close(uv_loop_t* loop) {
/* close the async handle without needeing an extra loop iteration */
assert(!loop->wq_async.async_sent);
loop->wq_async.close_cb = NULL;
uv__handle_closing(&loop->wq_async);
uv__handle_close(&loop->wq_async);
if (loop != &uv_default_loop_) {
size_t i;
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i];
if (sock != 0 && sock != INVALID_SOCKET)
closesocket(sock);
}
}
/* TODO: cleanup default loop*/
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
}
int uv_loop_close(uv_loop_t* loop) { int uv_loop_close(uv_loop_t* loop) {
QUEUE* q; QUEUE* q;
uv_handle_t* h; uv_handle_t* h;
@ -193,15 +236,13 @@ int uv_loop_close(uv_loop_t* loop) {
if (!(h->flags & UV__HANDLE_INTERNAL)) if (!(h->flags & UV__HANDLE_INTERNAL))
return UV_EBUSY; return UV_EBUSY;
} }
if (loop != &uv_default_loop_) {
size_t i; uv__loop_close(loop);
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i]; #ifndef NDEBUG
if (sock != 0 && sock != INVALID_SOCKET) memset(loop, -1, sizeof(*loop));
closesocket(sock); #endif
}
}
/* TODO: cleanup default loop*/
return 0; return 0;
} }
@ -224,7 +265,8 @@ uv_loop_t* uv_loop_new(void) {
void uv_loop_delete(uv_loop_t* loop) { void uv_loop_delete(uv_loop_t* loop) {
assert(uv_loop_close(loop) == 0); int err = uv_loop_close(loop);
assert(err == 0);
if (loop != &uv_default_loop_) if (loop != &uv_default_loop_)
free(loop); free(loop);
} }
@ -236,22 +278,31 @@ int uv_backend_fd(const uv_loop_t* loop) {
int uv_backend_timeout(const uv_loop_t* loop) { int uv_backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag != 0)
return 0;
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
if (loop->pending_reqs_tail)
return 0;
if (loop->endgame_handles)
return 0;
if (loop->idle_handles)
return 0; return 0;
return uv__next_timeout(loop);
} }
static void uv_poll(uv_loop_t* loop, int block) { static void uv_poll(uv_loop_t* loop, DWORD timeout) {
DWORD bytes, timeout; DWORD bytes;
ULONG_PTR key; ULONG_PTR key;
OVERLAPPED* overlapped; OVERLAPPED* overlapped;
uv_req_t* req; uv_req_t* req;
if (block) {
timeout = uv_get_poll_timeout(loop);
} else {
timeout = 0;
}
GetQueuedCompletionStatus(loop->iocp, GetQueuedCompletionStatus(loop->iocp,
&bytes, &bytes,
&key, &key,
@ -266,28 +317,22 @@ static void uv_poll(uv_loop_t* loop, int block) {
/* Serious error */ /* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else { } else {
/* We're sure that at least `timeout` milliseconds have expired, but */ /* We're sure that at least `timeout` milliseconds have expired, but
/* this may not be reflected yet in the GetTickCount() return value. */ * this may not be reflected yet in the GetTickCount() return value.
/* Therefore we ensure it's taken into account here. */ * Therefore we ensure it's taken into account here.
*/
uv__time_forward(loop, timeout); uv__time_forward(loop, timeout);
} }
} }
static void uv_poll_ex(uv_loop_t* loop, int block) { static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
BOOL success; BOOL success;
DWORD timeout;
uv_req_t* req; uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128]; OVERLAPPED_ENTRY overlappeds[128];
ULONG count; ULONG count;
ULONG i; ULONG i;
if (block) {
timeout = uv_get_poll_timeout(loop);
} else {
timeout = 0;
}
success = pGetQueuedCompletionStatusEx(loop->iocp, success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds, overlappeds,
ARRAY_SIZE(overlappeds), ARRAY_SIZE(overlappeds),
@ -305,9 +350,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
/* Serious error */ /* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) { } else if (timeout > 0) {
/* We're sure that at least `timeout` milliseconds have expired, but */ /* We're sure that at least `timeout` milliseconds have expired, but
/* this may not be reflected yet in the GetTickCount() return value. */ * this may not be reflected yet in the GetTickCount() return value.
/* Therefore we ensure it's taken into account here. */ * Therefore we ensure it's taken into account here.
*/
uv__time_forward(loop, timeout); uv__time_forward(loop, timeout);
} }
} }
@ -326,8 +372,9 @@ int uv_loop_alive(const uv_loop_t* loop) {
int uv_run(uv_loop_t *loop, uv_run_mode mode) { int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r; int r;
void (*poll)(uv_loop_t* loop, int block); void (*poll)(uv_loop_t* loop, DWORD timeout);
if (pGetQueuedCompletionStatusEx) if (pGetQueuedCompletionStatusEx)
poll = &uv_poll_ex; poll = &uv_poll_ex;
@ -346,13 +393,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv_idle_invoke(loop); uv_idle_invoke(loop);
uv_prepare_invoke(loop); uv_prepare_invoke(loop);
(*poll)(loop, loop->idle_handles == NULL && timeout = 0;
loop->pending_reqs_tail == NULL && if ((mode & UV_RUN_NOWAIT) == 0)
loop->endgame_handles == NULL && timeout = uv_backend_timeout(loop);
!loop->stop_flag &&
(loop->active_handles > 0 || (*poll)(loop, timeout);
!QUEUE_EMPTY(&loop->active_reqs)) &&
!(mode & UV_RUN_NOWAIT));
uv_check_invoke(loop); uv_check_invoke(loop);
uv_process_endgames(loop); uv_process_endgames(loop);

1
deps/uv/src/win/error.c

@ -133,6 +133,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_DIRECTORY: return UV_ENOENT; case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT;
case ERROR_INVALID_DRIVE: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT; case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT; case ERROR_PATH_NOT_FOUND: return UV_ENOENT;

175
deps/uv/src/win/fs.c

@ -44,12 +44,8 @@
#define QUEUE_FS_TP_JOB(loop, req) \ #define QUEUE_FS_TP_JOB(loop, req) \
do { \ do { \
if (!QueueUserWorkItem(&uv_fs_thread_proc, \
req, \
WT_EXECUTEDEFAULT)) { \
return uv_translate_sys_error(GetLastError()); \
} \
uv__req_register(loop, req); \ uv__req_register(loop, req); \
uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
} while (0) } while (0)
#define SET_REQ_RESULT(req, result_value) \ #define SET_REQ_RESULT(req, result_value) \
@ -232,11 +228,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
req->result = 0; req->result = 0;
req->ptr = NULL; req->ptr = NULL;
req->path = NULL; req->path = NULL;
if (cb != NULL) {
req->cb = cb; req->cb = cb;
memset(&req->overlapped, 0, sizeof(req->overlapped));
}
} }
@ -729,6 +721,78 @@ void fs__mkdir(uv_fs_t* req) {
} }
/* Some parts of the implementation were borrowed from glibc. */
void fs__mkdtemp(uv_fs_t* req) {
static const WCHAR letters[] =
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
size_t len;
WCHAR* template_part;
static uint64_t value;
unsigned int count;
int fd;
/* A lower bound on the number of temporary files to attempt to
generate. The maximum total number of temporary file names that
can exist for a given template is 62**6. It should never be
necessary to try all these combinations. Instead if a reasonable
number of names is tried (we define reasonable as 62**3) fail to
give the system administrator the chance to remove the problems. */
#define ATTEMPTS_MIN (62 * 62 * 62)
/* The number of times to attempt to generate a temporary file. To
conform to POSIX, this must be no smaller than TMP_MAX. */
#if ATTEMPTS_MIN < TMP_MAX
unsigned int attempts = TMP_MAX;
#else
unsigned int attempts = ATTEMPTS_MIN;
#endif
len = wcslen(req->pathw);
if (len < 6 || wcsncmp(&req->pathw[len - 6], L"XXXXXX", 6)) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return;
}
/* This is where the Xs start. */
template_part = &req->pathw[len - 6];
/* Get some random data. */
value += uv_hrtime() ^ _getpid();
for (count = 0; count < attempts; value += 7777, ++count) {
uint64_t v = value;
/* Fill in the random bits. */
template_part[0] = letters[v % 62];
v /= 62;
template_part[1] = letters[v % 62];
v /= 62;
template_part[2] = letters[v % 62];
v /= 62;
template_part[3] = letters[v % 62];
v /= 62;
template_part[4] = letters[v % 62];
v /= 62;
template_part[5] = letters[v % 62];
fd = _wmkdir(req->pathw);
if (fd >= 0) {
len = strlen(req->path);
wcstombs((char*) req->path + len - 6, template_part, 6);
SET_REQ_RESULT(req, 0);
return;
} else if (errno != EEXIST) {
SET_REQ_RESULT(req, -1);
return;
}
}
/* We got out of the loop because we ran out of combinations to try. */
SET_REQ_RESULT(req, -1);
}
void fs__readdir(uv_fs_t* req) { void fs__readdir(uv_fs_t* req) {
WCHAR* pathw = req->pathw; WCHAR* pathw = req->pathw;
size_t len = wcslen(pathw); size_t len = wcslen(pathw);
@ -1401,7 +1465,7 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
/* Open the directory */ /* Open the directory */
handle = CreateFileW(new_path, handle = CreateFileW(new_path,
GENERIC_ALL, GENERIC_WRITE,
0, 0,
NULL, NULL,
OPEN_EXISTING, OPEN_EXISTING,
@ -1510,11 +1574,10 @@ static void fs__fchown(uv_fs_t* req) {
} }
static DWORD WINAPI uv_fs_thread_proc(void* parameter) { static void uv__fs_work(struct uv__work* w) {
uv_fs_t* req = (uv_fs_t*) parameter; uv_fs_t* req;
uv_loop_t* loop = req->loop;
assert(req != NULL); req = container_of(w, uv_fs_t, work_req);
assert(req->type == UV_FS); assert(req->type == UV_FS);
#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break; #define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
@ -1537,6 +1600,7 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
XX(UNLINK, unlink) XX(UNLINK, unlink)
XX(RMDIR, rmdir) XX(RMDIR, rmdir)
XX(MKDIR, mkdir) XX(MKDIR, mkdir)
XX(MKDTEMP, mkdtemp)
XX(RENAME, rename) XX(RENAME, rename)
XX(READDIR, readdir) XX(READDIR, readdir)
XX(LINK, link) XX(LINK, link)
@ -1547,9 +1611,41 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
default: default:
assert(!"bad uv_fs_type"); assert(!"bad uv_fs_type");
} }
}
POST_COMPLETION_FOR_REQ(loop, req);
return 0; static void uv__fs_done(struct uv__work* w, int status) {
uv_fs_t* req;
req = container_of(w, uv_fs_t, work_req);
uv__req_unregister(req->loop, req);
if (status == UV_ECANCELED) {
assert(req->result == 0);
req->result = UV_ECANCELED;
}
if (req->cb != NULL)
req->cb(req);
}
void uv_fs_req_cleanup(uv_fs_t* req) {
if (req->flags & UV_FS_CLEANEDUP)
return;
if (req->flags & UV_FS_FREE_PATHS)
free(req->pathw);
if (req->flags & UV_FS_FREE_PTR)
free(req->ptr);
req->path = NULL;
req->pathw = NULL;
req->new_pathw = NULL;
req->ptr = NULL;
req->flags |= UV_FS_CLEANEDUP;
} }
@ -1701,6 +1797,26 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
} }
int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
uv_fs_cb cb) {
int err;
uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
err = fs__capture_path(loop, req, tpl, NULL, TRUE);
if (err)
return uv_translate_sys_error(err);
if (cb) {
QUEUE_FS_TP_JOB(loop, req);
return 0;
} else {
fs__mkdtemp(req);
return req->result;
}
}
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err; int err;
@ -2064,30 +2180,3 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
return req->result; return req->result;
} }
} }
void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
assert(req->cb);
uv__req_unregister(loop, req);
req->cb(req);
}
void uv_fs_req_cleanup(uv_fs_t* req) {
if (req->flags & UV_FS_CLEANEDUP)
return;
if (req->flags & UV_FS_FREE_PATHS)
free(req->pathw);
if (req->flags & UV_FS_FREE_PTR)
free(req->ptr);
req->path = NULL;
req->pathw = NULL;
req->new_pathw = NULL;
req->ptr = NULL;
req->flags |= UV_FS_CLEANEDUP;
}

63
deps/uv/src/win/getaddrinfo.c

@ -56,25 +56,13 @@
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
/* getaddrinfo worker thread implementation */ static void uv__getaddrinfo_work(struct uv__work* w) {
static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { uv_getaddrinfo_t* req;
uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; int err;
uv_loop_t* loop = req->loop;
int ret;
assert(req != NULL);
/* call OS function on this thread */
ret = GetAddrInfoW(req->node,
req->service,
req->hints,
&req->res);
req->retcode = ret;
/* post getaddrinfo completed */
POST_COMPLETION_FOR_REQ(loop, req);
return 0; req = container_of(w, uv_getaddrinfo_t, work_req);
err = GetAddrInfoW(req->node, req->service, req->hints, &req->res);
req->retcode = uv__getaddrinfo_translate_error(err);
} }
@ -87,7 +75,8 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
* and copy all structs and referenced strings into the one block. * and copy all structs and referenced strings into the one block.
* Each size calculation is adjusted to avoid unaligned pointers. * Each size calculation is adjusted to avoid unaligned pointers.
*/ */
void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
int addrinfo_len = 0; int addrinfo_len = 0;
int name_len = 0; int name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
@ -95,7 +84,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
struct addrinfo* addrinfo_ptr; struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL; char* alloc_ptr = NULL;
char* cur_ptr = NULL; char* cur_ptr = NULL;
int err = 0;
req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */ /* release input parameter memory */
if (req->alloc != NULL) { if (req->alloc != NULL) {
@ -103,6 +93,16 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
req->alloc = NULL; req->alloc = NULL;
} }
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
if (req->res != NULL) {
FreeAddrInfoW(req->res);
req->res = NULL;
}
goto complete;
}
if (req->retcode == 0) { if (req->retcode == 0) {
/* convert addrinfoW to addrinfo */ /* convert addrinfoW to addrinfo */
/* first calculate required length */ /* first calculate required length */
@ -113,7 +113,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
if (addrinfow_ptr->ai_canonname != NULL) { if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
if (name_len == 0) { if (name_len == 0) {
err = uv_translate_sys_error(GetLastError()); req->retcode = uv_translate_sys_error(GetLastError());
goto complete; goto complete;
} }
addrinfo_len += ALIGNED_SIZE(name_len); addrinfo_len += ALIGNED_SIZE(name_len);
@ -178,11 +178,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
} }
} }
} else { } else {
err = UV_EAI_MEMORY; req->retcode = UV_EAI_MEMORY;
} }
} else {
/* GetAddrInfo failed */
err = uv__getaddrinfo_translate_error(req->retcode);
} }
/* return memory to system */ /* return memory to system */
@ -192,10 +189,10 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
} }
complete: complete:
uv__req_unregister(loop, req); uv__req_unregister(req->loop, req);
/* finally do callback with converted result */ /* finally do callback with converted result */
req->getaddrinfo_cb(req, err, (struct addrinfo*)alloc_ptr); req->getaddrinfo_cb(req, req->retcode, (struct addrinfo*)alloc_ptr);
} }
@ -246,6 +243,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->res = NULL; req->res = NULL;
req->type = UV_GETADDRINFO; req->type = UV_GETADDRINFO;
req->loop = loop; req->loop = loop;
req->retcode = 0;
/* calculate required memory size for all input values */ /* calculate required memory size for all input values */
if (node != NULL) { if (node != NULL) {
@ -323,13 +321,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->hints = NULL; req->hints = NULL;
} }
/* Ask thread to run. Treat this as a long operation */ uv__work_submit(loop,
if (QueueUserWorkItem(&getaddrinfo_thread_proc, &req->work_req,
req, uv__getaddrinfo_work,
WT_EXECUTELONGFUNCTION) == 0) { uv__getaddrinfo_done);
err = GetLastError();
goto error;
}
uv__req_register(loop, req); uv__req_register(loop, req);

61
deps/uv/src/win/getnameinfo.c

@ -27,23 +27,31 @@
#include "internal.h" #include "internal.h"
#include "req-inl.h" #include "req-inl.h"
#ifndef GetNameInfo
/* getnameinfo worker thread implementation */ int WSAAPI GetNameInfoW(
static DWORD WINAPI getnameinfo_thread_proc(void* parameter) { const SOCKADDR *pSockaddr,
uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter; socklen_t SockaddrLength,
uv_loop_t* loop = req->loop; PWCHAR pNodeBuffer,
DWORD NodeBufferSize,
PWCHAR pServiceBuffer,
DWORD ServiceBufferSize,
INT Flags
);
#endif
static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
WCHAR host[NI_MAXHOST]; WCHAR host[NI_MAXHOST];
WCHAR service[NI_MAXSERV]; WCHAR service[NI_MAXSERV];
int ret = 0; int ret = 0;
assert(req != NULL); req = container_of(w, uv_getnameinfo_t, work_req);
ret = GetNameInfoW((struct sockaddr*)&req->storage, ret = GetNameInfoW((struct sockaddr*)&req->storage,
sizeof(req->storage), sizeof(req->storage),
host, host,
sizeof(host), ARRAY_SIZE(host),
service, service,
sizeof(service), ARRAY_SIZE(service),
req->flags); req->flags);
req->retcode = uv__getaddrinfo_translate_error(ret); req->retcode = uv__getaddrinfo_translate_error(ret);
@ -65,30 +73,29 @@ static DWORD WINAPI getnameinfo_thread_proc(void* parameter) {
sizeof(req->service), sizeof(req->service),
NULL, NULL,
NULL); NULL);
/* post getnameinfo completed */
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
} }
/* /*
* Called from uv_run when complete. * Called from uv_run when complete.
*/ */
void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req) { static void uv__getnameinfo_done(struct uv__work* w, int status) {
uv_getnameinfo_t* req;
char* host; char* host;
char* service; char* service;
if (req->retcode == 0) { req = container_of(w, uv_getnameinfo_t, work_req);
uv__req_unregister(req->loop, req);
host = service = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host; host = req->host;
service = req->service; service = req->service;
} else {
host = NULL;
service = NULL;
} }
uv__req_unregister(loop, req);
req->getnameinfo_cb(req, req->retcode, host, service); req->getnameinfo_cb(req, req->retcode, host, service);
} }
@ -119,20 +126,18 @@ int uv_getnameinfo(uv_loop_t* loop,
} }
uv_req_init(loop, (uv_req_t*)req); uv_req_init(loop, (uv_req_t*)req);
uv__req_register(loop, req);
req->getnameinfo_cb = getnameinfo_cb; req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags; req->flags = flags;
req->type = UV_GETNAMEINFO; req->type = UV_GETNAMEINFO;
req->loop = loop; req->loop = loop;
req->retcode = 0;
/* Ask thread to run. Treat this as a long operation. */ uv__work_submit(loop,
if (QueueUserWorkItem(&getnameinfo_thread_proc, &req->work_req,
req, uv__getnameinfo_work,
WT_EXECUTELONGFUNCTION) == 0) { uv__getnameinfo_done);
return uv_translate_sys_error(GetLastError());
}
uv__req_register(loop, req);
return 0; return 0;
} }

35
deps/uv/src/win/internal.h

@ -31,13 +31,16 @@
#ifdef _MSC_VER #ifdef _MSC_VER
# define INLINE __inline # define INLINE __inline
# define UV_THREAD_LOCAL __declspec( thread )
#else #else
# define INLINE inline # define INLINE inline
# define UV_THREAD_LOCAL __thread
#endif #endif
#ifdef _DEBUG #ifdef _DEBUG
extern __declspec( thread ) int uv__crt_assert_enabled;
extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
#define UV_BEGIN_DISABLE_CRT_ASSERT() \ #define UV_BEGIN_DISABLE_CRT_ASSERT() \
{ \ { \
@ -72,7 +75,6 @@ extern __declspec( thread ) int uv__crt_assert_enabled;
/* Used by streams and UDP handles. */ /* Used by streams and UDP handles. */
#define UV_HANDLE_READING 0x00000100 #define UV_HANDLE_READING 0x00000100
#define UV_HANDLE_BOUND 0x00000200 #define UV_HANDLE_BOUND 0x00000200
#define UV_HANDLE_BIND_ERROR 0x00000400
#define UV_HANDLE_LISTENING 0x00000800 #define UV_HANDLE_LISTENING 0x00000800
#define UV_HANDLE_CONNECTION 0x00001000 #define UV_HANDLE_CONNECTION 0x00001000
#define UV_HANDLE_CONNECTED 0x00002000 #define UV_HANDLE_CONNECTED 0x00002000
@ -122,6 +124,12 @@ extern __declspec( thread ) int uv__crt_assert_enabled;
/* /*
* TCP * TCP
*/ */
typedef struct {
WSAPROTOCOL_INFOW socket_info;
int delayed_error;
} uv__ipc_socket_info_ex;
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
@ -140,7 +148,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection); int tcp_connection);
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
@ -231,7 +239,7 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
*/ */
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
DWORD uv_get_poll_timeout(uv_loop_t* loop); DWORD uv__next_timeout(const uv_loop_t* loop);
void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv__time_forward(uv_loop_t* loop, uint64_t msecs);
void uv_process_timers(uv_loop_t* loop); void uv_process_timers(uv_loop_t* loop);
@ -285,29 +293,10 @@ void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
int uv_translate_sys_error(int sys_errno); int uv_translate_sys_error(int sys_errno);
/*
* Getaddrinfo
*/
void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req);
/*
* Getnameinfo
*/
void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req);
/* /*
* FS * FS
*/ */
void uv_fs_init(); void uv_fs_init();
void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req);
/*
* Threadpool
*/
void uv_process_work_req(uv_loop_t* loop, uv_work_t* req);
/* /*

64
deps/uv/src/win/pipe.c

@ -35,10 +35,10 @@ typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
struct uv__ipc_queue_item_s { struct uv__ipc_queue_item_s {
/* /*
* NOTE: It is important for socket_info to be the first field, * NOTE: It is important for socket_info_ex to be the first field,
* because we will we assigning it to the pending_ipc_info.socket_info * because we will we assigning it to the pending_ipc_info.socket_info
*/ */
WSAPROTOCOL_INFOW socket_info; uv__ipc_socket_info_ex socket_info_ex;
QUEUE member; QUEUE member;
int tcp_connection; int tcp_connection;
}; };
@ -73,7 +73,7 @@ typedef struct {
/* IPC frame, which contains an imported TCP socket stream. */ /* IPC frame, which contains an imported TCP socket stream. */
typedef struct { typedef struct {
uv_ipc_frame_header_t header; uv_ipc_frame_header_t header;
WSAPROTOCOL_INFOW socket_info; uv__ipc_socket_info_ex socket_info_ex;
} uv_ipc_frame_uv_stream; } uv_ipc_frame_uv_stream;
static void eof_timer_init(uv_pipe_t* pipe); static void eof_timer_init(uv_pipe_t* pipe);
@ -230,7 +230,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
NTSTATUS nt_status; NTSTATUS nt_status;
IO_STATUS_BLOCK io_status; IO_STATUS_BLOCK io_status;
FILE_MODE_INFORMATION mode_info; FILE_MODE_INFORMATION mode_info;
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
DWORD current_mode = 0; DWORD current_mode = 0;
DWORD err = 0; DWORD err = 0;
@ -246,11 +246,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL, if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
NULL, NULL, 0)) { NULL, NULL, 0)) {
return -1; return -1;
} else if (current_mode != mode) { } else if (current_mode & PIPE_NOWAIT) {
SetLastError(ERROR_ACCESS_DENIED); SetLastError(ERROR_ACCESS_DENIED);
return -1; return -1;
} else {
duplex_flags &= ~UV_HANDLE_WRITABLE;
} }
} else { } else {
/* If this returns ERROR_INVALID_PARAMETER we probably opened /* If this returns ERROR_INVALID_PARAMETER we probably opened
@ -410,7 +408,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
socket = WSASocketW(FROM_PROTOCOL_INFO, socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
&item->socket_info, &item->socket_info_ex.socket_info,
0, 0,
WSA_FLAG_OVERLAPPED); WSA_FLAG_OVERLAPPED);
free(item); free(item);
@ -789,7 +787,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
err = uv_tcp_import((uv_tcp_t*)client, err = uv_tcp_import((uv_tcp_t*)client,
&item->socket_info, &item->socket_info_ex,
item->tcp_connection); item->tcp_connection);
if (err != 0) if (err != 0)
return err; return err;
@ -1134,10 +1132,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
tcp_send_handle = (uv_tcp_t*)send_handle; tcp_send_handle = (uv_tcp_t*)send_handle;
err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid, err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
&ipc_frame.socket_info); &ipc_frame.socket_info_ex.socket_info);
if (err) { if (err) {
return err; return err;
} }
ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
ipc_frame.header.flags |= UV_IPC_TCP_SERVER; ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
@ -1254,7 +1255,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
} }
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, nbufs); req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->write_queue_size += req->queued_bytes; handle->write_queue_size += req->queued_bytes;
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
/* Using overlapped IO, but wait for completion before returning */ /* Using overlapped IO, but wait for completion before returning */
@ -1311,7 +1312,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
req->queued_bytes = 0; req->queued_bytes = 0;
} else { } else {
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, nbufs); req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->write_queue_size += req->queued_bytes; handle->write_queue_size += req->queued_bytes;
} }
@ -1397,7 +1398,7 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
void uv__pipe_insert_pending_socket(uv_pipe_t* handle, void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
WSAPROTOCOL_INFOW* info, uv__ipc_socket_info_ex* info,
int tcp_connection) { int tcp_connection) {
uv__ipc_queue_item_t* item; uv__ipc_queue_item_t* item;
@ -1405,7 +1406,7 @@ void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
if (item == NULL) if (item == NULL)
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
memcpy(&item->socket_info, info, sizeof(item->socket_info)); memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
item->tcp_connection = tcp_connection; item->tcp_connection = tcp_connection;
QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member); QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member);
handle->pending_ipc_info.queue_len++; handle->pending_ipc_info.queue_len++;
@ -1471,11 +1472,11 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
assert(avail - sizeof(ipc_frame.header) >= assert(avail - sizeof(ipc_frame.header) >=
sizeof(ipc_frame.socket_info)); sizeof(ipc_frame.socket_info_ex));
/* Read the TCP socket info. */ /* Read the TCP socket info. */
if (!ReadFile(handle->handle, if (!ReadFile(handle->handle,
&ipc_frame.socket_info, &ipc_frame.socket_info_ex,
sizeof(ipc_frame) - sizeof(ipc_frame.header), sizeof(ipc_frame) - sizeof(ipc_frame.header),
&bytes, &bytes,
NULL)) { NULL)) {
@ -1489,7 +1490,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
/* Store the pending socket info. */ /* Store the pending socket info. */
uv__pipe_insert_pending_socket( uv__pipe_insert_pending_socket(
handle, handle,
&ipc_frame.socket_info, &ipc_frame.socket_info_ex,
ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
} }
@ -1772,7 +1773,34 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
HANDLE os_handle = uv__get_osfhandle(file); HANDLE os_handle = uv__get_osfhandle(file);
DWORD duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_ACCESS_INFORMATION access;
DWORD duplex_flags = 0;
/* Determine what kind of permissions we have on this handle.
* Cygwin opens the pipe in message mode, but we can support it,
* just query the access flags and set the stream flags accordingly.
*/
nt_status = pNtQueryInformationFile(os_handle,
&io_status,
&access,
sizeof(access),
FileAccessInformation);
if (nt_status != STATUS_SUCCESS)
return UV_EINVAL;
if (pipe->ipc) {
if (!(access.AccessFlags & FILE_WRITE_DATA) ||
!(access.AccessFlags & FILE_READ_DATA)) {
return UV_EINVAL;
}
}
if (access.AccessFlags & FILE_WRITE_DATA)
duplex_flags |= UV_HANDLE_WRITABLE;
if (access.AccessFlags & FILE_READ_DATA)
duplex_flags |= UV_HANDLE_READABLE;
if (os_handle == INVALID_HANDLE_VALUE || if (os_handle == INVALID_HANDLE_VALUE ||
uv_set_pipe_handle(pipe->loop, pipe, os_handle, duplex_flags) == -1) { uv_set_pipe_handle(pipe->loop, pipe, os_handle, duplex_flags) == -1) {

252
deps/uv/src/win/process.c

@ -25,6 +25,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <limits.h> #include <limits.h>
#include <malloc.h>
#include <wchar.h>
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"
@ -36,14 +38,27 @@
typedef struct env_var { typedef struct env_var {
const char* narrow; const WCHAR* const wide;
const WCHAR* wide; const WCHAR* const wide_eq;
size_t len; /* including null or '=' */ const size_t len; /* including null or '=' */
DWORD value_len;
int supplied;
} env_var_t; } env_var_t;
#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } #define E_V(str) { L##str, L##str L"=", sizeof(str) }
static const env_var_t required_vars[] = { /* keep me sorted */
E_V("HOMEDRIVE"),
E_V("HOMEPATH"),
E_V("LOGONSERVER"),
E_V("PATH"),
E_V("SYSTEMDRIVE"),
E_V("SYSTEMROOT"),
E_V("TEMP"),
E_V("USERDOMAIN"),
E_V("USERNAME"),
E_V("USERPROFILE"),
E_V("WINDIR"),
};
static size_t n_required_vars = ARRAY_SIZE(required_vars);
static HANDLE uv_global_job_handle_; static HANDLE uv_global_job_handle_;
@ -587,22 +602,53 @@ error:
} }
/* int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
* If we learn that people are passing in huge environment blocks wchar_t* a_eq;
* then we should probably qsort() the array and then bsearch() wchar_t* b_eq;
* to see if it contains this variable. But there are ownership wchar_t* A;
* issues associated with that solution; this is the caller's wchar_t* B;
* char**, and modifying it is rude. int nb;
*/ int r;
static void check_required_vars_contains_var(env_var_t* required, int count,
const char* var) { if (na < 0) {
int i; a_eq = wcschr(a, L'=');
for (i = 0; i < count; ++i) { assert(a_eq);
if (_strnicmp(required[i].narrow, var, required[i].len) == 0) { na = (int)(long)(a_eq - a);
required[i].supplied = 1; } else {
return; na--;
}
b_eq = wcschr(b, L'=');
assert(b_eq);
nb = b_eq - b;
A = alloca((na+1) * sizeof(wchar_t));
B = alloca((nb+1) * sizeof(wchar_t));
r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
assert(r==na);
A[na] = L'\0';
r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
assert(r==nb);
B[nb] = L'\0';
while (1) {
wchar_t AA = *A++;
wchar_t BB = *B++;
if (AA < BB) {
return -1;
} else if (AA > BB) {
return 1;
} else if (!AA && !BB) {
return 0;
}
} }
} }
static int qsort_wcscmp(const void *a, const void *b) {
wchar_t* astr = *(wchar_t* const*)a;
wchar_t* bstr = *(wchar_t* const*)b;
return env_strncmp(astr, -1, bstr);
} }
@ -616,28 +662,30 @@ static void check_required_vars_contains_var(env_var_t* required, int count,
* TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
* these get defined if the input environment block does not contain any * these get defined if the input environment block does not contain any
* values for them. * values for them.
*
* Also add variables known to Cygwin to be required for correct
* subprocess operation in many cases:
* https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
*
*/ */
int make_program_env(char* env_block[], WCHAR** dst_ptr) { int make_program_env(char* env_block[], WCHAR** dst_ptr) {
WCHAR* dst; WCHAR* dst;
WCHAR* ptr; WCHAR* ptr;
char** env; char** env;
size_t env_len = 1; /* room for closing null */ size_t env_len = 0;
int len; int len;
size_t i; size_t i;
DWORD var_size; DWORD var_size;
size_t env_block_count = 1; /* 1 for null-terminator */
WCHAR* dst_copy;
WCHAR** ptr_copy;
WCHAR** env_copy;
DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
env_var_t required_vars[] = { /* first pass: determine size in UTF-16 */
E_V("SYSTEMROOT"),
E_V("SYSTEMDRIVE"),
E_V("TEMP"),
};
for (env = env_block; *env; env++) { for (env = env_block; *env; env++) {
int len; int len;
check_required_vars_contains_var(required_vars, if (strchr(*env, '=')) {
ARRAY_SIZE(required_vars),
*env);
len = MultiByteToWideChar(CP_UTF8, len = MultiByteToWideChar(CP_UTF8,
0, 0,
*env, *env,
@ -647,64 +695,138 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
if (len <= 0) { if (len <= 0) {
return GetLastError(); return GetLastError();
} }
env_len += len; env_len += len;
} env_block_count++;
for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
if (!required_vars[i].supplied) {
env_len += required_vars[i].len;
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
if (var_size == 0) {
return GetLastError();
}
required_vars[i].value_len = var_size;
env_len += var_size;
} }
} }
dst = malloc(env_len * sizeof(WCHAR)); /* second pass: copy to UTF-16 environment block */
if (!dst) { dst_copy = _malloca(env_len * sizeof(WCHAR));
if (!dst_copy) {
return ERROR_OUTOFMEMORY; return ERROR_OUTOFMEMORY;
} }
env_copy = alloca(env_block_count * sizeof(WCHAR*));
ptr = dst; ptr = dst_copy;
ptr_copy = env_copy;
for (env = env_block; *env; env++, ptr += len) { for (env = env_block; *env; env++) {
if (strchr(*env, '=')) {
len = MultiByteToWideChar(CP_UTF8, len = MultiByteToWideChar(CP_UTF8,
0, 0,
*env, *env,
-1, -1,
ptr, ptr,
(int) (env_len - (ptr - dst))); (int) (env_len - (ptr - dst_copy)));
if (len <= 0) { if (len <= 0) {
free(dst); DWORD err = GetLastError();
return GetLastError(); _freea(dst_copy);
return err;
}
*ptr_copy++ = ptr;
ptr += len;
}
}
*ptr_copy = NULL;
assert(env_len == ptr - dst_copy);
/* sort our (UTF-16) copy */
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
/* third pass: check for required variables */
for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
int cmp;
if (!*ptr_copy) {
cmp = -1;
} else {
cmp = env_strncmp(required_vars[i].wide_eq,
required_vars[i].len,
*ptr_copy);
}
if (cmp < 0) {
/* missing required var */
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
required_vars_value_len[i] = var_size;
if (var_size != 0) {
env_len += required_vars[i].len;
env_len += var_size;
}
i++;
} else {
ptr_copy++;
if (cmp == 0)
i++;
} }
} }
for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { /* final pass: copy, in sort order, and inserting required variables */
if (!required_vars[i].supplied) { dst = malloc((1+env_len) * sizeof(WCHAR));
wcscpy(ptr, required_vars[i].wide); if (!dst) {
ptr += required_vars[i].len - 1; _freea(dst_copy);
*ptr++ = L'='; return ERROR_OUTOFMEMORY;
}
for (ptr = dst, ptr_copy = env_copy, i = 0;
*ptr_copy || i < n_required_vars;
ptr += len) {
int cmp;
if (i >= n_required_vars) {
cmp = 1;
} else if (!*ptr_copy) {
cmp = -1;
} else {
cmp = env_strncmp(required_vars[i].wide_eq,
required_vars[i].len,
*ptr_copy);
}
if (cmp < 0) {
/* missing required var */
len = required_vars_value_len[i];
if (len) {
wcscpy(ptr, required_vars[i].wide_eq);
ptr += required_vars[i].len;
var_size = GetEnvironmentVariableW(required_vars[i].wide, var_size = GetEnvironmentVariableW(required_vars[i].wide,
ptr, ptr,
required_vars[i].value_len); (int) (env_len - (ptr - dst)));
if (var_size == 0) { if (var_size != len-1) { /* race condition? */
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
} }
ptr += required_vars[i].value_len; }
i++;
} else {
/* copy var from env_block */
DWORD r;
len = wcslen(*ptr_copy) + 1;
r = wmemcpy_s(ptr, (env_len - (ptr - dst)), *ptr_copy, len);
assert(!r);
ptr_copy++;
if (cmp == 0)
i++;
} }
} }
/* Terminate with an extra NULL. */ /* Terminate with an extra NULL. */
assert(env_len == (ptr - dst));
*ptr = L'\0'; *ptr = L'\0';
_freea(dst_copy);
*dst_ptr = dst; *dst_ptr = dst;
return 0; return 0;
} }
/*
* Attempt to find the value of the PATH environment variable in the child's
* preprocessed environment.
*
* If found, a pointer into `env` is returned. If not found, NULL is returned.
*/
static WCHAR* find_path(WCHAR *env) {
for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
if (wcsncmp(env, L"PATH=", 5) == 0)
return &env[5];
}
return NULL;
}
/* /*
* Called on Windows thread-pool thread to indicate that * Called on Windows thread-pool thread to indicate that
@ -802,7 +924,7 @@ int uv_spawn(uv_loop_t* loop,
const uv_process_options_t* options) { const uv_process_options_t* options) {
int i; int i;
int err = 0; int err = 0;
WCHAR* path = NULL; WCHAR* path = NULL, *alloc_path = NULL;
BOOL result; BOOL result;
WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL; *env = NULL, *cwd = NULL;
@ -876,7 +998,8 @@ int uv_spawn(uv_loop_t* loop,
} }
/* Get PATH environment variable. */ /* Get PATH environment variable. */
{ path = find_path(env);
if (path == NULL) {
DWORD path_len, r; DWORD path_len, r;
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
@ -885,11 +1008,12 @@ int uv_spawn(uv_loop_t* loop,
goto done; goto done;
} }
path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); alloc_path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
if (path == NULL) { if (alloc_path == NULL) {
err = ERROR_OUTOFMEMORY; err = ERROR_OUTOFMEMORY;
goto done; goto done;
} }
path = alloc_path;
r = GetEnvironmentVariableW(L"PATH", path, path_len); r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) { if (r == 0 || r >= path_len) {
@ -1023,7 +1147,7 @@ int uv_spawn(uv_loop_t* loop,
free(arguments); free(arguments);
free(cwd); free(cwd);
free(env); free(env);
free(path); free(alloc_path);
if (process->child_stdio_buffer != NULL) { if (process->child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */ /* Clean up child stdio handles. */

16
deps/uv/src/win/req-inl.h

@ -195,26 +195,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
uv_process_poll_req(loop, (uv_poll_t*) req->data, req); uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break; break;
case UV_GETADDRINFO:
uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
break;
case UV_GETNAMEINFO:
uv_process_getnameinfo_req(loop, (uv_getnameinfo_t*)req);
break;
case UV_PROCESS_EXIT: case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data); uv_process_proc_exit(loop, (uv_process_t*) req->data);
break; break;
case UV_FS:
uv_process_fs_req(loop, (uv_fs_t*) req);
break;
case UV_WORK:
uv_process_work_req(loop, (uv_work_t*) req);
break;
case UV_FS_EVENT_REQ: case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break; break;

11
deps/uv/src/win/stream-inl.h

@ -53,15 +53,4 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
} }
INLINE static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
unsigned int i;
size_t bytes;
bytes = 0;
for (i = 0; i < nbufs; i++)
bytes += (size_t) bufs[i].len;
return bytes;
}
#endif /* UV_WIN_STREAM_INL_H_ */ #endif /* UV_WIN_STREAM_INL_H_ */

63
deps/uv/src/win/tcp.c

@ -156,6 +156,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->func_acceptex = NULL; handle->func_acceptex = NULL;
handle->func_connectex = NULL; handle->func_connectex = NULL;
handle->processed_accepts = 0; handle->processed_accepts = 0;
handle->delayed_error = 0;
return 0; return 0;
} }
@ -235,6 +236,17 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
} }
/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
* allow binding to addresses that are in use by sockets in TIME_WAIT, it
* effectively allows 'stealing' a port which is in use by another application.
*
* SO_EXCLUSIVEADDRUSE is also not good here because it does cehck all sockets,
* regardless of state, so we'd get an error even if the port is in use by a
* socket in TIME_WAIT state.
*
* See issue #1360.
*
*/
static int uv_tcp_try_bind(uv_tcp_t* handle, static int uv_tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int addrlen, unsigned int addrlen,
@ -291,8 +303,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
err = WSAGetLastError(); err = WSAGetLastError();
if (err == WSAEADDRINUSE) { if (err == WSAEADDRINUSE) {
/* Some errors are not to be reported until connect() or listen() */ /* Some errors are not to be reported until connect() or listen() */
handle->bind_error = err; handle->delayed_error = err;
handle->flags |= UV_HANDLE_BIND_ERROR;
} else { } else {
return err; return err;
} }
@ -517,8 +528,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
return WSAEISCONN; return WSAEISCONN;
} }
if (handle->flags & UV_HANDLE_BIND_ERROR) { if (handle->delayed_error) {
return handle->bind_error; return handle->delayed_error;
} }
if (!(handle->flags & UV_HANDLE_BOUND)) { if (!(handle->flags & UV_HANDLE_BOUND)) {
@ -528,6 +539,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
0); 0);
if (err) if (err)
return err; return err;
if (handle->delayed_error)
return handle->delayed_error;
} }
if (!handle->func_acceptex) { if (!handle->func_acceptex) {
@ -699,8 +712,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
DWORD bytes; DWORD bytes;
int err; int err;
if (handle->flags & UV_HANDLE_BIND_ERROR) { if (handle->delayed_error) {
return handle->bind_error; return handle->delayed_error;
} }
if (!(handle->flags & UV_HANDLE_BOUND)) { if (!(handle->flags & UV_HANDLE_BOUND)) {
@ -714,6 +727,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return err; return err;
if (handle->delayed_error)
return handle->delayed_error;
} }
if (!handle->func_connectex) { if (!handle->func_connectex) {
@ -762,8 +777,8 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
return UV_EINVAL; return UV_EINVAL;
} }
if (handle->flags & UV_HANDLE_BIND_ERROR) { if (handle->delayed_error) {
return uv_translate_sys_error(handle->bind_error); return uv_translate_sys_error(handle->delayed_error);
} }
result = getsockname(handle->socket, name, namelen); result = getsockname(handle->socket, name, namelen);
@ -784,8 +799,8 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
return UV_EINVAL; return UV_EINVAL;
} }
if (handle->flags & UV_HANDLE_BIND_ERROR) { if (handle->delayed_error) {
return uv_translate_sys_error(handle->bind_error); return uv_translate_sys_error(handle->delayed_error);
} }
result = getpeername(handle->socket, name, namelen); result = getpeername(handle->socket, name, namelen);
@ -839,7 +854,7 @@ int uv_tcp_write(uv_loop_t* loop,
uv_insert_pending_req(loop, (uv_req_t*) req); uv_insert_pending_req(loop, (uv_req_t*) req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, nbufs); req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->reqs_pending++; handle->reqs_pending++;
handle->write_reqs_pending++; handle->write_reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
@ -1009,8 +1024,12 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
} }
if (req->cb) { if (req->cb) {
err = GET_REQ_SOCK_ERROR(req); err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
req->cb(req, uv_translate_sys_error(err)); if (err == UV_ECONNABORTED) {
/* use UV_ECANCELED for consistency with Unix */
err = UV_ECANCELED;
}
req->cb(req, err);
} }
handle->write_reqs_pending--; handle->write_reqs_pending--;
@ -1102,14 +1121,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
} }
int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection) { int tcp_connection) {
int err; int err;
SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
socket_protocol_info, &socket_info_ex->socket_info,
0, 0,
WSA_FLAG_OVERLAPPED); WSA_FLAG_OVERLAPPED);
@ -1126,7 +1144,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
err = uv_tcp_set_socket(tcp->loop, err = uv_tcp_set_socket(tcp->loop,
tcp, tcp,
socket, socket,
socket_protocol_info->iAddressFamily, socket_info_ex->socket_info.iAddressFamily,
1); 1);
if (err) { if (err) {
closesocket(socket); closesocket(socket);
@ -1141,6 +1159,8 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
tcp->flags |= UV_HANDLE_BOUND; tcp->flags |= UV_HANDLE_BOUND;
tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
tcp->delayed_error = socket_info_ex->delayed_error;
tcp->loop->active_tcp_streams++; tcp->loop->active_tcp_streams++;
return 0; return 0;
} }
@ -1201,13 +1221,10 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
} }
/* Report any deferred bind errors now. */ if (!(handle->delayed_error)) {
if (handle->flags & UV_HANDLE_BIND_ERROR) {
return handle->bind_error;
}
if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
return WSAGetLastError(); handle->delayed_error = WSAGetLastError();
}
} }
} }
} }

81
deps/uv/src/win/threadpool.c

@ -1,81 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "req-inl.h"
static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req,
uv_work_cb work_cb, uv_after_work_cb after_work_cb) {
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_WORK;
req->loop = loop;
req->work_cb = work_cb;
req->after_work_cb = after_work_cb;
memset(&req->overlapped, 0, sizeof(req->overlapped));
}
static DWORD WINAPI uv_work_thread_proc(void* parameter) {
uv_work_t* req = (uv_work_t*)parameter;
uv_loop_t* loop = req->loop;
assert(req != NULL);
assert(req->type == UV_WORK);
assert(req->work_cb);
req->work_cb(req);
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
}
int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
uv_after_work_cb after_work_cb) {
if (work_cb == NULL)
return UV_EINVAL;
uv_work_req_init(loop, req, work_cb, after_work_cb);
if (!QueueUserWorkItem(&uv_work_thread_proc, req, WT_EXECUTELONGFUNCTION)) {
return uv_translate_sys_error(GetLastError());
}
uv__req_register(loop, req);
return 0;
}
int uv_cancel(uv_req_t* req) {
return UV_ENOSYS;
}
void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) {
uv__req_unregister(loop, req);
if(req->after_work_cb)
req->after_work_cb(req, 0);
}

50
deps/uv/src/win/timer.c

@ -36,10 +36,11 @@ void uv_update_time(uv_loop_t* loop) {
time.QuadPart = loop->time; time.QuadPart = loop->time;
/* GetTickCount() can conceivably wrap around, so when the current tick */ /* GetTickCount() can conceivably wrap around, so when the current tick
/* count is lower than the last tick count, we'll assume it has wrapped. */ * count is lower than the last tick count, we'll assume it has wrapped.
/* uv_poll must make sure that the timer can never overflow more than */ * uv_poll must make sure that the timer can never overflow more than
/* once between two subsequent uv_update_time calls. */ * once between two subsequent uv_update_time calls.
*/
time.LowPart = ticks; time.LowPart = ticks;
if (ticks < loop->last_tick_count) if (ticks < loop->last_tick_count)
time.HighPart++; time.HighPart++;
@ -47,13 +48,14 @@ void uv_update_time(uv_loop_t* loop) {
/* Remember the last tick count. */ /* Remember the last tick count. */
loop->last_tick_count = ticks; loop->last_tick_count = ticks;
/* The GetTickCount() resolution isn't too good. Sometimes it'll happen */ /* The GetTickCount() resolution isn't too good. Sometimes it'll happen
/* that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has */ * that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has
/* waited for a couple of ms but this is not reflected in the GetTickCount */ * waited for a couple of ms but this is not reflected in the GetTickCount
/* result yet. Therefore whenever GetQueuedCompletionStatus times out */ * result yet. Therefore whenever GetQueuedCompletionStatus times out
/* we'll add the number of ms that it has waited to the current loop time. */ * we'll add the number of ms that it has waited to the current loop time.
/* When that happened the loop time might be a little ms farther than what */ * When that happened the loop time might be a little ms farther than what
/* we've just computed, and we shouldn't update the loop time. */ * we've just computed, and we shouldn't update the loop time.
*/
if (loop->time < time.QuadPart) if (loop->time < time.QuadPart)
loop->time = time.QuadPart; loop->time = time.QuadPart;
} }
@ -193,24 +195,26 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
} }
DWORD uv_get_poll_timeout(uv_loop_t* loop) { DWORD uv__next_timeout(const uv_loop_t* loop) {
uv_timer_t* timer; uv_timer_t* timer;
int64_t delta; int64_t delta;
/* Check if there are any running timers */ /* Check if there are any running timers
timer = RB_MIN(uv_timer_tree_s, &loop->timers); * Need to cast away const first, since RB_MIN doesn't know what we are
* going to do with this return value, it can't be marked const
*/
timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
if (timer) { if (timer) {
uv_update_time(loop);
delta = timer->due - loop->time; delta = timer->due - loop->time;
if (delta >= UINT_MAX >> 1) { if (delta >= UINT_MAX >> 1) {
/* A timeout value of UINT_MAX means infinite, so that's no good. But */ /* A timeout value of UINT_MAX means infinite, so that's no good. But
/* more importantly, there's always the risk that GetTickCount wraps. */ * more importantly, there's always the risk that GetTickCount wraps.
/* uv_update_time can detect this, but we must make sure that the */ * uv_update_time can detect this, but we must make sure that the
/* tick counter never overflows twice between two subsequent */ * tick counter never overflows twice between two subsequent
/* uv_update_time calls. We do this by never sleeping more than half */ * uv_update_time calls. We do this by never sleeping more than half
/* the time it takes to wrap the counter - which is huge overkill, */ * the time it takes to wrap the counter - which is huge overkill,
/* but hey, it's not so bad to wake up every 25 days. */ * but hey, it's not so bad to wake up every 25 days.
*/
return UINT_MAX >> 1; return UINT_MAX >> 1;
} else if (delta < 0) { } else if (delta < 0) {
/* Negative timeout values are not allowed */ /* Negative timeout values are not allowed */

4
deps/uv/src/win/tty.c

@ -30,6 +30,10 @@
# include <stdint.h> # include <stdint.h>
#endif #endif
#ifndef COMMON_LVB_REVERSE_VIDEO
# define COMMON_LVB_REVERSE_VIDEO 0x4000
#endif
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"
#include "handle-inl.h" #include "handle-inl.h"

25
deps/uv/src/win/udp.c

@ -37,7 +37,8 @@ const unsigned int uv_active_udp_streams_threshold = 0;
/* A zero-size buffer for use by uv_udp_read */ /* A zero-size buffer for use by uv_udp_read */
static char uv_zero_[] = ""; static char uv_zero_[] = "";
int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int uv_udp_getsockname(const uv_udp_t* handle,
struct sockaddr* name,
int* namelen) { int* namelen) {
int result; int result;
@ -129,6 +130,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
handle->activecnt = 0; handle->activecnt = 0;
handle->func_wsarecv = WSARecv; handle->func_wsarecv = WSARecv;
handle->func_wsarecvfrom = WSARecvFrom; handle->func_wsarecvfrom = WSARecvFrom;
handle->send_queue_size = 0;
handle->send_queue_count = 0;
uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
handle->recv_req.type = UV_UDP_RECV; handle->recv_req.type = UV_UDP_RECV;
@ -396,12 +399,16 @@ static int uv__send(uv_udp_send_t* req,
/* Request completed immediately. */ /* Request completed immediately. */
req->queued_bytes = 0; req->queued_bytes = 0;
handle->reqs_pending++; handle->reqs_pending++;
handle->send_queue_size += req->queued_bytes;
handle->send_queue_count++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*)req); uv_insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, nbufs); req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->reqs_pending++; handle->reqs_pending++;
handle->send_queue_size += req->queued_bytes;
handle->send_queue_count++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
} else { } else {
/* Send failed due to an error. */ /* Send failed due to an error. */
@ -524,6 +531,11 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
assert(handle->type == UV_UDP); assert(handle->type == UV_UDP);
assert(handle->send_queue_size >= req->queued_bytes);
assert(handle->send_queue_count >= 1);
handle->send_queue_size -= req->queued_bytes;
handle->send_queue_count--;
UNREGISTER_HANDLE_REQ(loop, handle, req); UNREGISTER_HANDLE_REQ(loop, handle, req);
if (req->cb) { if (req->cb) {
@ -860,3 +872,12 @@ int uv__udp_send(uv_udp_send_t* req,
return 0; return 0;
} }
int uv__udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen) {
return UV_ENOSYS;
}

5
deps/uv/test/run-tests.c

@ -39,6 +39,7 @@
int ipc_helper(int listen_after_write); int ipc_helper(int listen_after_write);
int ipc_helper_tcp_connection(void); int ipc_helper_tcp_connection(void);
int ipc_send_recv_helper(void); int ipc_send_recv_helper(void);
int ipc_helper_bind_twice(void);
int stdio_over_pipes_helper(void); int stdio_over_pipes_helper(void);
static int maybe_run_test(int argc, char **argv); static int maybe_run_test(int argc, char **argv);
@ -82,6 +83,10 @@ static int maybe_run_test(int argc, char **argv) {
return ipc_helper_tcp_connection(); return ipc_helper_tcp_connection();
} }
if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
return ipc_helper_bind_twice();
}
if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
return stdio_over_pipes_helper(); return stdio_over_pipes_helper();
} }

29
deps/uv/test/test-barrier.c

@ -41,10 +41,6 @@ static void worker(void* arg) {
uv_sleep(c->delay); uv_sleep(c->delay);
c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier); c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier);
if (c->worker_barrier_wait_rval == 1) {
uv_barrier_destroy(&c->barrier);
ASSERT(c->main_barrier_wait_rval == 0);
}
} }
@ -53,21 +49,16 @@ TEST_IMPL(barrier_1) {
worker_config wc; worker_config wc;
memset(&wc, 0, sizeof(wc)); memset(&wc, 0, sizeof(wc));
wc.main_barrier_wait_rval = -1;
wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc)); ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_sleep(100); uv_sleep(100);
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
if (wc.main_barrier_wait_rval == 1) {
uv_barrier_destroy(&wc.barrier);
ASSERT(wc.worker_barrier_wait_rval == 0);
}
ASSERT(0 == uv_thread_join(&thread)); ASSERT(0 == uv_thread_join(&thread));
uv_barrier_destroy(&wc.barrier);
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0; return 0;
@ -80,19 +71,15 @@ TEST_IMPL(barrier_2) {
memset(&wc, 0, sizeof(wc)); memset(&wc, 0, sizeof(wc));
wc.delay = 100; wc.delay = 100;
wc.main_barrier_wait_rval = -1;
wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc)); ASSERT(0 == uv_thread_create(&thread, worker, &wc));
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
if (wc.main_barrier_wait_rval == 1) {
uv_barrier_destroy(&wc.barrier);
ASSERT(wc.worker_barrier_wait_rval == 0);
}
ASSERT(0 == uv_thread_join(&thread)); ASSERT(0 == uv_thread_join(&thread));
uv_barrier_destroy(&wc.barrier);
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0; return 0;
@ -104,19 +91,15 @@ TEST_IMPL(barrier_3) {
worker_config wc; worker_config wc;
memset(&wc, 0, sizeof(wc)); memset(&wc, 0, sizeof(wc));
wc.main_barrier_wait_rval = -1;
wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc)); ASSERT(0 == uv_thread_create(&thread, worker, &wc));
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
if (wc.main_barrier_wait_rval == 1) {
uv_barrier_destroy(&wc.barrier);
ASSERT(wc.worker_barrier_wait_rval == 0);
}
ASSERT(0 == uv_thread_join(&thread)); ASSERT(0 == uv_thread_join(&thread));
uv_barrier_destroy(&wc.barrier);
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0; return 0;

67
deps/uv/test/test-fs.c

@ -65,6 +65,7 @@ static int read_cb_count;
static int write_cb_count; static int write_cb_count;
static int unlink_cb_count; static int unlink_cb_count;
static int mkdir_cb_count; static int mkdir_cb_count;
static int mkdtemp_cb_count;
static int rmdir_cb_count; static int rmdir_cb_count;
static int readdir_cb_count; static int readdir_cb_count;
static int stat_cb_count; static int stat_cb_count;
@ -93,6 +94,8 @@ static uv_fs_t write_req;
static uv_fs_t unlink_req; static uv_fs_t unlink_req;
static uv_fs_t close_req; static uv_fs_t close_req;
static uv_fs_t mkdir_req; static uv_fs_t mkdir_req;
static uv_fs_t mkdtemp_req1;
static uv_fs_t mkdtemp_req2;
static uv_fs_t rmdir_req; static uv_fs_t rmdir_req;
static uv_fs_t readdir_req; static uv_fs_t readdir_req;
static uv_fs_t stat_req; static uv_fs_t stat_req;
@ -376,6 +379,32 @@ static void mkdir_cb(uv_fs_t* req) {
} }
static void check_mkdtemp_result(uv_fs_t* req) {
int r;
ASSERT(req->fs_type == UV_FS_MKDTEMP);
ASSERT(req->result == 0);
ASSERT(req->path);
ASSERT(strlen(req->path) == 15);
ASSERT(memcmp(req->path, "test_dir_", 9) == 0);
ASSERT(memcmp(req->path + 9, "XXXXXX", 6) != 0);
check_permission(req->path, 0700);
/* Check if req->path is actually a directory */
r = uv_fs_stat(uv_default_loop(), &stat_req, req->path, NULL);
ASSERT(r == 0);
ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
uv_fs_req_cleanup(&stat_req);
}
static void mkdtemp_cb(uv_fs_t* req) {
ASSERT(req == &mkdtemp_req1);
check_mkdtemp_result(req);
mkdtemp_cb_count++;
}
static void rmdir_cb(uv_fs_t* req) { static void rmdir_cb(uv_fs_t* req) {
ASSERT(req == &rmdir_req); ASSERT(req == &rmdir_req);
ASSERT(req->fs_type == UV_FS_RMDIR); ASSERT(req->fs_type == UV_FS_RMDIR);
@ -927,6 +956,37 @@ TEST_IMPL(fs_async_sendfile) {
} }
TEST_IMPL(fs_mkdtemp) {
int r;
const char* path_template = "test_dir_XXXXXX";
loop = uv_default_loop();
r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
ASSERT(r == 0);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(mkdtemp_cb_count == 1);
/* sync mkdtemp */
r = uv_fs_mkdtemp(loop, &mkdtemp_req2, path_template, NULL);
ASSERT(r == 0);
check_mkdtemp_result(&mkdtemp_req2);
/* mkdtemp return different values on subsequent calls */
ASSERT(strcmp(mkdtemp_req1.path, mkdtemp_req2.path) != 0);
/* Cleanup */
rmdir(mkdtemp_req1.path);
rmdir(mkdtemp_req2.path);
uv_fs_req_cleanup(&mkdtemp_req1);
uv_fs_req_cleanup(&mkdtemp_req2);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(fs_fstat) { TEST_IMPL(fs_fstat) {
int r; int r;
uv_fs_t req; uv_fs_t req;
@ -985,6 +1045,13 @@ TEST_IMPL(fs_fstat) {
ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec); ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec);
ASSERT(s->st_flags == t.st_flags); ASSERT(s->st_flags == t.st_flags);
ASSERT(s->st_gen == t.st_gen); ASSERT(s->st_gen == t.st_gen);
#elif defined(_AIX)
ASSERT(s->st_atim.tv_sec == t.st_atime);
ASSERT(s->st_atim.tv_nsec == 0);
ASSERT(s->st_mtim.tv_sec == t.st_mtime);
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) || \ #elif defined(__sun) || \
defined(_BSD_SOURCE) || \ defined(_BSD_SOURCE) || \
defined(_SVID_SOURCE) || \ defined(_SVID_SOURCE) || \

3
deps/uv/test/test-getsockname.c

@ -353,6 +353,9 @@ TEST_IMPL(getsockname_udp) {
ASSERT(getsocknamecount == 2); ASSERT(getsocknamecount == 2);
ASSERT(udp.send_queue_size == 0);
ASSERT(udpServer.send_queue_size == 0);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }

125
deps/uv/test/test-ipc.c

@ -27,6 +27,7 @@
static uv_pipe_t channel; static uv_pipe_t channel;
static uv_tcp_t tcp_server; static uv_tcp_t tcp_server;
static uv_tcp_t tcp_server2;
static uv_tcp_t tcp_connection; static uv_tcp_t tcp_connection;
static int exit_cb_called; static int exit_cb_called;
@ -38,8 +39,6 @@ static int local_conn_accepted;
static int remote_conn_accepted; static int remote_conn_accepted;
static int tcp_server_listening; static int tcp_server_listening;
static uv_write_t write_req; static uv_write_t write_req;
static uv_pipe_t channel;
static uv_tcp_t tcp_server;
static uv_write_t conn_notify_req; static uv_write_t conn_notify_req;
static int close_cb_called; static int close_cb_called;
static int connection_accepted; static int connection_accepted;
@ -205,6 +204,71 @@ static void on_read(uv_stream_t* handle,
free(buf->base); free(buf->base);
} }
#ifdef _WIN32
static void on_read_listen_after_bound_twice(uv_stream_t* handle,
ssize_t nread,
const uv_buf_t* buf) {
int r;
uv_pipe_t* pipe;
uv_handle_type pending;
pipe = (uv_pipe_t*) handle;
if (nread == 0) {
/* Everything OK, but nothing read. */
free(buf->base);
return;
}
if (nread < 0) {
if (nread == UV_EOF) {
free(buf->base);
return;
}
printf("error recving on channel: %s\n", uv_strerror(nread));
abort();
}
fprintf(stderr, "got %d bytes\n", (int)nread);
ASSERT(uv_pipe_pending_count(pipe) > 0);
pending = uv_pipe_pending_type(pipe);
ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
read_cb_called++;
if (read_cb_called == 1) {
/* Accept the first TCP server, and start listening on it. */
ASSERT(pending == UV_TCP);
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 12, on_connection);
ASSERT(r == 0);
} else if (read_cb_called == 2) {
/* Accept the second TCP server, and start listening on it. */
ASSERT(pending == UV_TCP);
r = uv_tcp_init(uv_default_loop(), &tcp_server2);
ASSERT(r == 0);
r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server2, 12, on_connection);
ASSERT(r == UV_EADDRINUSE);
uv_close((uv_handle_t*)&tcp_server, NULL);
uv_close((uv_handle_t*)&tcp_server2, NULL);
ASSERT(0 == uv_pipe_pending_count(pipe));
uv_close((uv_handle_t*)&channel, NULL);
}
free(buf->base);
}
#endif
void spawn_helper(uv_pipe_t* channel, void spawn_helper(uv_pipe_t* channel,
uv_process_t* process, uv_process_t* process,
@ -424,6 +488,13 @@ TEST_IMPL(listen_no_simultaneous_accepts) {
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }
TEST_IMPL(ipc_listen_after_bind_twice) {
int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice);
ASSERT(read_cb_called == 2);
ASSERT(exit_cb_called == 1);
return r;
}
#endif #endif
@ -608,7 +679,7 @@ int ipc_helper(int listen_after_write) {
int ipc_helper_tcp_connection(void) { int ipc_helper_tcp_connection(void) {
/* /*
* This is launched from test-ipc.c. stdin is a duplex channel that we * This is launched from test-ipc.c. stdin is a duplex channel
* over which a handle will be transmitted. * over which a handle will be transmitted.
*/ */
@ -657,3 +728,51 @@ int ipc_helper_tcp_connection(void) {
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }
int ipc_helper_bind_twice(void) {
/*
* This is launched from test-ipc.c. stdin is a duplex channel
* over which two handles will be transmitted.
*/
struct sockaddr_in addr;
uv_write_t write_req;
uv_write_t write_req2;
int r;
uv_buf_t buf;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_pipe_init(uv_default_loop(), &channel, 1);
ASSERT(r == 0);
uv_pipe_open(&channel, 0);
ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
buf = uv_buf_init("hello\n", 6);
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
r = uv_tcp_init(uv_default_loop(), &tcp_server2);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
(uv_stream_t*)&tcp_server, NULL);
ASSERT(r == 0);
r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1,
(uv_stream_t*)&tcp_server2, NULL);
ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}

19
deps/uv/test/test-list.h

@ -28,6 +28,7 @@ TEST_DECLARE (loop_alive)
TEST_DECLARE (loop_close) TEST_DECLARE (loop_close)
TEST_DECLARE (loop_stop) TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_update_time)
TEST_DECLARE (loop_backend_timeout)
TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_2)
TEST_DECLARE (barrier_3) TEST_DECLARE (barrier_3)
@ -56,6 +57,7 @@ TEST_DECLARE (delayed_accept)
TEST_DECLARE (multiple_listen) TEST_DECLARE (multiple_listen)
TEST_DECLARE (tcp_writealot) TEST_DECLARE (tcp_writealot)
TEST_DECLARE (tcp_try_write) TEST_DECLARE (tcp_try_write)
TEST_DECLARE (tcp_write_queue_order)
TEST_DECLARE (tcp_open) TEST_DECLARE (tcp_open)
TEST_DECLARE (tcp_connect_error_after_write) TEST_DECLARE (tcp_connect_error_after_write)
TEST_DECLARE (tcp_shutdown_after_write) TEST_DECLARE (tcp_shutdown_after_write)
@ -71,7 +73,9 @@ TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_connect_timeout)
TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close)
#ifndef _WIN32
TEST_DECLARE (tcp_close_accept) TEST_DECLARE (tcp_close_accept)
#endif
TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_unexpected_read)
@ -84,6 +88,7 @@ TEST_DECLARE (tcp_bind6_localhost_ok)
TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind)
TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_bind_reuseaddr)
TEST_DECLARE (udp_send_and_recv) TEST_DECLARE (udp_send_and_recv)
TEST_DECLARE (udp_send_immediate)
TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_join)
TEST_DECLARE (udp_multicast_join6) TEST_DECLARE (udp_multicast_join6)
TEST_DECLARE (udp_multicast_ttl) TEST_DECLARE (udp_multicast_ttl)
@ -95,6 +100,7 @@ TEST_DECLARE (udp_ipv6_only)
TEST_DECLARE (udp_options) TEST_DECLARE (udp_options)
TEST_DECLARE (udp_no_autobind) TEST_DECLARE (udp_no_autobind)
TEST_DECLARE (udp_open) TEST_DECLARE (udp_open)
TEST_DECLARE (udp_try_send)
TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrinuse)
TEST_DECLARE (pipe_bind_error_addrnotavail) TEST_DECLARE (pipe_bind_error_addrnotavail)
TEST_DECLARE (pipe_bind_error_inval) TEST_DECLARE (pipe_bind_error_inval)
@ -186,6 +192,7 @@ TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file) TEST_DECLARE (spawn_stdout_and_stderr_to_file)
TEST_DECLARE (spawn_auto_unref) TEST_DECLARE (spawn_auto_unref)
TEST_DECLARE (spawn_closed_process_io) TEST_DECLARE (spawn_closed_process_io)
TEST_DECLARE (spawn_reads_child_path)
TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (kill) TEST_DECLARE (kill)
@ -197,6 +204,7 @@ TEST_DECLARE (fs_file_sync)
TEST_DECLARE (fs_file_write_null_buffer) TEST_DECLARE (fs_file_write_null_buffer)
TEST_DECLARE (fs_async_dir) TEST_DECLARE (fs_async_dir)
TEST_DECLARE (fs_async_sendfile) TEST_DECLARE (fs_async_sendfile)
TEST_DECLARE (fs_mkdtemp)
TEST_DECLARE (fs_fstat) TEST_DECLARE (fs_fstat)
TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_chmod)
TEST_DECLARE (fs_chown) TEST_DECLARE (fs_chown)
@ -254,6 +262,7 @@ TEST_DECLARE (listen_with_simultaneous_accepts)
TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root) TEST_DECLARE (fs_stat_root)
TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (spawn_with_an_odd_path)
TEST_DECLARE (ipc_listen_after_bind_twice)
#else #else
TEST_DECLARE (emfile) TEST_DECLARE (emfile)
TEST_DECLARE (close_fd) TEST_DECLARE (close_fd)
@ -286,6 +295,7 @@ TASK_LIST_START
TEST_ENTRY (loop_close) TEST_ENTRY (loop_close)
TEST_ENTRY (loop_stop) TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_update_time)
TEST_ENTRY (loop_backend_timeout)
TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_2)
TEST_ENTRY (barrier_3) TEST_ENTRY (barrier_3)
@ -330,6 +340,8 @@ TASK_LIST_START
TEST_ENTRY (tcp_try_write) TEST_ENTRY (tcp_try_write)
TEST_ENTRY (tcp_write_queue_order)
TEST_ENTRY (tcp_open) TEST_ENTRY (tcp_open)
TEST_HELPER (tcp_open, tcp4_echo_server) TEST_HELPER (tcp_open, tcp4_echo_server)
@ -349,7 +361,9 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close)
#ifndef _WIN32
TEST_ENTRY (tcp_close_accept) TEST_ENTRY (tcp_close_accept)
#endif
TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_to_half_open_connection) TEST_ENTRY (tcp_write_to_half_open_connection)
TEST_ENTRY (tcp_unexpected_read) TEST_ENTRY (tcp_unexpected_read)
@ -366,6 +380,7 @@ TASK_LIST_START
TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind)
TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_bind_reuseaddr)
TEST_ENTRY (udp_send_and_recv) TEST_ENTRY (udp_send_and_recv)
TEST_ENTRY (udp_send_immediate)
TEST_ENTRY (udp_dgram_too_big) TEST_ENTRY (udp_dgram_too_big)
TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_dual_stack)
TEST_ENTRY (udp_ipv6_only) TEST_ENTRY (udp_ipv6_only)
@ -376,6 +391,7 @@ TASK_LIST_START
TEST_ENTRY (udp_multicast_join) TEST_ENTRY (udp_multicast_join)
TEST_ENTRY (udp_multicast_join6) TEST_ENTRY (udp_multicast_join6)
TEST_ENTRY (udp_multicast_ttl) TEST_ENTRY (udp_multicast_ttl)
TEST_ENTRY (udp_try_send)
TEST_ENTRY (udp_open) TEST_ENTRY (udp_open)
TEST_HELPER (udp_open, udp4_echo_server) TEST_HELPER (udp_open, udp4_echo_server)
@ -505,6 +521,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout_and_stderr_to_file) TEST_ENTRY (spawn_stdout_and_stderr_to_file)
TEST_ENTRY (spawn_auto_unref) TEST_ENTRY (spawn_auto_unref)
TEST_ENTRY (spawn_closed_process_io) TEST_ENTRY (spawn_closed_process_io)
TEST_ENTRY (spawn_reads_child_path)
TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (kill) TEST_ENTRY (kill)
@ -518,6 +535,7 @@ TASK_LIST_START
TEST_ENTRY (listen_no_simultaneous_accepts) TEST_ENTRY (listen_no_simultaneous_accepts)
TEST_ENTRY (fs_stat_root) TEST_ENTRY (fs_stat_root)
TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (spawn_with_an_odd_path)
TEST_ENTRY (ipc_listen_after_bind_twice)
#else #else
TEST_ENTRY (emfile) TEST_ENTRY (emfile)
TEST_ENTRY (close_fd) TEST_ENTRY (close_fd)
@ -541,6 +559,7 @@ TASK_LIST_START
TEST_ENTRY (fs_file_write_null_buffer) TEST_ENTRY (fs_file_write_null_buffer)
TEST_ENTRY (fs_async_dir) TEST_ENTRY (fs_async_dir)
TEST_ENTRY (fs_async_sendfile) TEST_ENTRY (fs_async_sendfile)
TEST_ENTRY (fs_mkdtemp)
TEST_ENTRY (fs_fstat) TEST_ENTRY (fs_fstat)
TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_chmod)
TEST_ENTRY (fs_chown) TEST_ENTRY (fs_chown)

29
deps/uv/test/test-loop-time.c

@ -30,5 +30,34 @@ TEST_IMPL(loop_update_time) {
while (uv_now(uv_default_loop()) - start < 1000) while (uv_now(uv_default_loop()) - start < 1000)
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
MAKE_VALGRIND_HAPPY();
return 0;
}
static void cb(uv_timer_t* timer) {
uv_close((uv_handle_t*)timer, NULL);
}
TEST_IMPL(loop_backend_timeout) {
uv_loop_t *loop = uv_default_loop();
uv_timer_t timer;
int r;
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
ASSERT(!uv_loop_alive(loop));
ASSERT(uv_backend_timeout(loop) == 0);
r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */
ASSERT(r == 0);
ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */
ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(uv_backend_timeout(loop) == 0);
MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }

151
deps/uv/test/test-spawn.c

@ -31,6 +31,7 @@
# include <basetyps.h> # include <basetyps.h>
# endif # endif
# include <shellapi.h> # include <shellapi.h>
# include <wchar.h>
#else #else
# include <unistd.h> # include <unistd.h>
#endif #endif
@ -897,45 +898,110 @@ TEST_IMPL(environment_creation) {
"SYSTEM=ROOT", /* substring of a supplied var name */ "SYSTEM=ROOT", /* substring of a supplied var name */
"SYSTEMROOTED=OMG", /* supplied var name is a substring */ "SYSTEMROOTED=OMG", /* supplied var name is a substring */
"TEMP=C:\\Temp", "TEMP=C:\\Temp",
"INVALID",
"BAZ=QUX", "BAZ=QUX",
"B_Z=QUX",
"B\xe2\x82\xacZ=QUX",
"B\xf0\x90\x80\x82Z=QUX",
"B\xef\xbd\xa1Z=QUX",
"B\xf0\xa3\x91\x96Z=QUX",
"BAZ", /* repeat, invalid variable */
NULL NULL
}; };
WCHAR* wenvironment[] = {
WCHAR expected[512]; L"BAZ=QUX",
WCHAR* ptr = expected; L"B_Z=QUX",
L"B\x20acZ=QUX",
L"B\xd800\xdc02Z=QUX",
L"B\xd84d\xdc56Z=QUX",
L"B\xff61Z=QUX",
L"FOO=BAR",
L"SYSTEM=ROOT", /* substring of a supplied var name */
L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
L"TEMP=C:\\Temp",
};
WCHAR* from_env[] = {
/* list should be kept in sync with list
* in process.c, minus variables in wenvironment */
L"HOMEDRIVE",
L"HOMEPATH",
L"LOGONSERVER",
L"PATH",
L"USERDOMAIN",
L"USERNAME",
L"USERPROFILE",
L"SYSTEMDRIVE",
L"SYSTEMROOT",
L"WINDIR",
/* test for behavior in the absence of a
* required-environment variable: */
L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
};
int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
WCHAR *expected[ARRAY_SIZE(from_env)];
int result; int result;
WCHAR* str; WCHAR* str;
WCHAR* prev;
WCHAR* env; WCHAR* env;
for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) { for (i = 0; i < ARRAY_SIZE(from_env); i++) {
ptr += uv_utf8_to_utf16(environment[i], /* copy expected additions to environment locally */
ptr, size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
expected + sizeof(expected) - ptr); if (len == 0) {
found_in_usr_env[i] = 1;
str = malloc(1 * sizeof(WCHAR));
*str = 0;
expected[i] = str;
} else {
size_t name_len = wcslen(from_env[i]);
str = malloc((name_len+1+len) * sizeof(WCHAR));
wmemcpy(str, from_env[i], name_len);
expected[i] = str;
str += name_len;
*str++ = L'=';
GetEnvironmentVariableW(from_env[i], str, len);
}
} }
memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT="));
ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1;
ptr += GetEnvironmentVariableW(L"SYSTEMROOT",
ptr,
expected + sizeof(expected) - ptr);
++ptr;
memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE="));
ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1;
ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE",
ptr,
expected + sizeof(expected) - ptr);
++ptr;
*ptr = '\0';
result = make_program_env(environment, &env); result = make_program_env(environment, &env);
ASSERT(result == 0); ASSERT(result == 0);
for (str = env; *str; str += wcslen(str) + 1) { for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
wprintf(L"%s\n", str); int found = 0;
#if 0
_cputws(str);
putchar('\n');
#endif
for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
if (!wcscmp(str, wenvironment[i])) {
ASSERT(!found_in_loc_env[i]);
found_in_loc_env[i] = 1;
found = 1;
}
}
for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
if (!wcscmp(str, expected[i])) {
ASSERT(!found_in_usr_env[i]);
found_in_usr_env[i] = 1;
found = 1;
}
}
if (prev) { /* verify sort order -- requires Vista */
#if _WIN32_WINNT >= 0x0600
ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
#endif
}
ASSERT(found); /* verify that we expected this variable */
} }
ASSERT(wcscmp(expected, env) == 0); /* verify that we found all expected variables */
for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
ASSERT(found_in_loc_env[i]);
}
for (i = 0; i < ARRAY_SIZE(expected); i++) {
ASSERT(found_in_usr_env[i]);
}
return 0; return 0;
} }
@ -1225,3 +1291,38 @@ TEST_IMPL(closed_fd_events) {
return 0; return 0;
} }
#endif /* !_WIN32 */ #endif /* !_WIN32 */
TEST_IMPL(spawn_reads_child_path) {
int r;
int len;
char path[1024];
char *env[2] = {path, NULL};
/* Set up the process, but make sure that the file to run is relative and */
/* requires a lookup into PATH */
init_process_options("spawn_helper1", exit_cb);
options.file = "run-tests";
args[0] = "run-tests";
/* Set up the PATH env variable */
for (len = strlen(exepath);
exepath[len - 1] != '/' && exepath[len - 1] != '\\';
len--);
exepath[len] = 0;
strcpy(path, "PATH=");
strcpy(path + 5, exepath);
options.env = env;
r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}

5
deps/uv/test/test-tcp-close-accept.c

@ -19,6 +19,9 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
/* this test is Unix only */
#ifndef _WIN32
#include "uv.h" #include "uv.h"
#include "task.h" #include "task.h"
@ -181,3 +184,5 @@ TEST_IMPL(tcp_close_accept) {
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }
#endif /* !_WIN32 */

10
deps/uv/test/test-tcp-try-write.c

@ -54,21 +54,19 @@ static void close_cb(uv_handle_t* handle) {
static void connect_cb(uv_connect_t* req, int status) { static void connect_cb(uv_connect_t* req, int status) {
static char zeroes[1024];
int r; int r;
uv_buf_t buf; uv_buf_t buf;
ASSERT(status == 0); ASSERT(status == 0);
connect_cb_called++; connect_cb_called++;
do { do {
buf = uv_buf_init(zeroes, sizeof(zeroes)); buf = uv_buf_init("PING", 4);
r = uv_try_write((uv_stream_t*) &client, &buf, 1); r = uv_try_write((uv_stream_t*) &client, &buf, 1);
ASSERT(r >= 0); ASSERT(r > 0 || r == UV_EAGAIN);
if (r > 0) {
bytes_written += r; bytes_written += r;
/* Partial write */
if (r != (int) sizeof(zeroes))
break; break;
}
} while (1); } while (1);
uv_close((uv_handle_t*) &client, close_cb); uv_close((uv_handle_t*) &client, close_cb);
} }

137
deps/uv/test/test-tcp-write-queue-order.c

@ -0,0 +1,137 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uv.h"
#include "task.h"
#define REQ_COUNT 100000
static uv_timer_t timer;
static uv_tcp_t server;
static uv_tcp_t client;
static uv_tcp_t incoming;
static int connect_cb_called;
static int close_cb_called;
static int connection_cb_called;
static int write_callbacks;
static int write_cancelled_callbacks;
static int write_error_callbacks;
static uv_write_t write_requests[REQ_COUNT];
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
void timer_cb(uv_timer_t* handle) {
uv_close((uv_handle_t*) &client, close_cb);
uv_close((uv_handle_t*) &server, close_cb);
uv_close((uv_handle_t*) &incoming, close_cb);
}
void write_cb(uv_write_t* req, int status) {
if (status == 0)
write_callbacks++;
else if (status == UV_ECANCELED)
write_cancelled_callbacks++;
else
write_error_callbacks++;
}
static void connect_cb(uv_connect_t* req, int status) {
static char base[1024];
int r;
int i;
uv_buf_t buf;
ASSERT(status == 0);
connect_cb_called++;
buf = uv_buf_init(base, sizeof(base));
for (i = 0; i < REQ_COUNT; i++) {
r = uv_write(&write_requests[i],
req->handle,
&buf,
1,
write_cb);
ASSERT(r == 0);
}
}
static void connection_cb(uv_stream_t* tcp, int status) {
ASSERT(status == 0);
ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
connection_cb_called++;
}
static void start_server(void) {
struct sockaddr_in addr;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
}
TEST_IMPL(tcp_write_queue_order) {
uv_connect_t connect_req;
struct sockaddr_in addr;
start_server();
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
ASSERT(0 == uv_tcp_connect(&connect_req,
&client,
(struct sockaddr*) &addr,
connect_cb));
ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(connect_cb_called == 1);
ASSERT(connection_cb_called == 1);
ASSERT(write_callbacks > 0);
ASSERT(write_cancelled_callbacks > 0);
ASSERT(write_callbacks +
write_error_callbacks +
write_cancelled_callbacks == REQ_COUNT);
ASSERT(close_cb_called == 3);
MAKE_VALGRIND_HAPPY();
return 0;
}

3
deps/uv/test/test-udp-multicast-interface.c

@ -91,6 +91,9 @@ TEST_IMPL(udp_multicast_interface) {
ASSERT(sv_send_cb_called == 1); ASSERT(sv_send_cb_called == 1);
ASSERT(close_cb_called == 1); ASSERT(close_cb_called == 1);
ASSERT(client.send_queue_size == 0);
ASSERT(server.send_queue_size == 0);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }

2
deps/uv/test/test-udp-open.c

@ -159,6 +159,8 @@ TEST_IMPL(udp_open) {
ASSERT(send_cb_called == 1); ASSERT(send_cb_called == 1);
ASSERT(close_cb_called == 1); ASSERT(close_cb_called == 1);
ASSERT(client.send_queue_size == 0);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }

3
deps/uv/test/test-udp-send-and-recv.c

@ -206,6 +206,9 @@ TEST_IMPL(udp_send_and_recv) {
ASSERT(sv_recv_cb_called == 1); ASSERT(sv_recv_cb_called == 1);
ASSERT(close_cb_called == 2); ASSERT(close_cb_called == 2);
ASSERT(client.send_queue_size == 0);
ASSERT(server.send_queue_size == 0);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }

148
deps/uv/test/test-udp-send-immediate.c

@ -0,0 +1,148 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
static uv_udp_t server;
static uv_udp_t client;
static int cl_send_cb_called;
static int sv_recv_cb_called;
static int close_cb_called;
static void alloc_cb(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
static char slab[65536];
CHECK_HANDLE(handle);
ASSERT(suggested_size <= sizeof(slab));
buf->base = slab;
buf->len = sizeof(slab);
}
static void close_cb(uv_handle_t* handle) {
CHECK_HANDLE(handle);
ASSERT(1 == uv_is_closing(handle));
close_cb_called++;
}
static void cl_send_cb(uv_udp_send_t* req, int status) {
ASSERT(req != NULL);
ASSERT(status == 0);
CHECK_HANDLE(req->handle);
cl_send_cb_called++;
}
static void sv_recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* rcvbuf,
const struct sockaddr* addr,
unsigned flags) {
if (nread < 0) {
ASSERT(0 && "unexpected error");
}
if (nread == 0) {
/* Returning unused buffer */
/* Don't count towards sv_recv_cb_called */
ASSERT(addr == NULL);
return;
}
CHECK_HANDLE(handle);
ASSERT(flags == 0);
ASSERT(addr != NULL);
ASSERT(nread == 4);
ASSERT(memcmp("PING", rcvbuf->base, nread) == 0 ||
memcmp("PANG", rcvbuf->base, nread) == 0);
if (++sv_recv_cb_called == 2) {
uv_close((uv_handle_t*) &server, close_cb);
uv_close((uv_handle_t*) &client, close_cb);
}
}
TEST_IMPL(udp_send_immediate) {
struct sockaddr_in addr;
uv_udp_send_t req1, req2;
uv_buf_t buf;
int r;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
ASSERT(r == 0);
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &client);
ASSERT(r == 0);
/* client sends "PING", then "PANG" */
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req1,
&client,
&buf,
1,
(const struct sockaddr*) &addr,
cl_send_cb);
ASSERT(r == 0);
buf = uv_buf_init("PANG", 4);
r = uv_udp_send(&req2,
&client,
&buf,
1,
(const struct sockaddr*) &addr,
cl_send_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(cl_send_cb_called == 2);
ASSERT(sv_recv_cb_called == 2);
ASSERT(close_cb_called == 2);
MAKE_VALGRIND_HAPPY();
return 0;
}

133
deps/uv/test/test-udp-try-send.c

@ -0,0 +1,133 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
TEST_IMPL(udp_try_send) {
MAKE_VALGRIND_HAPPY();
return 0;
}
#else /* !_WIN32 */
#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
static uv_udp_t server;
static uv_udp_t client;
static int sv_recv_cb_called;
static int close_cb_called;
static void alloc_cb(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
static char slab[65536];
CHECK_HANDLE(handle);
ASSERT(suggested_size <= sizeof(slab));
buf->base = slab;
buf->len = sizeof(slab);
}
static void close_cb(uv_handle_t* handle) {
CHECK_HANDLE(handle);
ASSERT(uv_is_closing(handle));
close_cb_called++;
}
static void sv_recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* rcvbuf,
const struct sockaddr* addr,
unsigned flags) {
ASSERT(nread > 0);
if (nread == 0) {
ASSERT(addr == NULL);
return;
}
ASSERT(nread == 4);
ASSERT(addr != NULL);
ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0);
uv_close((uv_handle_t*) handle, close_cb);
uv_close((uv_handle_t*) &client, close_cb);
sv_recv_cb_called++;
}
TEST_IMPL(udp_try_send) {
struct sockaddr_in addr;
static char buffer[64 * 1024];
uv_buf_t buf;
int r;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
ASSERT(r == 0);
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &client);
ASSERT(r == 0);
buf = uv_buf_init(buffer, sizeof(buffer));
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
ASSERT(r == UV_EMSGSIZE);
buf = uv_buf_init("EXIT", 4);
r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
ASSERT(r == 4);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(close_cb_called == 2);
ASSERT(sv_recv_cb_called == 1);
ASSERT(client.send_queue_size == 0);
ASSERT(server.send_queue_size == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */

2
deps/uv/test/test-watcher-cross-stop.c

@ -91,7 +91,7 @@ TEST_IMPL(watcher_cross_stop) {
for (i = 0; i < ARRAY_SIZE(sockets); i++) for (i = 0; i < ARRAY_SIZE(sockets); i++)
uv_close((uv_handle_t*) &sockets[i], close_cb); uv_close((uv_handle_t*) &sockets[i], close_cb);
ASSERT(0 < recv_cb_called && recv_cb_called <= ARRAY_SIZE(sockets)); ASSERT(recv_cb_called > 0);
ASSERT(ARRAY_SIZE(sockets) == send_cb_called); ASSERT(ARRAY_SIZE(sockets) == send_cb_called);
uv_run(loop, UV_RUN_DEFAULT); uv_run(loop, UV_RUN_DEFAULT);

23
deps/uv/uv.gyp

@ -61,11 +61,13 @@
'include/uv.h', 'include/uv.h',
'include/tree.h', 'include/tree.h',
'include/uv-errno.h', 'include/uv-errno.h',
'include/uv-threadpool.h',
'include/uv-version.h', 'include/uv-version.h',
'src/fs-poll.c', 'src/fs-poll.c',
'src/heap-inl.h', 'src/heap-inl.h',
'src/inet.c', 'src/inet.c',
'src/queue.h', 'src/queue.h',
'src/threadpool.c',
'src/uv-common.c', 'src/uv-common.c',
'src/uv-common.h', 'src/uv-common.h',
'src/version.c' 'src/version.c'
@ -103,7 +105,6 @@
'src/win/stream-inl.h', 'src/win/stream-inl.h',
'src/win/tcp.c', 'src/win/tcp.c',
'src/win/tty.c', 'src/win/tty.c',
'src/win/threadpool.c',
'src/win/timer.c', 'src/win/timer.c',
'src/win/udp.c', 'src/win/udp.c',
'src/win/util.c', 'src/win/util.c',
@ -114,11 +115,11 @@
], ],
'link_settings': { 'link_settings': {
'libraries': [ 'libraries': [
'-ladvapi32.lib', '-ladvapi32',
'-liphlpapi.lib', '-liphlpapi',
'-lpsapi.lib', '-lpsapi',
'-lshell32.lib', '-lshell32',
'-lws2_32.lib' '-lws2_32'
], ],
}, },
}, { # Not Windows i.e. POSIX }, { # Not Windows i.e. POSIX
@ -136,6 +137,7 @@
'include/uv-sunos.h', 'include/uv-sunos.h',
'include/uv-darwin.h', 'include/uv-darwin.h',
'include/uv-bsd.h', 'include/uv-bsd.h',
'include/uv-aix.h',
'src/unix/async.c', 'src/unix/async.c',
'src/unix/atomic-ops.h', 'src/unix/atomic-ops.h',
'src/unix/core.c', 'src/unix/core.c',
@ -154,7 +156,6 @@
'src/unix/stream.c', 'src/unix/stream.c',
'src/unix/tcp.c', 'src/unix/tcp.c',
'src/unix/thread.c', 'src/unix/thread.c',
'src/unix/threadpool.c',
'src/unix/timer.c', 'src/unix/timer.c',
'src/unix/tty.c', 'src/unix/tty.c',
'src/unix/udp.c', 'src/unix/udp.c',
@ -245,6 +246,7 @@
'defines': [ 'defines': [
'_ALL_SOURCE', '_ALL_SOURCE',
'_XOPEN_SOURCE=500', '_XOPEN_SOURCE=500',
'_LINUX_SOURCE_COMPAT',
], ],
'link_settings': { 'link_settings': {
'libraries': [ 'libraries': [
@ -378,6 +380,7 @@
'test/test-tcp-try-write.c', 'test/test-tcp-try-write.c',
'test/test-tcp-unexpected-read.c', 'test/test-tcp-unexpected-read.c',
'test/test-tcp-read-stop.c', 'test/test-tcp-read-stop.c',
'test/test-tcp-write-queue-order.c',
'test/test-threadpool.c', 'test/test-threadpool.c',
'test/test-threadpool-cancel.c', 'test/test-threadpool-cancel.c',
'test/test-mutexes.c', 'test/test-mutexes.c',
@ -394,6 +397,7 @@
'test/test-udp-open.c', 'test/test-udp-open.c',
'test/test-udp-options.c', 'test/test-udp-options.c',
'test/test-udp-send-and-recv.c', 'test/test-udp-send-and-recv.c',
'test/test-udp-send-immediate.c',
'test/test-udp-multicast-join.c', 'test/test-udp-multicast-join.c',
'test/test-udp-multicast-join6.c', 'test/test-udp-multicast-join6.c',
'test/test-dlerror.c', 'test/test-dlerror.c',
@ -402,6 +406,7 @@
'test/test-ip6-addr.c', 'test/test-ip6-addr.c',
'test/test-udp-multicast-interface.c', 'test/test-udp-multicast-interface.c',
'test/test-udp-multicast-interface6.c', 'test/test-udp-multicast-interface6.c',
'test/test-udp-try-send.c',
], ],
'conditions': [ 'conditions': [
[ 'OS=="win"', { [ 'OS=="win"', {
@ -409,7 +414,7 @@
'test/runner-win.c', 'test/runner-win.c',
'test/runner-win.h' 'test/runner-win.h'
], ],
'libraries': [ 'ws2_32.lib' ] 'libraries': [ '-lws2_32' ]
}, { # POSIX }, { # POSIX
'defines': [ '_GNU_SOURCE' ], 'defines': [ '_GNU_SOURCE' ],
'sources': [ 'sources': [
@ -473,7 +478,7 @@
'test/runner-win.c', 'test/runner-win.c',
'test/runner-win.h', 'test/runner-win.h',
], ],
'libraries': [ 'ws2_32.lib' ] 'libraries': [ '-lws2_32' ]
}, { # POSIX }, { # POSIX
'defines': [ '_GNU_SOURCE' ], 'defines': [ '_GNU_SOURCE' ],
'sources': [ 'sources': [

Loading…
Cancel
Save