summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremiah Senkpiel <fishrock123@rocketmail.com>2016-03-21 15:59:31 -0400
committerJeremiah Senkpiel <fishrock123@rocketmail.com>2016-04-07 12:44:19 -0400
commit7d8882ba9a8cfc8f0e2126deb3f3df7456de0ffa (patch)
tree44388842ee46106b5887707c6ae75db7155649a6
parent1879e1ef178197fd3593fdbbe65c23224c0d256d (diff)
downloadandroid-node-v8-7d8882ba9a8cfc8f0e2126deb3f3df7456de0ffa.tar.gz
android-node-v8-7d8882ba9a8cfc8f0e2126deb3f3df7456de0ffa.tar.bz2
android-node-v8-7d8882ba9a8cfc8f0e2126deb3f3df7456de0ffa.zip
handle_wrap: expose an `isRefed()` check to JS
This allows third-party tools to check whether or not a handle that can be unreferenced is unreferenced at a particular time. Notably, this should be helpful for inspection via AsyncWrap. Also, this is useful even to node's internals, particularly timers. Refs: https://github.com/nodejs/node/pull/5828 Refs: https://github.com/nodejs/node/pull/5827 PR-URL: https://github.com/nodejs/node/pull/5834 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
-rw-r--r--src/handle_wrap.cc10
-rw-r--r--src/handle_wrap.h1
-rw-r--r--src/pipe_wrap.cc1
-rw-r--r--src/process_wrap.cc1
-rw-r--r--src/signal_wrap.cc1
-rw-r--r--src/tcp_wrap.cc1
-rw-r--r--src/timer_wrap.cc1
-rw-r--r--src/tty_wrap.cc1
-rw-r--r--src/udp_wrap.cc1
-rw-r--r--test/parallel/test-handle-wrap-isrefed-tty.js31
-rw-r--r--test/parallel/test-handle-wrap-isrefed.js97
11 files changed, 146 insertions, 0 deletions
diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc
index 43c5490eef..9af60d5025 100644
--- a/src/handle_wrap.cc
+++ b/src/handle_wrap.cc
@@ -9,6 +9,7 @@
namespace node {
+using v8::Boolean;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
@@ -37,6 +38,15 @@ void HandleWrap::Unref(const FunctionCallbackInfo<Value>& args) {
}
+void HandleWrap::IsRefed(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ HandleWrap* wrap = Unwrap<HandleWrap>(args.Holder());
+
+ bool refed = IsAlive(wrap) && (wrap->flags_ & kUnref) == 0;
+ args.GetReturnValue().Set(refed);
+}
+
+
void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
diff --git a/src/handle_wrap.h b/src/handle_wrap.h
index da712b33be..cb3ba3f5d5 100644
--- a/src/handle_wrap.h
+++ b/src/handle_wrap.h
@@ -35,6 +35,7 @@ class HandleWrap : public AsyncWrap {
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Ref(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Unref(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void IsRefed(const v8::FunctionCallbackInfo<v8::Value>& args);
static inline bool IsAlive(const HandleWrap* wrap) {
return wrap != nullptr && wrap->GetHandle() != nullptr;
diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc
index db2fd16715..ec6ef32b08 100644
--- a/src/pipe_wrap.cc
+++ b/src/pipe_wrap.cc
@@ -81,6 +81,7 @@ void PipeWrap::Initialize(Local<Object> target,
env->SetProtoMethod(t, "close", HandleWrap::Close);
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
env->SetProtoMethod(t, "ref", HandleWrap::Ref);
+ env->SetProtoMethod(t, "isRefed", HandleWrap::IsRefed);
StreamWrap::AddMethods(env, t);
diff --git a/src/process_wrap.cc b/src/process_wrap.cc
index 7e9d2070bb..dec93ddd0c 100644
--- a/src/process_wrap.cc
+++ b/src/process_wrap.cc
@@ -40,6 +40,7 @@ class ProcessWrap : public HandleWrap {
env->SetProtoMethod(constructor, "ref", HandleWrap::Ref);
env->SetProtoMethod(constructor, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(constructor, "isRefed", HandleWrap::IsRefed);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Process"),
constructor->GetFunction());
diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc
index 5f6a6a52bc..ca5201d81a 100644
--- a/src/signal_wrap.cc
+++ b/src/signal_wrap.cc
@@ -32,6 +32,7 @@ class SignalWrap : public HandleWrap {
env->SetProtoMethod(constructor, "close", HandleWrap::Close);
env->SetProtoMethod(constructor, "ref", HandleWrap::Ref);
env->SetProtoMethod(constructor, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(constructor, "isRefed", HandleWrap::IsRefed);
env->SetProtoMethod(constructor, "start", Start);
env->SetProtoMethod(constructor, "stop", Stop);
diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc
index 50fcb506ae..4bfe9dd0d8 100644
--- a/src/tcp_wrap.cc
+++ b/src/tcp_wrap.cc
@@ -88,6 +88,7 @@ void TCPWrap::Initialize(Local<Object> target,
env->SetProtoMethod(t, "ref", HandleWrap::Ref);
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(t, "isRefed", HandleWrap::IsRefed);
StreamWrap::AddMethods(env, t, StreamBase::kFlagHasWritev);
diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc
index 79fa86953d..4a1cd3716a 100644
--- a/src/timer_wrap.cc
+++ b/src/timer_wrap.cc
@@ -39,6 +39,7 @@ class TimerWrap : public HandleWrap {
env->SetProtoMethod(constructor, "close", HandleWrap::Close);
env->SetProtoMethod(constructor, "ref", HandleWrap::Ref);
env->SetProtoMethod(constructor, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(constructor, "isRefed", HandleWrap::IsRefed);
env->SetProtoMethod(constructor, "start", Start);
env->SetProtoMethod(constructor, "stop", Stop);
diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc
index a78d231145..567a504276 100644
--- a/src/tty_wrap.cc
+++ b/src/tty_wrap.cc
@@ -37,6 +37,7 @@ void TTYWrap::Initialize(Local<Object> target,
env->SetProtoMethod(t, "close", HandleWrap::Close);
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(t, "isRefed", HandleWrap::IsRefed);
StreamWrap::AddMethods(env, t, StreamBase::kFlagNoShutdown);
diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc
index dc2804812f..ac087f395a 100644
--- a/src/udp_wrap.cc
+++ b/src/udp_wrap.cc
@@ -108,6 +108,7 @@ void UDPWrap::Initialize(Local<Object> target,
env->SetProtoMethod(t, "ref", HandleWrap::Ref);
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
+ env->SetProtoMethod(t, "isRefed", HandleWrap::IsRefed);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction());
env->set_udp_constructor_function(t->GetFunction());
diff --git a/test/parallel/test-handle-wrap-isrefed-tty.js b/test/parallel/test-handle-wrap-isrefed-tty.js
new file mode 100644
index 0000000000..9656fe06ee
--- /dev/null
+++ b/test/parallel/test-handle-wrap-isrefed-tty.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const common = require('../common');
+const strictEqual = require('assert').strictEqual;
+const spawn = require('child_process').spawn;
+
+function makeAssert(message) {
+ return function(actual, expected) {
+ strictEqual(actual, expected, message);
+ };
+}
+const assert = makeAssert('isRefed() not working on tty_wrap');
+
+if (process.argv[2] === 'child') {
+ // Test tty_wrap in piped child to guarentee stdin being a TTY.
+ const ReadStream = require('tty').ReadStream;
+ const tty = new ReadStream(0);
+ assert(Object.getPrototypeOf(tty._handle).hasOwnProperty('isRefed'), true);
+ assert(tty._handle.isRefed(), true);
+ tty.unref();
+ assert(tty._handle.isRefed(), false);
+ return;
+}
+
+// Use spawn so that we can be sure that stdin has a _handle property.
+// Refs: https://github.com/nodejs/node/pull/5916
+const proc = spawn(process.execPath, [__filename, 'child'], { stdio: 'pipe' });
+proc.stderr.pipe(process.stderr);
+proc.on('exit', common.mustCall(function(exitCode) {
+ process.exitCode = exitCode;
+}));
diff --git a/test/parallel/test-handle-wrap-isrefed.js b/test/parallel/test-handle-wrap-isrefed.js
new file mode 100644
index 0000000000..cd828aa1c4
--- /dev/null
+++ b/test/parallel/test-handle-wrap-isrefed.js
@@ -0,0 +1,97 @@
+'use strict';
+
+const common = require('../common');
+const strictEqual = require('assert').strictEqual;
+
+function makeAssert(message) {
+ return function(actual, expected) {
+ strictEqual(actual, expected, message);
+ };
+}
+
+
+// child_process
+{
+ const assert = makeAssert('isRefed() not working on process_wrap');
+ const spawn = require('child_process').spawn;
+ const cmd = common.isWindows ? 'rundll32' : 'ls';
+ const cp = spawn(cmd);
+ assert(Object.getPrototypeOf(cp._handle).hasOwnProperty('isRefed'), true);
+ assert(cp._handle.isRefed(), true);
+ cp.unref();
+ assert(cp._handle.isRefed(), false);
+ cp.ref();
+ assert(cp._handle.isRefed(), true);
+ cp.unref();
+}
+
+
+// dgram
+{
+ const assert = makeAssert('isRefed() not working on udp_wrap');
+ const dgram = require('dgram');
+
+ const sock4 = dgram.createSocket('udp4');
+ assert(Object.getPrototypeOf(sock4._handle).hasOwnProperty('isRefed'), true);
+ assert(sock4._handle.isRefed(), true);
+ sock4.unref();
+ assert(sock4._handle.isRefed(), false);
+ sock4.ref();
+ assert(sock4._handle.isRefed(), true);
+ sock4.unref();
+
+ const sock6 = dgram.createSocket('udp6');
+ assert(Object.getPrototypeOf(sock6._handle).hasOwnProperty('isRefed'), true);
+ assert(sock6._handle.isRefed(), true);
+ sock6.unref();
+ assert(sock6._handle.isRefed(), false);
+ sock6.ref();
+ assert(sock6._handle.isRefed(), true);
+ sock6.unref();
+}
+
+
+// pipe
+{
+ const assert = makeAssert('isRefed() not working on pipe_wrap');
+ const Pipe = process.binding('pipe_wrap').Pipe;
+ const handle = new Pipe();
+ assert(Object.getPrototypeOf(handle).hasOwnProperty('isRefed'), true);
+ assert(handle.isRefed(), true);
+ handle.unref();
+ assert(handle.isRefed(), false);
+ handle.ref();
+ assert(handle.isRefed(), true);
+ handle.unref();
+}
+
+
+// tcp
+{
+ const assert = makeAssert('isRefed() not working on tcp_wrap');
+ const net = require('net');
+ const server = net.createServer(() => {}).listen(common.PORT);
+ assert(Object.getPrototypeOf(server._handle).hasOwnProperty('isRefed'), true);
+ assert(server._handle.isRefed(), true);
+ assert(server._unref, false);
+ server.unref();
+ assert(server._handle.isRefed(), false);
+ assert(server._unref, true);
+ server.ref();
+ assert(server._handle.isRefed(), true);
+ assert(server._unref, false);
+ server.unref();
+}
+
+
+// timers
+{
+ const assert = makeAssert('isRefed() not working on timer_wrap');
+ const timer = setTimeout(() => {}, 500);
+ timer.unref();
+ assert(Object.getPrototypeOf(timer._handle).hasOwnProperty('isRefed'), true);
+ assert(timer._handle.isRefed(), false);
+ timer.ref();
+ assert(timer._handle.isRefed(), true);
+ timer.unref();
+}