From 9d9ed61c5a97562b93a2326f33922783ed509d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 21 Nov 2014 15:43:12 +0100 Subject: [PATCH 01/27] deps: update libuv to 1.0.0 PR-URL: https://github.com/joyent/node/pull/8762 Reviewed-by: Trevor Norris --- deps/uv/AUTHORS | 5 ++ deps/uv/ChangeLog | 32 +++++++++++++ deps/uv/Makefile.am | 40 +--------------- deps/uv/README.md | 16 +++++-- deps/uv/common.gypi | 4 ++ deps/uv/configure.ac | 3 +- deps/uv/docs/src/fs.rst | 2 +- deps/uv/docs/src/index.rst | 5 +- deps/uv/docs/src/misc.rst | 2 +- deps/uv/docs/src/threading.rst | 3 +- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv.h | 5 +- deps/uv/m4/.gitignore | 3 +- deps/uv/src/unix/core.c | 3 -- deps/uv/src/unix/internal.h | 8 ---- deps/uv/src/unix/thread.c | 50 +++++++++++++++++++ deps/uv/src/unix/tty.c | 7 +-- deps/uv/src/uv-common.c | 58 ---------------------- deps/uv/src/win/fs.c | 13 ++--- deps/uv/src/win/thread.c | 67 ++++++++++++++++++++++++++ deps/uv/src/win/util.c | 3 +- deps/uv/src/win/winsock.h | 19 ++++++++ deps/uv/test/test-fs.c | 12 +++-- deps/uv/test/test-list.h | 2 + deps/uv/test/test-thread-equal.c | 45 ++++++++++++++++++ deps/uv/uv.gyp | 82 +------------------------------- 26 files changed, 269 insertions(+), 222 deletions(-) create mode 100644 deps/uv/test/test-thread-equal.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 6dae58e02f2ee1..7a85150db017d5 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -166,3 +166,8 @@ Jeff Widman cjihrig Tomasz KoÅ‚odziejski Unknown W. Brackets +Emmanuel Odeke +Mikhail Mukovnikov +Thorsten Lorenz +Yuri D'Elia +Manos Nikolaidis diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index c06c782099f448..a76c4b5bb2c352 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,35 @@ +2014.11.21, Version 1.0.0 (Stable) + +Changes since version 1.0.0-rc2: + +* doc: fix git/svn url for gyp repo in README (Emmanuel Odeke) + +* windows: fix fs_read with nbufs > 1 and offset (Unknown W. Brackets) + +* win: add missing IP_ADAPTER_UNICAST_ADDRESS_LH definition for MinGW + (huxingyi) + +* doc: mention homebrew in README (Mikhail Mukovnikov) + +* doc: add learnuv workshop to README (Thorsten Lorenz) + +* doc: fix parameter name in uv_fs_access (Saúl Ibarra Corretgé) + +* unix: use cfmakeraw() for setting raw TTY mode (Yuri D'Elia) + +* win: fix uv_thread_self() (Alexis Campailla) + +* build: add x32 support to gyp build (Ben Noordhuis) + +* build: remove dtrace probes (Ben Noordhuis) + +* doc: fix link in misc.rst (Manos Nikolaidis) + +* mailmap: remove duplicated entries (Saúl Ibarra Corretgé) + +* gyp: fix comment regarding version info location (Saúl Ibarra Corretgé) + + 2014.10.21, Version 1.0.0-rc2 (Pre-release) Changes since version 1.0.0-rc1: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 3c6fcb595a5aa2..371df711d65633 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -206,6 +206,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-writealot.c \ test/test-tcp-try-write.c \ test/test-tcp-write-queue-order.c \ + test/test-thread-equal.c \ test/test-thread.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ @@ -306,46 +307,7 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 libuv_la_SOURCES += src/unix/sunos.c endif -if HAVE_DTRACE -BUILT_SOURCES = include/uv-dtrace.h -CLEANFILES += include/uv-dtrace.h -if FREEBSD -libuv_la_LDFLAGS += -lelf -endif -endif - -if DTRACE_NEEDS_OBJECTS -libuv_la_SOURCES += src/unix/uv-dtrace.d -libuv_la_DEPENDENCIES = src/unix/uv-dtrace.o -libuv_la_LIBADD = uv-dtrace.lo -CLEANFILES += src/unix/uv-dtrace.o src/unix/uv-dtrace.lo -endif - if HAVE_PKG_CONFIG pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = @PACKAGE_NAME@.pc endif - -if HAVE_DTRACE -include/uv-dtrace.h: src/unix/uv-dtrace.d - $(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -h -xnolibs -s $< -o $(top_srcdir)/$@ -endif - -if DTRACE_NEEDS_OBJECTS -SUFFIXES = .d - -src/unix/uv-dtrace.o: src/unix/uv-dtrace.d ${libuv_la_OBJECTS} - -# It's ok to specify the output here, because we have 1 .d file, and we process -# every created .o, most projects don't need to include more than one .d -.d.o: - $(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -G -o $(top_builddir)/uv-dtrace.o -s $< \ - `find ${top_builddir}/src -name "*.o"` - $(AM_V_GEN)printf %s\\n \ - '# ${top_builddir}/uv-dtrace.lo - a libtool object file' \ - '# Generated by libtool (GNU libtool) 2.4' \ - '# libtool wants a .lo not a .o' \ - "pic_object='uv-dtrace.o'" \ - "non_pic_object='uv-dtrace.o'" \ - > ${top_builddir}/uv-dtrace.lo -endif diff --git a/deps/uv/README.md b/deps/uv/README.md index 53c1b46afc0e06..1b079d9f347388 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -4,8 +4,7 @@ libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by [Node.js](http://nodejs.org), but it's also -used by Mozilla's [Rust language](http://www.rust-lang.org/), -[Luvit](http://luvit.io/), [Julia](http://julialang.org/), +used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), [pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). ## Feature highlights @@ -82,6 +81,8 @@ Documentation can be browsed online [here](http://docs.libuv.org). — API specification and usage examples. * [libuv-dox](https://github.com/thlorenz/libuv-dox) — Documenting types and methods of libuv, mostly by reading uv.h. + * [learnuv](https://github.com/thlorenz/learnuv) + — Learn uv for fun and profit, a self guided workshop to libuv. ## Build Instructions @@ -110,8 +111,9 @@ generate uv.sln as well as related project files. To have GYP generate build script for another system, checkout GYP into the project tree manually: - $ mkdir -p build - $ git clone https://git.chromium.org/external/gyp.git build/gyp + $ git clone https://chromium.googlesource.com/external/gyp.git build/gyp + OR + $ svn co http://gyp.googlecode.com/svn/trunk build/gyp ### Unix @@ -120,6 +122,8 @@ Run: $ ./gyp_uv.py -f make $ make -C out +Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. + ### OS X Run: @@ -128,6 +132,10 @@ Run: $ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ -configuration Release -target All +Using Homebrew: + + $ brew install --HEAD libuv + Note to OS X users: Make sure that you specify the architecture you wish to build for in the diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index a0e0eea06fe62f..a8e2ef44c6131d 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -143,6 +143,10 @@ 'cflags': [ '-m32' ], 'ldflags': [ '-m32' ], }], + [ 'target_arch=="x32"', { + 'cflags': [ '-mx32' ], + 'ldflags': [ '-mx32' ], + }], [ 'OS=="linux"', { 'cflags': [ '-ansi' ], }], diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index c6a30e16bfbb89..3ab69199d8ac03 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.0.0-rc2], [https://github.com/joyent/libuv/issues]) +AC_INIT([libuv], [1.0.0], [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]) @@ -50,7 +50,6 @@ AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) -PANDORA_ENABLE_DTRACE AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) AS_IF([test "x$PKG_CONFIG" != "x"], [ diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index cc8f5525b9b464..27d92d0b45319b 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -229,7 +229,7 @@ API Limited equivalent to ``sendfile(2)``. -.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) +.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) Equivalent to ``access(2)`` on Unix. Windows uses ``GetFileAttributesW()``. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst index ce30cf9651ee3d..a8f00dab38c316 100644 --- a/deps/uv/docs/src/index.rst +++ b/deps/uv/docs/src/index.rst @@ -6,15 +6,14 @@ Overview -------- libuv is a multi-platform support library with a focus on asynchronous I/O. It -was primarily developed for use by `Node.js`_, but it's also used by Mozilla's -`Rust language`_, `Luvit`_, `Julia`_, `pyuv`_, and `others`_. +was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_, +`Julia`_, `pyuv`_, and `others`_. .. note:: In case you find errors in this documentation you can help by sending `pull requests `_! .. _Node.js: http://nodejs.org -.. _Rust language: http://www.rust-lang.org .. _Luvit: http://luvit.io .. _Julia: http://julialang.org .. _pyuv: https://github.com/saghul/pyuv diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index b313159dba0159..1e1125ad6b06e6 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -171,7 +171,7 @@ API .. c:function:: void uv_loadavg(double avg[3]) - Gets the load average. See: http://en.wikipedia.org/wiki/Load_(computing) + Gets the load average. See: ``_ .. note:: Returns [0,0,0] on Windows (i.e., it's not implemented). diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst index 38daf4e5a17247..aab13f84b627b0 100644 --- a/deps/uv/docs/src/threading.rst +++ b/deps/uv/docs/src/threading.rst @@ -56,8 +56,9 @@ Threads ^^^^^^^ .. c:function:: int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg) -.. c:function:: unsigned long uv_thread_self(void) +.. c:function:: uv_thread_t uv_thread_self(void) .. c:function:: int uv_thread_join(uv_thread_t *tid) +.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) Thread-local storage ^^^^^^^^^^^^^^^^^^^^ diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 2ae3ca70f2dc4c..4f4220cf622949 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -34,6 +34,6 @@ #define UV_VERSION_MINOR 0 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "rc2" +#define UV_VERSION_SUFFIX "" #endif /* UV_VERSION_H */ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index ad6bde99cb1004..d17f977b44a501 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -1138,7 +1138,7 @@ UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, UV_EXTERN int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, - int flags, + int mode, uv_fs_cb cb); UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, @@ -1369,8 +1369,9 @@ UV_EXTERN void uv_key_set(uv_key_t* key, void* value); 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 uv_thread_t uv_thread_self(void); UV_EXTERN int uv_thread_join(uv_thread_t *tid); +UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); /* The presence of these unions force similar struct layout. */ #define XX(_, name) uv_ ## name ## _t name; diff --git a/deps/uv/m4/.gitignore b/deps/uv/m4/.gitignore index 9d0f4af88b3b75..c44e4c2929a4fb 100644 --- a/deps/uv/m4/.gitignore +++ b/deps/uv/m4/.gitignore @@ -1,5 +1,4 @@ # Ignore libtoolize-generated files. *.m4 !as_case.m4 -!dtrace.m4 -!libuv-check-flags.m4 \ No newline at end of file +!libuv-check-flags.m4 diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 7add085feabea8..e6a076831ccf4a 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -310,8 +310,6 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { uv__update_time(loop); while (r != 0 && loop->stop_flag == 0) { - UV_TICK_START(loop, mode); - uv__update_time(loop); uv__run_timers(loop); uv__run_pending(loop); @@ -340,7 +338,6 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { } r = uv__loop_alive(loop); - UV_TICK_STOP(loop, mode); if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) break; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index d5bc3109f020bf..b94508cba5932d 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -306,12 +306,4 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { return s + 1; } - -#ifdef HAVE_DTRACE -#include "uv-dtrace.h" -#else -#define UV_TICK_START(arg0, arg1) -#define UV_TICK_STOP(arg0, arg1) -#endif - #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 522426f634d628..7a55bd632476ba 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -31,11 +31,61 @@ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; +}; + + +static void* uv__thread_start(void *arg) +{ + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + free(ctx_p); + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + err = pthread_create(tid, NULL, uv__thread_start, ctx); + + if (err) + free(ctx); + + return err ? -1 : 0; +} + + +uv_thread_t uv_thread_self(void) { + return pthread_self(); +} + int uv_thread_join(uv_thread_t *tid) { return -pthread_join(*tid, NULL); } +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return pthread_equal(*t1, *t2); +} + + int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) return -pthread_mutex_init(mutex, NULL); diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7ae19905fbffcb..82fa27cc12ae3f 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -123,12 +123,7 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { uv_spinlock_unlock(&termios_spinlock); raw = tty->orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag |= (ONLCR); - raw.c_cflag |= (CS8); - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - raw.c_cc[VMIN] = 1; - raw.c_cc[VTIME] = 0; + cfmakeraw(&raw); /* Put terminal in raw mode after draining */ if (tcsetattr(fd, TCSADRAIN, &raw)) diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 97727baa542973..5ba1ea4df4df47 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -257,64 +257,6 @@ int uv_udp_recv_stop(uv_udp_t* handle) { } -struct thread_ctx { - void (*entry)(void* arg); - void* arg; -}; - - -#ifdef _WIN32 -static UINT __stdcall uv__thread_start(void* arg) -#else -static void* uv__thread_start(void *arg) -#endif -{ - struct thread_ctx *ctx_p; - struct thread_ctx ctx; - - ctx_p = arg; - ctx = *ctx_p; - free(ctx_p); - ctx.entry(ctx.arg); - - return 0; -} - - -int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - struct thread_ctx* ctx; - int err; - - ctx = malloc(sizeof(*ctx)); - if (ctx == NULL) - return UV_ENOMEM; - - ctx->entry = entry; - ctx->arg = arg; - -#ifdef _WIN32 - *tid = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, ctx, 0, NULL); - err = *tid ? 0 : errno; -#else - err = pthread_create(tid, NULL, uv__thread_start, ctx); -#endif - - if (err) - free(ctx); - - return err ? -1 : 0; -} - - -unsigned long uv_thread_self(void) { -#ifdef _WIN32 - return (unsigned long) GetCurrentThreadId(); -#else - return (unsigned long) pthread_self(); -#endif -} - - void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { QUEUE* q; uv_handle_t* h; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 11d20f2dbd66c7..13af7c41a36d6e 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -557,11 +557,6 @@ void fs__read(uv_fs_t* req) { if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); - - offset_.QuadPart = offset; - overlapped.Offset = offset_.LowPart; - overlapped.OffsetHigh = offset_.HighPart; - overlapped_ptr = &overlapped; } else { overlapped_ptr = NULL; @@ -571,6 +566,13 @@ void fs__read(uv_fs_t* req) { bytes = 0; do { DWORD incremental_bytes; + + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + result = ReadFile(handle, req->bufs[index].base, req->bufs[index].len, @@ -623,7 +625,6 @@ void fs__write(uv_fs_t* req) { do { DWORD incremental_bytes; - /* WriteFile() does not advance overlapped as ReadFile() does. */ if (offset != -1) { offset_.QuadPart = offset + bytes; overlapped.Offset = offset_.LowPart; diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index ccc5579fa7a3b5..7143743926eee0 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -117,6 +117,68 @@ void uv_once(uv_once_t* guard, void (*callback)(void)) { uv__once_inner(guard, callback); } +static UV_THREAD_LOCAL uv_thread_t uv__current_thread = NULL; + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; + uv_thread_t self; +}; + + +static UINT __stdcall uv__thread_start(void* arg) +{ + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + free(ctx_p); + + uv__current_thread = ctx.self; + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + HANDLE thread; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + /* Create the thread in suspended state so we have a chance to pass + * its own creation handle to it */ + thread = (HANDLE) _beginthreadex(NULL, + 0, + uv__thread_start, + ctx, + CREATE_SUSPENDED, + NULL); + if (thread == NULL) { + err = errno; + free(ctx); + } else { + err = 0; + *tid = thread; + ctx->self = thread; + ResumeThread(thread); + } + + return err; +} + + +uv_thread_t uv_thread_self(void) { + return uv__current_thread; +} int uv_thread_join(uv_thread_t *tid) { if (WaitForSingleObject(*tid, INFINITE)) @@ -129,6 +191,11 @@ int uv_thread_join(uv_thread_t *tid) { } +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return *t1 == *t2; +} + + int uv_mutex_init(uv_mutex_t* mutex) { InitializeCriticalSection(mutex); return 0; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index b7dba7bbdaef71..0bcb721a524a2d 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -1037,7 +1037,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, /* XP has no OnLinkPrefixLength field. */ if (is_vista_or_greater) { - prefix_len = unicast_address->OnLinkPrefixLength; + prefix_len = + ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; } else { /* Prior to Windows Vista the FirstPrefix pointed to the list with * single prefix for each IP address assigned to the adapter. diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index 957d08ec198273..7c007ab4934608 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -166,6 +166,25 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { ULONG LeaseLifetime; } IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; + UINT8 OnLinkPrefixLength; +} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; + #endif #endif /* UV_WIN_WINSOCK_H_ */ diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 3e9dcb81fc4354..471860a76c4c0e 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -109,6 +109,7 @@ static uv_fs_t utime_req; static uv_fs_t futime_req; static char buf[32]; +static char buf2[32]; static char test_buf[] = "test-buffer\n"; static char test_buf2[] = "second-buffer\n"; static uv_buf_t iov; @@ -2200,12 +2201,15 @@ TEST_IMPL(fs_write_multiple_bufs) { uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); - iov = uv_buf_init(buf, sizeof(buf)); - r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, NULL); + memset(buf2, 0, sizeof(buf2)); + /* Read the strings back to separate buffers. */ + iovs[0] = uv_buf_init(buf, sizeof(test_buf)); + iovs[1] = uv_buf_init(buf2, sizeof(test_buf2)); + r = uv_fs_read(loop, &read_req, open_req1.result, iovs, 2, 0, NULL); ASSERT(r >= 0); ASSERT(read_req.result >= 0); - ASSERT(memcmp(buf, test_buf, sizeof(test_buf)) == 0); - ASSERT(strcmp(buf + sizeof(test_buf), test_buf2) == 0); + ASSERT(strcmp(buf, test_buf) == 0); + ASSERT(strcmp(buf2, test_buf2) == 0); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 08ba3f83033899..85ddac82ae123a 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -259,6 +259,7 @@ TEST_DECLARE (thread_local_storage) TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_create) +TEST_DECLARE (thread_equal) TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) @@ -632,6 +633,7 @@ TASK_LIST_START TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_create) + TEST_ENTRY (thread_equal) TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) diff --git a/deps/uv/test/test-thread-equal.c b/deps/uv/test/test-thread-equal.c new file mode 100644 index 00000000000000..27c07ee2c7d33b --- /dev/null +++ b/deps/uv/test/test-thread-equal.c @@ -0,0 +1,45 @@ +/* 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" + +uv_thread_t main_thread_id; +uv_thread_t subthreads[2]; + +static void check_thread(void* arg) { + uv_thread_t *thread_id = arg; + uv_thread_t self_id = uv_thread_self(); + ASSERT(uv_thread_equal(&main_thread_id, &self_id) == 0); + *thread_id = uv_thread_self(); +} + +TEST_IMPL(thread_equal) { + uv_thread_t threads[2]; + main_thread_id = uv_thread_self(); + ASSERT(0 != uv_thread_equal(&main_thread_id, &main_thread_id)); + ASSERT(0 == uv_thread_create(threads + 0, check_thread, subthreads + 0)); + ASSERT(0 == uv_thread_create(threads + 1, check_thread, subthreads + 1)); + ASSERT(0 == uv_thread_join(threads + 0)); + ASSERT(0 == uv_thread_join(threads + 1)); + ASSERT(0 == uv_thread_equal(subthreads + 0, subthreads + 1)); + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 444182b62d7a86..a5ba14c315a14a 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -1,14 +1,4 @@ { - 'variables': { - 'uv_use_dtrace%': 'false', - # uv_parent_path is the relative path to libuv in the parent project - # this is only relevant when dtrace is enabled and libuv is a child project - # as it's necessary to correctly locate the object files for post - # processing. - # XXX gyp is quite sensitive about paths with double / they don't normalize - 'uv_parent_path': '/', - }, - 'target_defaults': { 'conditions': [ ['OS != "win"', { @@ -199,7 +189,7 @@ ['uv_library=="shared_library" and OS!="mac"', { 'link_settings': { # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR - # in src/version.c + # in include/uv-version.h 'libraries': [ '-Wl,-soname,libuv.so.1.0' ], }, }], @@ -296,20 +286,6 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], - # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. - ['uv_use_dtrace=="true"', { - 'defines': [ 'HAVE_DTRACE=1' ], - 'dependencies': [ 'uv_dtrace_header' ], - 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], - 'conditions': [ - [ 'OS not in "mac linux"', { - 'sources': [ 'src/unix/dtrace.c' ], - }], - [ 'OS=="linux"', { - 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ] - }], - ], - }], ] }, @@ -410,6 +386,7 @@ 'test/test-tcp-write-queue-order.c', 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', + 'test/test-thread-equal.c', 'test/test-mutexes.c', 'test/test-thread.c', 'test/test-barrier.c', @@ -521,60 +498,5 @@ }, }, }, - - { - 'target_name': 'uv_dtrace_header', - 'type': 'none', - 'conditions': [ - [ 'uv_use_dtrace=="true"', { - 'actions': [ - { - 'action_name': 'uv_dtrace_header', - 'inputs': [ 'src/unix/uv-dtrace.d' ], - 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/uv-dtrace.h' ], - 'action': [ 'dtrace', '-h', '-xnolibs', '-s', '<@(_inputs)', - '-o', '<@(_outputs)' ], - }, - ], - }], - ], - }, - - # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. - { - 'target_name': 'uv_dtrace_provider', - 'type': 'none', - 'conditions': [ - [ 'uv_use_dtrace=="true" and OS not in "mac linux"', { - 'actions': [ - { - 'action_name': 'uv_dtrace_o', - 'inputs': [ - 'src/unix/uv-dtrace.d', - '<(PRODUCT_DIR)/obj.target/libuv<(uv_parent_path)src/unix/core.o', - ], - 'outputs': [ - '<(PRODUCT_DIR)/obj.target/libuv<(uv_parent_path)src/unix/dtrace.o', - ], - 'action': [ 'dtrace', '-G', '-xnolibs', '-s', '<@(_inputs)', - '-o', '<@(_outputs)' ] - } - ] - }], - [ 'uv_use_dtrace=="true" and OS=="linux"', { - 'actions': [ - { - 'action_name': 'uv_dtrace_o', - 'inputs': [ 'src/unix/uv-dtrace.d' ], - 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ], - 'action': [ - 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' - ], - } - ] - }], - ] - }, - ] } From e0a0e913c7b340e756a6728226eb5c638f76be05 Mon Sep 17 00:00:00 2001 From: Nathan Woltman Date: Fri, 21 Nov 2014 03:22:07 -0500 Subject: [PATCH 02/27] path: refactor normalizeArray() The normalizeArray() function now avoids using the slow Array#splice() method to improve performance and now also filters out empty path parts. Code that pre-filtered empty parts has been removed. PR-URL: https://github.com/joyent/node/pull/8724 Reviewed-by: Trevor Norris --- lib/path.js | 64 +++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/lib/path.js b/lib/path.js index 70a9016449467e..1765ef075d3ec3 100644 --- a/lib/path.js +++ b/lib/path.js @@ -25,33 +25,30 @@ var util = require('util'); // resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array +// must be no slashes or device names (c:\) in the array // (so also no leading and trailing slashes - it does not distinguish // relative and absolute paths) function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } + var res = []; + for (var i = 0; i < parts.length; i++) { + var p = parts[i]; + + // ignore empty parts + if (!p || p === '.') + continue; - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); + if (p === '..') { + if (res.length && res[res.length - 1] !== '..') { + res.pop(); + } else if (allowAboveRoot) { + res.push('..'); + } + } else { + res.push(p); } } - return parts; + return res; } // Regex to split a windows path into three parts: [*, device, slash, @@ -153,12 +150,7 @@ win32.resolve = function() { // fails) // Normalize the tail path - - function f(p) { - return !!p; - } - - resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f), + resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/), !resolvedAbsolute).join('\\'); // If device is a drive letter, we'll normalize to lower case. @@ -186,9 +178,7 @@ win32.normalize = function(path) { } // Normalize the tail path - tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) { - return !!p; - }), !isAbsolute).join('\\'); + tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute).join('\\'); if (!tail && !isAbsolute) { tail = '.'; @@ -453,9 +443,8 @@ posix.resolve = function() { // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path - resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); + resolvedPath = normalizeArray(resolvedPath.split('/'), + !resolvedAbsolute).join('/'); return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; }; @@ -464,17 +453,10 @@ posix.resolve = function() { // posix version posix.normalize = function(path) { var isAbsolute = posix.isAbsolute(path), - trailingSlash = path.substr(-1) === '/', - segments = path.split('/'), - nonEmptySegments = []; + trailingSlash = path.substr(-1) === '/'; // Normalize the path - for (var i = 0; i < segments.length; i++) { - if (segments[i]) { - nonEmptySegments.push(segments[i]); - } - } - path = normalizeArray(nonEmptySegments, !isAbsolute).join('/'); + path = normalizeArray(path.split('/'), !isAbsolute).join('/'); if (!path && !isAbsolute) { path = '.'; From bf3e0f417bbf4ba749730a76dd36a3e59d44da3e Mon Sep 17 00:00:00 2001 From: Vladimir Kurchatkin Date: Tue, 18 Nov 2014 12:30:27 +0300 Subject: [PATCH 03/27] smalloc: don't allow to dispose typed arrays PR-URL: https://github.com/joyent/node/pull/8743 Reviewed-by: Trevor Norris --- lib/smalloc.js | 2 ++ src/smalloc.cc | 4 ++++ test/simple/test-smalloc.js | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/lib/smalloc.js b/lib/smalloc.js index fd82ba8c42a4f1..2b4175e0cb15b8 100644 --- a/lib/smalloc.js +++ b/lib/smalloc.js @@ -86,6 +86,8 @@ function dispose(obj) { throw new TypeError('obj must be an Object'); if (util.isBuffer(obj)) throw new TypeError('obj cannot be a Buffer'); + if (smalloc.isTypedArray(obj)) + throw new TypeError('obj cannot be a typed array'); if (!smalloc.hasExternalData(obj)) throw new Error('obj has no external array data'); diff --git a/src/smalloc.cc b/src/smalloc.cc index c7913d90ff849a..7dc3510a0bf540 100644 --- a/src/smalloc.cc +++ b/src/smalloc.cc @@ -446,6 +446,9 @@ bool HasExternalData(Environment* env, Local obj) { return obj->HasIndexedPropertiesInExternalArrayData(); } +void IsTypedArray(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(args[0]->IsTypedArray()); +} void AllocTruncate(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); @@ -547,6 +550,7 @@ void Initialize(Handle exports, NODE_SET_METHOD(exports, "truncate", AllocTruncate); NODE_SET_METHOD(exports, "hasExternalData", HasExternalData); + NODE_SET_METHOD(exports, "isTypedArray", IsTypedArray); exports->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"), Uint32::NewFromUnsigned(env->isolate(), kMaxLength)); diff --git a/test/simple/test-smalloc.js b/test/simple/test-smalloc.js index 091f5aa7e08e6d..198b5c7f5cc038 100644 --- a/test/simple/test-smalloc.js +++ b/test/simple/test-smalloc.js @@ -323,6 +323,10 @@ assert.throws(function() { smalloc.dispose(new Buffer()); }); +assert.throws(function() { + smalloc.dispose(new Uint8Array(new ArrayBuffer(1))); +}); + assert.throws(function() { smalloc.dispose({}); }); From 69904c8a7838ce4ef4023bb4b980bf87531d74ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 26 Nov 2014 22:37:41 +0100 Subject: [PATCH 04/27] deps: update libuv to 1.0.1 PR-URL: https://github.com/joyent/node/pull/8785 Reviewed-by: Trevor Norris --- deps/uv/AUTHORS | 2 ++ deps/uv/CONTRIBUTING.md | 6 +++--- deps/uv/ChangeLog | 17 ++++++++++++++++- deps/uv/README.md | 8 ++++---- deps/uv/configure.ac | 2 +- deps/uv/docs/src/handle.rst | 2 +- deps/uv/docs/src/index.rst | 6 +++--- deps/uv/docs/src/request.rst | 2 +- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv.h | 2 +- deps/uv/src/unix/process.c | 9 +++++++-- deps/uv/src/win/fs.c | 10 +++++----- 12 files changed, 45 insertions(+), 23 deletions(-) diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 7a85150db017d5..72fa470dab518a 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -171,3 +171,5 @@ Mikhail Mukovnikov Thorsten Lorenz Yuri D'Elia Manos Nikolaidis +Elijah Andrews +Michael Ira Krufky diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index ea4be395edecd1..332ed1129b848c 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -6,13 +6,13 @@ through the process. ### FORK -Fork the project [on GitHub](https://github.com/joyent/libuv) and check out +Fork the project [on GitHub](https://github.com/libuv/libuv) and check out your copy. ``` $ git clone https://github.com/username/libuv.git $ cd libuv -$ git remote add upstream https://github.com/joyent/libuv.git +$ git remote add upstream https://github.com/libuv/libuv.git ``` Now decide if you want your feature or bug fix to go into the master branch @@ -160,7 +160,7 @@ feature branch. Post a comment in the pull request afterwards; GitHub does not send out notifications when you add commits. -[issue tracker]: https://github.com/joyent/libuv/issues +[issue tracker]: https://github.com/libuv/libuv/issues [libuv mailing list]: http://groups.google.com/group/libuv [IRC]: http://webchat.freelibuv.net/?channels=libuv [Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index a76c4b5bb2c352..78600b78edd92e 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,19 @@ -2014.11.21, Version 1.0.0 (Stable) +2014.11.27, Version 1.0.1 (Stable), 0a8e81374e861d425b56c45c8599595d848911d2 + +Changes since version 1.0.0: + +* readme: remove Rust from users (Elijah Andrews) + +* doc,build,include: update project links (Ben Noordhuis) + +* doc: fix typo: Strcutures -> Structures (Michael Ira Krufky) + +* unix: fix processing process handles queue (Saúl Ibarra Corretgé) + +* win: replace non-ansi characters in source file (Bert Belder) + + +2014.11.21, Version 1.0.0 (Stable), feb2a9e6947d892f449b2770c4090f7d8c88381b Changes since version 1.0.0-rc2: diff --git a/deps/uv/README.md b/deps/uv/README.md index 1b079d9f347388..7fc7cfbd063ed4 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -5,7 +5,7 @@ libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by [Node.js](http://nodejs.org), but it's also used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), -[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). +[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/wiki/Projects-that-use-libuv). ## Feature highlights @@ -77,7 +77,7 @@ Documentation can be browsed online [here](http://docs.libuv.org). — An overview of libuv with tutorials. * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) — High-level introductory talk about libuv. - * [Tests and benchmarks](https://github.com/joyent/libuv/tree/master/test) + * [Tests and benchmarks](https://github.com/libuv/libuv/tree/master/test) — API specification and usage examples. * [libuv-dox](https://github.com/thlorenz/libuv-dox) — Documenting types and methods of libuv, mostly by reading uv.h. @@ -181,5 +181,5 @@ See the [guidelines for contributing][]. [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 -[libuv_banner]: https://raw.githubusercontent.com/joyent/libuv/master/img/banner.png +[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md +[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 3ab69199d8ac03..247e42bd272679 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.0.0], [https://github.com/joyent/libuv/issues]) +AC_INIT([libuv], [1.0.1], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/handle.rst b/deps/uv/docs/src/handle.rst index 4dcfc3dd90f03e..6ba597a21ab996 100644 --- a/deps/uv/docs/src/handle.rst +++ b/deps/uv/docs/src/handle.rst @@ -6,7 +6,7 @@ `uv_handle_t` is the base type for all libuv handle types. -Strcutures are aligned so that any libuv handle can be cast to `uv_handle_t`. +Structures are aligned so that any libuv handle can be cast to `uv_handle_t`. All API functions defined here work with any handle type. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst index a8f00dab38c316..9cdc494aecba79 100644 --- a/deps/uv/docs/src/index.rst +++ b/deps/uv/docs/src/index.rst @@ -11,13 +11,13 @@ was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_, .. note:: In case you find errors in this documentation you can help by sending - `pull requests `_! + `pull requests `_! .. _Node.js: http://nodejs.org .. _Luvit: http://luvit.io .. _Julia: http://julialang.org .. _pyuv: https://github.com/saghul/pyuv -.. _others: https://github.com/joyent/libuv/wiki/Projects-that-use-libuv +.. _others: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv Features @@ -46,7 +46,7 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found on `the README `_. +Installation instructions can be found on `the README `_. Upgrading diff --git a/deps/uv/docs/src/request.rst b/deps/uv/docs/src/request.rst index 29c1277924b02c..2f58d46b143c6d 100644 --- a/deps/uv/docs/src/request.rst +++ b/deps/uv/docs/src/request.rst @@ -6,7 +6,7 @@ `uv_req_t` is the base type for all libuv request types. -Strcutures are aligned so that any libuv request can be cast to `uv_req_t`. +Structures are aligned so that any libuv request can be cast to `uv_req_t`. All API functions defined here work with any request type. diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 4f4220cf622949..889abffca30897 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,7 +32,7 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 0 -#define UV_VERSION_PATCH 0 +#define UV_VERSION_PATCH 1 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index d17f977b44a501..7f4fa6dd8ad8de 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -19,7 +19,7 @@ * IN THE SOFTWARE. */ -/* See https://github.com/joyent/libuv#documentation for documentation. */ +/* See https://github.com/libuv/libuv#documentation for documentation. */ #ifndef UV_H #define UV_H diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 0aff5fd31f5cc2..be283b480d6a23 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -85,9 +85,14 @@ static void uv__chld(uv_signal_t* handle, int signum) { QUEUE_INSERT_TAIL(&pending, &process->queue); } - QUEUE_FOREACH(q, &pending) { + h = &pending; + q = QUEUE_HEAD(h); + while (q != h) { process = QUEUE_DATA(q, uv_process_t, queue); - QUEUE_REMOVE(q); + q = QUEUE_NEXT(q); + + QUEUE_REMOVE(&process->queue); + QUEUE_INIT(&process->queue); uv__handle_stop(process); if (process->exit_cb == NULL) diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 13af7c41a36d6e..7208a65c424e06 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -283,7 +283,7 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, (w_target[4] >= L'a' && w_target[4] <= L'z')) && w_target[5] == L':' && (w_target_len == 6 || w_target[6] == L'\\')) { - /* \??\«drive»:\ */ + /* \??\:\ */ w_target += 4; w_target_len -= 4; @@ -292,8 +292,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, (w_target[5] == L'N' || w_target[5] == L'n') && (w_target[6] == L'C' || w_target[6] == L'c') && w_target[7] == L'\\') { - /* \??\UNC\«server»\«share»\ - make sure the final path looks like */ - /* \\«server»\«share»\ */ + /* \??\UNC\\\ - make sure the final path looks like */ + /* \\\\ */ w_target += 6; w_target[0] = L'\\'; w_target_len -= 6; @@ -308,8 +308,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Only treat junctions that look like \??\«drive»:\ as symlink. */ - /* Junctions can also be used as mount points, like \??\Volume{«guid»}, */ + /* Only treat junctions that look like \??\:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{}, */ /* but that's confusing for programs since they wouldn't be able to */ /* actually understand such a path when returned by uv_readlink(). */ /* UNC paths are never valid for junctions so we don't care about them. */ From 0308ad2ce53f73368f265d5e7ee4c0e9f07600a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 26 Nov 2014 22:50:19 +0100 Subject: [PATCH 05/27] crypto: cast uv_thread_t to unsigned long Should work in all platforms and it fixes this compilation problem on OSX: ../src/node_crypto.cc:154:3: error: no matching function for call to 'CRYPTO_THREADID_set_numeric' CRYPTO_THREADID_set_numeric(tid, uv_thread_self()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~ ../deps/openssl/openssl/include/openssl/../../crypto/crypto.h:435:6: note: candidate function not viable: no known conversion from 'uv_thread_t' (aka '_opaque_pthread_t *') to 'unsigned long' for 2nd argument void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val); ^ 1 error generated. PR-URL: https://github.com/joyent/node/pull/8785 Reviewed-by: Trevor Norris --- src/node_crypto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 7a35314a94788a..51aed486beaad2 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -151,7 +151,7 @@ template int SSLWrap::TLSExtStatusCallback(SSL* s, void* arg); static void crypto_threadid_cb(CRYPTO_THREADID* tid) { - CRYPTO_THREADID_set_numeric(tid, uv_thread_self()); + CRYPTO_THREADID_set_numeric(tid, (unsigned long) uv_thread_self()); } From cb8cadbe6245ffc94948194240e4e5f9fbffd5e7 Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Fri, 28 Nov 2014 13:11:36 +0100 Subject: [PATCH 06/27] Revert "crypto: cast uv_thread_t to unsigned long" This reverts commit 0308ad2ce53f73368f265d5e7ee4c0e9f07600a6. --- src/node_crypto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 51aed486beaad2..7a35314a94788a 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -151,7 +151,7 @@ template int SSLWrap::TLSExtStatusCallback(SSL* s, void* arg); static void crypto_threadid_cb(CRYPTO_THREADID* tid) { - CRYPTO_THREADID_set_numeric(tid, (unsigned long) uv_thread_self()); + CRYPTO_THREADID_set_numeric(tid, uv_thread_self()); } From 304c0b43aa88fdeb13ac4607a89ff096b87c8b86 Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Mon, 17 Nov 2014 16:44:19 +0100 Subject: [PATCH 07/27] crypto: store thread id as pointer-sized In https://github.com/MSOpenTech/libuv/commit/59658a8de7cc05a58327a164fd2ed4b050f8b4f4 the return of uv_thread_self() was changed from unsigned long to uv_thread_t. uv_thread_t is a HANDLE (pointer-sized) on Windows, which means that on Win64 it cannot be stored with CRYPTO_THREADID_set_numeric without data loss. Furthermore, without this change there will be a build break on Windows when the libuv change is integrated into Node, because of the conversion from HANDLE to unsigned long. Other related commits: https://github.com/joyent/node/commit/5845a6bcd5b36168bdddeb85da8d8d9d36de7642 https://github.com/MSOpenTech/libuv/commit/919d8ec63ac53566ad1f090058ec15966bd0e960 --- src/node_crypto.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 7a35314a94788a..1e3fc2b6b39fbe 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -151,7 +151,8 @@ template int SSLWrap::TLSExtStatusCallback(SSL* s, void* arg); static void crypto_threadid_cb(CRYPTO_THREADID* tid) { - CRYPTO_THREADID_set_numeric(tid, uv_thread_self()); + assert(sizeof(uv_thread_t) <= sizeof(void*)); + CRYPTO_THREADID_set_pointer(tid, (void*) uv_thread_self()); } From c131c1f92043ed8cfaf7474178d54c7bc4a74226 Mon Sep 17 00:00:00 2001 From: Thorsten Lorenz Date: Mon, 15 Sep 2014 12:00:22 -0500 Subject: [PATCH 08/27] modules: adding load linked modules feature - introduced NM_F_LINKED flag to identify linked modules - setting node_is_initialized after calling V8::Initialize in order to make the right decision during initial module registration - introduced modlist_linked in order to track modules that were pre-registered in order to complete it once node is initialized - completing registration of linked module similarly to the way it's done inside DLOpen PR-URL: https://github.com/joyent/node/pull/8386 Reviewed-by: Trevor Norris --- src/node.cc | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/node.h | 2 ++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index 532f902aadf8e4..edb546052d43f2 100644 --- a/src/node.cc +++ b/src/node.cc @@ -131,8 +131,10 @@ static bool use_debug_agent = false; static bool debug_wait_connect = false; static int debug_port = 5858; static bool v8_is_profiling = false; +static bool node_is_initialized = false; static node_module* modpending; static node_module* modlist_builtin; +static node_module* modlist_linked; static node_module* modlist_addon; #if defined(NODE_HAVE_I18N_SUPPORT) @@ -2051,8 +2053,16 @@ extern "C" void node_module_register(void* m) { if (mp->nm_flags & NM_F_BUILTIN) { mp->nm_link = modlist_builtin; modlist_builtin = mp; + } else if (!node_is_initialized) { + // "Linked" modules are included as part of the node project. + // Like builtins they are registered *before* node::Init runs. + mp->nm_flags = NM_F_LINKED; + mp->nm_link = modlist_linked; + modlist_linked = mp; } else { - assert(modpending == NULL); + // Once node::Init was called we can only register dynamic modules. + // See DLOpen. + CHECK_NE(modpending, NULL); modpending = mp; } } @@ -2069,6 +2079,18 @@ struct node_module* get_builtin_module(const char* name) { return (mp); } +struct node_module* get_linked_module(const char* name) { + struct node_module* mp; + + for (mp = modlist_linked; mp != NULL; mp = mp->nm_link) { + if (strcmp(mp->nm_modname, name) == 0) + break; + } + + CHECK(mp == NULL || (mp->nm_flags & NM_F_LINKED) != 0); + return mp; +} + typedef void (UV_DYNAMIC* extInit)(Handle exports); // DLOpen is process.dlopen(module, filename). @@ -2275,6 +2297,46 @@ static void Binding(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(exports); } +static void LinkedBinding(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + + Local module = args[0]->ToString(); + + Local cache = env->binding_cache_object(); + Local exports_v = cache->Get(module); + + if (exports_v->IsObject()) + return args.GetReturnValue().Set(exports_v.As()); + + node::Utf8Value module_v(module); + node_module* mod = get_linked_module(*module_v); + + if (mod == NULL) { + char errmsg[1024]; + snprintf(errmsg, + sizeof(errmsg), + "No such module was linked: %s", + *module_v); + return env->ThrowError(errmsg); + } + + Local exports = Object::New(env->isolate()); + + if (mod->nm_context_register_func != NULL) { + mod->nm_context_register_func(exports, + module, + env->context(), + mod->nm_priv); + } else if (mod->nm_register_func != NULL) { + mod->nm_register_func(exports, module, mod->nm_priv); + } else { + return env->ThrowError("Linked module has no declared entry point."); + } + + cache->Set(module, exports); + + args.GetReturnValue().Set(exports); +} static void ProcessTitleGetter(Local property, const PropertyCallbackInfo& info) { @@ -2816,6 +2878,7 @@ void SetupProcessObject(Environment* env, NODE_SET_METHOD(process, "memoryUsage", MemoryUsage); NODE_SET_METHOD(process, "binding", Binding); + NODE_SET_METHOD(process, "_linkedBinding", LinkedBinding); NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener); NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick); @@ -3724,6 +3787,7 @@ int Start(int argc, char** argv) { int code; V8::Initialize(); + node_is_initialized = true; { Locker locker(node_isolate); Isolate::Scope isolate_scope(node_isolate); diff --git a/src/node.h b/src/node.h index 384b790c97fc5a..bb8a3de0e43bee 100644 --- a/src/node.h +++ b/src/node.h @@ -347,6 +347,7 @@ typedef void (*addon_context_register_func)( void* priv); #define NM_F_BUILTIN 0x01 +#define NM_F_LINKED 0x02 struct node_module { int nm_version; @@ -361,6 +362,7 @@ struct node_module { }; node_module* get_builtin_module(const char *name); +node_module* get_linked_module(const char *name); extern "C" NODE_EXTERN void node_module_register(void* mod); From d312b6d15c69cf4c438ed7d884e6396c481a57f6 Mon Sep 17 00:00:00 2001 From: Yazhong Liu Date: Thu, 20 Nov 2014 23:46:38 +0800 Subject: [PATCH 09/27] url: support `path` for url.format this adds support for a "path" field that overrides "query", "search", and "pathname" if given. Fixes: https://github.com/joyent/node/issues/8722 PR-URL: https://github.com/joyent/node/pull/8755 Reviewed-by: Chris Dickinson --- doc/api/url.markdown | 9 ++--- lib/url.js | 31 ++++++++++++++--- test/simple/test-url.js | 77 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/doc/api/url.markdown b/doc/api/url.markdown index 6b8ff9d5076817..3ace6995794171 100644 --- a/doc/api/url.markdown +++ b/doc/api/url.markdown @@ -95,11 +95,12 @@ Take a parsed URL object, and return a formatted URL string. * `hostname` will only be used if `host` is absent. * `port` will only be used if `host` is absent. * `host` will be used in place of `hostname` and `port` -* `pathname` is treated the same with or without the leading `/` (slash) -* `search` will be used in place of `query` +* `pathname` is treated the same with or without the leading `/` (slash). +* `path` is treated the same with `pathname` but able to contain `query` as well. +* `search` will be used in place of `query`. * `query` (object; see `querystring`) will only be used if `search` is absent. -* `search` is treated the same with or without the leading `?` (question mark) -* `hash` is treated the same with or without the leading `#` (pound sign, anchor) +* `search` is treated the same with or without the leading `?` (question mark). +* `hash` is treated the same with or without the leading `#` (pound sign, anchor). ## url.resolve(from, to) diff --git a/lib/url.js b/lib/url.js index e01343a50691e1..f5e7ec0a9f7b8e 100644 --- a/lib/url.js +++ b/lib/url.js @@ -360,7 +360,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { } // finally, reconstruct the href based on what has been validated. - this.href = this.format(); + this.href = this.format(parseQueryString); return this; }; @@ -375,7 +375,7 @@ function urlFormat(obj) { return obj.format(); } -Url.prototype.format = function() { +Url.prototype.format = function(parseQueryString) { var auth = this.auth || ''; if (auth) { auth = encodeURIComponent(auth); @@ -387,7 +387,26 @@ Url.prototype.format = function() { pathname = this.pathname || '', hash = this.hash || '', host = false, - query = ''; + query = '', + search = ''; + + if (this.path) { + var qm = this.path.indexOf('?'); + if (qm !== -1) { + query = this.path.slice(qm + 1); + search = '?' + query; + pathname = this.path.slice(0, qm); + } else { + if (parseQueryString) { + this.query = {}; + this.search = ''; + } else { + this.query = null; + this.search = null; + } + pathname = this.path; + } + } if (this.host) { host = auth + this.host; @@ -400,13 +419,15 @@ Url.prototype.format = function() { } } - if (this.query && + if (!query && + this.query && util.isObject(this.query) && Object.keys(this.query).length) { query = querystring.stringify(this.query); } - var search = this.search || (query && ('?' + query)) || ''; + if (!search) + search = this.search || (query && ('?' + query)) || ''; if (protocol && protocol.substr(-1) !== ':') protocol += ':'; diff --git a/test/simple/test-url.js b/test/simple/test-url.js index 8bfedcdf3d6b58..df72cc6f4e65e1 100644 --- a/test/simple/test-url.js +++ b/test/simple/test-url.js @@ -1085,7 +1085,7 @@ var formatTests = { // `#`,`?` in path '/path/to/%%23%3F+=&.txt?foo=theA1#bar' : { - href : '/path/to/%%23%3F+=&.txt?foo=theA1#bar', + href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'theA1' @@ -1095,7 +1095,7 @@ var formatTests = { // `#`,`?` in path + `#` in query '/path/to/%%23%3F+=&.txt?foo=the%231#bar' : { - href : '/path/to/%%23%3F+=&.txt?foo=the%231#bar', + href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'the#1' @@ -1110,7 +1110,7 @@ var formatTests = { hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', - pathname: '/foo?100%m#r', + pathname: '/foo?100%m#r' }, // `?` and `#` in search only @@ -1120,8 +1120,77 @@ var formatTests = { hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', - pathname: '/fooA100%mBr', + pathname: '/fooA100%mBr' + }, + + // path + 'http://github.com/joyent/node#js1': { + href: 'http://github.com/joyent/node#js1', + protocol: 'http:', + hostname: 'github.com', + hash: '#js1', + path: '/joyent/node' + }, + + // pathname vs. path, path wins + 'http://github.com/joyent/node2#js1': { + href: 'http://github.com/joyent/node2#js1', + protocol: 'http:', + hostname: 'github.com', + hash: '#js1', + path: '/joyent/node2', + pathname: '/joyent/node' + }, + + // pathname with query/search + 'http://github.com/joyent/node?foo=bar#js2': { + href: 'http://github.com/joyent/node?foo=bar#js2', + protocol: 'http:', + hostname: 'github.com', + hash: '#js2', + path: '/joyent/node?foo=bar' + }, + + // path vs. query, path wins + 'http://github.com/joyent/node?foo=bar2#js3': { + href: 'http://github.com/joyent/node?foo=bar2#js3', + protocol: 'http:', + hostname: 'github.com', + hash: '#js3', + path: '/joyent/node?foo=bar2', + query: {foo: 'bar'} + }, + + // path vs. search, path wins + 'http://github.com/joyent/node?foo=bar3#js4': { + href: 'http://github.com/joyent/node?foo=bar3#js4', + protocol: 'http:', + hostname: 'github.com', + hash: '#js4', + path: '/joyent/node?foo=bar3', + search: '?foo=bar' + }, + + // path is present without ? vs. query given + 'http://github.com/joyent/node#js5': { + href: 'http://github.com/joyent/node#js5', + protocol: 'http:', + hostname: 'github.com', + hash: '#js5', + path: '/joyent/node', + query: {foo: 'bar'} + }, + + // path is present without ? vs. search given + 'http://github.com/joyent/node#js6': { + href: 'http://github.com/joyent/node#js6', + protocol: 'http:', + hostname: 'github.com', + hash: '#js6', + path: '/joyent/node', + search: '?foo=bar' } + }; for (var u in formatTests) { var expect = formatTests[u].href; From c4f6c22c2033038c3629bc5c48f0f2346d211378 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 2 Dec 2014 17:10:40 -0800 Subject: [PATCH 10/27] lint: fix code style Couple code style fixes to pass cpplint Fixes: 304c0b4 "crypto: store thread id as pointer-sized" --- src/node_crypto.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 1e3fc2b6b39fbe..36836c1a7906ec 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -151,8 +151,8 @@ template int SSLWrap::TLSExtStatusCallback(SSL* s, void* arg); static void crypto_threadid_cb(CRYPTO_THREADID* tid) { - assert(sizeof(uv_thread_t) <= sizeof(void*)); - CRYPTO_THREADID_set_pointer(tid, (void*) uv_thread_self()); + assert(sizeof(uv_thread_t) <= sizeof(void*)); // NOLINT(runtime/sizeof) + CRYPTO_THREADID_set_pointer(tid, reinterpret_cast(uv_thread_self())); } From 61204720361824881aefd64f5bccda7d7be6617a Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Wed, 26 Nov 2014 20:02:25 -0600 Subject: [PATCH 11/27] url: change hostname regex to negate invalid chars Regarding joyent/node#8520 This changes hostname validation from a whitelist regex approach to a blacklist regex approach as described in https://url.spec.whatwg.org/#host-parsing. url.parse misinterpreted `https://good.com+.evil.org/` as `https://good.com/+.evil.org/`. If we use url.parse to check the validity of the hostname, the test passes, but in the browser the user is redirected to the evil.org website. --- lib/url.js | 5 +++-- test/simple/test-url.js | 36 ++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/url.js b/lib/url.js index f5e7ec0a9f7b8e..0302fda1427181 100644 --- a/lib/url.js +++ b/lib/url.js @@ -70,8 +70,9 @@ var protocolPattern = /^([a-z0-9.+-]+:)/i, nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), hostEndingChars = ['/', '?', '#'], hostnameMaxLen = 255, - hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/, + hostnamePatternString = '[^' + nonHostChars.join('') + ']{0,63}', + hostnamePartPattern = new RegExp('^' + hostnamePatternString + '$'), + hostnamePartStart = new RegExp('^(' + hostnamePatternString + ')(.*)$'), // protocols that can allow "unsafe" and "unwise" chars. unsafeProtocol = { 'javascript': true, diff --git a/test/simple/test-url.js b/test/simple/test-url.js index df72cc6f4e65e1..f12a00dbed0b72 100644 --- a/test/simple/test-url.js +++ b/test/simple/test-url.js @@ -177,32 +177,44 @@ var parseTests = { 'path': '/Y' }, + // + not an invalid host character + // per https://url.spec.whatwg.org/#host-parsing + 'http://x.y.com+a/b/c' : { + 'href': 'http://x.y.com+a/b/c', + 'protocol': 'http:', + 'slashes': true, + 'host': 'x.y.com+a', + 'hostname': 'x.y.com+a', + 'pathname': '/b/c', + 'path': '/b/c' + }, + // an unexpected invalid char in the hostname. - 'HtTp://x.y.cOm*a/b/c?d=e#f gi' : { - 'href': 'http://x.y.com/*a/b/c?d=e#f%20g%3Ch%3Ei', + 'HtTp://x.y.cOm;a/b/c?d=e#f gi' : { + 'href': 'http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'x.y.com', 'hostname': 'x.y.com', - 'pathname': '/*a/b/c', + 'pathname': ';a/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', - 'path': '/*a/b/c?d=e' + 'path': ';a/b/c?d=e' }, // make sure that we don't accidentally lcast the path parts. - 'HtTp://x.y.cOm*A/b/c?d=e#f gi' : { - 'href': 'http://x.y.com/*A/b/c?d=e#f%20g%3Ch%3Ei', + 'HtTp://x.y.cOm;A/b/c?d=e#f gi' : { + 'href': 'http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'x.y.com', 'hostname': 'x.y.com', - 'pathname': '/*A/b/c', + 'pathname': ';A/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', - 'path': '/*A/b/c?d=e' + 'path': ';A/b/c?d=e' }, 'http://x...y...#p': { @@ -517,17 +529,17 @@ var parseTests = { 'path': '/' }, - 'http://www.Äffchen.cOm*A/b/c?d=e#f gi' : { - 'href': 'http://www.xn--ffchen-9ta.com/*A/b/c?d=e#f%20g%3Ch%3Ei', + 'http://www.Äffchen.cOm;A/b/c?d=e#f gi' : { + 'href': 'http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'www.xn--ffchen-9ta.com', 'hostname': 'www.xn--ffchen-9ta.com', - 'pathname': '/*A/b/c', + 'pathname': ';A/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', - 'path': '/*A/b/c?d=e' + 'path': ';A/b/c?d=e' }, 'http://SÉLIER.COM/' : { From 4815873bb52f19e670d9b541e95d468c09b87105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Campderr=C3=B3s?= Date: Thu, 31 Jul 2014 10:34:51 +0200 Subject: [PATCH 12/27] doc: set logical umask in process.umask example 0644 seems to be the desired mode for new files (as it is a very weird umask), and to achieve that the correct umask would be 0022. PR-URL: https://github.com/joyent/node/pull/8039 Reviewed-by: Trevor Norris --- doc/api/process.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 614f5cf07aa225..ba0032509a276c 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -708,7 +708,7 @@ Sets or reads the process's file mode creation mask. Child processes inherit the mask from the parent process. Returns the old mask if `mask` argument is given, otherwise returns the current mask. - var oldmask, newmask = 0644; + var oldmask, newmask = 0022; oldmask = process.umask(newmask); console.log('Changed umask from: ' + oldmask.toString(8) + From e67db0191db01aca6c25a36b05485026cfb309bb Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 3 Dec 2014 17:16:31 -0800 Subject: [PATCH 13/27] node: fix bad assert It was my mistake to change an assert check. This changes it back to how the assert was originally done. Fixes: c131c1f "modules: adding load linked modules feature" Signed-off-by: Trevor Norris --- src/node.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index edb546052d43f2..5a9d0fc12caa11 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2062,7 +2062,7 @@ extern "C" void node_module_register(void* m) { } else { // Once node::Init was called we can only register dynamic modules. // See DLOpen. - CHECK_NE(modpending, NULL); + assert(modpending == NULL); modpending = mp; } } From df3a2b2cf21274fe7afc19d14ec0259b964e13f7 Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Fri, 7 Nov 2014 14:15:24 +0100 Subject: [PATCH 14/27] test: runner support for flaky tests Adding --flaky-tests option, to allow regarding flaky tests failures as non-fatal. Currently only observed by the TapProgressIndicator, which will add a # TODO directive to tests classified as flaky. According to the TAP specification, the test harness is supposed to treat failures that have a # TODO directive as non-fatal. --- tools/test.py | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/tools/test.py b/tools/test.py index 0772f9ad3212e6..579d444f6c59ef 100755 --- a/tools/test.py +++ b/tools/test.py @@ -55,8 +55,9 @@ class ProgressIndicator(object): - def __init__(self, cases): + def __init__(self, cases, flaky_tests_mode): self.cases = cases + self.flaky_tests_mode = flaky_tests_mode self.queue = Queue(len(cases)) for case in cases: self.queue.put_nowait(case) @@ -234,13 +235,19 @@ def HasRun(self, output): self._done += 1 command = basename(output.command[-1]) if output.UnexpectedOutput(): - print 'not ok %i - %s' % (self._done, command) + status_line = 'not ok %i - %s' % (self._done, command) + if FLAKY in output.test.outcomes and self.flaky_tests_mode == "dontcare": + status_line = status_line + " # TODO : Fix flaky test" + print status_line for l in output.output.stderr.splitlines(): print '#' + l for l in output.output.stdout.splitlines(): print '#' + l else: - print 'ok %i - %s' % (self._done, command) + status_line = 'ok %i - %s' % (self._done, command) + if FLAKY in output.test.outcomes: + status_line = status_line + " # TODO : Fix flaky test" + print status_line duration = output.test.duration @@ -258,8 +265,8 @@ def Done(self): class CompactProgressIndicator(ProgressIndicator): - def __init__(self, cases, templates): - super(CompactProgressIndicator, self).__init__(cases) + def __init__(self, cases, flaky_tests_mode, templates): + super(CompactProgressIndicator, self).__init__(cases, flaky_tests_mode) self.templates = templates self.last_status_length = 0 self.start_time = time.time() @@ -314,13 +321,13 @@ def PrintProgress(self, name): class ColorProgressIndicator(CompactProgressIndicator): - def __init__(self, cases): + def __init__(self, cases, flaky_tests_mode): templates = { 'status_line': "[%(mins)02i:%(secs)02i|\033[34m%%%(remaining) 4d\033[0m|\033[32m+%(passed) 4d\033[0m|\033[31m-%(failed) 4d\033[0m]: %(test)s", 'stdout': "\033[1m%s\033[0m", 'stderr': "\033[31m%s\033[0m", } - super(ColorProgressIndicator, self).__init__(cases, templates) + super(ColorProgressIndicator, self).__init__(cases, flaky_tests_mode, templates) def ClearLine(self, last_line_length): print "\033[1K\r", @@ -328,7 +335,7 @@ def ClearLine(self, last_line_length): class MonochromeProgressIndicator(CompactProgressIndicator): - def __init__(self, cases): + def __init__(self, cases, flaky_tests_mode): templates = { 'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%(failed) 4d]: %(test)s", 'stdout': '%s', @@ -336,7 +343,7 @@ def __init__(self, cases): 'clear': lambda last_line_length: ("\r" + (" " * last_line_length) + "\r"), 'max_length': 78 } - super(MonochromeProgressIndicator, self).__init__(cases, templates) + super(MonochromeProgressIndicator, self).__init__(cases, flaky_tests_mode, templates) def ClearLine(self, last_line_length): print ("\r" + (" " * last_line_length) + "\r"), @@ -738,8 +745,8 @@ def GetVmFlags(self, testcase, mode): def GetTimeout(self, mode): return self.timeout * TIMEOUT_SCALEFACTOR[mode] -def RunTestCases(cases_to_run, progress, tasks): - progress = PROGRESS_INDICATORS[progress](cases_to_run) +def RunTestCases(cases_to_run, progress, tasks, flaky_tests_mode): + progress = PROGRESS_INDICATORS[progress](cases_to_run, flaky_tests_mode) return progress.Run(tasks) @@ -763,6 +770,7 @@ def BuildRequirements(context, requirements, mode, scons_flags): TIMEOUT = 'timeout' CRASH = 'crash' SLOW = 'slow' +FLAKY = 'flaky' class Expression(object): @@ -1212,6 +1220,9 @@ def BuildOptions(): default=False, action="store_true") result.add_option("--cat", help="Print the source of the tests", default=False, action="store_true") + result.add_option("--flaky-tests", + help="Regard tests marked as flaky (run|skip|dontcare)", + default="run") result.add_option("--warn-unused", help="Report unused rules", default=False, action="store_true") result.add_option("-j", help="The number of parallel tasks to run", @@ -1258,6 +1269,13 @@ def ProcessOptions(options): options.scons_flags.append("arch=" + options.arch) if options.snapshot: options.scons_flags.append("snapshot=on") + def CheckTestMode(name, option): + if not option in ["run", "skip", "dontcare"]: + print "Unknown %s mode %s" % (name, option) + return False + return True + if not CheckTestMode("--flaky-tests", options.flaky_tests): + return False return True @@ -1457,15 +1475,15 @@ def wrap(processor): result = None def DoSkip(case): - return SKIP in case.outcomes or SLOW in case.outcomes + return SKIP in case.outcomes or SLOW in case.outcomes or (FLAKY in case.outcomes and options.flaky_tests == "skip") cases_to_run = [ c for c in all_cases if not DoSkip(c) ] if len(cases_to_run) == 0: print "No tests to run." - return 0 + return 1 else: try: start = time.time() - if RunTestCases(cases_to_run, options.progress, options.j): + if RunTestCases(cases_to_run, options.progress, options.j, options.flaky_tests): result = 0 else: result = 1 From 0674cbaceb81ba1130355aa7eb8e6389824e3cc4 Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Fri, 7 Nov 2014 14:31:39 +0100 Subject: [PATCH 15/27] test: mark current flaky tests as flaky --- test/internet/internet.status | 5 +++++ test/simple/simple.status | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/test/internet/internet.status b/test/internet/internet.status index 34aea6a6af7eae..584e9e5aac0b70 100644 --- a/test/internet/internet.status +++ b/test/internet/internet.status @@ -1 +1,6 @@ prefix internet + +test-dns : PASS,FLAKY + +[$system==solaris] +test-http-dns-fail : PASS,FLAKY diff --git a/test/simple/simple.status b/test/simple/simple.status index 438ce39f5f23db..f0aa4e99b9b59b 100644 --- a/test/simple/simple.status +++ b/test/simple/simple.status @@ -1 +1,17 @@ prefix simple + +test-crypto-domains : PASS,FLAKY + +[$system==win32] +test-timers-first-fire : PASS,FLAKY + +[$system==linux] +test-fs-readfile-error : PASS,FLAKY +test-net-GH-5504 : PASS,FLAKY +test-stdin-script-child : PASS,FLAKY +test-util-debug : PASS,FLAKY + +[$system==macos] + +[$system==solaris] +test-debug-signal-cluster : PASS,FLAKY From b6559553a42b05ad793e1ea755e252b230be6212 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 11 Nov 2014 16:48:34 -0800 Subject: [PATCH 16/27] src: remove Async Listener Async Listener was the name of the user-facing JS API, and is being completely removed. Instead low level hooks directly into the mechanism that AL used will be introduced in a future commit. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- doc/api/all.markdown | 1 - doc/api/tracing.markdown | 273 ------------ lib/repl.js | 3 +- lib/timers.js | 53 +-- lib/tracing.js | 395 ------------------ node.gyp | 1 - src/async-wrap-inl.h | 50 --- src/async-wrap.h | 8 - src/env-inl.h | 35 -- src/env.h | 29 -- src/node.cc | 64 --- src/node.js | 44 +- ...st-asynclistener-error-multiple-handled.js | 76 ---- .../test-asynclistener-error-multiple-mix.js | 65 --- ...-asynclistener-error-multiple-unhandled.js | 79 ---- test/simple/test-asynclistener-error-net.js | 108 ----- ...test-asynclistener-error-throw-in-after.js | 62 --- ...listener-error-throw-in-before-multiple.js | 80 ---- ...est-asynclistener-error-throw-in-before.js | 64 --- ...test-asynclistener-error-throw-in-error.js | 87 ---- test/simple/test-asynclistener-error.js | 257 ------------ .../test-asynclistener-multi-timeout.js | 70 ---- ...test-asynclistener-remove-add-in-before.js | 47 --- .../test-asynclistener-remove-before.js | 53 --- .../test-asynclistener-remove-in-before.js | 43 -- ...est-asynclistener-remove-inflight-error.js | 58 --- .../test-asynclistener-remove-inflight.js | 53 --- .../test-asynclistener-run-error-once.js | 59 --- .../test-asynclistener-run-inst-once.js | 46 -- ...istener-throw-before-infinite-recursion.js | 48 --- test/simple/test-asynclistener.js | 188 --------- test/simple/test-v8-gc.js | 53 --- test/simple/test-v8-stats.js | 36 -- 33 files changed, 8 insertions(+), 2580 deletions(-) delete mode 100644 doc/api/tracing.markdown delete mode 100644 lib/tracing.js delete mode 100644 test/simple/test-asynclistener-error-multiple-handled.js delete mode 100644 test/simple/test-asynclistener-error-multiple-mix.js delete mode 100644 test/simple/test-asynclistener-error-multiple-unhandled.js delete mode 100644 test/simple/test-asynclistener-error-net.js delete mode 100644 test/simple/test-asynclistener-error-throw-in-after.js delete mode 100644 test/simple/test-asynclistener-error-throw-in-before-multiple.js delete mode 100644 test/simple/test-asynclistener-error-throw-in-before.js delete mode 100644 test/simple/test-asynclistener-error-throw-in-error.js delete mode 100644 test/simple/test-asynclistener-error.js delete mode 100644 test/simple/test-asynclistener-multi-timeout.js delete mode 100644 test/simple/test-asynclistener-remove-add-in-before.js delete mode 100644 test/simple/test-asynclistener-remove-before.js delete mode 100644 test/simple/test-asynclistener-remove-in-before.js delete mode 100644 test/simple/test-asynclistener-remove-inflight-error.js delete mode 100644 test/simple/test-asynclistener-remove-inflight.js delete mode 100644 test/simple/test-asynclistener-run-error-once.js delete mode 100644 test/simple/test-asynclistener-run-inst-once.js delete mode 100644 test/simple/test-asynclistener-throw-before-infinite-recursion.js delete mode 100644 test/simple/test-asynclistener.js delete mode 100644 test/simple/test-v8-gc.js delete mode 100644 test/simple/test-v8-stats.js diff --git a/doc/api/all.markdown b/doc/api/all.markdown index 5ccef037f5e1ed..2a164abb78e98d 100644 --- a/doc/api/all.markdown +++ b/doc/api/all.markdown @@ -35,4 +35,3 @@ @include debugger @include cluster @include smalloc -@include tracing diff --git a/doc/api/tracing.markdown b/doc/api/tracing.markdown deleted file mode 100644 index 92e6809a04a0d4..00000000000000 --- a/doc/api/tracing.markdown +++ /dev/null @@ -1,273 +0,0 @@ -# Tracing - - Stability: 1 - Experimental - -The tracing module is designed for instrumenting your Node application. It is -not meant for general purpose use. - -***Be very careful with callbacks used in conjunction with this module*** - -Many of these callbacks interact directly with asynchronous subsystems in a -synchronous fashion. That is to say, you may be in a callback where a call to -`console.log()` could result in an infinite recursive loop. Also of note, many -of these callbacks are in hot execution code paths. That is to say your -callbacks are executed quite often in the normal operation of Node, so be wary -of doing CPU bound or synchronous workloads in these functions. Consider a ring -buffer and a timer to defer processing. - -`require('tracing')` to use this module. - -## v8 - -The `v8` property is an [EventEmitter][], it exposes events and interfaces -specific to the version of `v8` built with node. These interfaces are subject -to change by upstream and are therefore not covered under the stability index. - -### Event: 'gc' - -`function (before, after) { }` - -Emitted each time a GC run is completed. - -`before` and `after` are objects with the following properties: - -``` -{ - type: 'mark-sweep-compact', - flags: 0, - timestamp: 905535650119053, - total_heap_size: 6295040, - total_heap_size_executable: 4194304, - total_physical_size: 6295040, - used_heap_size: 2855416, - heap_size_limit: 1535115264 -} -``` - -### getHeapStatistics() - -Returns an object with the following properties - -``` -{ - total_heap_size: 7326976, - total_heap_size_executable: 4194304, - total_physical_size: 7326976, - used_heap_size: 3476208, - heap_size_limit: 1535115264 -} -``` - - -# Async Listeners - -The `AsyncListener` API is the JavaScript interface for the `AsyncWrap` -class which allows developers to be notified about key events in the -lifetime of an asynchronous event. Node performs a lot of asynchronous -events internally, and significant use of this API may have a -**significant performance impact** on your application. - - -## tracing.createAsyncListener(callbacksObj[, userData]) - -* `callbacksObj` {Object} Contains optional callbacks that will fire at -specific times in the life cycle of the asynchronous event. -* `userData` {Value} a value that will be passed to all callbacks. - -Returns a constructed `AsyncListener` object. - -To begin capturing asynchronous events pass either the `callbacksObj` or -pass an existing `AsyncListener` instance to [`tracing.addAsyncListener()`][]. -The same `AsyncListener` instance can only be added once to the active -queue, and subsequent attempts to add the instance will be ignored. - -To stop capturing pass the `AsyncListener` instance to -[`tracing.removeAsyncListener()`][]. This does _not_ mean the -`AsyncListener` previously added will stop triggering callbacks. Once -attached to an asynchronous event it will persist with the lifetime of the -asynchronous call stack. - -Explanation of function parameters: - - -`callbacksObj`: An `Object` which may contain several optional fields: - -* `create(userData)`: A `Function` called when an asynchronous -event is instantiated. If a `Value` is returned then it will be attached -to the event and overwrite any value that had been passed to -`tracing.createAsyncListener()`'s `userData` argument. If an initial -`userData` was passed when created, then `create()` will -receive that as a function argument. - -* `before(context, userData)`: A `Function` that is called immediately -before the asynchronous callback is about to run. It will be passed both -the `context` (i.e. `this`) of the calling function and the `userData` -either returned from `create()` or passed during construction (if -either occurred). - -* `after(context, userData)`: A `Function` called immediately after -the asynchronous event's callback has run. Note this will not be called -if the callback throws and the error is not handled. - -* `error(userData, error)`: A `Function` called if the event's -callback threw. If this registered callback returns `true` then Node will -assume the error has been properly handled and resume execution normally. -When multiple `error()` callbacks have been registered only **one** of -those callbacks needs to return `true` for `AsyncListener` to accept that -the error has been handled, but all `error()` callbacks will always be run. - -`userData`: A `Value` (i.e. anything) that will be, by default, -attached to all new event instances. This will be overwritten if a `Value` -is returned by `create()`. - -Here is an example of overwriting the `userData`: - - tracing.createAsyncListener({ - create: function listener(value) { - // value === true - return false; - }, { - before: function before(context, value) { - // value === false - } - }, true); - -**Note:** The [EventEmitter][], while used to emit status of an asynchronous -event, is not itself asynchronous. So `create()` will not fire when -an event is added, and `before()`/`after()` will not fire when emitted -callbacks are called. - - -## tracing.addAsyncListener(callbacksObj[, userData]) -## tracing.addAsyncListener(asyncListener) - -Returns a constructed `AsyncListener` object and immediately adds it to -the listening queue to begin capturing asynchronous events. - -Function parameters can either be the same as -[`tracing.createAsyncListener()`][], or a constructed `AsyncListener` -object. - -Example usage for capturing errors: - - var fs = require('fs'); - - var cntr = 0; - var key = tracing.addAsyncListener({ - create: function onCreate() { - return { uid: cntr++ }; - }, - before: function onBefore(context, storage) { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'uid: ' + storage.uid + ' is about to run\n'); - }, - after: function onAfter(context, storage) { - fs.writeSync(1, 'uid: ' + storage.uid + ' ran\n'); - }, - error: function onError(storage, err) { - // Handle known errors - if (err.message === 'everything is fine') { - // Writing to stderr this time. - fs.writeSync(2, 'handled error just threw:\n'); - fs.writeSync(2, err.stack + '\n'); - return true; - } - } - }); - - process.nextTick(function() { - throw new Error('everything is fine'); - }); - - // Output: - // uid: 0 is about to run - // handled error just threw: - // Error: really, it's ok - // at /tmp/test2.js:27:9 - // at process._tickCallback (node.js:583:11) - // at Function.Module.runMain (module.js:492:11) - // at startup (node.js:123:16) - // at node.js:1012:3 - -## tracing.removeAsyncListener(asyncListener) - -Removes the `AsyncListener` from the listening queue. - -Removing the `AsyncListener` from the active queue does _not_ mean the -`asyncListener` callbacks will cease to fire on the events they've been -registered. Subsequently, any asynchronous events fired during the -execution of a callback will also have the same `asyncListener` callbacks -attached for future execution. For example: - - var fs = require('fs'); - - var key = tracing.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - tracing.addAsyncListener(key); - - // Perform a few additional async events. - setTimeout(function() { - setImmediate(function() { - process.nextTick(function() { }); - }); - }); - - // Removing the listener doesn't mean to stop capturing events that - // have already been added. - tracing.removeAsyncListener(key); - }, 100); - - // Output: - // You summoned me? - // You summoned me? - // You summoned me? - // You summoned me? - -The fact that we logged 4 asynchronous events is an implementation detail -of Node's [Timers][]. - -To stop capturing from a specific asynchronous event stack -`tracing.removeAsyncListener()` must be called from within the call -stack itself. For example: - - var fs = require('fs'); - - var key = tracing.createAsyncListener({ - create: function asyncListener() { - // Write directly to stdout or we'll enter a recursive loop - fs.writeSync(1, 'You summoned me?\n'); - } - }); - - // We want to begin capturing async events some time in the future. - setTimeout(function() { - tracing.addAsyncListener(key); - - // Perform a few additional async events. - setImmediate(function() { - // Stop capturing from this call stack. - tracing.removeAsyncListener(key); - - process.nextTick(function() { }); - }); - }, 100); - - // Output: - // You summoned me? - -The user must be explicit and always pass the `AsyncListener` they wish -to remove. It is not possible to simply remove all listeners at once. - - -[EventEmitter]: events.html#events_class_events_eventemitter -[Timers]: timers.html -[`tracing.createAsyncListener()`]: #tracing_tracing_createasynclistener_asynclistener_callbacksobj_storagevalue -[`tracing.addAsyncListener()`]: #tracing_tracing_addasynclistener_asynclistener -[`tracing.removeAsyncListener()`]: #tracing_tracing_removeasynclistener_asynclistener diff --git a/lib/repl.js b/lib/repl.js index 578f99ed225705..a8fa060c5930d1 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -72,8 +72,7 @@ exports.writer = util.inspect; exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode', 'querystring', 'readline', 'stream', - 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc', - 'tracing']; + 'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc']; function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { diff --git a/lib/timers.js b/lib/timers.js index 3039b49f2c3727..68e3e65e9aaf4f 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -30,21 +30,6 @@ var TIMEOUT_MAX = 2147483647; // 2^31-1 var debug = require('util').debuglog('timer'); -var tracing = require('tracing'); -var asyncFlags = tracing._asyncFlags; -var runAsyncQueue = tracing._runAsyncQueue; -var loadAsyncQueue = tracing._loadAsyncQueue; -var unloadAsyncQueue = tracing._unloadAsyncQueue; - -// Same as in AsyncListener in env.h -var kHasListener = 0; - -// Do a little housekeeping. -delete tracing._asyncFlags; -delete tracing._runAsyncQueue; -delete tracing._loadAsyncQueue; -delete tracing._unloadAsyncQueue; - // IDLE TIMEOUTS // @@ -59,11 +44,6 @@ delete tracing._unloadAsyncQueue; // value = list var lists = {}; -// Make Timer as monomorphic as possible. -Timer.prototype._asyncQueue = undefined; -Timer.prototype._asyncData = undefined; -Timer.prototype._asyncFlags = 0; - // the main function - creates lists on demand and the watchers associated // with them. function insert(item, msecs) { @@ -100,7 +80,7 @@ function listOnTimeout() { var now = Timer.now(); debug('now: %s', now); - var diff, first, hasQueue, threw; + var diff, first, threw; while (first = L.peek(list)) { diff = now - first._idleStart; if (diff < msecs) { @@ -122,19 +102,13 @@ function listOnTimeout() { if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; - try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; first._onTimeout(); if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); threw = false; } finally { if (threw) { @@ -204,11 +178,6 @@ exports.active = function(item) { L.append(list, item); } } - // Whether or not a new TimerWrap needed to be created, this should run - // for each item. This way each "item" (i.e. timer) can properly have - // their own domain assigned. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(item); }; @@ -354,18 +323,15 @@ L.init(immediateQueue); function processImmediate() { var queue = immediateQueue; - var domain, hasQueue, immediate; + var domain, immediate; immediateQueue = {}; L.init(immediateQueue); while (L.isEmpty(queue) === false) { immediate = L.shift(queue); - hasQueue = !!immediate._asyncQueue; domain = immediate.domain; - if (hasQueue) - loadAsyncQueue(immediate); if (domain) domain.enter(); @@ -389,8 +355,6 @@ function processImmediate() { if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(immediate); } // Only round-trip to C++ land if we have to. Calling clearImmediate() on an @@ -406,11 +370,8 @@ function Immediate() { } Immediate.prototype.domain = undefined; Immediate.prototype._onImmediate = undefined; -Immediate.prototype._asyncQueue = undefined; -Immediate.prototype._asyncData = undefined; Immediate.prototype._idleNext = undefined; Immediate.prototype._idlePrev = undefined; -Immediate.prototype._asyncFlags = 0; exports.setImmediate = function(callback) { @@ -436,9 +397,6 @@ exports.setImmediate = function(callback) { process._immediateCallback = processImmediate; } - // setImmediates are handled more like nextTicks. - if (asyncFlags[kHasListener] > 0) - runAsyncQueue(immediate); if (process.domain) immediate.domain = process.domain; @@ -472,7 +430,7 @@ function unrefTimeout() { debug('unrefTimer fired'); - var diff, domain, first, hasQueue, threw; + var diff, domain, first, threw; while (first = L.peek(unrefList)) { diff = now - first._idleStart; @@ -490,11 +448,8 @@ function unrefTimeout() { if (!first._onTimeout) continue; if (domain && domain._disposed) continue; - hasQueue = !!first._asyncQueue; try { - if (hasQueue) - loadAsyncQueue(first); if (domain) domain.enter(); threw = true; debug('unreftimer firing timeout'); @@ -502,8 +457,6 @@ function unrefTimeout() { threw = false; if (domain) domain.exit(); - if (hasQueue) - unloadAsyncQueue(first); } finally { if (threw) process.nextTick(unrefTimeout); } diff --git a/lib/tracing.js b/lib/tracing.js deleted file mode 100644 index 49d0dec35c28ff..00000000000000 --- a/lib/tracing.js +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var EventEmitter = require('events'); -var v8binding, process; - -// This needs to be loaded early, and before the "process" object is made -// global. So allow src/node.js to pass the process object in during -// initialization. -exports._nodeInitialization = function nodeInitialization(pobj) { - process = pobj; - v8binding = process.binding('v8'); - - // Finish setting up the v8 Object. - v8.getHeapStatistics = v8binding.getHeapStatistics; - - // Part of the AsyncListener setup to share objects/callbacks with the - // native layer. - process._setupAsyncListener(asyncFlags, - runAsyncQueue, - loadAsyncQueue, - unloadAsyncQueue); - - // Do a little housekeeping. - delete exports._nodeInitialization; -}; - - -// v8 - -var v8 = exports.v8 = new EventEmitter(); - - -function emitGC(before, after) { - v8.emit('gc', before, after); -} - - -v8.on('newListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.startGarbageCollectionTracking(emitGC); - } -}); - - -v8.on('removeListener', function(name) { - if (name === 'gc' && EventEmitter.listenerCount(this, name) === 0) { - v8binding.stopGarbageCollectionTracking(); - } -}); - - -// AsyncListener - -// new Array() is used here because it is more efficient for sparse -// arrays. Please *do not* change these to simple bracket notation. - -// Track the active queue of AsyncListeners that have been added. -var asyncQueue = new Array(); - -// Keep the stack of all contexts that have been loaded in the -// execution chain of asynchronous events. -var contextStack = new Array(); -var currentContext = undefined; - -// Incremental uid for new AsyncListener instances. -var alUid = 0; - -// Stateful flags shared with Environment for quick JS/C++ -// communication. -var asyncFlags = {}; - -// Prevent accidentally suppressed thrown errors from before/after. -var inAsyncTick = false; - -// To prevent infinite recursion when an error handler also throws -// flag when an error is currenly being handled. -var inErrorTick = false; - -// Needs to be the same as src/env.h -var kHasListener = 0; - -// Flags to determine what async listeners are available. -var HAS_CREATE_AL = 1 << 0; -var HAS_BEFORE_AL = 1 << 1; -var HAS_AFTER_AL = 1 << 2; -var HAS_ERROR_AL = 1 << 3; - -// _errorHandler is scoped so it's also accessible by _fatalException. -exports._errorHandler = errorHandler; - -// Needs to be accessible from lib/timers.js so they know when async -// listeners are currently in queue. They'll be cleaned up once -// references there are made. -exports._asyncFlags = asyncFlags; -exports._runAsyncQueue = runAsyncQueue; -exports._loadAsyncQueue = loadAsyncQueue; -exports._unloadAsyncQueue = unloadAsyncQueue; - -// Public API. -exports.createAsyncListener = createAsyncListener; -exports.addAsyncListener = addAsyncListener; -exports.removeAsyncListener = removeAsyncListener; - -// Load the currently executing context as the current context, and -// create a new asyncQueue that can receive any added queue items -// during the executing of the callback. -function loadContext(ctx) { - contextStack.push(currentContext); - currentContext = ctx; - - asyncFlags[kHasListener] = 1; -} - -function unloadContext() { - currentContext = contextStack.pop(); - - if (currentContext === undefined && asyncQueue.length === 0) - asyncFlags[kHasListener] = 0; -} - -// Run all the async listeners attached when an asynchronous event is -// instantiated. -function runAsyncQueue(context) { - var queue = new Array(); - var data = new Array(); - var ccQueue, i, queueItem, value; - - context._asyncQueue = queue; - context._asyncData = data; - context._asyncFlags = 0; - - inAsyncTick = true; - - // First run through all callbacks in the currentContext. These may - // add new AsyncListeners to the asyncQueue during execution. Hence - // why they need to be evaluated first. - if (currentContext) { - ccQueue = currentContext._asyncQueue; - context._asyncFlags |= currentContext._asyncFlags; - for (i = 0; i < ccQueue.length; i++) { - queueItem = ccQueue[i]; - queue[queue.length] = queueItem; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - // Then run through all items in the asyncQueue - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - // Quick way to check if an AL instance with the same uid was - // already run from currentContext. - if (data[queueItem.uid] !== undefined) - continue; - queue[queue.length] = queueItem; - context._asyncFlags |= queueItem.callback_flags; - if ((queueItem.callback_flags & HAS_CREATE_AL) === 0) { - data[queueItem.uid] = queueItem.data; - continue; - } - value = queueItem.create(queueItem.data); - data[queueItem.uid] = (value === undefined) ? queueItem.data : value; - } - } - - inAsyncTick = false; -} - -// Load the AsyncListener queue attached to context and run all -// "before" callbacks, if they exist. -function loadAsyncQueue(context) { - loadContext(context); - - if ((context._asyncFlags & HAS_BEFORE_AL) === 0) - return; - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_BEFORE_AL) > 0) - queueItem.before(context, data[queueItem.uid]); - } - inAsyncTick = false; -} - -// Unload the AsyncListener queue attached to context and run all -// "after" callbacks, if they exist. -function unloadAsyncQueue(context) { - if ((context._asyncFlags & HAS_AFTER_AL) === 0) { - unloadContext(); - return; - } - - var queue = context._asyncQueue; - var data = context._asyncData; - var i, queueItem; - - inAsyncTick = true; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_AFTER_AL) > 0) - queueItem.after(context, data[queueItem.uid]); - } - inAsyncTick = false; - - unloadContext(); -} - -// Handle errors that are thrown while in the context of an -// AsyncListener. If an error is thrown from an AsyncListener -// callback error handlers will be called once more to report -// the error, then the application will die forcefully. -function errorHandler(er) { - if (inErrorTick) - return false; - - var handled = false; - var i, queueItem, threw; - - inErrorTick = true; - - // First process error callbacks from the current context. - if (currentContext && (currentContext._asyncFlags & HAS_ERROR_AL) > 0) { - var queue = currentContext._asyncQueue; - var data = currentContext._asyncData; - for (i = 0; i < queue.length; i++) { - queueItem = queue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0) - continue; - try { - threw = true; - // While it would be possible to pass in currentContext, if - // the error is thrown from the "create" callback then there's - // a chance the object hasn't been fully constructed. - handled = queueItem.error(data[queueItem.uid], er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - // Now process callbacks from any existing queue. - if (asyncQueue) { - for (i = 0; i < asyncQueue.length; i++) { - queueItem = asyncQueue[i]; - if ((queueItem.callback_flags & HAS_ERROR_AL) === 0 || - (data && data[queueItem.uid] !== undefined)) - continue; - try { - threw = true; - handled = queueItem.error(queueItem.data, er) || handled; - threw = false; - } finally { - // If the error callback thew then die quickly. Only allow the - // exit events to be processed. - if (threw) { - process._exiting = true; - process.emit('exit', 1); - } - } - } - } - - inErrorTick = false; - - unloadContext(); - - // TODO(trevnorris): If the error was handled, should the after callbacks - // be fired anyways? - - return handled && !inAsyncTick; -} - -// Instance function of an AsyncListener object. -function AsyncListenerInst(callbacks, data) { - if (typeof callbacks.create === 'function') { - this.create = callbacks.create; - this.callback_flags |= HAS_CREATE_AL; - } - if (typeof callbacks.before === 'function') { - this.before = callbacks.before; - this.callback_flags |= HAS_BEFORE_AL; - } - if (typeof callbacks.after === 'function') { - this.after = callbacks.after; - this.callback_flags |= HAS_AFTER_AL; - } - if (typeof callbacks.error === 'function') { - this.error = callbacks.error; - this.callback_flags |= HAS_ERROR_AL; - } - - this.uid = ++alUid; - this.data = data === undefined ? null : data; -} -AsyncListenerInst.prototype.create = undefined; -AsyncListenerInst.prototype.before = undefined; -AsyncListenerInst.prototype.after = undefined; -AsyncListenerInst.prototype.error = undefined; -AsyncListenerInst.prototype.data = undefined; -AsyncListenerInst.prototype.uid = 0; -AsyncListenerInst.prototype.callback_flags = 0; - -// Create new async listener object. Useful when instantiating a new -// object and want the listener instance, but not add it to the stack. -// If an existing AsyncListenerInst is passed then any new "data" is -// ignored. -function createAsyncListener(callbacks, data) { - if (typeof callbacks !== 'object' || callbacks == null) - throw new TypeError('callbacks argument must be an object'); - - if (callbacks instanceof AsyncListenerInst) - return callbacks; - else - return new AsyncListenerInst(callbacks, data); -} - -// Add a listener to the current queue. -function addAsyncListener(callbacks, data) { - // Fast track if a new AsyncListenerInst has to be created. - if (!(callbacks instanceof AsyncListenerInst)) { - callbacks = createAsyncListener(callbacks, data); - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - return callbacks; - } - - var inQueue = false; - // The asyncQueue will be small. Probably always <= 3 items. - for (var i = 0; i < asyncQueue.length; i++) { - if (callbacks === asyncQueue[i]) { - inQueue = true; - break; - } - } - - // Make sure the callback doesn't already exist in the queue. - if (!inQueue) { - asyncQueue.push(callbacks); - asyncFlags[kHasListener] = 1; - } - - return callbacks; -} - -// Remove listener from the current queue. Though this will not remove -// the listener from the current context. So callback propagation will -// continue. -function removeAsyncListener(obj) { - for (var i = 0; i < asyncQueue.length; i++) { - if (obj === asyncQueue[i]) { - asyncQueue.splice(i, 1); - break; - } - } - - if (asyncQueue.length > 0 || currentContext !== undefined) - asyncFlags[kHasListener] = 1; - else - asyncFlags[kHasListener] = 0; -} diff --git a/node.gyp b/node.gyp index daf06c7a7a0f41..220f9eb2ab2c51 100644 --- a/node.gyp +++ b/node.gyp @@ -57,7 +57,6 @@ 'lib/string_decoder.js', 'lib/sys.js', 'lib/timers.js', - 'lib/tracing.js', 'lib/tls.js', 'lib/_tls_common.js', 'lib/_tls_legacy.js', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index 59157cc0f4c63b..bcfa19ddf69147 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -39,20 +39,7 @@ inline AsyncWrap::AsyncWrap(Environment* env, v8::Handle object, ProviderType provider) : BaseObject(env, object), - async_flags_(NO_OPTIONS), provider_type_(provider) { - if (!env->has_async_listener()) - return; - - // TODO(trevnorris): Do we really need to TryCatch this call? - v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - v8::Local val = object.As(); - env->async_listener_run_function()->Call(env->process_object(), 1, &val); - - if (!try_catch.HasCaught()) - async_flags_ |= HAS_ASYNC_LISTENER; } @@ -64,11 +51,6 @@ inline uint32_t AsyncWrap::provider_type() const { } -inline bool AsyncWrap::has_async_listener() { - return async_flags_ & HAS_ASYNC_LISTENER; -} - - // I hate you domains. inline v8::Handle AsyncWrap::MakeDomainCallback( const v8::Handle cb, @@ -84,14 +66,6 @@ inline v8::Handle AsyncWrap::MakeDomainCallback( v8::TryCatch try_catch; try_catch.SetVerbose(true); - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_load_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - bool has_domain = domain_v->IsObject(); if (has_domain) { domain = domain_v.As(); @@ -124,14 +98,6 @@ inline v8::Handle AsyncWrap::MakeDomainCallback( } } - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_unload_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return Undefined(env()->isolate()); - } - Environment::TickInfo* tick_info = env()->tick_info(); if (tick_info->in_tick()) { @@ -177,28 +143,12 @@ inline v8::Handle AsyncWrap::MakeCallback( v8::TryCatch try_catch; try_catch.SetVerbose(true); - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_load_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - v8::Local ret = cb->Call(context, argc, argv); if (try_catch.HasCaught()) { return Undefined(env()->isolate()); } - if (has_async_listener()) { - v8::Local val = context.As(); - env()->async_listener_unload_function()->Call(process, 1, &val); - - if (try_catch.HasCaught()) - return v8::Undefined(env()->isolate()); - } - Environment::TickInfo* tick_info = env()->tick_info(); if (tick_info->in_tick()) { diff --git a/src/async-wrap.h b/src/async-wrap.h index 1b1802a68ffc89..f383ac90af903d 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -30,11 +30,6 @@ namespace node { class AsyncWrap : public BaseObject { public: - enum AsyncFlags { - NO_OPTIONS = 0, - HAS_ASYNC_LISTENER = 1 - }; - enum ProviderType { PROVIDER_NONE = 1 << 0, PROVIDER_CARES = 1 << 1, @@ -63,8 +58,6 @@ class AsyncWrap : public BaseObject { inline ~AsyncWrap(); - inline bool has_async_listener(); - inline uint32_t provider_type() const; // Only call these within a valid HandleScope. @@ -88,7 +81,6 @@ class AsyncWrap : public BaseObject { int argc, v8::Handle* argv); - uint32_t async_flags_; uint32_t provider_type_; }; diff --git a/src/env-inl.h b/src/env-inl.h index e6a3d1c5ecf092..0e714c80e68a73 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -111,27 +111,6 @@ inline v8::Isolate* Environment::IsolateData::isolate() const { return isolate_; } -inline Environment::AsyncListener::AsyncListener() { - for (int i = 0; i < kFieldsCount; ++i) - fields_[i] = 0; -} - -inline uint32_t* Environment::AsyncListener::fields() { - return fields_; -} - -inline int Environment::AsyncListener::fields_count() const { - return kFieldsCount; -} - -inline bool Environment::AsyncListener::has_listener() const { - return fields_[kHasListener] > 0; -} - -inline uint32_t Environment::AsyncListener::watched_providers() const { - return fields_[kWatchedProviders]; -} - inline Environment::DomainFlag::DomainFlag() { for (int i = 0; i < kFieldsCount; ++i) fields_[i] = 0; } @@ -264,16 +243,6 @@ inline v8::Isolate* Environment::isolate() const { return isolate_; } -inline bool Environment::has_async_listener() const { - // The const_cast is okay, it doesn't violate conceptual const-ness. - return const_cast(this)->async_listener()->has_listener(); -} - -inline uint32_t Environment::watched_providers() const { - // The const_cast is okay, it doesn't violate conceptual const-ness. - return const_cast(this)->async_listener()->watched_providers(); -} - inline bool Environment::in_domain() const { // The const_cast is okay, it doesn't violate conceptual const-ness. return using_domains() && @@ -325,10 +294,6 @@ inline uv_loop_t* Environment::event_loop() const { return isolate_data()->event_loop(); } -inline Environment::AsyncListener* Environment::async_listener() { - return &async_listener_count_; -} - inline Environment::DomainFlag* Environment::domain_flag() { return &domain_flag_; } diff --git a/src/env.h b/src/env.h index 655e804cb9e57a..8428a5511e2c39 100644 --- a/src/env.h +++ b/src/env.h @@ -64,7 +64,6 @@ namespace node { V(address_string, "address") \ V(args_string, "args") \ V(argv_string, "argv") \ - V(async_queue_string, "_asyncQueue") \ V(async, "async") \ V(atime_string, "atime") \ V(birthtime_string, "birthtime") \ @@ -250,9 +249,6 @@ namespace node { V(zero_return_string, "ZERO_RETURN") \ #define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ - V(async_listener_run_function, v8::Function) \ - V(async_listener_load_function, v8::Function) \ - V(async_listener_unload_function, v8::Function) \ V(binding_cache_object, v8::Object) \ V(buffer_constructor_function, v8::Function) \ V(context, v8::Context) \ @@ -286,28 +282,6 @@ RB_HEAD(ares_task_list, ares_task_t); class Environment { public: - class AsyncListener { - public: - inline uint32_t* fields(); - inline int fields_count() const; - inline bool has_listener() const; - inline uint32_t watched_providers() const; - - private: - friend class Environment; // So we can call the constructor. - inline AsyncListener(); - - enum Fields { - kHasListener, - kWatchedProviders, - kFieldsCount - }; - - uint32_t fields_[kFieldsCount]; - - DISALLOW_COPY_AND_ASSIGN(AsyncListener); - }; - class DomainFlag { public: inline uint32_t* fields(); @@ -395,7 +369,6 @@ class Environment { inline v8::Isolate* isolate() const; inline uv_loop_t* event_loop() const; - inline bool has_async_listener() const; inline bool in_domain() const; inline uint32_t watched_providers() const; @@ -415,7 +388,6 @@ class Environment { void *arg); inline void FinishHandleCleanup(uv_handle_t* handle); - inline AsyncListener* async_listener(); inline DomainFlag* domain_flag(); inline TickInfo* tick_info(); @@ -492,7 +464,6 @@ class Environment { uv_idle_t immediate_idle_handle_; uv_prepare_t idle_prepare_handle_; uv_check_t idle_check_handle_; - AsyncListener async_listener_count_; DomainFlag domain_flag_; TickInfo tick_info_; uv_timer_t cares_timer_handle_; diff --git a/src/node.cc b/src/node.cc index 5a9d0fc12caa11..df1c8eb1bf3738 100644 --- a/src/node.cc +++ b/src/node.cc @@ -909,32 +909,6 @@ Local WinapiErrnoException(Isolate* isolate, #endif -void SetupAsyncListener(const FunctionCallbackInfo& args) { - HandleScope handle_scope(args.GetIsolate()); - Environment* env = Environment::GetCurrent(args.GetIsolate()); - - assert(args[0]->IsObject()); - assert(args[1]->IsFunction()); - assert(args[2]->IsFunction()); - assert(args[3]->IsFunction()); - - env->set_async_listener_run_function(args[1].As()); - env->set_async_listener_load_function(args[2].As()); - env->set_async_listener_unload_function(args[3].As()); - - Local async_listener_flag_obj = args[0].As(); - Environment::AsyncListener* async_listener = env->async_listener(); - async_listener_flag_obj->SetIndexedPropertiesToExternalArrayData( - async_listener->fields(), - kExternalUint32Array, - async_listener->fields_count()); - - // Do a little housekeeping. - env->process_object()->Delete( - FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupAsyncListener")); -} - - void SetupDomainUse(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); @@ -1019,20 +993,6 @@ Handle MakeDomainCallback(Environment* env, TryCatch try_catch; try_catch.SetVerbose(true); - bool has_async_queue = false; - - if (recv->IsObject()) { - object = recv.As(); - // TODO(trevnorris): This is sucky for performance. Fix it. - has_async_queue = object->Has(env->async_queue_string()); - if (has_async_queue) { - env->async_listener_load_function()->Call(process, 1, &recv); - - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - } - bool has_domain = false; if (!object.IsEmpty()) { @@ -1070,13 +1030,6 @@ Handle MakeDomainCallback(Environment* env, } } - if (has_async_queue) { - env->async_listener_unload_function()->Call(process, 1, &recv); - - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - Environment::TickInfo* tick_info = env->tick_info(); if (tick_info->last_threw() == 1) { @@ -1128,28 +1081,12 @@ Handle MakeCallback(Environment* env, TryCatch try_catch; try_catch.SetVerbose(true); - // TODO(trevnorris): This is sucky for performance. Fix it. - bool has_async_queue = - recv->IsObject() && recv.As()->Has(env->async_queue_string()); - if (has_async_queue) { - env->async_listener_load_function()->Call(process, 1, &recv); - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - Local ret = callback->Call(recv, argc, argv); if (try_catch.HasCaught()) { return Undefined(env->isolate()); } - if (has_async_queue) { - env->async_listener_unload_function()->Call(process, 1, &recv); - - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } - Environment::TickInfo* tick_info = env->tick_info(); if (tick_info->in_tick()) { @@ -2880,7 +2817,6 @@ void SetupProcessObject(Environment* env, NODE_SET_METHOD(process, "binding", Binding); NODE_SET_METHOD(process, "_linkedBinding", LinkedBinding); - NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener); NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick); NODE_SET_METHOD(process, "_setupDomainUse", SetupDomainUse); diff --git a/src/node.js b/src/node.js index 59cca4e748cd76..046e1ab63775ba 100644 --- a/src/node.js +++ b/src/node.js @@ -39,9 +39,6 @@ process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated - // Setup the tracing module - NativeModule.require('tracing')._nodeInitialization(process); - // do this good and early, since it handles errors. startup.processFatal(); @@ -229,14 +226,8 @@ }; startup.processFatal = function() { - var tracing = NativeModule.require('tracing'); - var _errorHandler = tracing._errorHandler; - // Cleanup - delete tracing._errorHandler; - process._fatalException = function(er) { - // First run through error handlers from asyncListener. - var caught = _errorHandler(er); + var caught; if (process.domain && process.domain._errorHandler) caught = process.domain._errorHandler(er) || caught; @@ -259,10 +250,6 @@ // if we handled an error, then make sure any ticks get processed } else { var t = setImmediate(process._tickCallback); - // Complete hack to make sure any errors thrown from async - // listeners don't cause an infinite loop. - if (t._asyncQueue) - t._asyncQueue = []; } return caught; @@ -296,12 +283,7 @@ }; startup.processNextTick = function() { - var tracing = NativeModule.require('tracing'); var nextTickQueue = []; - var asyncFlags = tracing._asyncFlags; - var _runAsyncQueue = tracing._runAsyncQueue; - var _loadAsyncQueue = tracing._loadAsyncQueue; - var _unloadAsyncQueue = tracing._unloadAsyncQueue; var microtasksScheduled = false; // Used to run V8's micro task queue. @@ -315,10 +297,6 @@ var kIndex = 0; var kLength = 1; - // For asyncFlags. - // *Must* match Environment::AsyncListeners::Fields in src/env.h - var kCount = 0; - process.nextTick = nextTick; // Needs to be accessible from beyond this scope. process._tickCallback = _tickCallback; @@ -365,7 +343,7 @@ // Run callbacks that have no domain. // Using domains will cause this to be overridden. function _tickCallback() { - var callback, hasQueue, threw, tock; + var callback, threw, tock; scheduleMicrotasks(); @@ -373,9 +351,6 @@ tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; threw = true; - hasQueue = !!tock._asyncQueue; - if (hasQueue) - _loadAsyncQueue(tock); try { callback(); threw = false; @@ -383,8 +358,6 @@ if (threw) tickDone(); } - if (hasQueue) - _unloadAsyncQueue(tock); if (1e4 < tickInfo[kIndex]) tickDone(); } @@ -393,7 +366,7 @@ } function _tickDomainCallback() { - var callback, domain, hasQueue, threw, tock; + var callback, domain, threw, tock; scheduleMicrotasks(); @@ -401,9 +374,6 @@ tock = nextTickQueue[tickInfo[kIndex]++]; callback = tock.callback; domain = tock.domain; - hasQueue = !!tock._asyncQueue; - if (hasQueue) - _loadAsyncQueue(tock); if (domain) domain.enter(); threw = true; @@ -414,8 +384,6 @@ if (threw) tickDone(); } - if (hasQueue) - _unloadAsyncQueue(tock); if (1e4 < tickInfo[kIndex]) tickDone(); if (domain) @@ -432,13 +400,9 @@ var obj = { callback: callback, - domain: process.domain || null, - _asyncQueue: undefined + domain: process.domain || null }; - if (asyncFlags[kCount] > 0) - _runAsyncQueue(obj); - nextTickQueue.push(obj); tickInfo[kLength]++; } diff --git a/test/simple/test-asynclistener-error-multiple-handled.js b/test/simple/test-asynclistener-error-multiple-handled.js deleted file mode 100644 index 576ce58e4cf3b0..00000000000000 --- a/test/simple/test-asynclistener-error-multiple-handled.js +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var active = null; -var cntr = 0; - -function onAsync0() { - return 0; -} - -function onAsync1() { - return 1; -} - -function onError(stor) { - results.push(stor); - return true; -} - -var results = []; -var asyncNoHandleError0 = { - create: onAsync0, - error: onError -}; -var asyncNoHandleError1 = { - create: onAsync1, - error: onError -}; - -var listeners = [ - tracing.addAsyncListener(asyncNoHandleError0), - tracing.addAsyncListener(asyncNoHandleError1) -]; - -process.nextTick(function() { - throw new Error(); -}); - -tracing.removeAsyncListener(listeners[0]); -tracing.removeAsyncListener(listeners[1]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Handling of errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); - - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-multiple-mix.js b/test/simple/test-asynclistener-error-multiple-mix.js deleted file mode 100644 index 83716bc281c82d..00000000000000 --- a/test/simple/test-asynclistener-error-multiple-mix.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var results = []; -var asyncNoHandleError = { - error: function(stor) { - results.push(1); - } -}; - -var asyncHandleError = { - error: function(stor) { - results.push(0); - return true; - } -}; - -var listeners = [ - tracing.addAsyncListener(asyncHandleError), - tracing.addAsyncListener(asyncNoHandleError) -]; - -// Even if an error handler returns true, both should fire. -process.nextTick(function() { - throw new Error(); -}); - -tracing.removeAsyncListener(listeners[0]); -tracing.removeAsyncListener(listeners[1]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Mixed handling of errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); - - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-multiple-unhandled.js b/test/simple/test-asynclistener-error-multiple-unhandled.js deleted file mode 100644 index 33afaaa81b1460..00000000000000 --- a/test/simple/test-asynclistener-error-multiple-unhandled.js +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -function onAsync0() { - return 0; -} - -function onAsync1() { - return 1; -} - -function onError(stor) { - results.push(stor); -} - -var results = []; -var asyncNoHandleError0 = { - create: onAsync0, - error: onError -}; -var asyncNoHandleError1 = { - create: onAsync1, - error: onError -}; - -var listeners = [ - tracing.addAsyncListener(asyncNoHandleError0), - tracing.addAsyncListener(asyncNoHandleError1) -]; - -var uncaughtFired = false; -process.on('uncaughtException', function() { - uncaughtFired = true; - - // Unhandled errors should propagate to all listeners. - assert.equal(results[0], 0); - assert.equal(results[1], 1); - assert.equal(results.length, 2); -}); - -process.nextTick(function() { - throw new Error(); -}); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Need to remove the async listeners or tests will always pass - for (var i = 0; i < listeners.length; i++) - tracing.removeAsyncListener(listeners[i]); - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-net.js b/test/simple/test-asynclistener-error-net.js deleted file mode 100644 index 26a337a5044e21..00000000000000 --- a/test/simple/test-asynclistener-error-net.js +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var dns = require('dns'); -var fs = require('fs'); -var net = require('net'); -var tracing = require('tracing'); - -var errorMsgs = []; -var caught = 0; -var expectCaught = 0; - -var callbacksObj = { - error: function(value, er) { - var idx = errorMsgs.indexOf(er.message); - caught++; - - process._rawDebug('Handling error: ' + er.message); - - if (-1 < idx) - errorMsgs.splice(idx, 1); - else - throw new Error('Message not found: ' + er.message); - - return true; - } -}; - -var listener = tracing.addAsyncListener(callbacksObj); - -process.on('exit', function(code) { - tracing.removeAsyncListener(listener); - - if (code > 0) - return; - - if (errorMsgs.length > 0) - throw new Error('Errors not fired: ' + errorMsgs); - - assert.equal(caught, expectCaught); - process._rawDebug('ok'); -}); - - -// Net -var iter = 3; -for (var i = 0; i < iter; i++) { - errorMsgs.push('net - error: server connection'); - errorMsgs.push('net - error: client data'); - errorMsgs.push('net - error: server data'); -} -errorMsgs.push('net - error: server closed'); - -var server = net.createServer(function(c) { - c.on('data', function() { - if (0 === --iter) { - server.close(function() { - process._rawDebug('net - server closing'); - throw new Error('net - error: server closed'); - }); - expectCaught++; - } - process._rawDebug('net - connection received data'); - throw new Error('net - error: server data'); - }); - expectCaught++; - - c.end('bye'); - process._rawDebug('net - connection received'); - throw new Error('net - error: server connection'); -}); -expectCaught += iter; - -server.listen(common.PORT, function() { - for (var i = 0; i < iter; i++) - clientConnect(); -}); - -function clientConnect() { - var client = net.connect(common.PORT, function() { }); - - client.on('data', function() { - client.end('see ya'); - process._rawDebug('net - client received data'); - throw new Error('net - error: client data'); - }); - expectCaught++; -} diff --git a/test/simple/test-asynclistener-error-throw-in-after.js b/test/simple/test-asynclistener-error-throw-in-after.js deleted file mode 100644 index 3eb02e165d49da..00000000000000 --- a/test/simple/test-asynclistener-error-throw-in-after.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - after: function() { - throw 1; - }, - error: function(stor, err) { - // Error handler must be called exactly *once*. - once++; - assert.equal(err, 1); - return true; - } -} - -var key = tracing.addAsyncListener(handlers); - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - assert.equal(once, 1); -}); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-throw-in-before-multiple.js b/test/simple/test-asynclistener-error-throw-in-before-multiple.js deleted file mode 100644 index b9aecf3977b310..00000000000000 --- a/test/simple/test-asynclistener-error-throw-in-before-multiple.js +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - before: function() { - throw 1; - }, - error: function(stor, err) { - // Must catch error thrown in before callback. - assert.equal(err, 1); - once++; - return true; - } -} - -var handlers1 = { - before: function() { - throw 2; - }, - error: function(stor, err) { - // Must catch *other* handlers throw by error callback. - assert.equal(err, 1); - once++; - return true; - } -} - -var listeners = [ - tracing.addAsyncListener(handlers), - tracing.addAsyncListener(handlers1) -]; - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - // Both error handlers must fire. - assert.equal(once, 2); -}); - -process.nextTick(function() { }); - -for (var i = 0; i < listeners.length; i++) - tracing.removeAsyncListener(listeners[i]); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - // Make sure uncaughtException actually fired. - assert.ok(uncaughtFired); - console.log('ok'); -}); - diff --git a/test/simple/test-asynclistener-error-throw-in-before.js b/test/simple/test-asynclistener-error-throw-in-before.js deleted file mode 100644 index fb6b6eeecaedb7..00000000000000 --- a/test/simple/test-asynclistener-error-throw-in-before.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var once = 0; - -var results = []; -var handlers = { - before: function() { - throw 1; - }, - error: function(stor, err) { - // Error handler must be called exactly *once*. - once++; - assert.equal(err, 1); - return true; - } -} - -var key = tracing.addAsyncListener(handlers); - -var uncaughtFired = false; -process.on('uncaughtException', function(err) { - uncaughtFired = true; - - // Process should propagate error regardless of handlers return value. - assert.equal(once, 1); -}); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Make sure that the uncaughtException actually fired. - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-error-throw-in-error.js b/test/simple/test-asynclistener-error-throw-in-error.js deleted file mode 100644 index c66d688fbea8cd..00000000000000 --- a/test/simple/test-asynclistener-error-throw-in-error.js +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var spawn = require('child_process').spawn; -var tracing = require('tracing'); - -var checkStr = 'WRITTEN ON EXIT'; - -if (process.argv[2] === 'child') - runChild(); -else - runParent(); - - -function runChild() { - var cntr = 0; - - var key = tracing.addAsyncListener({ - error: function onError() { - cntr++; - throw new Error('onError'); - } - }); - - process.on('unhandledException', function() { - // Throwing in 'error' should bypass unhandledException. - process.exit(2); - }); - - process.on('exit', function() { - // Make sure that we can still write out to stderr even when the - // process dies. - process._rawDebug(checkStr); - }); - - process.nextTick(function() { - throw new Error('nextTick'); - }); -} - - -function runParent() { - var childDidExit = false; - var childStr = ''; - var child = spawn(process.execPath, [__filename, 'child']); - child.stderr.on('data', function(chunk) { - process._rawDebug('received data from child'); - childStr += chunk.toString(); - }); - - child.on('exit', function(code) { - process._rawDebug('child process exiting'); - childDidExit = true; - // This is thrown when Node throws from _fatalException. - assert.equal(code, 7); - }); - - process.on('exit', function() { - process._rawDebug('child ondata message:', - childStr.substr(0, checkStr.length)); - - assert.ok(childDidExit); - assert.equal(childStr.substr(0, checkStr.length), checkStr); - console.log('ok'); - }); -} - diff --git a/test/simple/test-asynclistener-error.js b/test/simple/test-asynclistener-error.js deleted file mode 100644 index 6e5f31b0348c15..00000000000000 --- a/test/simple/test-asynclistener-error.js +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var dns = require('dns'); -var fs = require('fs'); -var net = require('net'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var errorMsgs = []; -var currentMsg = ''; -var caught = 0; -var expectCaught = 0; -var exitCbRan = false; - -var callbacksObj = { - error: function(value, er) { - var idx = errorMsgs.indexOf(er.message); - - caught++; - - if (-1 < idx) - errorMsgs.splice(idx, 1); - - return currentMsg === er.message; - } -}; - -var listener = tracing.createAsyncListener(callbacksObj); - -process.on('exit', function(code) { - removeListener(listener); - - // Something else went wrong, no need to further check. - if (code > 0) - return; - - // Make sure the exit callback only runs once. - assert.ok(!exitCbRan); - exitCbRan = true; - - // Check if any error messages weren't removed from the msg queue. - if (errorMsgs.length > 0) - throw new Error('Errors not fired: ' + errorMsgs); - - assert.equal(caught, expectCaught, 'caught all expected errors'); - process._rawDebug('ok'); -}); - - -// Catch synchronous throws -errorMsgs.push('sync throw'); -process.nextTick(function() { - addListener(listener); - - expectCaught++; - currentMsg = 'sync throw'; - throw new Error(currentMsg); - - removeListener(listener); -}); - - -// Simple cases -errorMsgs.push('setTimeout - simple'); -errorMsgs.push('setImmediate - simple'); -errorMsgs.push('setInterval - simple'); -errorMsgs.push('process.nextTick - simple'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - currentMsg = 'setTimeout - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - setImmediate(function() { - currentMsg = 'setImmediate - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - var b = setInterval(function() { - clearInterval(b); - currentMsg = 'setInterval - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - process.nextTick(function() { - currentMsg = 'process.nextTick - simple'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// Deeply nested -errorMsgs.push('setInterval - nested'); -errorMsgs.push('setImmediate - nested'); -errorMsgs.push('process.nextTick - nested'); -errorMsgs.push('setTimeout2 - nested'); -errorMsgs.push('setTimeout - nested'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - process.nextTick(function() { - setImmediate(function() { - var b = setInterval(function() { - clearInterval(b); - currentMsg = 'setInterval - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'setImmediate - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'process.nextTick - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - setTimeout(function() { - currentMsg = 'setTimeout2 - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'setTimeout - nested'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// FS -errorMsgs.push('fs - file does not exist'); -errorMsgs.push('fs - exists'); -errorMsgs.push('fs - realpath'); -process.nextTick(function() { - addListener(listener); - - fs.stat('does not exist', function(err, stats) { - currentMsg = 'fs - file does not exist'; - throw new Error(currentMsg); - }); - expectCaught++; - - fs.exists('hi all', function(exists) { - currentMsg = 'fs - exists'; - throw new Error(currentMsg); - }); - expectCaught++; - - fs.realpath('/some/path', function(err, resolved) { - currentMsg = 'fs - realpath'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// Nested FS -errorMsgs.push('fs - nested file does not exist'); -process.nextTick(function() { - addListener(listener); - - setTimeout(function() { - setImmediate(function() { - var b = setInterval(function() { - clearInterval(b); - process.nextTick(function() { - fs.stat('does not exist', function(err, stats) { - currentMsg = 'fs - nested file does not exist'; - throw new Error(currentMsg); - }); - expectCaught++; - }); - }); - }); - }); - - removeListener(listener); -}); - - -// Net -errorMsgs.push('net - connection listener'); -errorMsgs.push('net - client connect'); -errorMsgs.push('net - server listening'); -process.nextTick(function() { - addListener(listener); - - var server = net.createServer(function(c) { - server.close(); - currentMsg = 'net - connection listener'; - throw new Error(currentMsg); - }); - expectCaught++; - - server.listen(common.PORT, function() { - var client = net.connect(common.PORT, function() { - client.end(); - currentMsg = 'net - client connect'; - throw new Error(currentMsg); - }); - expectCaught++; - currentMsg = 'net - server listening'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); - - -// DNS -errorMsgs.push('dns - lookup'); -process.nextTick(function() { - addListener(listener); - - dns.lookup('localhost', function() { - currentMsg = 'dns - lookup'; - throw new Error(currentMsg); - }); - expectCaught++; - - removeListener(listener); -}); diff --git a/test/simple/test-asynclistener-multi-timeout.js b/test/simple/test-asynclistener-multi-timeout.js deleted file mode 100644 index 9af48205450f25..00000000000000 --- a/test/simple/test-asynclistener-multi-timeout.js +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var caught = []; -var expect = []; - -var callbacksObj = { - error: function(value, er) { - process._rawDebug('caught', er.message); - caught.push(er.message); - return (expect.indexOf(er.message) !== -1); - } -}; - -var listener = tracing.createAsyncListener(callbacksObj); - -process.on('exit', function(code) { - removeListener(listener); - - if (code > 0) - return; - - expect = expect.sort(); - caught = caught.sort(); - - process._rawDebug('expect', expect); - process._rawDebug('caught', caught); - assert.deepEqual(caught, expect, 'caught all expected errors'); - process._rawDebug('ok'); -}); - - -expect.push('immediate simple a'); -expect.push('immediate simple b'); -process.nextTick(function() { - addListener(listener); - // Tests for a setImmediate specific bug encountered while implementing - // AsyncListeners. - setImmediate(function() { - throw new Error('immediate simple a'); - }); - setImmediate(function() { - throw new Error('immediate simple b'); - }); - removeListener(listener); -}); diff --git a/test/simple/test-asynclistener-remove-add-in-before.js b/test/simple/test-asynclistener-remove-add-in-before.js deleted file mode 100644 index af0bc78e0e83ba..00000000000000 --- a/test/simple/test-asynclistener-remove-add-in-before.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var val; -var callbacks = { - create: function() { - return 42; - }, - before: function() { - tracing.removeAsyncListener(listener); - tracing.addAsyncListener(listener); - }, - after: function(context, storage) { - val = storage; - } -}; - -var listener = tracing.addAsyncListener(callbacks); - -process.nextTick(function() {}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(listener); - assert.equal(status, 0); - assert.equal(val, 42); -}); diff --git a/test/simple/test-asynclistener-remove-before.js b/test/simple/test-asynclistener-remove-before.js deleted file mode 100644 index bc306dbc3c87b5..00000000000000 --- a/test/simple/test-asynclistener-remove-before.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var set = 0; - -var asyncNoHandleError = { - before: function() { - set++; - }, - after: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -tracing.removeAsyncListener(key); - -process.nextTick(function() { }); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // The async handler should never be called. - assert.equal(set, 0); - console.log('ok'); -}); - - diff --git a/test/simple/test-asynclistener-remove-in-before.js b/test/simple/test-asynclistener-remove-in-before.js deleted file mode 100644 index 06f470ce075f07..00000000000000 --- a/test/simple/test-asynclistener-remove-in-before.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); -var done = false; -var callbacks = { - before: function() { - tracing.removeAsyncListener(listener); - }, - after: function() { - done = true; - } -}; - -var listener = tracing.addAsyncListener(callbacks); - -process.nextTick(function() {}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(listener); - assert.equal(status, 0); - assert.ok(done); -}); diff --git a/test/simple/test-asynclistener-remove-inflight-error.js b/test/simple/test-asynclistener-remove-inflight-error.js deleted file mode 100644 index 1b9150152a709d..00000000000000 --- a/test/simple/test-asynclistener-remove-inflight-error.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var set = 0; -var asyncNoHandleError = { - error: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -process.nextTick(function() { - throw 1; -}); - -tracing.removeAsyncListener(key); - -var uncaughtFired = false; -process.on('uncaughtException', function() { - uncaughtFired = true; - - // Throwing should call the error handler once, then propagate to - // uncaughtException - assert.equal(set, 1); -}); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - assert.ok(uncaughtFired); - console.log('ok'); -}); diff --git a/test/simple/test-asynclistener-remove-inflight.js b/test/simple/test-asynclistener-remove-inflight.js deleted file mode 100644 index a21b1923f40827..00000000000000 --- a/test/simple/test-asynclistener-remove-inflight.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var set = 0; -var asyncNoHandleError = { - before: function() { - set++; - }, - after: function() { - set++; - } -} - -var key = tracing.addAsyncListener(asyncNoHandleError); - -process.nextTick(function() { }); - -tracing.removeAsyncListener(key); - -process.on('exit', function(code) { - // If the exit code isn't ok then return early to throw the stack that - // caused the bad return code. - if (code !== 0) - return; - - // Calling removeAsyncListener *after* a callback is scheduled - // should not affect the handler from responding to the callback. - assert.equal(set, 2); - console.log('ok'); -}); - diff --git a/test/simple/test-asynclistener-run-error-once.js b/test/simple/test-asynclistener-run-error-once.js deleted file mode 100644 index 154decb99af994..00000000000000 --- a/test/simple/test-asynclistener-run-error-once.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var net = require('net'); -var tracing = require('tracing'); - -var errMsg = 'net - error: server connection'; -var cntr = 0; -var al = tracing.addAsyncListener({ - error: function(stor, er) { - cntr++; - process._rawDebug('Handling error: ' + er.message); - assert.equal(errMsg, er.message); - return true; - } -}); - -process.on('exit', function(status) { - tracing.removeAsyncListener(al); - - console.log('exit status:', status); - assert.equal(status, 0); - console.log('cntr:', cntr); - assert.equal(cntr, 1); - console.log('ok'); -}); - - -var server = net.createServer(function(c) { - this.close(); - throw new Error(errMsg); -}); - - -server.listen(common.PORT, function() { - net.connect(common.PORT, function() { - this.destroy(); - }); -}); diff --git a/test/simple/test-asynclistener-run-inst-once.js b/test/simple/test-asynclistener-run-inst-once.js deleted file mode 100644 index b1492528eedea6..00000000000000 --- a/test/simple/test-asynclistener-run-inst-once.js +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -var cntr = 0; -var al = tracing.createAsyncListener({ - create: function() { cntr++; }, -}); - -process.on('exit', function() { - assert.equal(cntr, 4); - console.log('ok'); -}); - -tracing.addAsyncListener(al); - -process.nextTick(function() { - tracing.addAsyncListener(al); - process.nextTick(function() { - tracing.addAsyncListener(al); - process.nextTick(function() { - process.nextTick(function() { }); - }); - }); -}); diff --git a/test/simple/test-asynclistener-throw-before-infinite-recursion.js b/test/simple/test-asynclistener-throw-before-infinite-recursion.js deleted file mode 100644 index fdbb50be17d558..00000000000000 --- a/test/simple/test-asynclistener-throw-before-infinite-recursion.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var tracing = require('tracing'); - -// If there is an uncaughtException listener then the error thrown from -// "before" will be considered handled, thus calling setImmediate to -// finish execution of the nextTickQueue. This in turn will cause "before" -// to fire again, entering into an infinite loop. -// So the asyncQueue is cleared from the returned setImmediate in -// _fatalException to prevent this from happening. -var cntr = 0; - - -tracing.addAsyncListener({ - before: function() { - if (++cntr > 1) { - // Can't throw since uncaughtException will also catch that. - process._rawDebug('Error: Multiple before callbacks called'); - process.exit(1); - } - throw new Error('before'); - } -}); - -process.on('uncaughtException', function() { }); - -process.nextTick(); diff --git a/test/simple/test-asynclistener.js b/test/simple/test-asynclistener.js deleted file mode 100644 index 4c29ec9054f809..00000000000000 --- a/test/simple/test-asynclistener.js +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var net = require('net'); -var fs = require('fs'); -var dgram = require('dgram'); -var tracing = require('tracing'); - -var addListener = tracing.addAsyncListener; -var removeListener = tracing.removeAsyncListener; -var actualAsync = 0; -var expectAsync = 0; - -var callbacks = { - create: function onAsync() { - actualAsync++; - } -}; - -var listener = tracing.createAsyncListener(callbacks); - -process.on('exit', function() { - process._rawDebug('expected', expectAsync); - process._rawDebug('actual ', actualAsync); - // TODO(trevnorris): Not a great test. If one was missed, but others - // overflowed then the test would still pass. - assert.ok(actualAsync >= expectAsync); -}); - - -// Test listeners side-by-side -process.nextTick(function() { - addListener(listener); - - var b = setInterval(function() { - clearInterval(b); - }); - expectAsync++; - - var c = setInterval(function() { - clearInterval(c); - }); - expectAsync++; - - setTimeout(function() { }); - expectAsync++; - - setTimeout(function() { }); - expectAsync++; - - process.nextTick(function() { }); - expectAsync++; - - process.nextTick(function() { }); - expectAsync++; - - setImmediate(function() { }); - expectAsync++; - - setImmediate(function() { }); - expectAsync++; - - setTimeout(function() { }, 10); - expectAsync++; - - setTimeout(function() { }, 10); - expectAsync++; - - removeListener(listener); -}); - - -// Async listeners should propagate with nested callbacks -process.nextTick(function() { - addListener(listener); - var interval = 3; - - process.nextTick(function() { - setTimeout(function() { - setImmediate(function() { - var i = setInterval(function() { - if (--interval <= 0) - clearInterval(i); - }); - expectAsync++; - }); - expectAsync++; - process.nextTick(function() { - setImmediate(function() { - setTimeout(function() { }, 20); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test triggers with two async listeners -process.nextTick(function() { - addListener(listener); - addListener(listener); - - setTimeout(function() { - process.nextTick(function() { }); - expectAsync += 2; - }); - expectAsync += 2; - - removeListener(listener); - removeListener(listener); -}); - - -// Test callbacks from fs I/O -process.nextTick(function() { - addListener(listener); - - fs.stat('something random', function(err, stat) { }); - expectAsync++; - - setImmediate(function() { - fs.stat('random again', function(err, stat) { }); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test net I/O -process.nextTick(function() { - addListener(listener); - - var server = net.createServer(function(c) { }); - expectAsync++; - - server.listen(common.PORT, function() { - server.close(); - expectAsync++; - }); - expectAsync++; - - removeListener(listener); -}); - - -// Test UDP -process.nextTick(function() { - addListener(listener); - - var server = dgram.createSocket('udp4'); - expectAsync++; - - server.bind(common.PORT); - - server.close(); - expectAsync++; - - removeListener(listener); -}); diff --git a/test/simple/test-v8-gc.js b/test/simple/test-v8-gc.js deleted file mode 100644 index 077e48c574e750..00000000000000 --- a/test/simple/test-v8-gc.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Flags: --expose_gc - -var common = require('../common'); -var assert = require('assert'); -var v8 = require('tracing').v8; - -assert(typeof gc === 'function', 'Run this test with --expose_gc.'); - -var ncalls = 0; -var before; -var after; - -function ongc(before_, after_) { - // Try very hard to not create garbage because that could kick off another - // garbage collection cycle. - before = before_; - after = after_; - ncalls += 1; -} - -gc(); -v8.on('gc', ongc); -gc(); -v8.removeListener('gc', ongc); -gc(); - -assert.equal(ncalls, 1); -assert.equal(typeof before, 'object'); -assert.equal(typeof after, 'object'); -assert.equal(typeof before.timestamp, 'number'); -assert.equal(typeof after.timestamp, 'number'); -assert.equal(before.timestamp <= after.timestamp, true); diff --git a/test/simple/test-v8-stats.js b/test/simple/test-v8-stats.js deleted file mode 100644 index 6d70fb9a02a544..00000000000000 --- a/test/simple/test-v8-stats.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var common = require('../common'); -var assert = require('assert'); -var v8 = require('tracing').v8; - -var s = v8.getHeapStatistics(); -var keys = [ - 'heap_size_limit', - 'total_heap_size', - 'total_heap_size_executable', - 'total_physical_size', - 'used_heap_size']; -assert.deepEqual(Object.keys(s).sort(), keys); -keys.forEach(function(key) { - assert.equal(typeof s[key], 'number'); -}); From 2593c1413155a42604c53327b9c2b23b017f0dfa Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 12 Nov 2014 15:58:23 -0800 Subject: [PATCH 17/27] async-wrap: move MakeCallback to .cc MakeCallback is too large a function to be inlined. Likewise, only having header files will not allow for any part of AsyncWrap to be exposed cleanly via NODE_MODULE_CONTEXT_AWARE_BUILTIN(). PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- node.gyp | 1 + src/async-wrap-inl.h | 128 --------------------------------- src/async-wrap.cc | 164 +++++++++++++++++++++++++++++++++++++++++++ src/async-wrap.h | 8 +-- 4 files changed, 169 insertions(+), 132 deletions(-) create mode 100644 src/async-wrap.cc diff --git a/node.gyp b/node.gyp index 220f9eb2ab2c51..1ed8d673eeca2b 100644 --- a/node.gyp +++ b/node.gyp @@ -88,6 +88,7 @@ ], 'sources': [ + 'src/async-wrap.cc', 'src/fs_event_wrap.cc', 'src/cares_wrap.cc', 'src/handle_wrap.cc', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index bcfa19ddf69147..f3270c9837b814 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -51,134 +51,6 @@ inline uint32_t AsyncWrap::provider_type() const { } -// I hate you domains. -inline v8::Handle AsyncWrap::MakeDomainCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv) { - assert(env()->context() == env()->isolate()->GetCurrentContext()); - - v8::Local context = object(); - v8::Local process = env()->process_object(); - v8::Local domain_v = context->Get(env()->domain_string()); - v8::Local domain; - - v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - bool has_domain = domain_v->IsObject(); - if (has_domain) { - domain = domain_v.As(); - - if (domain->Get(env()->disposed_string())->IsTrue()) - return Undefined(env()->isolate()); - - v8::Local enter = - domain->Get(env()->enter_string()).As(); - if (enter->IsFunction()) { - enter->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env()->isolate()); - } - } - - v8::Local ret = cb->Call(context, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env()->isolate()); - } - - if (has_domain) { - v8::Local exit = - domain->Get(env()->exit_string()).As(); - if (exit->IsFunction()) { - exit->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env()->isolate()); - } - } - - Environment::TickInfo* tick_info = env()->tick_info(); - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env()->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env()->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); - - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env()->isolate()); - } - - return ret; -} - - -inline v8::Handle AsyncWrap::MakeCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv) { - if (env()->using_domains()) - return MakeDomainCallback(cb, argc, argv); - - assert(env()->context() == env()->isolate()->GetCurrentContext()); - - v8::Local context = object(); - v8::Local process = env()->process_object(); - - v8::TryCatch try_catch; - try_catch.SetVerbose(true); - - v8::Local ret = cb->Call(context, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env()->isolate()); - } - - Environment::TickInfo* tick_info = env()->tick_info(); - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env()->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env()->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); - - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env()->isolate()); - } - - return ret; -} - - inline v8::Handle AsyncWrap::MakeCallback( const v8::Handle symbol, int argc, diff --git a/src/async-wrap.cc b/src/async-wrap.cc new file mode 100644 index 00000000000000..6f3f1e92123a49 --- /dev/null +++ b/src/async-wrap.cc @@ -0,0 +1,164 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "async-wrap.h" +#include "async-wrap-inl.h" +#include "env.h" +#include "env-inl.h" +#include "util.h" +#include "util-inl.h" + +#include "v8.h" + +using v8::Function; +using v8::Handle; +using v8::Local; +using v8::Object; +using v8::TryCatch; +using v8::Value; + +namespace node { + +Handle AsyncWrap::MakeDomainCallback(const Handle cb, + int argc, + Handle* argv) { + CHECK(env()->context() == env()->isolate()->GetCurrentContext()); + + Local context = object(); + Local process = env()->process_object(); + Local domain_v = context->Get(env()->domain_string()); + Local domain; + + TryCatch try_catch; + try_catch.SetVerbose(true); + + bool has_domain = domain_v->IsObject(); + if (has_domain) { + domain = domain_v.As(); + + if (domain->Get(env()->disposed_string())->IsTrue()) + return Undefined(env()->isolate()); + + Local enter = + domain->Get(env()->enter_string()).As(); + if (enter->IsFunction()) { + enter->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env()->isolate()); + } + } + + Local ret = cb->Call(context, argc, argv); + + if (try_catch.HasCaught()) { + return Undefined(env()->isolate()); + } + + if (has_domain) { + Local exit = + domain->Get(env()->exit_string()).As(); + if (exit->IsFunction()) { + exit->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env()->isolate()); + } + } + + Environment::TickInfo* tick_info = env()->tick_info(); + + if (tick_info->in_tick()) { + return ret; + } + + if (tick_info->length() == 0) { + env()->isolate()->RunMicrotasks(); + } + + if (tick_info->length() == 0) { + tick_info->set_index(0); + return ret; + } + + tick_info->set_in_tick(true); + + env()->tick_callback_function()->Call(process, 0, NULL); + + tick_info->set_in_tick(false); + + if (try_catch.HasCaught()) { + tick_info->set_last_threw(true); + return Undefined(env()->isolate()); + } + + return ret; +} + + +Handle AsyncWrap::MakeCallback(const Handle cb, + int argc, + Handle* argv) { + if (env()->using_domains()) + return MakeDomainCallback(cb, argc, argv); + + CHECK(env()->context() == env()->isolate()->GetCurrentContext()); + + Local context = object(); + Local process = env()->process_object(); + + TryCatch try_catch; + try_catch.SetVerbose(true); + + Local ret = cb->Call(context, argc, argv); + + if (try_catch.HasCaught()) { + return Undefined(env()->isolate()); + } + + Environment::TickInfo* tick_info = env()->tick_info(); + + if (tick_info->in_tick()) { + return ret; + } + + if (tick_info->length() == 0) { + env()->isolate()->RunMicrotasks(); + } + + if (tick_info->length() == 0) { + tick_info->set_index(0); + return ret; + } + + tick_info->set_in_tick(true); + + env()->tick_callback_function()->Call(process, 0, NULL); + + tick_info->set_in_tick(false); + + if (try_catch.HasCaught()) { + tick_info->set_last_threw(true); + return Undefined(env()->isolate()); + } + + return ret; +} + +} // namespace node diff --git a/src/async-wrap.h b/src/async-wrap.h index f383ac90af903d..1d30a3b1db4517 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -61,9 +61,9 @@ class AsyncWrap : public BaseObject { inline uint32_t provider_type() const; // Only call these within a valid HandleScope. - inline v8::Handle MakeCallback(const v8::Handle cb, - int argc, - v8::Handle* argv); + v8::Handle MakeCallback(const v8::Handle cb, + int argc, + v8::Handle* argv); inline v8::Handle MakeCallback(const v8::Handle symbol, int argc, v8::Handle* argv); @@ -76,7 +76,7 @@ class AsyncWrap : public BaseObject { // TODO(trevnorris): BURN IN FIRE! Remove this as soon as a suitable // replacement is committed. - inline v8::Handle MakeDomainCallback( + v8::Handle MakeDomainCallback( const v8::Handle cb, int argc, v8::Handle* argv); From 42df679c458b3edc2d4754baaf3b16ba015a1dd6 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 12 Nov 2014 16:08:12 -0800 Subject: [PATCH 18/27] node, async-wrap: remove MakeDomainCallback C++ won't deoptimize like JS if specific conditional branches are sporadically met in the future. Combined with the amount of code duplication removal and simplified maintenance complexity, it makes more sense to merge MakeCallback and MakeDomainCallback. Additionally, type casting in V8 before verifying what that type is will cause V8 to abort in debug mode if that type isn't what was expected. Fix this by first checking the v8::Value before casting. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/async-wrap-inl.h | 14 ++--- src/async-wrap.cc | 88 +++++++--------------------- src/async-wrap.h | 7 --- src/node.cc | 133 ++++++++++--------------------------------- 4 files changed, 55 insertions(+), 187 deletions(-) diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index f3270c9837b814..9bd5744b164197 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -31,7 +31,6 @@ #include "util-inl.h" #include "v8.h" -#include namespace node { @@ -46,6 +45,7 @@ inline AsyncWrap::AsyncWrap(Environment* env, inline AsyncWrap::~AsyncWrap() { } + inline uint32_t AsyncWrap::provider_type() const { return provider_type_; } @@ -56,10 +56,8 @@ inline v8::Handle AsyncWrap::MakeCallback( int argc, v8::Handle* argv) { v8::Local cb_v = object()->Get(symbol); - v8::Local cb = cb_v.As(); - assert(cb->IsFunction()); - - return MakeCallback(cb, argc, argv); + ASSERT(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); } @@ -68,10 +66,8 @@ inline v8::Handle AsyncWrap::MakeCallback( int argc, v8::Handle* argv) { v8::Local cb_v = object()->Get(index); - v8::Local cb = cb_v.As(); - assert(cb->IsFunction()); - - return MakeCallback(cb, argc, argv); + ASSERT(cb_v->IsFunction()); + return MakeCallback(cb_v.As(), argc, argv); } } // namespace node diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 6f3f1e92123a49..66455a3046e196 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -37,30 +37,33 @@ using v8::Value; namespace node { -Handle AsyncWrap::MakeDomainCallback(const Handle cb, - int argc, - Handle* argv) { +Handle AsyncWrap::MakeCallback(const Handle cb, + int argc, + Handle* argv) { CHECK(env()->context() == env()->isolate()->GetCurrentContext()); Local context = object(); Local process = env()->process_object(); - Local domain_v = context->Get(env()->domain_string()); Local domain; + bool has_domain = false; + + if (env()->using_domains()) { + Local domain_v = context->Get(env()->domain_string()); + has_domain = domain_v->IsObject(); + if (has_domain) { + domain = domain_v.As(); + if (domain->Get(env()->disposed_string())->IsTrue()) + return Undefined(env()->isolate()); + } + } TryCatch try_catch; try_catch.SetVerbose(true); - bool has_domain = domain_v->IsObject(); if (has_domain) { - domain = domain_v.As(); - - if (domain->Get(env()->disposed_string())->IsTrue()) - return Undefined(env()->isolate()); - - Local enter = - domain->Get(env()->enter_string()).As(); - if (enter->IsFunction()) { - enter->Call(domain, 0, NULL); + Local enter_v = domain->Get(env()->enter_string()); + if (enter_v->IsFunction()) { + enter_v.As()->Call(domain, 0, NULL); if (try_catch.HasCaught()) return Undefined(env()->isolate()); } @@ -73,10 +76,9 @@ Handle AsyncWrap::MakeDomainCallback(const Handle cb, } if (has_domain) { - Local exit = - domain->Get(env()->exit_string()).As(); - if (exit->IsFunction()) { - exit->Call(domain, 0, NULL); + Local exit_v = domain->Get(env()->exit_string()); + if (exit_v->IsFunction()) { + exit_v.As()->Call(domain, 0, NULL); if (try_catch.HasCaught()) return Undefined(env()->isolate()); } @@ -111,54 +113,4 @@ Handle AsyncWrap::MakeDomainCallback(const Handle cb, return ret; } - -Handle AsyncWrap::MakeCallback(const Handle cb, - int argc, - Handle* argv) { - if (env()->using_domains()) - return MakeDomainCallback(cb, argc, argv); - - CHECK(env()->context() == env()->isolate()->GetCurrentContext()); - - Local context = object(); - Local process = env()->process_object(); - - TryCatch try_catch; - try_catch.SetVerbose(true); - - Local ret = cb->Call(context, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env()->isolate()); - } - - Environment::TickInfo* tick_info = env()->tick_info(); - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env()->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env()->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); - - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env()->isolate()); - } - - return ret; -} - } // namespace node diff --git a/src/async-wrap.h b/src/async-wrap.h index 1d30a3b1db4517..b1f1fef3bded7f 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -74,13 +74,6 @@ class AsyncWrap : public BaseObject { private: inline AsyncWrap(); - // TODO(trevnorris): BURN IN FIRE! Remove this as soon as a suitable - // replacement is committed. - v8::Handle MakeDomainCallback( - const v8::Handle cb, - int argc, - v8::Handle* argv); - uint32_t provider_type_; }; diff --git a/src/node.cc b/src/node.cc index df1c8eb1bf3738..f4809a5147acd9 100644 --- a/src/node.cc +++ b/src/node.cc @@ -978,111 +978,53 @@ void SetupNextTick(const FunctionCallbackInfo& args) { } -Handle MakeDomainCallback(Environment* env, - Handle recv, - const Handle callback, - int argc, - Handle argv[]) { +Handle MakeCallback(Environment* env, + Handle recv, + const Handle callback, + int argc, + Handle argv[]) { // If you hit this assertion, you forgot to enter the v8::Context first. - assert(env->context() == env->isolate()->GetCurrentContext()); + CHECK(env->context() == env->isolate()->GetCurrentContext()); Local process = env->process_object(); Local object, domain; - Local domain_v; - - TryCatch try_catch; - try_catch.SetVerbose(true); - bool has_domain = false; - if (!object.IsEmpty()) { - domain_v = object->Get(env->domain_string()); + if (env->using_domains()) { + CHECK(recv->IsObject()); + object = recv.As(); + Local domain_v = object->Get(env->domain_string()); has_domain = domain_v->IsObject(); if (has_domain) { domain = domain_v.As(); - - if (domain->Get(env->disposed_string())->IsTrue()) { - // domain has been disposed of. + if (domain->Get(env->disposed_string())->IsTrue()) return Undefined(env->isolate()); - } - - Local enter = domain->Get(env->enter_string()).As(); - if (enter->IsFunction()) { - enter->Call(domain, 0, NULL); - if (try_catch.HasCaught()) - return Undefined(env->isolate()); - } } } - Local ret = callback->Call(recv, argc, argv); - - if (try_catch.HasCaught()) { - return Undefined(env->isolate()); - } + TryCatch try_catch; + try_catch.SetVerbose(true); if (has_domain) { - Local exit = domain->Get(env->exit_string()).As(); - if (exit->IsFunction()) { - exit->Call(domain, 0, NULL); + Local enter_v = domain->Get(env->enter_string()); + if (enter_v->IsFunction()) { + enter_v.As()->Call(domain, 0, NULL); if (try_catch.HasCaught()) return Undefined(env->isolate()); } } - Environment::TickInfo* tick_info = env->tick_info(); - - if (tick_info->last_threw() == 1) { - tick_info->set_last_threw(0); - return ret; - } - - if (tick_info->in_tick()) { - return ret; - } - - if (tick_info->length() == 0) { - env->isolate()->RunMicrotasks(); - } - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return ret; - } - - tick_info->set_in_tick(true); - - env->tick_callback_function()->Call(process, 0, NULL); - - tick_info->set_in_tick(false); + Local ret = callback->Call(recv, argc, argv); - if (try_catch.HasCaught()) { - tick_info->set_last_threw(true); - return Undefined(env->isolate()); + if (has_domain) { + Local exit_v = domain->Get(env->exit_string()); + if (exit_v->IsFunction()) { + exit_v.As()->Call(domain, 0, NULL); + if (try_catch.HasCaught()) + return Undefined(env->isolate()); + } } - return ret; -} - - -Handle MakeCallback(Environment* env, - Handle recv, - const Handle callback, - int argc, - Handle argv[]) { - if (env->using_domains()) - return MakeDomainCallback(env, recv, callback, argc, argv); - - // If you hit this assertion, you forgot to enter the v8::Context first. - assert(env->context() == env->isolate()->GetCurrentContext()); - - Local process = env->process_object(); - - TryCatch try_catch; - try_catch.SetVerbose(true); - - Local ret = callback->Call(recv, argc, argv); - if (try_catch.HasCaught()) { return Undefined(env->isolate()); } @@ -1124,10 +1066,9 @@ Handle MakeCallback(Environment* env, uint32_t index, int argc, Handle argv[]) { - Local callback = recv->Get(index).As(); - assert(callback->IsFunction()); - - return MakeCallback(env, recv.As(), callback, argc, argv); + Local cb_v = recv->Get(index); + CHECK(cb_v->IsFunction()); + return MakeCallback(env, recv.As(), cb_v.As(), argc, argv); } @@ -1136,9 +1077,9 @@ Handle MakeCallback(Environment* env, Handle symbol, int argc, Handle argv[]) { - Local callback = recv->Get(symbol).As(); - assert(callback->IsFunction()); - return MakeCallback(env, recv.As(), callback, argc, argv); + Local cb_v = recv->Get(symbol); + CHECK(cb_v->IsFunction()); + return MakeCallback(env, recv.As(), cb_v.As(), argc, argv); } @@ -1195,20 +1136,6 @@ Handle MakeCallback(Isolate* isolate, } -Handle MakeDomainCallback(Handle recv, - Handle callback, - int argc, - Handle argv[]) { - Local context = recv->CreationContext(); - Environment* env = Environment::GetCurrent(context); - Context::Scope context_scope(context); - EscapableHandleScope handle_scope(env->isolate()); - return handle_scope.Escape(Local::New( - env->isolate(), - MakeDomainCallback(env, recv, callback, argc, argv))); -} - - enum encoding ParseEncoding(Isolate* isolate, Handle encoding_v, enum encoding _default) { From b1e9d330aa603e40430724f1c834d15fd66a55f2 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 12 Nov 2014 16:35:48 -0800 Subject: [PATCH 19/27] node: fix throws before timer module is loaded An edge case could occur when the setImmediate() in _fatalException() would fire before the timers module had been loaded globally, causing Node to crash. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/node.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.js b/src/node.js index 046e1ab63775ba..50460383ff71f1 100644 --- a/src/node.js +++ b/src/node.js @@ -249,7 +249,7 @@ // if we handled an error, then make sure any ticks get processed } else { - var t = setImmediate(process._tickCallback); + NativeModule.require('timers').setImmediate(process._tickCallback); } return caught; From 5962dbef49ae6dccc98004b6b955c34336ccbbf5 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 26 Aug 2014 12:21:39 -0700 Subject: [PATCH 20/27] src: all wrap's now use actual FunctionTemplate Instead of simply creating a new v8::Object to contain the connection information, instantiate a new instance of a FunctionTemplate. This will allow future improvements for debugging and performance probes. Additionally, the "provider" argument in the ReqWrap constructor is no longer optional. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- lib/child_process.js | 4 +- lib/dgram.js | 5 +- lib/dns.js | 26 ++--- lib/fs.js | 142 +++++++++++++++++++-------- lib/net.js | 17 +++- src/async-wrap.h | 41 ++++---- src/cares_wrap.cc | 64 +++++++++--- src/node_file.cc | 109 +++++++++++--------- src/pipe_wrap.cc | 31 +++++- src/req_wrap.h | 4 +- src/stream_wrap.cc | 29 +++++- src/stream_wrap.h | 23 ++++- src/tcp_wrap.cc | 35 +++++-- src/udp_wrap.cc | 18 +++- test/internet/test-dns.js | 5 +- test/simple/test-tcp-wrap-connect.js | 6 +- test/simple/test-tcp-wrap-listen.js | 4 +- 17 files changed, 404 insertions(+), 159 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index 4840c9e2bac51e..c4345f90c2ab9f 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -27,6 +27,7 @@ var assert = require('assert'); var util = require('util'); var Process = process.binding('process_wrap').Process; +var WriteWrap = process.binding('stream_wrap').WriteWrap; var uv = process.binding('uv'); var spawn_sync; // Lazy-loaded process.binding('spawn_sync') @@ -473,7 +474,8 @@ function setupChannel(target, channel) { return; } - var req = { oncomplete: nop }; + var req = new WriteWrap(); + req.oncomplete = nop; var string = JSON.stringify(message) + '\n'; var err = channel.writeUtf8String(req, string, handle); diff --git a/lib/dgram.js b/lib/dgram.js index aae2f51bc86b70..d1bfa14caa0732 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -25,6 +25,7 @@ var events = require('events'); var constants = require('constants'); var UDP = process.binding('udp_wrap').UDP; +var SendWrap = process.binding('udp_wrap').SendWrap; var BIND_STATE_UNBOUND = 0; var BIND_STATE_BINDING = 1; @@ -317,7 +318,9 @@ Socket.prototype.send = function(buffer, self.emit('error', ex); } else if (self._handle) { - var req = { buffer: buffer, length: length }; // Keep reference alive. + var req = new SendWrap(); + req.buffer = buffer; // Keep reference alive. + req.length = length; if (callback) { req.callback = callback; req.oncomplete = afterSend; diff --git a/lib/dns.js b/lib/dns.js index 4eb34d6651b119..18023fab16211f 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -25,6 +25,9 @@ var util = require('util'); var cares = process.binding('cares_wrap'); var uv = process.binding('uv'); +var GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap; +var GetNameInfoReqWrap = cares.GetNameInfoReqWrap; + var isIp = net.isIP; @@ -142,12 +145,11 @@ exports.lookup = function lookup(hostname, options, callback) { return {}; } - var req = { - callback: callback, - family: family, - hostname: hostname, - oncomplete: onlookup - }; + var req = new GetAddrInfoReqWrap(); + req.callback = callback; + req.family = family; + req.hostname = hostname; + req.oncomplete = onlookup; var err = cares.getaddrinfo(req, hostname, family, hints); if (err) { @@ -178,12 +180,12 @@ exports.lookupService = function(host, port, callback) { callback = makeAsync(callback); - var req = { - callback: callback, - host: host, - port: port, - oncomplete: onlookupservice - }; + var req = new GetNameInfoReqWrap(); + req.callback = callback; + req.host = host; + req.port = port; + req.oncomplete = onlookupservice; + var err = cares.getnameinfo(req, host, port); if (err) throw errnoException(err, 'getnameinfo', host); diff --git a/lib/fs.js b/lib/fs.js index 3301a6af8474dd..a97ba3aa639bd9 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -33,6 +33,7 @@ var constants = process.binding('constants'); var fs = exports; var Stream = require('stream').Stream; var EventEmitter = require('events').EventEmitter; +var FSReqWrap = binding.FSReqWrap; var Readable = Stream.Readable; var Writable = Stream.Writable; @@ -182,7 +183,9 @@ fs.Stats.prototype.isSocket = function() { fs.exists = function(path, callback) { if (!nullCheck(path, cb)) return; - binding.stat(pathModule._makeLong(path), cb); + var req = new FSReqWrap(); + req.oncomplete = cb; + binding.stat(pathModule._makeLong(path), req); function cb(err, stats) { if (callback) callback(err ? false : true); } @@ -421,7 +424,9 @@ Object.defineProperty(exports, '_stringToFlags', { // list to make the arguments clear. fs.close = function(fd, callback) { - binding.close(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.close(fd, req); }; fs.closeSync = function(fd) { @@ -443,10 +448,14 @@ fs.open = function(path, flags, mode, callback) { mode = modeNum(mode, 438 /*=0666*/); if (!nullCheck(path, callback)) return; + + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.open(pathModule._makeLong(path), stringToFlags(flags), mode, - callback); + req); }; fs.openSync = function(path, flags, mode) { @@ -482,7 +491,10 @@ fs.read = function(fd, buffer, offset, length, position, callback) { callback && callback(err, bytesRead || 0, buffer); } - binding.read(fd, buffer, offset, length, position, wrapper); + var req = new FSReqWrap(); + req.oncomplete = wrapper; + + binding.read(fd, buffer, offset, length, position, req); }; fs.readSync = function(fd, buffer, offset, length, position) { @@ -515,6 +527,16 @@ fs.readSync = function(fd, buffer, offset, length, position) { // OR // fs.write(fd, string[, position[, encoding]], callback); fs.write = function(fd, buffer, offset, length, position, callback) { + function strWrapper(err, written) { + // Retain a reference to buffer so that it can't be GC'ed too soon. + callback(err, written || 0, buffer); + } + + function bufWrapper(err, written) { + // retain reference to string in case it's external + callback(err, written || 0, buffer); + } + if (util.isBuffer(buffer)) { // if no position is passed then assume null if (util.isFunction(position)) { @@ -522,11 +544,9 @@ fs.write = function(fd, buffer, offset, length, position, callback) { position = null; } callback = maybeCallback(callback); - var wrapper = function(err, written) { - // Retain a reference to buffer so that it can't be GC'ed too soon. - callback(err, written || 0, buffer); - }; - return binding.writeBuffer(fd, buffer, offset, length, position, wrapper); + var req = new FSReqWrap(); + req.oncomplete = strWrapper; + return binding.writeBuffer(fd, buffer, offset, length, position, req); } if (util.isString(buffer)) @@ -541,11 +561,9 @@ fs.write = function(fd, buffer, offset, length, position, callback) { length = 'utf8'; } callback = maybeCallback(position); - position = function(err, written) { - // retain reference to string in case it's external - callback(err, written || 0, buffer); - }; - return binding.writeString(fd, buffer, offset, length, position); + var req = new FSReqWrap(); + req.oncomplete = bufWrapper; + return binding.writeString(fd, buffer, offset, length, req); }; // usage: @@ -569,9 +587,11 @@ fs.rename = function(oldPath, newPath, callback) { callback = makeCallback(callback); if (!nullCheck(oldPath, callback)) return; if (!nullCheck(newPath, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.rename(pathModule._makeLong(oldPath), pathModule._makeLong(newPath), - callback); + req); }; fs.renameSync = function(oldPath, newPath) { @@ -583,8 +603,9 @@ fs.renameSync = function(oldPath, newPath) { fs.truncate = function(path, len, callback) { if (util.isNumber(path)) { - // legacy - return fs.ftruncate(path, len, callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + return fs.ftruncate(path, len, req); } if (util.isFunction(len)) { callback = len; @@ -592,14 +613,17 @@ fs.truncate = function(path, len, callback) { } else if (util.isUndefined(len)) { len = 0; } + callback = maybeCallback(callback); fs.open(path, 'r+', function(er, fd) { if (er) return callback(er); - binding.ftruncate(fd, len, function(er) { + var req = new FSReqWrap(); + req.oncomplete = function ftruncateCb(er) { fs.close(fd, function(er2) { callback(er || er2); }); - }); + }; + binding.ftruncate(fd, len, req); }); }; @@ -628,7 +652,9 @@ fs.ftruncate = function(fd, len, callback) { } else if (util.isUndefined(len)) { len = 0; } - binding.ftruncate(fd, len, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.ftruncate(fd, len, req); }; fs.ftruncateSync = function(fd, len) { @@ -639,9 +665,11 @@ fs.ftruncateSync = function(fd, len) { }; fs.rmdir = function(path, callback) { - callback = makeCallback(callback); + callback = maybeCallback(callback); if (!nullCheck(path, callback)) return; - binding.rmdir(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.rmdir(pathModule._makeLong(path), req); }; fs.rmdirSync = function(path) { @@ -650,7 +678,9 @@ fs.rmdirSync = function(path) { }; fs.fdatasync = function(fd, callback) { - binding.fdatasync(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fdatasync(fd, req); }; fs.fdatasyncSync = function(fd) { @@ -658,7 +688,9 @@ fs.fdatasyncSync = function(fd) { }; fs.fsync = function(fd, callback) { - binding.fsync(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fsync(fd, req); }; fs.fsyncSync = function(fd) { @@ -669,9 +701,11 @@ fs.mkdir = function(path, mode, callback) { if (util.isFunction(mode)) callback = mode; callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.mkdir(pathModule._makeLong(path), modeNum(mode, 511 /*=0777*/), - callback); + req); }; fs.mkdirSync = function(path, mode) { @@ -683,7 +717,9 @@ fs.mkdirSync = function(path, mode) { fs.readdir = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.readdir(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.readdir(pathModule._makeLong(path), req); }; fs.readdirSync = function(path) { @@ -692,19 +728,25 @@ fs.readdirSync = function(path) { }; fs.fstat = function(fd, callback) { - binding.fstat(fd, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fstat(fd, req); }; fs.lstat = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.lstat(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.lstat(pathModule._makeLong(path), req); }; fs.stat = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.stat(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.stat(pathModule._makeLong(path), req); }; fs.fstatSync = function(fd) { @@ -724,7 +766,9 @@ fs.statSync = function(path) { fs.readlink = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.readlink(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.readlink(pathModule._makeLong(path), req); }; fs.readlinkSync = function(path) { @@ -752,10 +796,13 @@ fs.symlink = function(destination, path, type_, callback) { if (!nullCheck(destination, callback)) return; if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.symlink(preprocessSymlinkDestination(destination, type), pathModule._makeLong(path), type, - callback); + req); }; fs.symlinkSync = function(destination, path, type) { @@ -774,9 +821,12 @@ fs.link = function(srcpath, dstpath, callback) { if (!nullCheck(srcpath, callback)) return; if (!nullCheck(dstpath, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.link(pathModule._makeLong(srcpath), pathModule._makeLong(dstpath), - callback); + req); }; fs.linkSync = function(srcpath, dstpath) { @@ -789,7 +839,9 @@ fs.linkSync = function(srcpath, dstpath) { fs.unlink = function(path, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.unlink(pathModule._makeLong(path), callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.unlink(pathModule._makeLong(path), req); }; fs.unlinkSync = function(path) { @@ -798,7 +850,9 @@ fs.unlinkSync = function(path) { }; fs.fchmod = function(fd, mode, callback) { - binding.fchmod(fd, modeNum(mode), makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fchmod(fd, modeNum(mode), req); }; fs.fchmodSync = function(fd, mode) { @@ -848,9 +902,11 @@ if (constants.hasOwnProperty('O_SYMLINK')) { fs.chmod = function(path, mode, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.chmod(pathModule._makeLong(path), modeNum(mode), - callback); + req); }; fs.chmodSync = function(path, mode) { @@ -877,7 +933,9 @@ if (constants.hasOwnProperty('O_SYMLINK')) { } fs.fchown = function(fd, uid, gid, callback) { - binding.fchown(fd, uid, gid, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.fchown(fd, uid, gid, req); }; fs.fchownSync = function(fd, uid, gid) { @@ -887,7 +945,9 @@ fs.fchownSync = function(fd, uid, gid) { fs.chown = function(path, uid, gid, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; - binding.chown(pathModule._makeLong(path), uid, gid, callback); + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.chown(pathModule._makeLong(path), uid, gid, req); }; fs.chownSync = function(path, uid, gid) { @@ -913,10 +973,12 @@ fs._toUnixTimestamp = toUnixTimestamp; fs.utimes = function(path, atime, mtime, callback) { callback = makeCallback(callback); if (!nullCheck(path, callback)) return; + var req = new FSReqWrap(); + req.oncomplete = callback; binding.utimes(pathModule._makeLong(path), toUnixTimestamp(atime), toUnixTimestamp(mtime), - callback); + req); }; fs.utimesSync = function(path, atime, mtime) { @@ -929,7 +991,9 @@ fs.utimesSync = function(path, atime, mtime) { fs.futimes = function(fd, atime, mtime, callback) { atime = toUnixTimestamp(atime); mtime = toUnixTimestamp(mtime); - binding.futimes(fd, atime, mtime, makeCallback(callback)); + var req = new FSReqWrap(); + req.oncomplete = makeCallback(callback); + binding.futimes(fd, atime, mtime, req); }; fs.futimesSync = function(fd, atime, mtime) { diff --git a/lib/net.js b/lib/net.js index 34de98bc3c01ff..fac78f8c04dcbc 100644 --- a/lib/net.js +++ b/lib/net.js @@ -28,6 +28,11 @@ var cares = process.binding('cares_wrap'); var uv = process.binding('uv'); var Pipe = process.binding('pipe_wrap').Pipe; +var TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap; +var PipeConnectWrap = process.binding('pipe_wrap').PipeConnectWrap; +var ShutdownWrap = process.binding('stream_wrap').ShutdownWrap; +var WriteWrap = process.binding('stream_wrap').WriteWrap; + var cluster; var errnoException = util._errnoException; @@ -218,7 +223,8 @@ function onSocketFinish() { if (!this._handle || !this._handle.shutdown) return this.destroy(); - var req = { oncomplete: afterShutdown }; + var req = new ShutdownWrap(); + req.oncomplete = afterShutdown; var err = this._handle.shutdown(req); if (err) @@ -641,7 +647,9 @@ Socket.prototype._writeGeneric = function(writev, data, encoding, cb) { return false; } - var req = { oncomplete: afterWrite, async: false }; + var req = new WriteWrap(); + req.oncomplete = afterWrite; + req.async = false; var err; if (writev) { @@ -821,8 +829,9 @@ function connect(self, address, port, addressType, localAddress, localPort) { } } - var req = { oncomplete: afterConnect }; if (addressType === 6 || addressType === 4) { + var req = new TCPConnectWrap(); + req.oncomplete = afterConnect; port = port | 0; if (port <= 0 || port > 65535) throw new RangeError('Port should be > 0 and < 65536'); @@ -833,6 +842,8 @@ function connect(self, address, port, addressType, localAddress, localPort) { err = self._handle.connect(req, address, port); } } else { + var req = new PipeConnectWrap(); + req.oncomplete = afterConnect; err = self._handle.connect(req, address, afterConnect); } diff --git a/src/async-wrap.h b/src/async-wrap.h index b1f1fef3bded7f..f53246f38de2b4 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -31,25 +31,28 @@ namespace node { class AsyncWrap : public BaseObject { public: enum ProviderType { - PROVIDER_NONE = 1 << 0, - PROVIDER_CARES = 1 << 1, - PROVIDER_CONNECTWRAP = 1 << 2, - PROVIDER_CRYPTO = 1 << 3, - PROVIDER_FSEVENTWRAP = 1 << 4, - PROVIDER_GETADDRINFOREQWRAP = 1 << 5, - PROVIDER_PIPEWRAP = 1 << 6, - PROVIDER_PROCESSWRAP = 1 << 7, - PROVIDER_REQWRAP = 1 << 8, - PROVIDER_SHUTDOWNWRAP = 1 << 9, - PROVIDER_SIGNALWRAP = 1 << 10, - PROVIDER_STATWATCHER = 1 << 11, - PROVIDER_TCPWRAP = 1 << 12, - PROVIDER_TIMERWRAP = 1 << 13, - PROVIDER_TLSWRAP = 1 << 14, - PROVIDER_TTYWRAP = 1 << 15, - PROVIDER_UDPWRAP = 1 << 16, - PROVIDER_ZLIB = 1 << 17, - PROVIDER_GETNAMEINFOREQWRAP = 1 << 18 + PROVIDER_NONE, + PROVIDER_CARES, + PROVIDER_CONNECTWRAP, + PROVIDER_CRYPTO, + PROVIDER_FSEVENTWRAP, + PROVIDER_FSREQWRAP, + PROVIDER_GETADDRINFOREQWRAP, + PROVIDER_GETNAMEINFOREQWRAP, + PROVIDER_PIPEWRAP, + PROVIDER_PROCESSWRAP, + PROVIDER_QUERYWRAP, + PROVIDER_REQWRAP, + PROVIDER_SHUTDOWNWRAP, + PROVIDER_SIGNALWRAP, + PROVIDER_STATWATCHER, + PROVIDER_TCPWRAP, + PROVIDER_TIMERWRAP, + PROVIDER_TLSWRAP, + PROVIDER_TTYWRAP, + PROVIDER_UDPWRAP, + PROVIDER_WRITEWRAP, + PROVIDER_ZLIB }; inline AsyncWrap(Environment* env, diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 66b4806e7ef6e3..64974adfcbb824 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -55,6 +55,7 @@ using v8::Context; using v8::EscapableHandleScope; using v8::Function; using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; using v8::Handle; using v8::HandleScope; using v8::Integer; @@ -64,8 +65,39 @@ using v8::Object; using v8::String; using v8::Value; -typedef class ReqWrap GetAddrInfoReqWrap; -typedef class ReqWrap GetNameInfoReqWrap; + +class GetAddrInfoReqWrap : public ReqWrap { + public: + GetAddrInfoReqWrap(Environment* env, Local req_wrap_obj); +}; + +GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, + Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} + + +class GetNameInfoReqWrap : public ReqWrap { + public: + GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); +}; + +GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, + Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewGetNameInfoReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) { @@ -229,7 +261,7 @@ static Local HostentToNames(Environment* env, struct hostent* host) { class QueryWrap : public AsyncWrap { public: QueryWrap(Environment* env, Local req_wrap_obj) - : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_CARES) { + : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP) { if (env->in_domain()) req_wrap_obj->Set(env->domain_string(), env->domain_array()->Get(0)); } @@ -1037,10 +1069,7 @@ static void GetAddrInfo(const FunctionCallbackInfo& args) { abort(); } - GetAddrInfoReqWrap* req_wrap = - new GetAddrInfoReqWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_GETADDRINFOREQWRAP); + GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj); struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); @@ -1077,10 +1106,7 @@ static void GetNameInfo(const FunctionCallbackInfo& args) { CHECK(uv_ip4_addr(*ip, port, reinterpret_cast(&addr)) == 0 || uv_ip6_addr(*ip, port, reinterpret_cast(&addr)) == 0); - GetNameInfoReqWrap* req_wrap = - new GetNameInfoReqWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP); + GetNameInfoReqWrap* req_wrap = new GetNameInfoReqWrap(env, req_wrap_obj); int err = uv_getnameinfo(env->event_loop(), &req_wrap->req_, @@ -1273,6 +1299,22 @@ static void Initialize(Handle target, Integer::New(env->isolate(), AI_ADDRCONFIG)); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), Integer::New(env->isolate(), AI_V4MAPPED)); + + Local aiw = + FunctionTemplate::New(env->isolate(), NewGetAddrInfoReqWrap); + aiw->InstanceTemplate()->SetInternalFieldCount(1); + aiw->SetClassName( + FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"), + aiw->GetFunction()); + + Local niw = + FunctionTemplate::New(env->isolate(), NewGetNameInfoReqWrap); + niw->InstanceTemplate()->SetInternalFieldCount(1); + niw->SetClassName( + FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"), + niw->GetFunction()); } } // namespace cares_wrap diff --git a/src/node_file.cc b/src/node_file.cc index de43b92e6e0639..8ce8f4205bb7b7 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -71,11 +71,15 @@ class FSReqWrap: public ReqWrap { void* operator new(size_t size) { return new char[size]; } void* operator new(size_t size, char* storage) { return storage; } - FSReqWrap(Environment* env, const char* syscall, char* data = NULL) - : ReqWrap(env, Object::New(env->isolate())), + FSReqWrap(Environment* env, + Local req, + const char* syscall, + char* data = NULL) + : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP), syscall_(syscall), data_(data), dest_len_(0) { + Wrap(object(), this); } void ReleaseEarly() { @@ -98,6 +102,11 @@ class FSReqWrap: public ReqWrap { }; +static void NewFSReqWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} + + #define ASSERT_OFFSET(a) \ if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \ return env->ThrowTypeError("Not an integer"); \ @@ -256,35 +265,35 @@ struct fs_req_wrap { }; -#define ASYNC_DEST_CALL(func, callback, dest_path, ...) \ +#define ASYNC_DEST_CALL(func, req, dest_path, ...) \ Environment* env = Environment::GetCurrent(args.GetIsolate()); \ FSReqWrap* req_wrap; \ char* dest_str = (dest_path); \ int dest_len = dest_str == NULL ? 0 : strlen(dest_str); \ char* storage = new char[sizeof(*req_wrap) + dest_len]; \ - req_wrap = new(storage) FSReqWrap(env, #func); \ + CHECK(req->IsObject()); \ + req_wrap = new(storage) FSReqWrap(env, req.As(), #func); \ req_wrap->dest_len(dest_len); \ if (dest_str != NULL) { \ memcpy(const_cast(req_wrap->dest()), \ dest_str, \ dest_len + 1); \ } \ - int err = uv_fs_ ## func(env->event_loop() , \ + int err = uv_fs_ ## func(env->event_loop(), \ &req_wrap->req_, \ __VA_ARGS__, \ After); \ - req_wrap->object()->Set(env->oncomplete_string(), callback); \ req_wrap->Dispatched(); \ if (err < 0) { \ - uv_fs_t* req = &req_wrap->req_; \ - req->result = err; \ - req->path = NULL; \ - After(req); \ + uv_fs_t* uv_req = &req_wrap->req_; \ + uv_req->result = err; \ + uv_req->path = NULL; \ + After(uv_req); \ } \ args.GetReturnValue().Set(req_wrap->persistent()); -#define ASYNC_CALL(func, callback, ...) \ - ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__) \ +#define ASYNC_CALL(func, req, ...) \ + ASYNC_DEST_CALL(func, req, NULL, __VA_ARGS__) \ #define SYNC_DEST_CALL(func, path, dest, ...) \ fs_req_wrap req_wrap; \ @@ -321,7 +330,7 @@ static void Close(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(close, args[1], fd) } else { SYNC_CALL(close, 0, fd) @@ -437,7 +446,7 @@ static void Stat(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(stat, args[1], *path) } else { SYNC_CALL(stat, *path, *path) @@ -457,7 +466,7 @@ static void LStat(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(lstat, args[1], *path) } else { SYNC_CALL(lstat, *path, *path) @@ -476,7 +485,7 @@ static void FStat(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fstat, args[1], fd) } else { SYNC_CALL(fstat, 0, fd) @@ -514,7 +523,7 @@ static void Symlink(const FunctionCallbackInfo& args) { } } - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_DEST_CALL(symlink, args[3], *path, *dest, *path, flags) } else { SYNC_DEST_CALL(symlink, *dest, *path, *dest, *path, flags) @@ -538,7 +547,7 @@ static void Link(const FunctionCallbackInfo& args) { node::Utf8Value orig_path(args[0]); node::Utf8Value new_path(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path) } else { SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path) @@ -556,7 +565,7 @@ static void ReadLink(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(readlink, args[1], *path) } else { SYNC_CALL(readlink, *path, *path) @@ -583,7 +592,7 @@ static void Rename(const FunctionCallbackInfo& args) { node::Utf8Value old_path(args[0]); node::Utf8Value new_path(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path) } else { SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path) @@ -603,7 +612,7 @@ static void FTruncate(const FunctionCallbackInfo& args) { ASSERT_TRUNCATE_LENGTH(args[1]); int64_t len = GET_TRUNCATE_LENGTH(args[1]); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(ftruncate, args[2], fd, len) } else { SYNC_CALL(ftruncate, 0, fd, len) @@ -620,7 +629,7 @@ static void Fdatasync(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fdatasync, args[1], fd) } else { SYNC_CALL(fdatasync, 0, fd) @@ -637,7 +646,7 @@ static void Fsync(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(fsync, args[1], fd) } else { SYNC_CALL(fsync, 0, fd) @@ -655,7 +664,7 @@ static void Unlink(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(unlink, args[1], *path) } else { SYNC_CALL(unlink, *path, *path) @@ -673,7 +682,7 @@ static void RMDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(rmdir, args[1], *path) } else { SYNC_CALL(rmdir, *path, *path) @@ -691,7 +700,7 @@ static void MKDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(mkdir, args[2], *path, mode) } else { SYNC_CALL(mkdir, *path, *path, mode) @@ -709,7 +718,7 @@ static void ReadDir(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); - if (args[1]->IsFunction()) { + if (args[1]->IsObject()) { ASYNC_CALL(scandir, args[1], *path, 0 /*flags*/) } else { SYNC_CALL(scandir, *path, *path, 0 /*flags*/) @@ -758,7 +767,7 @@ static void Open(const FunctionCallbackInfo& args) { int flags = args[1]->Int32Value(); int mode = static_cast(args[2]->Int32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(open, args[3], *path, flags, mode) } else { SYNC_CALL(open, *path, *path, flags, mode) @@ -790,7 +799,7 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { size_t off = args[2]->Uint32Value(); size_t len = args[3]->Uint32Value(); int64_t pos = GET_OFFSET(args[4]); - Local cb = args[5]; + Local req = args[5]; if (off > buffer_length) return env->ThrowRangeError("offset out of bounds"); @@ -805,8 +814,8 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - if (cb->IsFunction()) { - ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos) + if (req->IsObject()) { + ASYNC_CALL(write, req, fd, &uvbuf, 1, pos) return; } @@ -830,7 +839,7 @@ static void WriteString(const FunctionCallbackInfo& args) { if (!args[0]->IsInt32()) return env->ThrowTypeError("First argument must be file descriptor"); - Local cb; + Local req; Local string = args[1]; int fd = args[0]->Int32Value(); char* buf = NULL; @@ -852,18 +861,19 @@ static void WriteString(const FunctionCallbackInfo& args) { must_free = true; } pos = GET_OFFSET(args[2]); - cb = args[4]; + req = args[4]; uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - if (!cb->IsFunction()) { + if (!req->IsObject()) { SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos) if (must_free) delete[] buf; return args.GetReturnValue().Set(SYNC_RESULT); } - FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL); + FSReqWrap* req_wrap = + new FSReqWrap(env, req.As(), "write", must_free ? buf : NULL); int err = uv_fs_write(env->event_loop(), &req_wrap->req_, fd, @@ -871,7 +881,6 @@ static void WriteString(const FunctionCallbackInfo& args) { 1, pos, After); - req_wrap->object()->Set(env->oncomplete_string(), cb); req_wrap->Dispatched(); if (err < 0) { uv_fs_t* req = &req_wrap->req_; @@ -906,7 +915,7 @@ static void Read(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); - Local cb; + Local req; size_t len; int64_t pos; @@ -936,10 +945,10 @@ static void Read(const FunctionCallbackInfo& args) { uv_buf_t uvbuf = uv_buf_init(const_cast(buf), len); - cb = args[5]; + req = args[5]; - if (cb->IsFunction()) { - ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos); + if (req->IsObject()) { + ASYNC_CALL(read, req, fd, &uvbuf, 1, pos); } else { SYNC_CALL(read, 0, fd, &uvbuf, 1, pos) args.GetReturnValue().Set(SYNC_RESULT); @@ -960,7 +969,7 @@ static void Chmod(const FunctionCallbackInfo& args) { node::Utf8Value path(args[0]); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(chmod, args[2], *path, mode); } else { SYNC_CALL(chmod, *path, *path, mode); @@ -981,7 +990,7 @@ static void FChmod(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); int mode = static_cast(args[1]->Int32Value()); - if (args[2]->IsFunction()) { + if (args[2]->IsObject()) { ASYNC_CALL(fchmod, args[2], fd, mode); } else { SYNC_CALL(fchmod, 0, fd, mode); @@ -1014,7 +1023,7 @@ static void Chown(const FunctionCallbackInfo& args) { uv_uid_t uid = static_cast(args[1]->Uint32Value()); uv_gid_t gid = static_cast(args[2]->Uint32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(chown, args[3], *path, uid, gid); } else { SYNC_CALL(chown, *path, *path, uid, gid); @@ -1047,7 +1056,7 @@ static void FChown(const FunctionCallbackInfo& args) { uv_uid_t uid = static_cast(args[1]->Uint32Value()); uv_gid_t gid = static_cast(args[2]->Uint32Value()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(fchown, args[3], fd, uid, gid); } else { SYNC_CALL(fchown, 0, fd, uid, gid); @@ -1077,7 +1086,7 @@ static void UTimes(const FunctionCallbackInfo& args) { const double atime = static_cast(args[1]->NumberValue()); const double mtime = static_cast(args[2]->NumberValue()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(utime, args[3], *path, atime, mtime); } else { SYNC_CALL(utime, *path, *path, atime, mtime); @@ -1106,7 +1115,7 @@ static void FUTimes(const FunctionCallbackInfo& args) { const double atime = static_cast(args[1]->NumberValue()); const double mtime = static_cast(args[2]->NumberValue()); - if (args[3]->IsFunction()) { + if (args[3]->IsObject()) { ASYNC_CALL(futime, args[3], fd, atime, mtime); } else { SYNC_CALL(futime, 0, fd, atime, mtime); @@ -1164,6 +1173,14 @@ void InitFs(Handle target, NODE_SET_METHOD(target, "futimes", FUTimes); StatWatcher::Initialize(env, target); + + // Create FunctionTemplate for FSReqWrap + Local fst = + FunctionTemplate::New(env->isolate(), NewFSReqWrap); + fst->InstanceTemplate()->SetInternalFieldCount(1); + fst->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"), + fst->GetFunction()); } } // end namespace node diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 05472de5d92d6d..e9f4fbeb9b3af2 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -50,8 +50,23 @@ using v8::String; using v8::Undefined; using v8::Value; + // TODO(bnoordhuis) share with TCPWrap? -typedef class ReqWrap ConnectWrap; +class PipeConnectWrap : public ReqWrap { + public: + PipeConnectWrap(Environment* env, Local req_wrap_obj); +}; + + +PipeConnectWrap::PipeConnectWrap(Environment* env, Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPEWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewPipeConnectWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} uv_pipe_t* PipeWrap::UVHandle() { @@ -119,6 +134,14 @@ void PipeWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe"), t->GetFunction()); env->set_pipe_constructor_template(t); + + // Create FunctionTemplate for PipeConnectWrap. + Local cwt = + FunctionTemplate::New(env->isolate(), NewPipeConnectWrap); + cwt->InstanceTemplate()->SetInternalFieldCount(1); + cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"), + cwt->GetFunction()); } @@ -224,7 +247,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { // TODO(bnoordhuis) Maybe share this with TCPWrap? void PipeWrap::AfterConnect(uv_connect_t* req, int status) { - ConnectWrap* req_wrap = static_cast(req->data); + PipeConnectWrap* req_wrap = static_cast(req->data); PipeWrap* wrap = static_cast(req->handle->data); assert(req_wrap->env() == wrap->env()); Environment* env = wrap->env(); @@ -287,9 +310,7 @@ void PipeWrap::Connect(const FunctionCallbackInfo& args) { Local req_wrap_obj = args[0].As(); node::Utf8Value name(args[1]); - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + PipeConnectWrap* req_wrap = new PipeConnectWrap(env, req_wrap_obj); uv_pipe_connect(&req_wrap->req_, &wrap->handle_, *name, diff --git a/src/req_wrap.h b/src/req_wrap.h index df4ed2ced1a884..8c818e634a8386 100644 --- a/src/req_wrap.h +++ b/src/req_wrap.h @@ -36,8 +36,8 @@ class ReqWrap : public AsyncWrap { public: ReqWrap(Environment* env, v8::Handle object, - AsyncWrap::ProviderType provider = AsyncWrap::PROVIDER_REQWRAP) - : AsyncWrap(env, object, AsyncWrap::PROVIDER_REQWRAP) { + AsyncWrap::ProviderType provider) + : AsyncWrap(env, object, provider) { if (env->in_domain()) object->Set(env->domain_string(), env->domain_array()->Get(0)); diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index fe3e82799dfa63..b02c58999d78d7 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -43,6 +43,7 @@ using v8::Array; using v8::Context; using v8::EscapableHandleScope; using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; using v8::Handle; using v8::HandleScope; using v8::Integer; @@ -56,6 +57,27 @@ using v8::Undefined; using v8::Value; +void StreamWrap::Initialize(Handle target, + Handle unused, + Handle context) { + Environment* env = Environment::GetCurrent(context); + + Local sw = + FunctionTemplate::New(env->isolate(), ShutdownWrap::NewShutdownWrap); + sw->InstanceTemplate()->SetInternalFieldCount(1); + sw->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap"), + sw->GetFunction()); + + Local ww = + FunctionTemplate::New(env->isolate(), WriteWrap::NewWriteWrap); + ww->InstanceTemplate()->SetInternalFieldCount(1); + ww->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap"), + ww->GetFunction()); +} + + StreamWrap::StreamWrap(Environment* env, Local object, uv_stream_t* stream, @@ -89,6 +111,7 @@ void StreamWrap::UpdateWriteQueueSize() { object()->Set(env()->write_queue_size_string(), write_queue_size); } + void StreamWrap::ReadStart(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); HandleScope scope(env->isolate()); @@ -560,9 +583,7 @@ void StreamWrap::Shutdown(const FunctionCallbackInfo& args) { assert(args[0]->IsObject()); Local req_wrap_obj = args[0].As(); - ShutdownWrap* req_wrap = new ShutdownWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_SHUTDOWNWRAP); + ShutdownWrap* req_wrap = new ShutdownWrap(env, req_wrap_obj); int err = wrap->callbacks()->DoShutdown(req_wrap, AfterShutdown); req_wrap->Dispatched(); if (err) @@ -744,3 +765,5 @@ int StreamWrapCallbacks::DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb) { } } // namespace node + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(stream_wrap, node::StreamWrap::Initialize) diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 34e2799357d24b..aefb7707513f42 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -33,15 +33,26 @@ namespace node { // Forward declaration class StreamWrap; -typedef class ReqWrap ShutdownWrap; +class ShutdownWrap : public ReqWrap { + public: + ShutdownWrap(Environment* env, v8::Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_SHUTDOWNWRAP) { + Wrap(req_wrap_obj, this); + } + + static void NewShutdownWrap(const v8::FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + } +}; class WriteWrap: public ReqWrap { public: // TODO(trevnorris): WrapWrap inherits from ReqWrap, which I've globbed // into the same provider. How should these be broken apart? WriteWrap(Environment* env, v8::Local obj, StreamWrap* wrap) - : ReqWrap(env, obj), + : ReqWrap(env, obj, AsyncWrap::PROVIDER_WRITEWRAP), wrap_(wrap) { + Wrap(obj, this); } void* operator new(size_t size, char* storage) { return storage; } @@ -54,6 +65,10 @@ class WriteWrap: public ReqWrap { return wrap_; } + static void NewWriteWrap(const v8::FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + } + private: // People should not be using the non-placement new and delete operator on a // WriteWrap. Ensure this never happens. @@ -105,6 +120,10 @@ class StreamWrapCallbacks { class StreamWrap : public HandleWrap { public: + static void Initialize(v8::Handle target, + v8::Handle unused, + v8::Handle context); + void OverrideCallbacks(StreamWrapCallbacks* callbacks, bool gc) { StreamWrapCallbacks* old = callbacks_; callbacks_ = callbacks; diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 09671d0095e27e..34aecefd3ddb7f 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -52,7 +52,22 @@ using v8::Undefined; using v8::Value; using v8::Boolean; -typedef class ReqWrap ConnectWrap; + +class TCPConnectWrap : public ReqWrap { + public: + TCPConnectWrap(Environment* env, Local req_wrap_obj); +}; + + +TCPConnectWrap::TCPConnectWrap(Environment* env, Local req_wrap_obj) + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPWRAP) { + Wrap(req_wrap_obj, this); +} + + +static void NewTCPConnectWrap(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); +} Local TCPWrap::Instantiate(Environment* env) { @@ -135,6 +150,14 @@ void TCPWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"), t->GetFunction()); env->set_tcp_constructor_template(t); + + // Create FunctionTemplate for TCPConnectWrap. + Local cwt = + FunctionTemplate::New(env->isolate(), NewTCPConnectWrap); + cwt->InstanceTemplate()->SetInternalFieldCount(1); + cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"), + cwt->GetFunction()); } @@ -359,7 +382,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) { void TCPWrap::AfterConnect(uv_connect_t* req, int status) { - ConnectWrap* req_wrap = static_cast(req->data); + TCPConnectWrap* req_wrap = static_cast(req->data); TCPWrap* wrap = static_cast(req->handle->data); assert(req_wrap->env() == wrap->env()); Environment* env = wrap->env(); @@ -404,9 +427,7 @@ void TCPWrap::Connect(const FunctionCallbackInfo& args) { int err = uv_ip4_addr(*ip_address, port, &addr); if (err == 0) { - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), @@ -438,9 +459,7 @@ void TCPWrap::Connect6(const FunctionCallbackInfo& args) { int err = uv_ip6_addr(*ip_address, port, &addr); if (err == 0) { - ConnectWrap* req_wrap = new ConnectWrap(env, - req_wrap_obj, - AsyncWrap::PROVIDER_CONNECTWRAP); + TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index f0d491333976b2..1df8da425d8742 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -62,8 +62,9 @@ class SendWrap : public ReqWrap { SendWrap::SendWrap(Environment* env, Local req_wrap_obj, bool have_callback) - : ReqWrap(env, req_wrap_obj), + : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPWRAP), have_callback_(have_callback) { + Wrap(req_wrap_obj, this); } @@ -72,6 +73,11 @@ inline bool SendWrap::have_callback() const { } +static void NewSendWrap(const FunctionCallbackInfo& args) { + assert(args.IsConstructCall()); +} + + UDPWrap::UDPWrap(Environment* env, Handle object) : HandleWrap(env, object, @@ -124,11 +130,19 @@ void UDPWrap::Initialize(Handle target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction()); env->set_udp_constructor_function(t->GetFunction()); + + // Create FunctionTemplate for SendWrap + Local swt = + FunctionTemplate::New(env->isolate(), NewSendWrap); + swt->InstanceTemplate()->SetInternalFieldCount(1); + swt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap")); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"), + swt->GetFunction()); } void UDPWrap::New(const FunctionCallbackInfo& args) { - assert(args.IsConstructCall()); + CHECK(args.IsConstructCall()); HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); new UDPWrap(env, args.This()); diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js index 60227df7ca678b..623a845c03f3e6 100644 --- a/test/internet/test-dns.js +++ b/test/internet/test-dns.js @@ -632,8 +632,9 @@ var getaddrinfoCallbackCalled = false; console.log('looking up nodejs.org...'); -var req = {}; -var err = process.binding('cares_wrap').getaddrinfo(req, 'nodejs.org', 4); +var cares = process.binding('cares_wrap'); +var req = new cares.GetAddrInfoReqWrap(); +var err = cares.getaddrinfo(req, 'nodejs.org', 4); req.oncomplete = function(err, domains) { assert.strictEqual(err, 0); diff --git a/test/simple/test-tcp-wrap-connect.js b/test/simple/test-tcp-wrap-connect.js index 43fb37ac7011c4..9e915d243bae35 100644 --- a/test/simple/test-tcp-wrap-connect.js +++ b/test/simple/test-tcp-wrap-connect.js @@ -22,11 +22,13 @@ var common = require('../common'); var assert = require('assert'); var TCP = process.binding('tcp_wrap').TCP; +var TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap; +var ShutdownWrap = process.binding('stream_wrap').ShutdownWrap; function makeConnection() { var client = new TCP(); - var req = {}; + var req = new TCPConnectWrap(); var err = client.connect(req, '127.0.0.1', common.PORT); assert.equal(err, 0); @@ -36,7 +38,7 @@ function makeConnection() { assert.equal(req, req_); console.log('connected'); - var shutdownReq = {}; + var shutdownReq = new ShutdownWrap(); var err = client.shutdown(shutdownReq); assert.equal(err, 0); diff --git a/test/simple/test-tcp-wrap-listen.js b/test/simple/test-tcp-wrap-listen.js index fb3175a008a1ee..5801368ba1e889 100644 --- a/test/simple/test-tcp-wrap-listen.js +++ b/test/simple/test-tcp-wrap-listen.js @@ -23,6 +23,7 @@ var common = require('../common'); var assert = require('assert'); var TCP = process.binding('tcp_wrap').TCP; +var WriteWrap = process.binding('stream_wrap').WriteWrap; var server = new TCP(); @@ -55,7 +56,8 @@ server.onconnection = function(err, client) { assert.equal(0, client.writeQueueSize); - var req = { async: false }; + var req = new WriteWrap(); + req.async = false; var err = client.writeBuffer(req, buffer); assert.equal(err, 0); client.pendingWrites.push(req); From add955e6b831970fae6c9f693b64cb1f4aeb999d Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Fri, 14 Nov 2014 15:47:34 -0800 Subject: [PATCH 21/27] src: remove unnecessary template parameter The template class information is received via the type of the first argument. So there is no need to use Wrap(handle). PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/base-object-inl.h | 2 +- src/cares_wrap.cc | 4 ++-- src/handle_wrap.cc | 2 +- src/node_contextify.cc | 2 +- src/node_file.cc | 2 +- src/pipe_wrap.cc | 2 +- src/stream_wrap.h | 4 ++-- src/tcp_wrap.cc | 2 +- src/tls_wrap.cc | 2 +- src/udp_wrap.cc | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/base-object-inl.h b/src/base-object-inl.h index 4d726df7ca7989..8cd9e2fd0738dc 100644 --- a/src/base-object-inl.h +++ b/src/base-object-inl.h @@ -72,7 +72,7 @@ inline void BaseObject::MakeWeak(Type* ptr) { v8::HandleScope scope(env_->isolate()); v8::Local handle = object(); assert(handle->InternalFieldCount() > 0); - Wrap(handle, ptr); + Wrap(handle, ptr); handle_.MarkIndependent(); handle_.SetWeak(ptr, WeakCallback); } diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 64974adfcbb824..39c88001563604 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -74,7 +74,7 @@ class GetAddrInfoReqWrap : public ReqWrap { GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } @@ -91,7 +91,7 @@ class GetNameInfoReqWrap : public ReqWrap { GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index 83015f1dfd8f2a..f8294723ff6b33 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -96,7 +96,7 @@ HandleWrap::HandleWrap(Environment* env, handle__(handle) { handle__->data = this; HandleScope scope(env->isolate()); - Wrap(object, this); + Wrap(object, this); QUEUE_INSERT_TAIL(env->handle_wrap_queue(), &handle_wrap_queue_); } diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 3f190a407b6b49..2e8fd2cade6253 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -205,7 +205,7 @@ class ContextifyContext { if (wrapper.IsEmpty()) return scope.Escape(Local::New(env->isolate(), Handle())); - Wrap(wrapper, this); + Wrap(wrapper, this); return scope.Escape(wrapper); } diff --git a/src/node_file.cc b/src/node_file.cc index 8ce8f4205bb7b7..6736864bc57c36 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -79,7 +79,7 @@ class FSReqWrap: public ReqWrap { syscall_(syscall), data_(data), dest_len_(0) { - Wrap(object(), this); + Wrap(object(), this); } void ReleaseEarly() { diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index e9f4fbeb9b3af2..6eb7f576c6cfa6 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -60,7 +60,7 @@ class PipeConnectWrap : public ReqWrap { PipeConnectWrap::PipeConnectWrap(Environment* env, Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPEWRAP) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } diff --git a/src/stream_wrap.h b/src/stream_wrap.h index aefb7707513f42..5cb13cd67c3abc 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -37,7 +37,7 @@ class ShutdownWrap : public ReqWrap { public: ShutdownWrap(Environment* env, v8::Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_SHUTDOWNWRAP) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } static void NewShutdownWrap(const v8::FunctionCallbackInfo& args) { @@ -52,7 +52,7 @@ class WriteWrap: public ReqWrap { WriteWrap(Environment* env, v8::Local obj, StreamWrap* wrap) : ReqWrap(env, obj, AsyncWrap::PROVIDER_WRITEWRAP), wrap_(wrap) { - Wrap(obj, this); + Wrap(obj, this); } void* operator new(size_t size, char* storage) { return storage; } diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 34aecefd3ddb7f..1b54b85c6eec65 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -61,7 +61,7 @@ class TCPConnectWrap : public ReqWrap { TCPConnectWrap::TCPConnectWrap(Environment* env, Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPWRAP) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index ac05c8ecaceb5b..607f786501e37b 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -78,7 +78,7 @@ TLSCallbacks::TLSCallbacks(Environment* env, error_(NULL), cycle_depth_(0), eof_(false) { - node::Wrap(object(), this); + node::Wrap(object(), this); MakeWeak(this); // Initialize queue for clearIn writes diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 1df8da425d8742..8b860689feb058 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -64,7 +64,7 @@ SendWrap::SendWrap(Environment* env, bool have_callback) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPWRAP), have_callback_(have_callback) { - Wrap(req_wrap_obj, this); + Wrap(req_wrap_obj, this); } From 1293f0a228a3a01863896c82f6734aaaf93bd16b Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Fri, 14 Nov 2014 16:15:06 -0800 Subject: [PATCH 22/27] async-wrap: expose async-wrap as binding Expose basic hooks for AsyncWrap via the async_wrap binding. Right now only the PROVIDER types are exposed. This is a preliminary step before more functionality is added. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/async-wrap.cc | 23 ++++++++++++++++++++++ src/async-wrap.h | 50 ++++++++++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 66455a3046e196..508accf06c4af6 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -28,8 +28,12 @@ #include "v8.h" +using v8::Context; using v8::Function; using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Isolate; using v8::Local; using v8::Object; using v8::TryCatch; @@ -37,6 +41,23 @@ using v8::Value; namespace node { +static void Initialize(Handle target, + Handle unused, + Handle context) { + Environment* env = Environment::GetCurrent(context); + Isolate* isolate = env->isolate(); + HandleScope scope(isolate); + + Local async_providers = Object::New(isolate); +#define V(PROVIDER) \ + async_providers->Set(FIXED_ONE_BYTE_STRING(isolate, #PROVIDER), \ + Integer::New(isolate, AsyncWrap::PROVIDER_ ## PROVIDER)); + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V + target->Set(FIXED_ONE_BYTE_STRING(isolate, "Providers"), async_providers); +} + + Handle AsyncWrap::MakeCallback(const Handle cb, int argc, Handle* argv) { @@ -114,3 +135,5 @@ Handle AsyncWrap::MakeCallback(const Handle cb, } } // namespace node + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(async_wrap, node::Initialize) diff --git a/src/async-wrap.h b/src/async-wrap.h index f53246f38de2b4..cfdaf50d523b86 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -28,31 +28,37 @@ namespace node { +#define NODE_ASYNC_PROVIDER_TYPES(V) \ + V(NONE) \ + V(CARES) \ + V(CONNECTWRAP) \ + V(CRYPTO) \ + V(FSEVENTWRAP) \ + V(FSREQWRAP) \ + V(GETADDRINFOREQWRAP) \ + V(GETNAMEINFOREQWRAP) \ + V(PIPEWRAP) \ + V(PROCESSWRAP) \ + V(QUERYWRAP) \ + V(REQWRAP) \ + V(SHUTDOWNWRAP) \ + V(SIGNALWRAP) \ + V(STATWATCHER) \ + V(TCPWRAP) \ + V(TIMERWRAP) \ + V(TLSWRAP) \ + V(TTYWRAP) \ + V(UDPWRAP) \ + V(WRITEWRAP) \ + V(ZLIB) + class AsyncWrap : public BaseObject { public: enum ProviderType { - PROVIDER_NONE, - PROVIDER_CARES, - PROVIDER_CONNECTWRAP, - PROVIDER_CRYPTO, - PROVIDER_FSEVENTWRAP, - PROVIDER_FSREQWRAP, - PROVIDER_GETADDRINFOREQWRAP, - PROVIDER_GETNAMEINFOREQWRAP, - PROVIDER_PIPEWRAP, - PROVIDER_PROCESSWRAP, - PROVIDER_QUERYWRAP, - PROVIDER_REQWRAP, - PROVIDER_SHUTDOWNWRAP, - PROVIDER_SIGNALWRAP, - PROVIDER_STATWATCHER, - PROVIDER_TCPWRAP, - PROVIDER_TIMERWRAP, - PROVIDER_TLSWRAP, - PROVIDER_TTYWRAP, - PROVIDER_UDPWRAP, - PROVIDER_WRITEWRAP, - PROVIDER_ZLIB +#define V(PROVIDER) \ + PROVIDER_ ## PROVIDER, + NODE_ASYNC_PROVIDER_TYPES(V) +#undef V }; inline AsyncWrap(Environment* env, From 419f18d2e245405b839e7441e5f59bc08e9c8d6c Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 17 Nov 2014 12:54:03 -0800 Subject: [PATCH 23/27] async-wrap: explicitly pass parent When instantiating a new AsyncWrap allow the parent AsyncWrap to be passed. This is useful for cases like TCP incoming connections, so the connection can be tied to the server receiving the connection. Because the current architecture instantiates the *Wrap inside a v8::FunctionCallback, the parent pointer is currently wrapped inside a new v8::External every time and passed as an argument. This adds ~80ns to instantiation time. A future optimization would be to add the v8::External as the data field when creating the v8::FunctionTemplate, change the pointer just before making the call then NULL'ing it out afterwards. This adds enough code complexity that it will not be attempted until the current approach demonstrates it is a bottle neck. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/async-wrap-inl.h | 3 ++- src/async-wrap.h | 3 ++- src/handle_wrap.cc | 5 +++-- src/handle_wrap.h | 3 ++- src/pipe_wrap.cc | 25 ++++++++++++++++++------- src/pipe_wrap.h | 8 ++++++-- src/stream_wrap.cc | 21 ++++++++++++++------- src/stream_wrap.h | 3 ++- src/tcp_wrap.cc | 25 ++++++++++++++++++------- src/tcp_wrap.h | 5 +++-- src/udp_wrap.cc | 21 ++++++++++++++++----- src/udp_wrap.h | 5 +++-- 12 files changed, 89 insertions(+), 38 deletions(-) diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index 9bd5744b164197..6850a019b604ab 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -36,7 +36,8 @@ namespace node { inline AsyncWrap::AsyncWrap(Environment* env, v8::Handle object, - ProviderType provider) + ProviderType provider, + AsyncWrap* parent) : BaseObject(env, object), provider_type_(provider) { } diff --git a/src/async-wrap.h b/src/async-wrap.h index cfdaf50d523b86..920d1452ec3fe4 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -63,7 +63,8 @@ class AsyncWrap : public BaseObject { inline AsyncWrap(Environment* env, v8::Handle object, - ProviderType provider); + ProviderType provider, + AsyncWrap* parent = NULL); inline ~AsyncWrap(); diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index f8294723ff6b33..a355e5bbba54ee 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -90,8 +90,9 @@ void HandleWrap::Close(const FunctionCallbackInfo& args) { HandleWrap::HandleWrap(Environment* env, Handle object, uv_handle_t* handle, - AsyncWrap::ProviderType provider) - : AsyncWrap(env, object, provider), + AsyncWrap::ProviderType provider, + AsyncWrap* parent) + : AsyncWrap(env, object, provider, parent), flags_(0), handle__(handle) { handle__->data = this; diff --git a/src/handle_wrap.h b/src/handle_wrap.h index 4f6f6e03236987..95551a756355a8 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -63,7 +63,8 @@ class HandleWrap : public AsyncWrap { HandleWrap(Environment* env, v8::Handle object, uv_handle_t* handle, - AsyncWrap::ProviderType provider); + AsyncWrap::ProviderType provider, + AsyncWrap* parent = NULL); virtual ~HandleWrap(); private: diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 6eb7f576c6cfa6..69cdfcdff3cf2f 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -21,6 +21,7 @@ #include "pipe_wrap.h" +#include "async-wrap.h" #include "env.h" #include "env-inl.h" #include "handle_wrap.h" @@ -37,6 +38,7 @@ namespace node { using v8::Boolean; using v8::Context; using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -74,12 +76,13 @@ uv_pipe_t* PipeWrap::UVHandle() { } -Local PipeWrap::Instantiate(Environment* env) { +Local PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); assert(!env->pipe_constructor_template().IsEmpty()); Local constructor = env->pipe_constructor_template()->GetFunction(); assert(!constructor.IsEmpty()); - Local instance = constructor->NewInstance(); + Local ptr = External::New(env->isolate(), parent); + Local instance = constructor->NewInstance(1, &ptr); assert(!instance.IsEmpty()); return handle_scope.Escape(instance); } @@ -150,17 +153,25 @@ void PipeWrap::New(const FunctionCallbackInfo& args) { // Therefore we assert that we are not trying to call this as a // normal function. assert(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - new PipeWrap(env, args.This(), args[0]->IsTrue()); + if (args[0]->IsExternal()) { + void* ptr = args[0].As()->Value(); + new PipeWrap(env, args.This(), false, static_cast(ptr)); + } else { + new PipeWrap(env, args.This(), args[0]->IsTrue(), NULL); + } } -PipeWrap::PipeWrap(Environment* env, Handle object, bool ipc) +PipeWrap::PipeWrap(Environment* env, + Handle object, + bool ipc, + AsyncWrap* parent) : StreamWrap(env, object, reinterpret_cast(&handle_), - AsyncWrap::PROVIDER_PIPEWRAP) { + AsyncWrap::PROVIDER_PIPEWRAP, + parent) { int r = uv_pipe_init(env->event_loop(), &handle_, ipc); assert(r == 0); // How do we proxy this error up to javascript? // Suggestion: uv_pipe_init() returns void. @@ -232,7 +243,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { } // Instanciate the client javascript object and handle. - Local client_obj = Instantiate(env); + Local client_obj = Instantiate(env, pipe_wrap); // Unwrap the client javascript object. PipeWrap* wrap = Unwrap(client_obj); diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index 92492c42b73c8f..959f28f4dca92f 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_PIPE_WRAP_H_ #define SRC_PIPE_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "stream_wrap.h" @@ -31,13 +32,16 @@ class PipeWrap : public StreamWrap { public: uv_pipe_t* UVHandle(); - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); static void Initialize(v8::Handle target, v8::Handle unused, v8::Handle context); private: - PipeWrap(Environment* env, v8::Handle object, bool ipc); + PipeWrap(Environment* env, + v8::Handle object, + bool ipc, + AsyncWrap* parent); static void New(const v8::FunctionCallbackInfo& args); static void Bind(const v8::FunctionCallbackInfo& args); diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index b02c58999d78d7..840b16614a139d 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -81,8 +81,13 @@ void StreamWrap::Initialize(Handle target, StreamWrap::StreamWrap(Environment* env, Local object, uv_stream_t* stream, - AsyncWrap::ProviderType provider) - : HandleWrap(env, object, reinterpret_cast(stream), provider), + AsyncWrap::ProviderType provider, + AsyncWrap* parent) + : HandleWrap(env, + object, + reinterpret_cast(stream), + provider, + parent), stream_(stream), default_callbacks_(this), callbacks_(&default_callbacks_), @@ -145,12 +150,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle, template -static Local AcceptHandle(Environment* env, uv_stream_t* pipe) { +static Local AcceptHandle(Environment* env, + uv_stream_t* pipe, + AsyncWrap* parent) { EscapableHandleScope scope(env->isolate()); Local wrap_obj; UVType* handle; - wrap_obj = WrapType::Instantiate(env); + wrap_obj = WrapType::Instantiate(env, parent); if (wrap_obj.IsEmpty()) return Local(); @@ -743,11 +750,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle, Local pending_obj; if (pending == UV_TCP) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else if (pending == UV_NAMED_PIPE) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else if (pending == UV_UDP) { - pending_obj = AcceptHandle(env, handle); + pending_obj = AcceptHandle(env, handle, wrap()); } else { assert(pending == UV_UNKNOWN_HANDLE); } diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 5cb13cd67c3abc..38e5d48422572c 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -177,7 +177,8 @@ class StreamWrap : public HandleWrap { StreamWrap(Environment* env, v8::Local object, uv_stream_t* stream, - AsyncWrap::ProviderType provider); + AsyncWrap::ProviderType provider, + AsyncWrap* parent = NULL); ~StreamWrap() { if (!callbacks_gc_ && callbacks_ != &default_callbacks_) { diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 1b54b85c6eec65..a5b20a6ac5a636 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -38,6 +38,7 @@ namespace node { using v8::Context; using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -70,12 +71,13 @@ static void NewTCPConnectWrap(const FunctionCallbackInfo& args) { } -Local TCPWrap::Instantiate(Environment* env) { +Local TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); assert(env->tcp_constructor_template().IsEmpty() == false); Local constructor = env->tcp_constructor_template()->GetFunction(); assert(constructor.IsEmpty() == false); - Local instance = constructor->NewInstance(); + Local ptr = External::New(env->isolate(), parent); + Local instance = constructor->NewInstance(1, &ptr); assert(instance.IsEmpty() == false); return handle_scope.Escape(instance); } @@ -171,18 +173,26 @@ void TCPWrap::New(const FunctionCallbackInfo& args) { // Therefore we assert that we are not trying to call this as a // normal function. assert(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - TCPWrap* wrap = new TCPWrap(env, args.This()); + TCPWrap* wrap; + if (args.Length() == 0) { + wrap = new TCPWrap(env, args.This(), NULL); + } else if (args[0]->IsExternal()) { + void* ptr = args[0].As()->Value(); + wrap = new TCPWrap(env, args.This(), static_cast(ptr)); + } else { + UNREACHABLE(); + } assert(wrap); } -TCPWrap::TCPWrap(Environment* env, Handle object) +TCPWrap::TCPWrap(Environment* env, Handle object, AsyncWrap* parent) : StreamWrap(env, object, reinterpret_cast(&handle_), - AsyncWrap::PROVIDER_TCPWRAP) { + AsyncWrap::PROVIDER_TCPWRAP, + parent) { int r = uv_tcp_init(env->event_loop(), &handle_); assert(r == 0); // How do we proxy this error up to javascript? // Suggestion: uv_tcp_init() returns void. @@ -365,7 +375,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) { if (status == 0) { // Instantiate the client javascript object and handle. - Local client_obj = Instantiate(env); + Local client_obj = + Instantiate(env, static_cast(tcp_wrap)); // Unwrap the client javascript object. TCPWrap* wrap = Unwrap(client_obj); diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index c9981f572dbe2a..c923b387f0e7cc 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_TCP_WRAP_H_ #define SRC_TCP_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "stream_wrap.h" @@ -29,7 +30,7 @@ namespace node { class TCPWrap : public StreamWrap { public: - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); static void Initialize(v8::Handle target, v8::Handle unused, v8::Handle context); @@ -37,7 +38,7 @@ class TCPWrap : public StreamWrap { uv_tcp_t* UVHandle(); private: - TCPWrap(Environment* env, v8::Handle object); + TCPWrap(Environment* env, v8::Handle object, AsyncWrap* parent); ~TCPWrap(); static void New(const v8::FunctionCallbackInfo& args); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 8b860689feb058..614326fa1fb971 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -34,6 +34,8 @@ namespace node { using v8::Context; +using v8::EscapableHandleScope; +using v8::External; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -78,7 +80,7 @@ static void NewSendWrap(const FunctionCallbackInfo& args) { } -UDPWrap::UDPWrap(Environment* env, Handle object) +UDPWrap::UDPWrap(Environment* env, Handle object, AsyncWrap* parent) : HandleWrap(env, object, reinterpret_cast(&handle_), @@ -143,9 +145,16 @@ void UDPWrap::Initialize(Handle target, void UDPWrap::New(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); - HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); - new UDPWrap(env, args.This()); + if (args.Length() == 0) { + new UDPWrap(env, args.This(), NULL); + } else if (args[0]->IsExternal()) { + new UDPWrap(env, + args.This(), + static_cast(args[0].As()->Value())); + } else { + UNREACHABLE(); + } } @@ -443,10 +452,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle, } -Local UDPWrap::Instantiate(Environment* env) { +Local UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) { // If this assert fires then Initialize hasn't been called yet. assert(env->udp_constructor_function().IsEmpty() == false); - return env->udp_constructor_function()->NewInstance(); + EscapableHandleScope scope(env->isolate()); + Local ptr = External::New(env->isolate(), parent); + return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr)); } diff --git a/src/udp_wrap.h b/src/udp_wrap.h index ab0d6fa8e69e8e..693fa51b7180cc 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -22,6 +22,7 @@ #ifndef SRC_UDP_WRAP_H_ #define SRC_UDP_WRAP_H_ +#include "async-wrap.h" #include "env.h" #include "handle_wrap.h" #include "req_wrap.h" @@ -53,11 +54,11 @@ class UDPWrap: public HandleWrap { static void SetBroadcast(const v8::FunctionCallbackInfo& args); static void SetTTL(const v8::FunctionCallbackInfo& args); - static v8::Local Instantiate(Environment* env); + static v8::Local Instantiate(Environment* env, AsyncWrap* parent); uv_udp_t* UVHandle(); private: - UDPWrap(Environment* env, v8::Handle object); + UDPWrap(Environment* env, v8::Handle object, AsyncWrap* parent); virtual ~UDPWrap(); static void DoBind(const v8::FunctionCallbackInfo& args, From 709fc160e5204f9a926c2867a8ee77e55d6c30aa Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Thu, 20 Nov 2014 11:27:06 -0800 Subject: [PATCH 24/27] async-wrap: add event hooks Call a user-defined callback at specific points in the lifetime of an asynchronous event. Which are on instantiation, just before/after the callback has been run. **If any of these callbacks throws an exception, there is no forgiveness or recovery. A message will be displayed and a core file dumped.** Currently these only tie into AsyncWrap, meaning no call to a hook callback will be made for timers or process.nextTick() events. Though those will be added in a future commit. Here are a few notes on how to make the hooks work: - The "this" of all event hook callbacks is the request object. - The zero field (kCallInitHook) of the flags object passed to setupHooks() must be set != 0 before the init callback will be called. - kCallInitHook only affects the calling of the init callback. If the request object has been run through the create callback it will always run the before/after callbacks. Regardless of kCallInitHook. - In the init callback the property "_asyncQueue" must be attached to the request object. e.g. function initHook() { this._asyncQueue = {}; } - DO NOT inspect the properties of the object in the init callback. Since the object is in the middle of being instantiated there are some cases when a getter is not complete, and doing so will cause Node to crash. PR-URL: https://github.com/joyent/node/pull/8110 Signed-off-by: Trevor Norris Reviewed-by: Fedor Indutny Reviewed-by: Alexis Campailla Reviewed-by: Julien Gilli --- src/async-wrap-inl.h | 36 ++++++++++++++++++++++++++++++++ src/async-wrap.cc | 49 ++++++++++++++++++++++++++++++++++++++++++++ src/async-wrap.h | 6 +++++- src/env-inl.h | 25 ++++++++++++++++++++++ src/env.h | 28 +++++++++++++++++++++++++ src/node.cc | 25 +++++++++++++++++++++- 6 files changed, 167 insertions(+), 2 deletions(-) diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index 6850a019b604ab..f064ea96cf44fd 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -27,6 +27,7 @@ #include "base-object-inl.h" #include "env.h" #include "env-inl.h" +#include "node_internals.h" #include "util.h" #include "util-inl.h" @@ -39,7 +40,42 @@ inline AsyncWrap::AsyncWrap(Environment* env, ProviderType provider, AsyncWrap* parent) : BaseObject(env, object), + has_async_queue_(false), provider_type_(provider) { + // Check user controlled flag to see if the init callback should run. + if (!env->call_async_init_hook()) + return; + + // TODO(trevnorris): Until it's verified all passed object's are not weak, + // add a HandleScope to make sure there's no leak. + v8::HandleScope scope(env->isolate()); + + v8::Local parent_obj; + + v8::TryCatch try_catch; + + // If a parent value was sent then call its pre/post functions to let it know + // a conceptual "child" is being instantiated (e.g. that a server has + // received a connection). + if (parent != NULL) { + parent_obj = parent->object(); + env->async_hooks_pre_function()->Call(parent_obj, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::AsyncWrap", "parent pre hook threw"); + } + + env->async_hooks_init_function()->Call(object, 0, NULL); + + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::AsyncWrap", "init hook threw"); + + has_async_queue_ = true; + + if (parent != NULL) { + env->async_hooks_post_function()->Call(parent_obj, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::AsyncWrap", "parent post hook threw"); + } } diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 508accf06c4af6..de1007e73d1dc3 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -30,6 +30,7 @@ using v8::Context; using v8::Function; +using v8::FunctionCallbackInfo; using v8::Handle; using v8::HandleScope; using v8::Integer; @@ -38,9 +39,39 @@ using v8::Local; using v8::Object; using v8::TryCatch; using v8::Value; +using v8::kExternalUint32Array; namespace node { +static void SetupHooks(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + + CHECK(args[0]->IsObject()); + CHECK(args[1]->IsFunction()); + CHECK(args[2]->IsFunction()); + CHECK(args[3]->IsFunction()); + + // Attach Fields enum from Environment::AsyncHooks. + // Flags attached to this object are: + // - kCallInitHook (0): Tells the AsyncWrap constructor whether it should + // make a call to the init JS callback. This is disabled by default, so + // even after setting the callbacks the flag will have to be set to + // non-zero to have those callbacks called. This only affects the init + // callback. If the init callback was called, then the pre/post callbacks + // will automatically be called. + Local async_hooks_obj = args[0].As(); + Environment::AsyncHooks* async_hooks = env->async_hooks(); + async_hooks_obj->SetIndexedPropertiesToExternalArrayData( + async_hooks->fields(), + kExternalUint32Array, + async_hooks->fields_count()); + + env->set_async_hooks_init_function(args[1].As()); + env->set_async_hooks_pre_function(args[2].As()); + env->set_async_hooks_post_function(args[3].As()); +} + + static void Initialize(Handle target, Handle unused, Handle context) { @@ -48,6 +79,8 @@ static void Initialize(Handle target, Isolate* isolate = env->isolate(); HandleScope scope(isolate); + NODE_SET_METHOD(target, "setupHooks", SetupHooks); + Local async_providers = Object::New(isolate); #define V(PROVIDER) \ async_providers->Set(FIXED_ONE_BYTE_STRING(isolate, #PROVIDER), \ @@ -90,12 +123,28 @@ Handle AsyncWrap::MakeCallback(const Handle cb, } } + if (has_async_queue_) { + try_catch.SetVerbose(false); + env()->async_hooks_pre_function()->Call(context, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::MakeCallback", "pre hook threw"); + try_catch.SetVerbose(true); + } + Local ret = cb->Call(context, argc, argv); if (try_catch.HasCaught()) { return Undefined(env()->isolate()); } + if (has_async_queue_) { + try_catch.SetVerbose(false); + env()->async_hooks_post_function()->Call(context, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::AsyncWrap::MakeCallback", "post hook threw"); + try_catch.SetVerbose(true); + } + if (has_domain) { Local exit_v = domain->Get(env()->exit_string()); if (exit_v->IsFunction()) { diff --git a/src/async-wrap.h b/src/async-wrap.h index 920d1452ec3fe4..403002a63f5dfb 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -84,7 +84,11 @@ class AsyncWrap : public BaseObject { private: inline AsyncWrap(); - uint32_t provider_type_; + // When the async hooks init JS function is called from the constructor it is + // expected the context object will receive a _asyncQueue object property + // that will be used to call pre/post in MakeCallback. + bool has_async_queue_; + ProviderType provider_type_; }; } // namespace node diff --git a/src/env-inl.h b/src/env-inl.h index 0e714c80e68a73..a2245130664b17 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -111,6 +111,22 @@ inline v8::Isolate* Environment::IsolateData::isolate() const { return isolate_; } +inline Environment::AsyncHooks::AsyncHooks() { + for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0; +} + +inline uint32_t* Environment::AsyncHooks::fields() { + return fields_; +} + +inline int Environment::AsyncHooks::fields_count() const { + return kFieldsCount; +} + +inline bool Environment::AsyncHooks::call_init_hook() { + return fields_[kCallInitHook] != 0; +} + inline Environment::DomainFlag::DomainFlag() { for (int i = 0; i < kFieldsCount; ++i) fields_[i] = 0; } @@ -243,6 +259,11 @@ inline v8::Isolate* Environment::isolate() const { return isolate_; } +inline bool Environment::call_async_init_hook() const { + // The const_cast is okay, it doesn't violate conceptual const-ness. + return const_cast(this)->async_hooks()->call_init_hook(); +} + inline bool Environment::in_domain() const { // The const_cast is okay, it doesn't violate conceptual const-ness. return using_domains() && @@ -294,6 +315,10 @@ inline uv_loop_t* Environment::event_loop() const { return isolate_data()->event_loop(); } +inline Environment::AsyncHooks* Environment::async_hooks() { + return &async_hooks_; +} + inline Environment::DomainFlag* Environment::domain_flag() { return &domain_flag_; } diff --git a/src/env.h b/src/env.h index 8428a5511e2c39..e028a23f048367 100644 --- a/src/env.h +++ b/src/env.h @@ -65,6 +65,7 @@ namespace node { V(args_string, "args") \ V(argv_string, "argv") \ V(async, "async") \ + V(async_queue_string, "_asyncQueue") \ V(atime_string, "atime") \ V(birthtime_string, "birthtime") \ V(blksize_string, "blksize") \ @@ -249,6 +250,9 @@ namespace node { V(zero_return_string, "ZERO_RETURN") \ #define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ + V(async_hooks_init_function, v8::Function) \ + V(async_hooks_pre_function, v8::Function) \ + V(async_hooks_post_function, v8::Function) \ V(binding_cache_object, v8::Object) \ V(buffer_constructor_function, v8::Function) \ V(context, v8::Context) \ @@ -282,6 +286,27 @@ RB_HEAD(ares_task_list, ares_task_t); class Environment { public: + class AsyncHooks { + public: + inline uint32_t* fields(); + inline int fields_count() const; + inline bool call_init_hook(); + + private: + friend class Environment; // So we can call the constructor. + inline AsyncHooks(); + + enum Fields { + // Set this to not zero if the init hook should be called. + kCallInitHook, + kFieldsCount + }; + + uint32_t fields_[kFieldsCount]; + + DISALLOW_COPY_AND_ASSIGN(AsyncHooks); + }; + class DomainFlag { public: inline uint32_t* fields(); @@ -369,6 +394,7 @@ class Environment { inline v8::Isolate* isolate() const; inline uv_loop_t* event_loop() const; + inline bool call_async_init_hook() const; inline bool in_domain() const; inline uint32_t watched_providers() const; @@ -388,6 +414,7 @@ class Environment { void *arg); inline void FinishHandleCleanup(uv_handle_t* handle); + inline AsyncHooks* async_hooks(); inline DomainFlag* domain_flag(); inline TickInfo* tick_info(); @@ -464,6 +491,7 @@ class Environment { uv_idle_t immediate_idle_handle_; uv_prepare_t idle_prepare_handle_; uv_check_t idle_check_handle_; + AsyncHooks async_hooks_; DomainFlag domain_flag_; TickInfo tick_info_; uv_timer_t cares_timer_handle_; diff --git a/src/node.cc b/src/node.cc index f4809a5147acd9..d15b47577f4a62 100644 --- a/src/node.cc +++ b/src/node.cc @@ -988,11 +988,18 @@ Handle MakeCallback(Environment* env, Local process = env->process_object(); Local object, domain; + bool has_async_queue = false; bool has_domain = false; + if (recv->IsObject()) { + object = recv.As(); + Local async_queue_v = object->Get(env->async_queue_string()); + if (async_queue_v->IsObject()) + has_async_queue = true; + } + if (env->using_domains()) { CHECK(recv->IsObject()); - object = recv.As(); Local domain_v = object->Get(env->domain_string()); has_domain = domain_v->IsObject(); if (has_domain) { @@ -1014,8 +1021,24 @@ Handle MakeCallback(Environment* env, } } + if (has_async_queue) { + try_catch.SetVerbose(false); + env->async_hooks_pre_function()->Call(object, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node:;MakeCallback", "pre hook threw"); + try_catch.SetVerbose(true); + } + Local ret = callback->Call(recv, argc, argv); + if (has_async_queue) { + try_catch.SetVerbose(false); + env->async_hooks_post_function()->Call(object, 0, NULL); + if (try_catch.HasCaught()) + FatalError("node::MakeCallback", "post hook threw"); + try_catch.SetVerbose(true); + } + if (has_domain) { Local exit_v = domain->Get(env->exit_string()); if (exit_v->IsFunction()) { From fe6d5be6b40bde07a5509f808576f7772b0fb4af Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Fri, 5 Dec 2014 05:34:03 -0800 Subject: [PATCH 25/27] uv: float patch to revert tty breakage Float https://github.com/libuv/libuv/commit/484a3a9 to fix incorrect indentation in REPL. --- deps/uv/src/unix/tty.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 82fa27cc12ae3f..7ae19905fbffcb 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -123,7 +123,12 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { uv_spinlock_unlock(&termios_spinlock); raw = tty->orig_termios; - cfmakeraw(&raw); + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag |= (ONLCR); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + raw.c_cc[VMIN] = 1; + raw.c_cc[VTIME] = 0; /* Put terminal in raw mode after draining */ if (tcsetattr(fd, TCSADRAIN, &raw)) From 9653c4b8c7e58cfc17c4c759b2bbcb914b27fd95 Mon Sep 17 00:00:00 2001 From: Jackson Tian Date: Tue, 2 Dec 2014 11:14:57 +0800 Subject: [PATCH 26/27] doc: mention callback for http res/req write & end Add documentation for the callback parameter of http.ClientRequest's and http.ServerResponse's write and end methods. --- doc/api/http.markdown | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 709508fe75fd30..c639bdfd5d9794 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -389,7 +389,7 @@ Example: response.removeHeader("Content-Encoding"); -### response.write(chunk[, encoding]) +### response.write(chunk[, encoding][, callback]) If this method is called and [response.writeHead()][] has not been called, it will switch to implicit header mode and flush the implicit headers. @@ -399,7 +399,8 @@ be called multiple times to provide successive parts of the body. `chunk` can be a string or a buffer. If `chunk` is a string, the second parameter specifies how to encode it into a byte stream. -By default the `encoding` is `'utf8'`. +By default the `encoding` is `'utf8'`. The last parameter `callback` +will be called when this chunk of data is flushed. **Note**: This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used. @@ -433,15 +434,15 @@ emit trailers, with a list of the header fields in its value. E.g., response.end(); -### response.end([data][, encoding]) +### response.end([data][, encoding][, callback]) This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete. The method, `response.end()`, MUST be called on each response. -If `data` is specified, it is equivalent to calling `response.write(data, encoding)` -followed by `response.end()`. +If `data` is specified, it is equivalent to calling +`response.write(data, encoding)` followed by `response.end(callback)`. ## http.request(options[, callback]) @@ -864,7 +865,7 @@ That's usually what you want (it saves a TCP round-trip) but not when the first data isn't sent until possibly much later. `request.flush()` lets you bypass the optimization and kickstart the request. -### request.write(chunk[, encoding]) +### request.write(chunk[, encoding][, callback]) Sends a chunk of the body. By calling this method many times, the user can stream a request body to a @@ -877,15 +878,17 @@ The `chunk` argument should be a [Buffer][] or a string. The `encoding` argument is optional and only applies when `chunk` is a string. Defaults to `'utf8'`. +The `callback` argument is optional and will be called when this chunk of data +is flushed. -### request.end([data][, encoding]) +### request.end([data][, encoding][, callback]) Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating `'0\r\n\r\n'`. If `data` is specified, it is equivalent to calling -`request.write(data, encoding)` followed by `request.end()`. +`request.write(data, encoding)` followed by `request.end(callback)`. ### request.abort() From 70195acbe36f56b87d697a16b5bfc2699c89bac5 Mon Sep 17 00:00:00 2001 From: Brendan Ashworth Date: Sun, 19 Oct 2014 11:54:48 -0700 Subject: [PATCH 27/27] doc: fix grammar and wording in tls and timers In `tls.markdown`, there was a misuse of 'a' which has been replaced with 'an'. In `timers.markdown`... line 31: misuse of 'a', replaced with 'an' line 59: unclear wording, haywire 'a', added new comma --- doc/api/timers.markdown | 4 ++-- doc/api/tls.markdown | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/timers.markdown b/doc/api/timers.markdown index 92af0b64b4e07b..d05046a50efca9 100644 --- a/doc/api/timers.markdown +++ b/doc/api/timers.markdown @@ -28,7 +28,7 @@ you can also pass arguments to the callback. ## clearInterval(intervalObject) -Stops a interval from triggering. +Stops an interval from triggering. ## unref() @@ -56,7 +56,7 @@ can also pass arguments to the callback. Callbacks for immediates are queued in the order in which they were created. The entire callback queue is processed every event loop iteration. If you queue -an immediate from a inside an executing callback that immediate won't fire +an immediate from inside an executing callback, that immediate won't fire until the next event loop iteration. ## clearImmediate(immediateObject) diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index 1b00e488f9d90a..c03845e8721d5c 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -221,7 +221,7 @@ automatically set as a listener for the [secureConnection][] event. The NOTE: Automatically shared between `cluster` module workers. - - `sessionIdContext`: A string containing a opaque identifier for session + - `sessionIdContext`: A string containing an opaque identifier for session resumption. If `requestCert` is `true`, the default is MD5 hash value generated from command-line. Otherwise, the default is not provided. @@ -501,7 +501,7 @@ connections using TLS or SSL. `function (tlsSocket) {}` This event is emitted after a new connection has been successfully -handshaked. The argument is a instance of [tls.TLSSocket][]. It has all the +handshaked. The argument is an instance of [tls.TLSSocket][]. It has all the common stream methods and events. `socket.authorized` is a boolean value which indicates if the