Skip to content

Instantly share code, notes, and snippets.

@retep998
Created July 3, 2014 18:08
Show Gist options
  • Save retep998/3a3142bbe92f33a78165 to your computer and use it in GitHub Desktop.
Save retep998/3a3142bbe92f33a78165 to your computer and use it in GitHub Desktop.
libuv changes
diff --git a/.mailmap b/.mailmap
index 7d627a3..89c1ade 100644
--- a/.mailmap
+++ b/.mailmap
@@ -10,10 +10,12 @@ Fedor Indutny <[email protected]> <[email protected]>
Frank Denis <[email protected]>
Isaac Z. Schlueter <[email protected]>
Justin Venus <[email protected]> <[email protected]>
-Keno Fischer <[email protected]> <[email protected]>
Keno Fischer <[email protected]> <[email protected]>
+Keno Fischer <[email protected]> <[email protected]>
Maciej Małecki <[email protected]> <[email protected]>
Marc Schlaich <[email protected]> <[email protected]>
+Rasmus Christian Pedersen <[email protected]>
+Rasmus Christian Pedersen <[email protected]> <[email protected]>
Rasmus Pedersen <[email protected]> <[email protected]>
Robert Mustacchi <[email protected]> <[email protected]>
Ryan Dahl <[email protected]> <[email protected]>
diff --git a/AUTHORS b/AUTHORS
index eea91d8..e3de576 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -137,3 +137,12 @@ Javier Hernández <[email protected]>
Tonis Tiigi <[email protected]>
Norio Kobota <[email protected]>
李港平 <[email protected]>
+Chernyshev Viacheslav <[email protected]>
+Stephen von Takach <[email protected]>
+JD Ballard <[email protected]>
+Luka Perkov <[email protected]>
+Ryan Cole <[email protected]>
+HungMingWu <[email protected]>
+Jay Satiro <[email protected]>
+Leith Bade <[email protected]>
+Peter Atashian <[email protected]>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 960a945..28a32ba 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -142,11 +142,8 @@ Bug fixes and features should come with tests. Add your tests in the
Look at other tests to see how they should be structured (license boilerplate,
the way entry points are declared, etc.).
-```
-$ make test
-```
-
-Make sure that there are no test regressions.
+Check README.md file to find out how to run the test suite and make sure that
+there are no test regressions.
### PUSH
@@ -163,15 +160,7 @@ feature branch. Post a comment in the pull request afterwards; GitHub does
not send out notifications when you add commits.
-### CONTRIBUTOR LICENSE AGREEMENT
-
-The current state of affairs is that, in order to get a patch accepted, you need
-to sign Node.js's [contributor license agreement][]. You only need to do that
-once.
-
-
[issue tracker]: https://github.com/joyent/libuv/issues
[libuv mailing list]: http://groups.google.com/group/libuv
[IRC]: http://webchat.freelibuv.net/?channels=libuv
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
-[contributor license agreement]: http://nodejs.org/cla.html
diff --git a/ChangeLog b/ChangeLog
index aa1581b..cb900f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,59 @@
+2014.06.28, Version 0.11.26 (Unstable), 115281a1058c4034d5c5ccedacb667fe3f6327ea
+
+Changes since version 0.11.25:
+
+* windows: add VT100 codes ?25l and ?25h (JD Ballard)
+
+* windows: add invert ANSI (7 / 27) emulation (JD Ballard)
+
+* unix: fix handling error on UDP socket creation (Saúl Ibarra Corretgé)
+
+* unix, windows: getnameinfo implementation (Rasmus Pedersen)
+
+* heap: fix `heap_remove()` (Fedor Indutny)
+
+* unix, windows: fix parsing scoped IPv6 addresses (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* thread: barrier functions (Ben Noordhuis)
+
+* windows: fix PYTHON environment variable usage (Jay Satiro)
+
+* unix, windows: return system error on EAI_SYSTEM (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* unix: don't run i/o callbacks after prepare callbacks (Saúl Ibarra Corretgé)
+
+* windows: add tty unicode support for input (Peter Atashian)
+
+* header: introduce `uv_loop_size()` (Andrius Bentkus)
+
+* darwin: invoke `mach_timebase_info` only once (Fedor Indutny)
+
+
+2014.05.02, Version 0.11.25 (Unstable), 2acd544cff7142e06aa3b09ec64b4a33dd9ab996
+
+Changes since version 0.11.24:
+
+* osx: pass const handle pointer to uv___stream_fd (Chernyshev Viacheslav)
+
+* unix, windows: pass const handle ptr to uv_tcp_get*name (Chernyshev
+ Viacheslav)
+
+* common: pass const sockaddr ptr to uv_ip*_name (Chernyshev Viacheslav)
+
+* unix, windows: validate flags on uv_udp|tcp_bind (Saúl Ibarra Corretgé)
+
+* unix: handle case when addr is not initialized after recvmsg (Saúl Ibarra
+ Corretgé)
+
+* unix, windows: uv_now constness (Rasmus Pedersen)
+
+
2014.04.15, Version 0.11.24 (Unstable), ed948c29f6e8c290f79325a6f0bc9ef35bcde644
Changes since version 0.11.23:
@@ -14,8 +70,6 @@ Changes since version 0.11.23:
* inet: allow scopeid in uv_inet_pton (Fedor Indutny)
-* win: always leave crit section in get_proc_title (Fedor Indutny)
-
2014.04.07, Version 0.11.23 (Unstable), e54de537efcacd593f36fcaaf8b4cb9e64313275
@@ -58,25 +112,6 @@ Changes since version 0.11.22:
* unix: fix setting written size on uv_wd (Saúl Ibarra Corretgé)
-2014.04.07, Version 0.10.26 (Stable), d864907611c25ec986c5e77d4d6d6dee88f26926
-
-Changes since version 0.10.25:
-
-* process: don't close stdio fds during spawn (Tonis Tiigi)
-
-* build, windows: do not fail on Windows SDK Prompt (Marc Schlaich)
-
-* build, windows: fix x64 configuration issue (Marc Schlaich)
-
-* win: fix buffer leak on error in pipe.c (Fedor Indutny)
-
-* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
-
-* linux: always deregister closing fds from epoll (Geoffry Song)
-
-* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
-
-
2014.03.11, Version 0.11.22 (Unstable), cd0c19b1d3c56acf0ade7687006e12e75fbda36d
Changes since version 0.11.21:
@@ -206,6 +241,34 @@ Changes since version 0.11.18:
* linux: fix C99/C++ comment (Fedor Indutny)
+2014.05.02, Version 0.10.27 (Stable), 6e24ce23b1e7576059f85a608eca13b766458a01
+
+Changes since version 0.10.26:
+
+* windows: fix console signal handler refcount (Saúl Ibarra Corretgé)
+
+* win: always leave crit section in get_proc_title (Fedor Indutny)
+
+
+2014.04.07, Version 0.10.26 (Stable), d864907611c25ec986c5e77d4d6d6dee88f26926
+
+Changes since version 0.10.25:
+
+* process: don't close stdio fds during spawn (Tonis Tiigi)
+
+* build, windows: do not fail on Windows SDK Prompt (Marc Schlaich)
+
+* build, windows: fix x64 configuration issue (Marc Schlaich)
+
+* win: fix buffer leak on error in pipe.c (Fedor Indutny)
+
+* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
+
+
2014.02.19, Version 0.10.25 (Stable), d778dc588507588b12b9f9d2905078db542ed751
Changes since version 0.10.24:
diff --git a/Makefile.am b/Makefile.am
index 41833c9..25c8714 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,7 +17,7 @@ ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -I$(top_srcdir)/include \
-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 =
@@ -28,6 +28,7 @@ libuv_la_SOURCES = src/fs-poll.c \
src/heap-inl.h \
src/inet.c \
src/queue.h \
+ src/threadpool.c \
src/uv-common.c \
src/uv-common.h \
src/version.c
@@ -51,6 +52,7 @@ libuv_la_SOURCES += src/win/async.c \
src/win/fs-event.c \
src/win/fs.c \
src/win/getaddrinfo.c \
+ src/win/getnameinfo.c \
src/win/handle.c \
src/win/handle-inl.h \
src/win/internal.h \
@@ -66,7 +68,6 @@ libuv_la_SOURCES += src/win/async.c \
src/win/stream-inl.h \
src/win/tcp.c \
src/win/thread.c \
- src/win/threadpool.c \
src/win/timer.c \
src/win/tty.c \
src/win/udp.c \
@@ -86,6 +87,7 @@ libuv_la_SOURCES += src/unix/async.c \
src/unix/dl.c \
src/unix/fs.c \
src/unix/getaddrinfo.c \
+ src/unix/getnameinfo.c \
src/unix/internal.h \
src/unix/loop-watcher.c \
src/unix/loop.c \
@@ -97,7 +99,6 @@ libuv_la_SOURCES += src/unix/async.c \
src/unix/stream.c \
src/unix/tcp.c \
src/unix/thread.c \
- src/unix/threadpool.c \
src/unix/timer.c \
src/unix/tty.c \
src/unix/udp.c
@@ -138,6 +139,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-get-loadavg.c \
test/test-get-memory.c \
test/test-getaddrinfo.c \
+ test/test-getnameinfo.c \
test/test-getsockname.c \
test/test-hrtime.c \
test/test-idle.c \
@@ -163,6 +165,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-pipe-server-close.c \
test/test-platform-output.c \
test/test-poll-close.c \
+ test/test-poll-closesocket.c \
test/test-poll.c \
test/test-process-title.c \
test/test-ref.c \
@@ -238,8 +241,10 @@ libuv_la_SOURCES += src/unix/aix.c
endif
if ANDROID
-include_HEADERS += include/android-ifaddrs.h
-libuv_la_SOURCES += src/unix/android-ifaddrs.c
+include_HEADERS += include/android-ifaddrs.h \
+ include/pthread-fixes.h
+libuv_la_SOURCES += src/unix/android-ifaddrs.c \
+ src/unix/pthread-fixes.c
endif
if DARWIN
diff --git a/Makefile.mingw b/Makefile.mingw
index af84c75..156f15d 100644
--- a/Makefile.mingw
+++ b/Makefile.mingw
@@ -26,6 +26,7 @@ CFLAGS += -Wall \
INCLUDES = include/stdint-msvc2008.h \
include/tree.h \
include/uv-errno.h \
+ include/uv-threadpool.h \
include/uv-version.h \
include/uv-win.h \
include/uv.h \
@@ -42,6 +43,7 @@ INCLUDES = include/stdint-msvc2008.h \
OBJS = src/fs-poll.o \
src/inet.o \
+ src/threadpool.o \
src/uv-common.o \
src/version.o \
src/win/async.o \
@@ -51,6 +53,7 @@ OBJS = src/fs-poll.o \
src/win/fs-event.o \
src/win/fs.o \
src/win/getaddrinfo.o \
+ src/win/getnameinfo.o \
src/win/handle.o \
src/win/loop-watcher.o \
src/win/pipe.o \
@@ -62,7 +65,6 @@ OBJS = src/fs-poll.o \
src/win/stream.o \
src/win/tcp.o \
src/win/thread.o \
- src/win/threadpool.o \
src/win/timer.o \
src/win/tty.o \
src/win/udp.o \
diff --git a/README.md b/README.md
index 00b539c..e0e7359 100644
--- a/README.md
+++ b/README.md
@@ -66,10 +66,9 @@ To build with autotools:
### Windows
-First, Python 2.6 or 2.7 must be installed as it is required by [GYP][].
-
-Also, the directory for the preferred Python executable must be specified
-by the `PYTHON` or `Path` environment variables.
+First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][].
+If python is not in your path set the environment variable `PYTHON` to its
+location. For example: `set PYTHON=C:\Python27\python.exe`
To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell)
and run vcbuild.bat which will checkout the GYP code into build/gyp and
@@ -139,5 +138,6 @@ See the [guidelines for contributing][].
[node.js]: http://nodejs.org/
[GYP]: http://code.google.com/p/gyp/
+[Python]: https://www.python.org/downloads/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md
diff --git a/configure.ac b/configure.ac
index 078c717..35ef2c4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
-AC_INIT([libuv], [0.11.25], [https://github.com/joyent/libuv/issues])
+AC_INIT([libuv], [0.11.27], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
diff --git a/include/uv-bsd.h b/include/uv-bsd.h
index 3458d5d..2d72b3d 100644
--- a/include/uv-bsd.h
+++ b/include/uv-bsd.h
@@ -31,6 +31,4 @@
#define UV_HAVE_KQUEUE 1
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_BSD_H */
diff --git a/include/uv-darwin.h b/include/uv-darwin.h
index 24bc35b..d226415 100644
--- a/include/uv-darwin.h
+++ b/include/uv-darwin.h
@@ -58,6 +58,4 @@
#define UV_HAVE_KQUEUE 1
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_DARWIN_H */
diff --git a/include/uv-errno.h b/include/uv-errno.h
index 0981834..00b4860 100644
--- a/include/uv-errno.h
+++ b/include/uv-errno.h
@@ -39,7 +39,6 @@
#define UV__EAI_OVERFLOW (-3009)
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
-#define UV__EAI_SYSTEM (-3012) /* TODO(bnoordhuis) Return system error. */
#define UV__EAI_BADHINTS (-3013)
#define UV__EAI_PROTOCOL (-3014)
diff --git a/include/uv-linux.h b/include/uv-linux.h
index 62ebfe2..9b38405 100644
--- a/include/uv-linux.h
+++ b/include/uv-linux.h
@@ -31,6 +31,4 @@
void* watchers[2]; \
int wd; \
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_LINUX_H */
diff --git a/include/uv-sunos.h b/include/uv-sunos.h
index c4cd83d..0421664 100644
--- a/include/uv-sunos.h
+++ b/include/uv-sunos.h
@@ -41,6 +41,4 @@
#endif /* defined(PORT_SOURCE_FILE) */
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_SUNOS_H */
diff --git a/include/uv-threadpool.h b/include/uv-threadpool.h
new file mode 100644
index 0000000..9708ebd
--- /dev/null
+++ b/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_ */
diff --git a/include/uv-unix.h b/include/uv-unix.h
index 40c4989..f58bd50 100644
--- a/include/uv-unix.h
+++ b/include/uv-unix.h
@@ -42,6 +42,8 @@
#endif
#include <signal.h>
+#include "uv-threadpool.h"
+
#if defined(__linux__)
# include "uv-linux.h"
#elif defined(__sun)
@@ -55,6 +57,14 @@
# include "uv-bsd.h"
#endif
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
#endif
@@ -88,13 +98,6 @@ struct uv__async {
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
# define UV_PLATFORM_SEM_T sem_t
#endif
@@ -281,6 +284,15 @@ typedef struct {
struct addrinfo* res; \
int retcode;
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
#define UV_PROCESS_PRIVATE_FIELDS \
void* queue[2]; \
int status; \
diff --git a/include/uv-version.h b/include/uv-version.h
index 3deadbf..0045e73 100644
--- a/include/uv-version.h
+++ b/include/uv-version.h
@@ -32,7 +32,7 @@
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
-#define UV_VERSION_PATCH 25
+#define UV_VERSION_PATCH 27
#define UV_VERSION_IS_RELEASE 0
#endif /* UV_VERSION_H */
diff --git a/include/uv-win.h b/include/uv-win.h
index 211c593..23b4232 100644
--- a/include/uv-win.h
+++ b/include/uv-win.h
@@ -45,6 +45,7 @@ typedef intptr_t ssize_t;
#endif
#include "tree.h"
+#include "uv-threadpool.h"
#define MAX_PIPENAME_LEN 256
@@ -307,7 +308,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams; \
/* 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 \
/* TODO: remove the req suffix */ \
@@ -520,6 +525,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
unsigned int flags;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
uv_getaddrinfo_cb getaddrinfo_cb; \
void* alloc; \
WCHAR* node; \
@@ -528,6 +534,15 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
struct addrinfoW* res; \
int retcode;
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
#define UV_PROCESS_PRIVATE_FIELDS \
struct uv_process_exit_s { \
UV_REQ_FIELDS \
@@ -539,6 +554,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
volatile char exit_cb_pending;
#define UV_FS_PRIVATE_FIELDS \
+ struct uv__work work_req; \
int flags; \
DWORD sys_errno_; \
union { \
@@ -564,6 +580,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
};
#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
#define UV_FS_EVENT_PRIVATE_FIELDS \
struct uv_fs_event_req_s { \
@@ -587,4 +604,3 @@ int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size);
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
diff --git a/include/uv.h b/include/uv.h
index 130b630..d3dcff4 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -83,7 +83,6 @@ extern "C" {
XX(EAI_PROTOCOL, "resolved protocol is unknown") \
XX(EAI_SERVICE, "service not available for socket type") \
XX(EAI_SOCKTYPE, "socket type not supported") \
- XX(EAI_SYSTEM, "system error") \
XX(EALREADY, "connection already in progress") \
XX(EBADF, "bad file descriptor") \
XX(EBUSY, "resource busy or locked") \
@@ -167,6 +166,7 @@ extern "C" {
XX(FS, fs) \
XX(WORK, work) \
XX(GETADDRINFO, getaddrinfo) \
+ XX(GETNAMEINFO, getnameinfo) \
typedef enum {
#define XX(code, _) UV_ ## code = UV__ ## code,
@@ -216,6 +216,7 @@ typedef struct uv_signal_s uv_signal_t;
/* Request types. */
typedef struct uv_req_s uv_req_t;
typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
+typedef struct uv_getnameinfo_s uv_getnameinfo_t;
typedef struct uv_shutdown_s uv_shutdown_t;
typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
@@ -288,6 +289,11 @@ UV_EXTERN uv_loop_t* uv_loop_new(void);
UV_EXTERN void uv_loop_delete(uv_loop_t*);
/*
+ * Returns size of the loop struct, useful for dynamic lookup with FFI
+ */
+UV_EXTERN size_t uv_loop_size(void);
+
+/*
* This function runs the event loop. It will act differently depending on the
* specified mode:
* - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to
@@ -297,7 +303,9 @@ UV_EXTERN void uv_loop_delete(uv_loop_t*);
* or requests left), or non-zero if more events are expected (meaning you
* should run the event loop again sometime in the future).
* - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no
- * pending events.
+ * pending events. Returns zero when done (no active handles
+ * or requests left), or non-zero if more events are expected (meaning you
+ * should run the event loop again sometime in the future).
*/
UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
@@ -345,7 +353,7 @@ UV_EXTERN void uv_update_time(uv_loop_t*);
*
* Use uv_hrtime() if you need sub-millisecond granularity.
*/
-UV_EXTERN uint64_t uv_now(uv_loop_t*);
+UV_EXTERN uint64_t uv_now(const uv_loop_t*);
/*
* Get backend file descriptor. Only kqueue, epoll and event ports are
@@ -419,6 +427,10 @@ typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
int status,
struct addrinfo* res);
+typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service);
typedef struct {
long tv_sec;
@@ -695,9 +707,8 @@ UV_EXTERN int uv_write2(uv_write_t* req,
* Same as `uv_write()`, but won't queue write request if it can't be completed
* immediately.
* Will return either:
- * - positive number of bytes written
- * - zero - if queued write is needed
- * - negative error code
+ * - >= 0: number of bytes written (can be less than the supplied buffer size)
+ * - < 0: negative error code
*/
UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[],
@@ -875,8 +886,8 @@ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
* discard or repurpose the read buffer.
* < 0 if a transmission error was detected.
* buf uv_buf_t with the received data.
- * addr struct sockaddr_in or struct sockaddr_in6.
- * Valid for the duration of the callback only.
+ * addr struct sockaddr* containing the address of the sender.
+ * Can be NULL. Valid for the duration of the callback only.
* flags One or more OR'ed UV_UDP_* constants.
* Right now only UV_UDP_PARTIAL is used.
*/
@@ -1216,10 +1227,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
* 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
- * recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is
- * much faster and more scalable than what can be achieved with uv_poll_t,
- * especially on Windows.
+ * c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended;
+ * uv_tcp_t, uv_udp_t, etc. provide an implementation that is much faster and
+ * more scalable than what can be achieved with uv_poll_t, especially on
+ * Windows.
*
* 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
@@ -1452,6 +1463,33 @@ UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop,
UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
+/*
+* uv_getnameinfo_t is a subclass of uv_req_t
+*
+* Request object for uv_getnameinfo.
+*/
+struct uv_getnameinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ UV_GETNAMEINFO_PRIVATE_FIELDS
+};
+
+/*
+ * Asynchronous getnameinfo.
+ *
+ * Returns 0 on success or an error code < 0 on failure.
+ *
+ * If successful, your callback gets called sometime in the future with the
+ * lookup result.
+ */
+UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags);
+
+
/* uv_spawn() options */
typedef enum {
UV_IGNORE = 0x00,
@@ -2125,7 +2163,7 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
/*
* Returns the last uv_dlopen() or uv_dlsym() error message.
*/
-UV_EXTERN const char* uv_dlerror(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
@@ -2165,6 +2203,19 @@ UV_EXTERN int uv_cond_init(uv_cond_t* cond);
UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
+
+/*
+ * Same goes for the barrier functions. Note that uv_barrier_wait() returns
+ * a value > 0 to an arbitrarily chosen "serializer" thread to facilitate
+ * cleanup, i.e.:
+ *
+ * if (uv_barrier_wait(&barrier) > 0)
+ * uv_barrier_destroy(&barrier);
+ */
+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 int uv_barrier_wait(uv_barrier_t* barrier);
+
/* Waits on a condition variable without a timeout.
*
* Note:
@@ -2183,10 +2234,6 @@ UV_EXTERN void uv_cond_wait(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);
-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_wait(uv_barrier_t* barrier);
-
/* 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).
* The guard should be initialized statically with the UV_ONCE_INIT macro.
@@ -2205,8 +2252,14 @@ UV_EXTERN void uv_key_delete(uv_key_t* key);
UV_EXTERN void* uv_key_get(uv_key_t* key);
UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
-UV_EXTERN int uv_thread_create(uv_thread_t *tid,
- void (*entry)(void *arg), void *arg);
+/*
+ * Callback that is invoked to initialize thread execution.
+ *
+ * `arg` is the same value that was passed to uv_thread_create().
+ */
+typedef void (*uv_thread_cb)(void* arg);
+
+UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
UV_EXTERN unsigned long uv_thread_self(void);
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
@@ -2247,6 +2300,7 @@ struct uv_loop_s {
#undef UV_ASYNC_PRIVATE_FIELDS
#undef UV_TIMER_PRIVATE_FIELDS
#undef UV_GETADDRINFO_PRIVATE_FIELDS
+#undef UV_GETNAMEINFO_PRIVATE_FIELDS
#undef UV_FS_REQ_PRIVATE_FIELDS
#undef UV_WORK_PRIVATE_FIELDS
#undef UV_FS_EVENT_PRIVATE_FIELDS
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 907abe6..1e2ed60 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -227,6 +227,13 @@ HEAP_EXPORT(void heap_remove(struct heap* heap,
break;
heap_node_swap(heap, child, smallest);
}
+
+ /* Walk up the subtree and check that each parent is less than the node
+ * this is required, because `max` node is not guaranteed to be the
+ * actual maximum in tree
+ */
+ while (child->parent != NULL && less_than(child, child->parent))
+ heap_node_swap(heap, child->parent, child);
}
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
diff --git a/src/inet.c b/src/inet.c
index 9220de6..c948b2e 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -27,6 +27,9 @@
#include "uv.h"
#include "uv-common.h"
+#define UV__INET_ADDRSTRLEN 16
+#define UV__INET6_ADDRSTRLEN 46
+
static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
@@ -49,7 +52,7 @@ int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
static const char fmt[] = "%u.%u.%u.%u";
- char tmp[sizeof "255.255.255.255"];
+ char tmp[UV__INET_ADDRSTRLEN];
int l;
#ifndef _WIN32
@@ -74,7 +77,7 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
- char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ char tmp[UV__INET6_ADDRSTRLEN], *tp;
struct { int base, len; } best, cur;
unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
int i;
@@ -156,11 +159,27 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
int uv_inet_pton(int af, const char* src, void* dst) {
+ if (src == NULL || dst == NULL)
+ return UV_EINVAL;
+
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
- case AF_INET6:
- return (inet_pton6(src, dst));
+ case AF_INET6: {
+ int len;
+ char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
+ s = (char*) src;
+ p = strchr(src, '%');
+ if (p != NULL) {
+ s = tmp;
+ len = p - src;
+ if (len > UV__INET6_ADDRSTRLEN-1)
+ return UV_EINVAL;
+ memcpy(s, src, len);
+ s[len] = '\0';
+ }
+ return inet_pton6(s, dst);
+ }
default:
return UV_EAFNOSUPPORT;
}
@@ -225,7 +244,7 @@ static int inet_pton6(const char *src, unsigned char *dst) {
curtok = src;
seen_xdigits = 0;
val = 0;
- while ((ch = *src++) != '\0' && ch != '%') {
+ while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
@@ -256,19 +275,7 @@ static int inet_pton6(const char *src, unsigned char *dst) {
continue;
}
if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
- int err;
-
- /* Scope id present, parse ipv4 addr without it */
- pch = strchr(curtok, '%');
- if (pch != NULL) {
- char tmp[sizeof "255.255.255.255"];
-
- memcpy(tmp, curtok, pch - curtok);
- curtok = tmp;
- src = pch;
- }
-
- err = inet_pton4(curtok, tp);
+ int err = inet_pton4(curtok, tp);
if (err == 0) {
tp += sizeof(struct in_addr);
seen_xdigits = 0;
diff --git a/src/threadpool.c b/src/threadpool.c
new file mode 100644
index 0000000..fd1cab5
--- /dev/null
+++ b/src/threadpool.c
@@ -0,0 +1,302 @@
+/* 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-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>
+
+#define MAX_THREADPOOL_SIZE 128
+
+static uv_once_t once = UV_ONCE_INIT;
+static uv_cond_t cond;
+static uv_mutex_t mutex;
+static unsigned int nthreads;
+static uv_thread_t* threads;
+static uv_thread_t default_threads[4];
+static QUEUE exit_message;
+static QUEUE wq;
+static volatile int initialized;
+
+
+static void uv__cancelled(struct uv__work* w) {
+ abort();
+}
+
+
+/* To avoid deadlock with uv_cancel() it's crucial that the worker
+ * never holds the global mutex and the loop-local mutex at the same time.
+ */
+static void worker(void* arg) {
+ struct uv__work* w;
+ QUEUE* q;
+
+ (void) arg;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+
+ while (QUEUE_EMPTY(&wq))
+ uv_cond_wait(&cond, &mutex);
+
+ q = QUEUE_HEAD(&wq);
+
+ if (q == &exit_message)
+ uv_cond_signal(&cond);
+ else {
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
+ executing. */
+ }
+
+ uv_mutex_unlock(&mutex);
+
+ if (q == &exit_message)
+ break;
+
+ w = QUEUE_DATA(q, struct uv__work, wq);
+ w->work(w);
+
+ uv_mutex_lock(&w->loop->wq_mutex);
+ w->work = NULL; /* Signal uv_cancel() that the work req is done
+ executing. */
+ QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
+ uv_async_send(&w->loop->wq_async);
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ }
+}
+
+
+static void post(QUEUE* q) {
+ uv_mutex_lock(&mutex);
+ QUEUE_INSERT_TAIL(&wq, q);
+ uv_cond_signal(&cond);
+ uv_mutex_unlock(&mutex);
+}
+
+
+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;
+}
+
+
+static void init_once(void) {
+ unsigned int i;
+ const char* val;
+
+ nthreads = ARRAY_SIZE(default_threads);
+ val = getenv("UV_THREADPOOL_SIZE");
+ if (val != NULL)
+ nthreads = atoi(val);
+ if (nthreads == 0)
+ nthreads = 1;
+ if (nthreads > MAX_THREADPOOL_SIZE)
+ nthreads = MAX_THREADPOOL_SIZE;
+
+ threads = default_threads;
+ if (nthreads > ARRAY_SIZE(default_threads)) {
+ threads = malloc(nthreads * sizeof(threads[0]));
+ if (threads == NULL) {
+ nthreads = ARRAY_SIZE(default_threads);
+ threads = default_threads;
+ }
+ }
+
+ if (uv_cond_init(&cond))
+ abort();
+
+ if (uv_mutex_init(&mutex))
+ abort();
+
+ QUEUE_INIT(&wq);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_create(threads + i, worker, NULL))
+ abort();
+
+ initialized = 1;
+ atexit(cleanup);
+}
+
+
+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)) {
+ uv_once(&once, init_once);
+ w->loop = loop;
+ w->work = work;
+ w->done = done;
+ post(&w->wq);
+}
+
+
+static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
+ int cancelled;
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_lock(&w->loop->wq_mutex);
+
+ cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
+ if (cancelled)
+ QUEUE_REMOVE(&w->wq);
+
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ uv_mutex_unlock(&mutex);
+
+ if (!cancelled)
+ return UV_EBUSY;
+
+ w->work = uv__cancelled;
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
+ uv_async_send(&loop->wq_async);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ return 0;
+}
+
+
+void uv__work_done(uv_async_t* handle) {
+ struct uv__work* w;
+ uv_loop_t* loop;
+ QUEUE* q;
+ QUEUE wq;
+ int err;
+
+ loop = container_of(handle, uv_loop_t, wq_async);
+ QUEUE_INIT(&wq);
+
+ uv_mutex_lock(&loop->wq_mutex);
+ if (!QUEUE_EMPTY(&loop->wq)) {
+ q = QUEUE_HEAD(&loop->wq);
+ QUEUE_SPLIT(&loop->wq, q, &wq);
+ }
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ while (!QUEUE_EMPTY(&wq)) {
+ q = QUEUE_HEAD(&wq);
+ QUEUE_REMOVE(q);
+
+ w = container_of(q, struct uv__work, wq);
+ err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
+ w->done(w, err);
+ }
+}
+
+
+static void uv__queue_work(struct uv__work* w) {
+ uv_work_t* req = container_of(w, uv_work_t, work_req);
+
+ req->work_cb(req);
+}
+
+
+static void uv__queue_done(struct uv__work* w, int err) {
+ uv_work_t* req;
+
+ req = container_of(w, uv_work_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (req->after_work_cb == NULL)
+ return;
+
+ req->after_work_cb(req, err);
+}
+
+
+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__req_init(loop, req, UV_WORK);
+ req->loop = loop;
+ req->work_cb = work_cb;
+ req->after_work_cb = after_work_cb;
+ uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
+ return 0;
+}
+
+
+int uv_cancel(uv_req_t* req) {
+ struct uv__work* wreq;
+ uv_loop_t* loop;
+
+ switch (req->type) {
+ case UV_FS:
+ loop = ((uv_fs_t*) req)->loop;
+ wreq = &((uv_fs_t*) req)->work_req;
+ break;
+ case UV_GETADDRINFO:
+ loop = ((uv_getaddrinfo_t*) req)->loop;
+ wreq = &((uv_getaddrinfo_t*) req)->work_req;
+ break;
+ case UV_GETNAMEINFO:
+ loop = ((uv_getnameinfo_t*) req)->loop;
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
+ break;
+ case UV_WORK:
+ loop = ((uv_work_t*) req)->loop;
+ wreq = &((uv_work_t*) req)->work_req;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ return uv__work_cancel(loop, req, wreq);
+}
diff --git a/src/unix/async.c b/src/unix/async.c
index 5ef787c..b794ea6 100644
--- a/src/unix/async.c
+++ b/src/unix/async.c
@@ -231,7 +231,7 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
fd = uv__open_cloexec(buf, O_RDWR);
- if (fd != -1) {
+ if (fd >= 0) {
uv__close(pipefd[0]);
uv__close(pipefd[1]);
pipefd[0] = fd;
diff --git a/src/unix/core.c b/src/unix/core.c
index 9680a2d..402bb00 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -283,9 +283,9 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
uv__update_time(loop);
uv__run_timers(loop);
+ uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
- uv__run_pending(loop);
timeout = 0;
if ((mode & UV_RUN_NOWAIT) == 0)
diff --git a/src/unix/darwin.c b/src/unix/darwin.c
index bc282e7..c9a45ed 100644
--- a/src/unix/darwin.c
+++ b/src/unix/darwin.c
@@ -53,9 +53,11 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
uint64_t uv__hrtime(uv_clocktype_t type) {
- mach_timebase_info_data_t info;
+ static mach_timebase_info_data_t info;
- if (mach_timebase_info(&info) != KERN_SUCCESS)
+ if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
+ ACCESS_ONCE(uint32_t, info.denom) == 0) &&
+ mach_timebase_info(&info) != KERN_SUCCESS)
abort();
return mach_absolute_time() * info.numer / info.denom;
diff --git a/src/unix/dl.c b/src/unix/dl.c
index cbffe4a..ad45fc8 100644
--- a/src/unix/dl.c
+++ b/src/unix/dl.c
@@ -59,7 +59,7 @@ int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
}
-const char* uv_dlerror(uv_lib_t* lib) {
+const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c
index dcae244..d59e377 100644
--- a/src/unix/freebsd.c
+++ b/src/unix/freebsd.c
@@ -298,7 +298,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
for (i = 0; i < numcpus; i++) {
cpu_info = &(*cpu_infos)[i];
-
+
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c
new file mode 100644
index 0000000..c3fb983
--- /dev/null
+++ b/src/unix/getnameinfo.c
@@ -0,0 +1,114 @@
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ int err;
+ socklen_t salen;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+
+ if (req->storage.ss_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ else if (req->storage.ss_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+ else
+ abort();
+
+ err = getnameinfo((struct sockaddr*) &req->storage,
+ salen,
+ req->host,
+ sizeof(req->host),
+ req->service,
+ sizeof(req->service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || getnameinfo_cb == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+
+ return 0;
+}
diff --git a/src/unix/internal.h b/src/unix/internal.h
index fd29b88..258aadd 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -210,13 +210,6 @@ void uv__signal_close(uv_signal_t* handle);
void uv__signal_global_once_init(void);
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 */
uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop);
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
index 7706417..b4f9f5d 100644
--- a/src/unix/kqueue.c
+++ b/src/unix/kqueue.c
@@ -377,7 +377,7 @@ fallback:
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
uv__handle_stop(handle);
diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c
index 20bc173..2ecc5eb 100644
--- a/src/unix/linux-inotify.c
+++ b/src/unix/linux-inotify.c
@@ -231,7 +231,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
struct watcher_list* w;
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
w = find_watcher(handle->loop, handle->wd);
assert(w != NULL);
diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c
index f052d80..75ba921 100644
--- a/src/unix/openbsd.c
+++ b/src/unix/openbsd.c
@@ -267,7 +267,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
cpu_info = &(*cpu_infos)[i];
-
+
cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
diff --git a/src/unix/stream.c b/src/unix/stream.c
index ac943ec..43334f0 100644
--- a/src/unix/stream.c
+++ b/src/unix/stream.c
@@ -444,6 +444,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
*/
static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
int err;
+ int emfile_fd;
if (loop->emfile_fd == -1)
return -EMFILE;
@@ -457,7 +458,10 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
uv__close(err);
} while (err >= 0 || err == -EINTR);
- SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY));
+ emfile_fd = uv__open_cloexec("/", O_RDONLY);
+ if (emfile_fd >= 0)
+ loop->emfile_fd = emfile_fd;
+
return err;
}
diff --git a/src/unix/sunos.c b/src/unix/sunos.c
index b8a39c7..a630dba 100644
--- a/src/unix/sunos.c
+++ b/src/unix/sunos.c
@@ -431,7 +431,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd,
diff --git a/src/unix/tcp.c b/src/unix/tcp.c
index cd842b0..8c19c1a 100644
--- a/src/unix/tcp.c
+++ b/src/unix/tcp.c
@@ -63,6 +63,10 @@ int uv__tcp_bind(uv_tcp_t* tcp,
int err;
int on;
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
err = maybe_new_socket(tcp,
addr->sa_family,
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
diff --git a/src/unix/thread.c b/src/unix/thread.c
index f2ce082..522426f 100644
--- a/src/unix/thread.c
+++ b/src/unix/thread.c
@@ -399,7 +399,9 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
@@ -411,7 +413,8 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
- if (--barrier->count == 0) {
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
@@ -419,6 +422,7 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
}
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
@@ -434,10 +438,11 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
int r = pthread_barrier_wait(barrier);
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
}
#endif /* defined(__APPLE__) && defined(__MACH__) */
diff --git a/src/unix/threadpool.c b/src/unix/threadpool.c
deleted file mode 100644
index f2eb1cb..0000000
--- a/src/unix/threadpool.c
+++ /dev/null
@@ -1,280 +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 "internal.h"
-#include <stdlib.h>
-
-#define MAX_THREADPOOL_SIZE 128
-
-static uv_once_t once = UV_ONCE_INIT;
-static uv_cond_t cond;
-static uv_mutex_t mutex;
-static unsigned int nthreads;
-static uv_thread_t* threads;
-static uv_thread_t default_threads[4];
-static QUEUE exit_message;
-static QUEUE wq;
-static volatile int initialized;
-
-
-static void uv__cancelled(struct uv__work* w) {
- abort();
-}
-
-
-/* To avoid deadlock with uv_cancel() it's crucial that the worker
- * never holds the global mutex and the loop-local mutex at the same time.
- */
-static void worker(void* arg) {
- struct uv__work* w;
- QUEUE* q;
-
- (void) arg;
-
- for (;;) {
- uv_mutex_lock(&mutex);
-
- while (QUEUE_EMPTY(&wq))
- uv_cond_wait(&cond, &mutex);
-
- q = QUEUE_HEAD(&wq);
-
- if (q == &exit_message)
- uv_cond_signal(&cond);
- else {
- QUEUE_REMOVE(q);
- QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
- executing. */
- }
-
- uv_mutex_unlock(&mutex);
-
- if (q == &exit_message)
- break;
-
- w = QUEUE_DATA(q, struct uv__work, wq);
- w->work(w);
-
- uv_mutex_lock(&w->loop->wq_mutex);
- w->work = NULL; /* Signal uv_cancel() that the work req is done
- executing. */
- QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
- uv_async_send(&w->loop->wq_async);
- uv_mutex_unlock(&w->loop->wq_mutex);
- }
-}
-
-
-static void post(QUEUE* q) {
- uv_mutex_lock(&mutex);
- QUEUE_INSERT_TAIL(&wq, q);
- uv_cond_signal(&cond);
- uv_mutex_unlock(&mutex);
-}
-
-
-static void init_once(void) {
- unsigned int i;
- const char* val;
-
- nthreads = ARRAY_SIZE(default_threads);
- val = getenv("UV_THREADPOOL_SIZE");
- if (val != NULL)
- nthreads = atoi(val);
- if (nthreads == 0)
- nthreads = 1;
- if (nthreads > MAX_THREADPOOL_SIZE)
- nthreads = MAX_THREADPOOL_SIZE;
-
- threads = default_threads;
- if (nthreads > ARRAY_SIZE(default_threads)) {
- threads = malloc(nthreads * sizeof(threads[0]));
- if (threads == NULL) {
- nthreads = ARRAY_SIZE(default_threads);
- threads = default_threads;
- }
- }
-
- if (uv_cond_init(&cond))
- abort();
-
- if (uv_mutex_init(&mutex))
- abort();
-
- QUEUE_INIT(&wq);
-
- for (i = 0; i < nthreads; i++)
- if (uv_thread_create(threads + i, worker, NULL))
- abort();
-
- initialized = 1;
-}
-
-
-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,
- struct uv__work* w,
- void (*work)(struct uv__work* w),
- void (*done)(struct uv__work* w, int status)) {
- uv_once(&once, init_once);
- w->loop = loop;
- w->work = work;
- w->done = done;
- post(&w->wq);
-}
-
-
-static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
- int cancelled;
-
- uv_mutex_lock(&mutex);
- uv_mutex_lock(&w->loop->wq_mutex);
-
- cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
- if (cancelled)
- QUEUE_REMOVE(&w->wq);
-
- uv_mutex_unlock(&w->loop->wq_mutex);
- uv_mutex_unlock(&mutex);
-
- if (!cancelled)
- return -EBUSY;
-
- w->work = uv__cancelled;
- uv_mutex_lock(&loop->wq_mutex);
- QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
- uv_async_send(&loop->wq_async);
- uv_mutex_unlock(&loop->wq_mutex);
-
- return 0;
-}
-
-
-void uv__work_done(uv_async_t* handle) {
- struct uv__work* w;
- uv_loop_t* loop;
- QUEUE* q;
- QUEUE wq;
- int err;
-
- loop = container_of(handle, uv_loop_t, wq_async);
- QUEUE_INIT(&wq);
-
- uv_mutex_lock(&loop->wq_mutex);
- if (!QUEUE_EMPTY(&loop->wq)) {
- q = QUEUE_HEAD(&loop->wq);
- QUEUE_SPLIT(&loop->wq, q, &wq);
- }
- uv_mutex_unlock(&loop->wq_mutex);
-
- while (!QUEUE_EMPTY(&wq)) {
- q = QUEUE_HEAD(&wq);
- QUEUE_REMOVE(q);
-
- w = container_of(q, struct uv__work, wq);
- err = (w->work == uv__cancelled) ? -ECANCELED : 0;
- w->done(w, err);
- }
-}
-
-
-static void uv__queue_work(struct uv__work* w) {
- uv_work_t* req = container_of(w, uv_work_t, work_req);
-
- req->work_cb(req);
-}
-
-
-static void uv__queue_done(struct uv__work* w, int err) {
- uv_work_t* req;
-
- req = container_of(w, uv_work_t, work_req);
- uv__req_unregister(req->loop, req);
-
- if (req->after_work_cb == NULL)
- return;
-
- req->after_work_cb(req, err);
-}
-
-
-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 -EINVAL;
-
- uv__req_init(loop, req, UV_WORK);
- req->loop = loop;
- req->work_cb = work_cb;
- req->after_work_cb = after_work_cb;
- uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
- return 0;
-}
-
-
-int uv_cancel(uv_req_t* req) {
- struct uv__work* wreq;
- uv_loop_t* loop;
-
- switch (req->type) {
- case UV_FS:
- loop = ((uv_fs_t*) req)->loop;
- wreq = &((uv_fs_t*) req)->work_req;
- break;
- case UV_GETADDRINFO:
- loop = ((uv_getaddrinfo_t*) req)->loop;
- wreq = &((uv_getaddrinfo_t*) req)->work_req;
- break;
- case UV_WORK:
- loop = ((uv_work_t*) req)->loop;
- wreq = &((uv_work_t*) req)->work_req;
- break;
- default:
- return -EINVAL;
- }
-
- return uv__work_cancel(loop, req, wreq);
-}
diff --git a/src/unix/udp.c b/src/unix/udp.c
index efc180c..9556bd7 100644
--- a/src/unix/udp.c
+++ b/src/unix/udp.c
@@ -221,16 +221,17 @@ static void uv__udp_recvmsg(uv_loop_t* loop,
handle->recv_cb(handle, -errno, &buf, NULL, 0);
}
else {
- flags = 0;
+ const struct sockaddr *addr;
+ if (h.msg_namelen == 0)
+ addr = NULL;
+ else
+ addr = (const struct sockaddr*) &peer;
+ flags = 0;
if (h.msg_flags & MSG_TRUNC)
flags |= UV_UDP_PARTIAL;
- handle->recv_cb(handle,
- nread,
- &buf,
- (const struct sockaddr*) &peer,
- flags);
+ handle->recv_cb(handle, nread, &buf, addr, flags);
}
}
/* recv_cb callback may decide to pause or close the handle */
@@ -319,9 +320,10 @@ int uv__udp_bind(uv_udp_t* handle,
fd = handle->io_watcher.fd;
if (fd == -1) {
- fd = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
- if (fd == -1)
- return -errno;
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
handle->io_watcher.fd = fd;
}
@@ -627,7 +629,6 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
}
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- int err;
struct sockaddr_storage addr_st;
struct sockaddr_in* addr4;
struct sockaddr_in6* addr6;
@@ -653,9 +654,6 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
}
if (addr_st.ss_family == AF_INET) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
- if (err)
- return err;
if (setsockopt(handle->io_watcher.fd,
IPPROTO_IP,
IP_MULTICAST_IF,
@@ -664,9 +662,6 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
return -errno;
}
} else if (addr_st.ss_family == AF_INET6) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
- if (err)
- return err;
if (setsockopt(handle->io_watcher.fd,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
diff --git a/src/uv-common.c b/src/uv-common.c
index a7a3f74..d9553c9 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -35,7 +35,7 @@
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) && !defined(_WIN32)
+#if !defined(_WIN32)
# include <net/if.h> /* if_nametoindex */
#endif
@@ -67,6 +67,11 @@ size_t uv_req_size(uv_req_type type) {
#undef XX
+size_t uv_loop_size(void) {
+ return sizeof(uv_loop_t);
+}
+
+
uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf;
buf.base = base;
@@ -107,17 +112,14 @@ int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS)
char address_part[40];
size_t address_part_size;
const char* zone_index;
-#endif
memset(addr, 0, sizeof(*addr));
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS)
zone_index = strchr(ip, '%');
if (zone_index != NULL) {
address_part_size = zone_index - ip;
@@ -136,7 +138,6 @@ int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
addr->sin6_scope_id = if_nametoindex(zone_index);
#endif
}
-#endif
return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
}
@@ -384,7 +385,7 @@ void uv_stop(uv_loop_t* loop) {
}
-uint64_t uv_now(uv_loop_t* loop) {
+uint64_t uv_now(const uv_loop_t* loop) {
return loop->time;
}
@@ -437,7 +438,7 @@ int uv__getaddrinfo_translate_error(int sys_err) {
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
- case EAI_SYSTEM: return UV_EAI_SYSTEM;
+ case EAI_SYSTEM: return -errno;
#endif
}
assert(!"unknown EAI_* error code");
diff --git a/src/uv-common.h b/src/uv-common.h
index 3bcdcef..97d1c5d 100644
--- a/src/uv-common.h
+++ b/src/uv-common.h
@@ -92,6 +92,13 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
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);
+
#define uv__has_active_reqs(loop) \
(QUEUE_EMPTY(&(loop)->active_reqs) == 0)
diff --git a/src/win/core.c b/src/win/core.c
index f749ba9..ee77c5d 100644
--- a/src/win/core.c
+++ b/src/win/core.c
@@ -26,9 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#if !defined(__MINGW32__)
#include <crtdbg.h>
-#endif
#include "uv.h"
#include "internal.h"
@@ -44,24 +42,24 @@ static uv_once_t uv_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)
/* Our crt debug report handler allows us to temporarily disable asserts */
/* 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) {
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
return FALSE;
-
+
if (ret_val) {
/* Set ret_val to 0 to continue with normal execution. */
/* Set ret_val to 1 to trigger a breakpoint. */
- if(IsDebuggerPresent())
- *ret_val = 1;
+ if(IsDebuggerPresent())
+ *ret_val = 1;
else
- *ret_val = 0;
+ *ret_val = 0;
}
/* Don't call _CrtDbgReport. */
@@ -133,6 +131,7 @@ int uv_loop_init(uv_loop_t* loop) {
loop->last_tick_count = 0;
uv_update_time(loop);
+ QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue);
QUEUE_INIT(&loop->active_reqs);
loop->active_handles = 0;
@@ -159,6 +158,15 @@ int uv_loop_init(uv_loop_t* loop) {
loop->timer_counter = 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;
}
diff --git a/src/win/dl.c b/src/win/dl.c
index d5b8f7c..2ef1f6c 100644
--- a/src/win/dl.c
+++ b/src/win/dl.c
@@ -64,7 +64,7 @@ int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
}
-const char* uv_dlerror(uv_lib_t* lib) {
+const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
diff --git a/src/win/fs-event.c b/src/win/fs-event.c
index f3de575..7ad99a8 100644
--- a/src/win/fs-event.c
+++ b/src/win/fs-event.c
@@ -290,7 +290,7 @@ error:
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return UV_EINVAL;
+ return 0;
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
diff --git a/src/win/fs.c b/src/win/fs.c
index 273ec39..4de2988 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -44,12 +44,8 @@
#define QUEUE_FS_TP_JOB(loop, req) \
do { \
- if (!QueueUserWorkItem(&uv_fs_thread_proc, \
- req, \
- WT_EXECUTEDEFAULT)) { \
- return uv_translate_sys_error(GetLastError()); \
- } \
uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
} while (0)
#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->ptr = NULL;
req->path = NULL;
-
- if (cb != NULL) {
- req->cb = cb;
- memset(&req->overlapped, 0, sizeof(req->overlapped));
- }
+ req->cb = cb;
}
@@ -553,7 +545,7 @@ void fs__read(uv_fs_t* req) {
VERIFY_FD(fd, req);
handle = uv__get_osfhandle(fd);
-
+
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
return;
@@ -1510,11 +1502,10 @@ static void fs__fchown(uv_fs_t* req) {
}
-static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
- uv_fs_t* req = (uv_fs_t*) parameter;
- uv_loop_t* loop = req->loop;
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
- assert(req != NULL);
+ req = container_of(w, uv_fs_t, work_req);
assert(req->type == UV_FS);
#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
@@ -1547,9 +1538,41 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
default:
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;
}
@@ -2064,30 +2087,3 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
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;
-}
-
diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c
index fb4ab0a..086200a 100644
--- a/src/win/getaddrinfo.c
+++ b/src/win/getaddrinfo.c
@@ -56,25 +56,13 @@
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
-/* getaddrinfo worker thread implementation */
-static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
- uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter;
- 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);
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ int err;
- 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.
* 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 name_len = 0;
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;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
- int err = 0;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */
if (req->alloc != NULL) {
@@ -103,6 +93,16 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
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) {
/* convert addrinfoW to addrinfo */
/* first calculate required length */
@@ -113,8 +113,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
if (name_len == 0) {
- /* FIXME(bnoordhuis) Retain GetLastError(). */
- err = UV_EAI_SYSTEM;
+ req->retcode = uv_translate_sys_error(GetLastError());
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
@@ -179,11 +178,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
}
}
} else {
- err = UV_EAI_MEMORY;
+ req->retcode = UV_EAI_MEMORY;
}
- } else {
- /* GetAddrInfo failed */
- err = uv__getaddrinfo_translate_error(req->retcode);
}
/* return memory to system */
@@ -193,10 +189,10 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
}
complete:
- uv__req_unregister(loop, req);
+ uv__req_unregister(req->loop, req);
/* 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);
}
@@ -247,6 +243,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->res = NULL;
req->type = UV_GETADDRINFO;
req->loop = loop;
+ req->retcode = 0;
/* calculate required memory size for all input values */
if (node != NULL) {
@@ -324,13 +321,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->hints = NULL;
}
- /* Ask thread to run. Treat this as a long operation */
- if (QueueUserWorkItem(&getaddrinfo_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION) == 0) {
- err = GetLastError();
- goto error;
- }
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
uv__req_register(loop, req);
diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c
new file mode 100644
index 0000000..c1aae13
--- /dev/null
+++ b/src/win/getnameinfo.c
@@ -0,0 +1,132 @@
+/* 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 <malloc.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ ret = GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ sizeof(host),
+ service,
+ sizeof(service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ 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;
+ service = req->service;
+ }
+
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || getnameinfo_cb == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+ uv__req_register(loop, req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+
+ return 0;
+}
diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h
index 5776eb7..8d0334c 100644
--- a/src/win/handle-inl.h
+++ b/src/win/handle-inl.h
@@ -168,7 +168,7 @@ INLINE static HANDLE uv__get_osfhandle(int fd)
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
/* for invalid FDs in release builds (or if you let the assert continue). */
/* So this wrapper function disables asserts when calling _get_osfhandle. */
-
+
HANDLE handle;
UV_BEGIN_DISABLE_CRT_ASSERT();
handle = (HANDLE) _get_osfhandle(fd);
diff --git a/src/win/internal.h b/src/win/internal.h
index 45ce177..798d33a 100644
--- a/src/win/internal.h
+++ b/src/win/internal.h
@@ -31,19 +31,22 @@
#ifdef _MSC_VER
# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
#else
# define INLINE inline
+# define UV_THREAD_LOCAL __thread
#endif
#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() \
{ \
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
uv__crt_assert_enabled = FALSE;
-
+
#define UV_END_DISABLE_CRT_ASSERT() \
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
@@ -286,22 +289,9 @@ int uv_translate_sys_error(int sys_errno);
/*
- * Getaddrinfo
- */
-void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req);
-
-
-/*
* FS
*/
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);
/*
diff --git a/src/win/pipe.c b/src/win/pipe.c
index 394faeb..2fcedde 100644
--- a/src/win/pipe.c
+++ b/src/win/pipe.c
@@ -115,7 +115,7 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) {
}
-static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
HANDLE pipeHandle;
/*
diff --git a/src/win/poll.c b/src/win/poll.c
index 1786c40..bf37399 100644
--- a/src/win/poll.c
+++ b/src/win/poll.c
@@ -187,7 +187,8 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
/* Stop polling. */
handle->events = 0;
- uv__handle_stop(handle);
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
}
if (events != 0) {
diff --git a/src/win/process.c b/src/win/process.c
index d52c837..7a85858 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -430,11 +430,10 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
int quote_hit;
WCHAR* start;
- /*
- * Check if the string must be quoted;
- * if unnecessary, don't do it, it may only confuse older programs.
- */
if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
return target;
}
@@ -965,7 +964,7 @@ int uv_spawn(uv_loop_t* loop,
/* Spawn succeeded */
/* Beyond this point, failure is reported asynchronously. */
-
+
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
@@ -1011,8 +1010,8 @@ int uv_spawn(uv_loop_t* loop,
CloseHandle(info.hThread);
- assert(!err);
-
+ assert(!err);
+
/* Make the handle active. It will remain active until the exit callback */
/* iis made or the handle is closed, whichever happens first. */
uv__handle_start(process);
diff --git a/src/win/req-inl.h b/src/win/req-inl.h
index 353fe90..97342e5 100644
--- a/src/win/req-inl.h
+++ b/src/win/req-inl.h
@@ -195,22 +195,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
- case UV_GETADDRINFO:
- uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
- break;
-
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
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:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break;
diff --git a/src/win/tcp.c b/src/win/tcp.c
index 5dcdcd4..ccd7a11 100644
--- a/src/win/tcp.c
+++ b/src/win/tcp.c
@@ -243,7 +243,13 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
int r;
if (handle->socket == INVALID_SOCKET) {
- SOCKET sock = socket(addr->sa_family, SOCK_STREAM, 0);
+ SOCKET sock;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return ERROR_INVALID_PARAMETER;
+
+ sock = socket(addr->sa_family, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
return WSAGetLastError();
}
@@ -804,7 +810,6 @@ int uv_tcp_write(uv_loop_t* loop,
req->type = UV_WRITE;
req->handle = (uv_stream_t*) handle;
req->cb = cb;
- memset(&req->overlapped, 0, sizeof(req->overlapped));
/* Prepare the overlapped structure. */
memset(&(req->overlapped), 0, sizeof(req->overlapped));
diff --git a/src/win/thread.c b/src/win/thread.c
index 5178f8f..ccc5579 100644
--- a/src/win/thread.c
+++ b/src/win/thread.c
@@ -660,7 +660,9 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
@@ -672,7 +674,8 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
- if (--barrier->count == 0) {
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
@@ -680,6 +683,7 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
}
diff --git a/src/win/threadpool.c b/src/win/threadpool.c
deleted file mode 100644
index 9539844..0000000
--- a/src/win/threadpool.c
+++ /dev/null
@@ -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);
-}
diff --git a/src/win/tty.c b/src/win/tty.c
index 7840fb2..87e3eb5 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -48,6 +48,8 @@
#define ANSI_IN_STRING 0x40
#define ANSI_BACKSLASH_SEEN 0x80
+#define MAX_INPUT_BUFFER_LENGTH 8192
+
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
@@ -303,6 +305,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
uv_tty_t* handle;
uv_req_t* req;
DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
assert(data);
@@ -314,18 +318,29 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
assert(handle->read_line_buffer.len > 0);
/* ReadConsole can't handle big buffers. */
- if (handle->read_line_buffer.len < 8192) {
+ if (handle->read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
bytes = handle->read_line_buffer.len;
} else {
- bytes = 8192;
+ bytes = MAX_INPUT_BUFFER_LENGTH;
}
- /* Todo: Unicode */
- if (ReadConsoleA(handle->read_line_handle,
- (void*) handle->read_line_buffer.base,
- bytes,
- &read_bytes,
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ if (ReadConsoleW(handle->read_line_handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
NULL)) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
SET_REQ_SUCCESS(req);
req->overlapped.InternalHigh = read_bytes;
} else {
@@ -1117,6 +1132,14 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
return 0;
}
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
unsigned short argc = handle->ansi_csi_argc;
@@ -1126,6 +1149,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
char fg_color = -1, bg_color = -1;
char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
if (argc == 0) {
/* Reset mode */
@@ -1133,6 +1157,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
bg_color = 0;
fg_bright = 0;
bg_bright = 0;
+ inverse = 0;
}
for (i = 0; i < argc; i++) {
@@ -1144,6 +1169,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
bg_color = 0;
fg_bright = 0;
bg_bright = 0;
+ inverse = 0;
} else if (arg == 1) {
/* Foreground bright on */
@@ -1158,6 +1184,10 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
/* Background bright on */
bg_bright = 1;
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
} else if (arg == 21 || arg == 22) {
/* Foreground bright off */
fg_bright = 0;
@@ -1166,6 +1196,10 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
/* Background bright off */
bg_bright = 0;
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
} else if (arg >= 30 && arg <= 37) {
/* Set foreground color */
fg_color = arg - 30;
@@ -1198,7 +1232,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
}
if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
- bg_bright == -1) {
+ bg_bright == -1 && inverse == -1) {
/* Nothing changed */
return 0;
}
@@ -1208,6 +1242,10 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
return -1;
}
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
if (fg_color != -1) {
info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
@@ -1238,6 +1276,18 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
}
}
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
*error = GetLastError();
return -1;
@@ -1316,6 +1366,25 @@ static int uv_tty_restore_state(uv_tty_t* handle,
return 0;
}
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
static int uv_tty_write_bufs(uv_tty_t* handle,
const uv_buf_t bufs[],
@@ -1527,6 +1596,13 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
continue;
}
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
(handle->ansi_csi_argc > 0 || utf8_codepoint != '[')) {
int x, y, d;
@@ -1629,6 +1705,24 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error);
break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->ansi_csi_argc == 1 &&
+ handle->ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->ansi_csi_argc == 1 &&
+ handle->ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
}
/* Sequence ended - go back to normal state. */
diff --git a/src/win/udp.c b/src/win/udp.c
index 8719fa7..8658904 100644
--- a/src/win/udp.c
+++ b/src/win/udp.c
@@ -662,7 +662,6 @@ int uv_udp_set_membership(uv_udp_t* handle,
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- int err;
struct sockaddr_storage addr_st;
struct sockaddr_in* addr4;
struct sockaddr_in6* addr6;
@@ -687,13 +686,10 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
return UV_EINVAL;
}
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
if (addr_st.ss_family == AF_INET) {
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip4_any_,
- sizeof(uv_addr_ip4_any_),
- UV_UDP_REUSEADDR);
- if (err)
- return uv_translate_sys_error(err);
if (setsockopt(handle->socket,
IPPROTO_IP,
IP_MULTICAST_IF,
@@ -702,12 +698,6 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
return uv_translate_sys_error(WSAGetLastError());
}
} else if (addr_st.ss_family == AF_INET6) {
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip6_any_,
- sizeof(uv_addr_ip6_any_),
- UV_UDP_REUSEADDR);
- if (err)
- return uv_translate_sys_error(err);
if (setsockopt(handle->socket,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
@@ -726,15 +716,9 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
BOOL optval = (BOOL) value;
- int err;
- /* If the socket is unbound, bind to inaddr_any. */
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip4_any_,
- sizeof(uv_addr_ip4_any_),
- 0);
- if (err)
- return uv_translate_sys_error(err);
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
if (setsockopt(handle->socket,
SOL_SOCKET,
@@ -774,19 +758,13 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
#define SOCKOPT_SETTER(name, option4, option6, validate) \
int uv_udp_set_##name(uv_udp_t* handle, int value) { \
DWORD optval = (DWORD) value; \
- int err; \
\
if (!(validate(value))) { \
return UV_EINVAL; \
} \
\
- /* If the socket is unbound, bind to inaddr_any. */ \
- err = uv_udp_maybe_bind(handle, \
- (const struct sockaddr*) &uv_addr_ip4_any_, \
- sizeof(uv_addr_ip4_any_), \
- 0); \
- if (err) \
- return uv_translate_sys_error(err); \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
\
if (!(handle->flags & UV_HANDLE_IPV6)) { \
/* Set IPv4 socket option */ \
diff --git a/src/win/util.c b/src/win/util.c
index d4173c5..a56fbea 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -314,8 +314,7 @@ uint64_t uv_get_free_memory(void) {
MEMORYSTATUSEX memory_status;
memory_status.dwLength = sizeof(memory_status);
- if(!GlobalMemoryStatusEx(&memory_status))
- {
+ if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
}
@@ -327,8 +326,7 @@ uint64_t uv_get_total_memory(void) {
MEMORYSTATUSEX memory_status;
memory_status.dwLength = sizeof(memory_status);
- if(!GlobalMemoryStatusEx(&memory_status))
- {
+ if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
}
@@ -388,7 +386,7 @@ int uv_set_process_title(const char* title) {
if (!length) {
err = GetLastError();
goto done;
- };
+ }
/* If the title must be truncated insert a \0 terminator there */
if (length > MAX_TITLE_LENGTH) {
diff --git a/test/echo-server.c b/test/echo-server.c
index 2c6ca0d..f0937cc 100644
--- a/test/echo-server.c
+++ b/test/echo-server.c
@@ -51,24 +51,20 @@ static void after_write(uv_write_t* req, int status) {
/* Free the read/write buffer and the request */
wr = (write_req_t*) req;
free(wr->buf.base);
- free(wr);
- if (status == 0)
+ if (status == 0) {
+ free(wr);
return;
+ }
- fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
-
- if (status == UV_ECANCELED)
- return;
-
- ASSERT(status == UV_EPIPE);
- uv_close((uv_handle_t*)req->handle, on_close);
-}
-
+ fprintf(stderr,
+ "uv_write error: %s - %s\n",
+ uv_err_name(status),
+ uv_strerror(status));
-static void after_shutdown(uv_shutdown_t* req, int status) {
- uv_close((uv_handle_t*)req->handle, on_close);
- free(req);
+ if (!uv_is_closing((uv_handle_t*) req->handle))
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(wr);
}
@@ -77,7 +73,6 @@ static void after_read(uv_stream_t* handle,
const uv_buf_t* buf) {
int i;
write_req_t *wr;
- uv_shutdown_t* req;
if (nread < 0) {
/* Error or EOF */
@@ -87,9 +82,7 @@ static void after_read(uv_stream_t* handle,
free(buf->base);
}
- req = (uv_shutdown_t*) malloc(sizeof *req);
- uv_shutdown(req, handle, after_shutdown);
-
+ uv_close((uv_handle_t*) handle, on_close);
return;
}
diff --git a/test/test-barrier.c b/test/test-barrier.c
index 97df704..25a55d6 100644
--- a/test/test-barrier.c
+++ b/test/test-barrier.c
@@ -29,6 +29,8 @@ typedef struct {
uv_barrier_t barrier;
int delay;
volatile int posted;
+ int main_barrier_wait_rval;
+ int worker_barrier_wait_rval;
} worker_config;
@@ -38,7 +40,11 @@ static void worker(void* arg) {
if (c->delay)
uv_sleep(c->delay);
- 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);
+ }
}
@@ -47,15 +53,22 @@ TEST_IMPL(barrier_1) {
worker_config 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_thread_create(&thread, worker, &wc));
uv_sleep(100);
- 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));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
@@ -67,14 +80,20 @@ TEST_IMPL(barrier_2) {
memset(&wc, 0, sizeof(wc));
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_thread_create(&thread, worker, &wc));
- 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));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
@@ -85,14 +104,20 @@ TEST_IMPL(barrier_3) {
worker_config 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_thread_create(&thread, worker, &wc));
- 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));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
diff --git a/test/test-fs.c b/test/test-fs.c
index 306ec6b..40c7726 100644
--- a/test/test-fs.c
+++ b/test/test-fs.c
@@ -36,11 +36,15 @@
# include <io.h>
# define unlink _unlink
# define rmdir _rmdir
-# define stat _stati64
# define open _open
# define write _write
-# define lseek _lseek
# define close _close
+# ifndef stat
+# define stat _stati64
+# endif
+# ifndef lseek
+# define lseek _lseek
+# endif
#endif
#define TOO_LONG_NAME_LENGTH 65536
diff --git a/test/test-getnameinfo.c b/test/test-getnameinfo.c
new file mode 100644
index 0000000..1ea0f3a
--- /dev/null
+++ b/test/test-getnameinfo.c
@@ -0,0 +1,83 @@
+/* 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>
+
+
+static const char* address_ip4 = "127.0.0.1";
+static const char* address_ip6 = "::1";
+static const int port = 80;
+
+static struct sockaddr_in addr4;
+static struct sockaddr_in6 addr6;
+static uv_getnameinfo_t req;
+
+static void getnameinfo_req(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(handle != NULL);
+ ASSERT(status == 0);
+ ASSERT(hostname != NULL);
+ ASSERT(service != NULL);
+}
+
+TEST_IMPL(getnameinfo_basic_ip4) {
+ int r;
+
+ r = uv_ip4_addr(address_ip4, port, &addr4);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr4,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(getnameinfo_basic_ip6) {
+ int r;
+
+ r = uv_ip6_addr(address_ip6, port, &addr6);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr6,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c
index 0d2606e..cf8491f 100644
--- a/test/test-ip6-addr.c
+++ b/test/test-ip6-addr.c
@@ -32,7 +32,6 @@
TEST_IMPL(ip6_addr_link_local) {
-#ifdef UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
char string_address[INET6_ADDRSTRLEN];
uv_interface_address_t* addresses;
uv_interface_address_t* address;
@@ -93,9 +92,6 @@ TEST_IMPL(ip6_addr_link_local) {
MAKE_VALGRIND_HAPPY();
return 0;
-#else
- RETURN_SKIP("Qualified link-local addresses are not supported.");
-#endif
}
@@ -107,6 +103,7 @@ TEST_IMPL(ip6_addr_link_local) {
X("fe80::2acf:daff:fedd:342a") \
X("fe80:0:0:0:2acf:daff:fedd:342a") \
X("fe80:0:0:0:2acf:daff:1.2.3.4") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") \
#define BAD_ADDR_LIST(X) \
X(":::1") \
@@ -114,6 +111,7 @@ TEST_IMPL(ip6_addr_link_local) {
X("fe80:0:0:0:2acf:daff:fedd:342a:5678") \
X("fe80:0:0:0:2acf:daff:abcd:1.2.3.4") \
X("fe80:0:0:2acf:daff:1.2.3.4.5") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \
#define TEST_GOOD(ADDR) \
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \
diff --git a/test/test-list.h b/test/test-list.h
index afb9a7a..15c2e4e 100644
--- a/test/test-list.h
+++ b/test/test-list.h
@@ -65,6 +65,7 @@ TEST_DECLARE (tcp_bind_error_addrnotavail_2)
TEST_DECLARE (tcp_bind_error_fault)
TEST_DECLARE (tcp_bind_error_inval)
TEST_DECLARE (tcp_bind_localhost_ok)
+TEST_DECLARE (tcp_bind_invalid_flags)
TEST_DECLARE (tcp_listen_without_bind)
TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout)
@@ -92,6 +93,7 @@ TEST_DECLARE (udp_dgram_too_big)
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
TEST_DECLARE (udp_options)
+TEST_DECLARE (udp_no_autobind)
TEST_DECLARE (udp_open)
TEST_DECLARE (pipe_bind_error_addrinuse)
TEST_DECLARE (pipe_bind_error_addrnotavail)
@@ -161,6 +163,8 @@ TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_basic)
TEST_DECLARE (getaddrinfo_concurrent)
+TEST_DECLARE (getnameinfo_basic_ip4)
+TEST_DECLARE (getnameinfo_basic_ip6)
TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp)
TEST_DECLARE (fail_always)
@@ -225,6 +229,7 @@ TEST_DECLARE (threadpool_queue_work_simple)
TEST_DECLARE (threadpool_queue_work_einval)
TEST_DECLARE (threadpool_multiple_event_loops)
TEST_DECLARE (threadpool_cancel_getaddrinfo)
+TEST_DECLARE (threadpool_cancel_getnameinfo)
TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
@@ -236,9 +241,12 @@ TEST_DECLARE (dlerror)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
+
TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
+
#ifdef _WIN32
+TEST_DECLARE (poll_closesocket)
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
TEST_DECLARE (environment_creation)
@@ -335,6 +343,7 @@ TASK_LIST_START
TEST_ENTRY (tcp_bind_error_fault)
TEST_ENTRY (tcp_bind_error_inval)
TEST_ENTRY (tcp_bind_localhost_ok)
+ TEST_ENTRY (tcp_bind_invalid_flags)
TEST_ENTRY (tcp_listen_without_bind)
TEST_ENTRY (tcp_connect_error_fault)
TEST_ENTRY (tcp_connect_timeout)
@@ -361,6 +370,7 @@ TASK_LIST_START
TEST_ENTRY (udp_dual_stack)
TEST_ENTRY (udp_ipv6_only)
TEST_ENTRY (udp_options)
+ TEST_ENTRY (udp_no_autobind)
TEST_ENTRY (udp_multicast_interface)
TEST_ENTRY (udp_multicast_interface6)
TEST_ENTRY (udp_multicast_join)
@@ -468,6 +478,9 @@ TASK_LIST_START
TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_concurrent)
+ TEST_ENTRY (getnameinfo_basic_ip4)
+ TEST_ENTRY (getnameinfo_basic_ip6)
+
TEST_ENTRY (getsockname_tcp)
TEST_ENTRY (getsockname_udp)
@@ -497,6 +510,7 @@ TASK_LIST_START
TEST_ENTRY (kill)
#ifdef _WIN32
+ TEST_ENTRY (poll_closesocket)
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
TEST_ENTRY (environment_creation)
@@ -558,6 +572,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_queue_work_einval)
TEST_ENTRY (threadpool_multiple_event_loops)
TEST_ENTRY (threadpool_cancel_getaddrinfo)
+ TEST_ENTRY (threadpool_cancel_getnameinfo)
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
diff --git a/test/test-poll-closesocket.c b/test/test-poll-closesocket.c
new file mode 100644
index 0000000..4db74a0
--- /dev/null
+++ b/test/test-poll-closesocket.c
@@ -0,0 +1,89 @@
+/* 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.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+#include "uv.h"
+#include "task.h"
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(h == &handle);
+
+ r = uv_poll_start(&handle, UV_READABLE, poll_cb);
+ ASSERT(r == 0);
+
+ closesocket(sock);
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+}
+
+
+TEST_IMPL(poll_closesocket) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
diff --git a/test/test-spawn.c b/test/test-spawn.c
index 0f4389f..c75f1ca 100644
--- a/test/test-spawn.c
+++ b/test/test-spawn.c
@@ -808,6 +808,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
TEST_IMPL(argument_escaping) {
const WCHAR* test_str[] = {
+ L"",
L"HelloWorld",
L"Hello World",
L"Hello\"World",
diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c
index 96bfe11..10ed68e 100644
--- a/test/test-tcp-bind-error.c
+++ b/test/test-tcp-bind-error.c
@@ -185,6 +185,23 @@ TEST_IMPL(tcp_bind_localhost_ok) {
}
+TEST_IMPL(tcp_bind_invalid_flags) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY);
+ ASSERT(r == UV_EINVAL);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
TEST_IMPL(tcp_listen_without_bind) {
int r;
uv_tcp_t server;
diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c
index a349876..d852e48 100644
--- a/test/test-threadpool-cancel.c
+++ b/test/test-threadpool-cancel.c
@@ -46,7 +46,6 @@ static unsigned work_cb_called;
static unsigned done_cb_called;
static unsigned done2_cb_called;
static unsigned timer_cb_called;
-static unsigned getaddrinfo_cb_called;
static void work_cb(uv_work_t* req) {
@@ -125,7 +124,16 @@ static void getaddrinfo_cb(uv_getaddrinfo_t* req,
ASSERT(status == UV_EAI_CANCELED);
ASSERT(res == NULL);
uv_freeaddrinfo(res); /* Should not crash. */
- getaddrinfo_cb_called++;
+}
+
+
+static void getnameinfo_cb(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(hostname == NULL);
+ ASSERT(service == NULL);
}
@@ -202,6 +210,44 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) {
}
+TEST_IMPL(threadpool_cancel_getnameinfo) {
+ uv_getnameinfo_t reqs[4];
+ struct sockaddr_in addr4;
+ struct cancel_info ci;
+ uv_loop_t* loop;
+ int r;
+
+ r = uv_ip4_addr("127.0.0.1", 80, &addr4);
+ ASSERT(r == 0);
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getnameinfo(loop, reqs + 0, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 1, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 2, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 3, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
TEST_IMPL(threadpool_cancel_work) {
struct cancel_info ci;
uv_work_t reqs[16];
diff --git a/test/test-udp-options.c b/test/test-udp-options.c
index 5cc3698..19c45c2 100644
--- a/test/test-udp-options.c
+++ b/test/test-udp-options.c
@@ -86,3 +86,25 @@ TEST_IMPL(udp_options) {
MAKE_VALGRIND_HAPPY();
return 0;
}
+
+
+TEST_IMPL(udp_no_autobind) {
+ uv_loop_t* loop;
+ uv_udp_t h;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_udp_init(loop, &h));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32));
+ ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0"));
+
+ uv_close((uv_handle_t*) &h, NULL);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/uv.gyp b/uv.gyp
index 710bd40..d9772b4 100644
--- a/uv.gyp
+++ b/uv.gyp
@@ -61,11 +61,13 @@
'include/uv.h',
'include/tree.h',
'include/uv-errno.h',
+ 'include/uv-threadpool.h',
'include/uv-version.h',
'src/fs-poll.c',
'src/heap-inl.h',
'src/inet.c',
'src/queue.h',
+ 'src/threadpool.c',
'src/uv-common.c',
'src/uv-common.h',
'src/version.c'
@@ -86,6 +88,7 @@
'src/win/fs.c',
'src/win/fs-event.c',
'src/win/getaddrinfo.c',
+ 'src/win/getnameinfo.c',
'src/win/handle.c',
'src/win/handle-inl.h',
'src/win/internal.h',
@@ -102,7 +105,6 @@
'src/win/stream-inl.h',
'src/win/tcp.c',
'src/win/tty.c',
- 'src/win/threadpool.c',
'src/win/timer.c',
'src/win/udp.c',
'src/win/util.c',
@@ -113,11 +115,11 @@
],
'link_settings': {
'libraries': [
- '-ladvapi32.lib',
- '-liphlpapi.lib',
- '-lpsapi.lib',
- '-lshell32.lib',
- '-lws2_32.lib'
+ '-ladvapi32',
+ '-liphlpapi',
+ '-lpsapi',
+ '-lshell32',
+ '-lws2_32'
],
},
}, { # Not Windows i.e. POSIX
@@ -141,6 +143,7 @@
'src/unix/dl.c',
'src/unix/fs.c',
'src/unix/getaddrinfo.c',
+ 'src/unix/getnameinfo.c',
'src/unix/internal.h',
'src/unix/loop.c',
'src/unix/loop-watcher.c',
@@ -152,7 +155,6 @@
'src/unix/stream.c',
'src/unix/tcp.c',
'src/unix/thread.c',
- 'src/unix/threadpool.c',
'src/unix/timer.c',
'src/unix/tty.c',
'src/unix/udp.c',
@@ -318,6 +320,7 @@
'test/test-get-currentexe.c',
'test/test-get-memory.c',
'test/test-getaddrinfo.c',
+ 'test/test-getnameinfo.c',
'test/test-getsockname.c',
'test/test-hrtime.c',
'test/test-idle.c',
@@ -344,6 +347,7 @@
'test/test-platform-output.c',
'test/test-poll.c',
'test/test-poll-close.c',
+ 'test/test-poll-closesocket.c',
'test/test-process-title.c',
'test/test-ref.c',
'test/test-run-nowait.c',
@@ -405,7 +409,7 @@
'test/runner-win.c',
'test/runner-win.h'
],
- 'libraries': [ 'ws2_32.lib' ]
+ 'libraries': [ '-lws2_32' ]
}, { # POSIX
'defines': [ '_GNU_SOURCE' ],
'sources': [
@@ -469,7 +473,7 @@
'test/runner-win.c',
'test/runner-win.h',
],
- 'libraries': [ 'ws2_32.lib' ]
+ 'libraries': [ '-lws2_32' ]
}, { # POSIX
'defines': [ '_GNU_SOURCE' ],
'sources': [
diff --git a/vcbuild.bat b/vcbuild.bat
index df6eda0..d3b7aa1 100644
--- a/vcbuild.bat
+++ b/vcbuild.bat
@@ -51,8 +51,8 @@ call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2013
goto select-target
-@rem Look for Visual Studio 2012
:vc-set-2012
+@rem Look for Visual Studio 2012
if not defined VS110COMNTOOLS goto vc-set-2010
if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010
call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
@@ -101,8 +101,8 @@ echo manually install gyp into %~dp0build\gyp.
exit /b 1
:have_gyp
-if not defined PYTHON set PYTHON="python"
-%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
+if not defined PYTHON set PYTHON=python
+"%PYTHON%" gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
if errorlevel 1 goto create-msvs-files-failed
if not exist uv.sln goto create-msvs-files-failed
echo Project files generated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment