Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

process: add _getActiveHandles(), _getActiveRequests()

* process._getActiveHandles() returns a list containing all active handles
  (timers, sockets, etc.) that have not been unref'd.

* process._getActiveRequests() returns a list of active requests (in-flight
  actions like connecting to a remote host, writing data to a socket, etc.).
  • Loading branch information...
commit 5f0406534ca4a465d11892a747a38c0e5c884cf2 1 parent 636add2
@bnoordhuis bnoordhuis authored
View
28 LICENSE
@@ -550,3 +550,31 @@ maintained libraries. The externally maintained libraries used by Node are:
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
+
+- src/ngx-queue.h ngx-queue.h is taken from the nginx source tree. nginx's
+ license follows
+ """
+ Copyright (C) 2002-2012 Igor Sysoev
+ Copyright (C) 2011,2012 Nginx, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ """
View
1  node.gyp
@@ -107,6 +107,7 @@
'src/node_script.h',
'src/node_string.h',
'src/node_version.h',
+ 'src/ngx-queue.h',
'src/pipe_wrap.h',
'src/req_wrap.h',
'src/slab_allocator.h',
View
8 src/handle_wrap.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
+#include "ngx-queue.h"
#include "handle_wrap.h"
namespace node {
+using v8::Array;
using v8::Object;
using v8::Handle;
using v8::Local;
@@ -52,6 +54,10 @@ using v8::Integer;
}
+// defined in node.cc
+extern ngx_queue_t handle_wrap_queue;
+
+
void HandleWrap::Initialize(Handle<Object> target) {
/* Doesn't do anything at the moment. */
}
@@ -125,6 +131,7 @@ HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
assert(object->InternalFieldCount() > 0);
object_ = v8::Persistent<v8::Object>::New(object);
object_->SetPointerInInternalField(0, this);
+ ngx_queue_insert_tail(&handle_wrap_queue, &handle_wrap_queue_);
}
@@ -136,6 +143,7 @@ void HandleWrap::SetHandle(uv_handle_t* h) {
HandleWrap::~HandleWrap() {
assert(object_.IsEmpty());
+ ngx_queue_remove(&handle_wrap_queue_);
}
View
4 src/handle_wrap.h
@@ -22,6 +22,8 @@
#ifndef HANDLE_WRAP_H_
#define HANDLE_WRAP_H_
+#include "ngx-queue.h"
+
namespace node {
// Rules:
@@ -61,7 +63,9 @@ class HandleWrap {
v8::Persistent<v8::Object> object_;
private:
+ friend v8::Handle<v8::Value> GetActiveHandles(const v8::Arguments&);
static void OnClose(uv_handle_t* handle);
+ ngx_queue_t handle_wrap_queue_;
// Using double underscore due to handle_ member in tcp_wrap. Probably
// tcp_wrap should rename it's member to 'handle'.
uv_handle_t* handle__;
View
106 src/ngx-queue.h
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef NGX_QUEUE_H_INCLUDED_
+#define NGX_QUEUE_H_INCLUDED_
+
+
+typedef struct ngx_queue_s ngx_queue_t;
+
+struct ngx_queue_s {
+ ngx_queue_t *prev;
+ ngx_queue_t *next;
+};
+
+
+#define ngx_queue_init(q) \
+ (q)->prev = q; \
+ (q)->next = q
+
+
+#define ngx_queue_empty(h) \
+ (h == (h)->prev)
+
+
+#define ngx_queue_insert_head(h, x) \
+ (x)->next = (h)->next; \
+ (x)->next->prev = x; \
+ (x)->prev = h; \
+ (h)->next = x
+
+
+#define ngx_queue_insert_after ngx_queue_insert_head
+
+
+#define ngx_queue_insert_tail(h, x) \
+ (x)->prev = (h)->prev; \
+ (x)->prev->next = x; \
+ (x)->next = h; \
+ (h)->prev = x
+
+
+#define ngx_queue_head(h) \
+ (h)->next
+
+
+#define ngx_queue_last(h) \
+ (h)->prev
+
+
+#define ngx_queue_sentinel(h) \
+ (h)
+
+
+#define ngx_queue_next(q) \
+ (q)->next
+
+
+#define ngx_queue_prev(q) \
+ (q)->prev
+
+
+#if (NGX_DEBUG)
+
+#define ngx_queue_remove(x) \
+ (x)->next->prev = (x)->prev; \
+ (x)->prev->next = (x)->next; \
+ (x)->prev = NULL; \
+ (x)->next = NULL
+
+#else
+
+#define ngx_queue_remove(x) \
+ (x)->next->prev = (x)->prev; \
+ (x)->prev->next = (x)->next
+
+#endif
+
+
+#define ngx_queue_split(h, q, n) \
+ (n)->prev = (h)->prev; \
+ (n)->prev->next = n; \
+ (n)->next = q; \
+ (h)->prev = (q)->prev; \
+ (h)->prev->next = h; \
+ (q)->prev = n;
+
+
+#define ngx_queue_add(h, n) \
+ (h)->prev->next = (n)->next; \
+ (n)->next->prev = (h)->prev; \
+ (h)->prev = (n)->prev; \
+ (h)->prev->next = h;
+
+
+#define ngx_queue_data(q, type, link) \
+ (type *) ((unsigned char *) q - offsetof(type, link))
+
+
+#define ngx_queue_foreach(q, h) \
+ for ((q) = ngx_queue_head(h); (q) != (h); (q) = ngx_queue_next(q))
+
+
+#endif /* NGX_QUEUE_H_INCLUDED_ */
View
44 src/node.cc
@@ -20,7 +20,8 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
-#include "handle_wrap.h" // HandleWrap::GetActiveHandles()
+#include "req_wrap.h"
+#include "handle_wrap.h"
#include "uv.h"
@@ -91,6 +92,9 @@ extern char **environ;
namespace node {
+ngx_queue_t handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue };
+ngx_queue_t req_wrap_queue = { &req_wrap_queue, &req_wrap_queue };
+
// declared in req_wrap.h
Persistent<String> process_symbol;
Persistent<String> domain_symbol;
@@ -1332,6 +1336,42 @@ Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) {
}
+static Handle<Value> GetActiveRequests(const Arguments& args) {
+ HandleScope scope;
+
+ Local<Array> ary = Array::New();
+ ngx_queue_t* q = NULL;
+ int i = 0;
+
+ ngx_queue_foreach(q, &req_wrap_queue) {
+ ReqWrap<uv_req_t>* w = container_of(q, ReqWrap<uv_req_t>, req_wrap_queue_);
+ if (w->object_.IsEmpty()) continue;
+ ary->Set(i++, w->object_);
+ }
+
+ return scope.Close(ary);
+}
+
+
+// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
+// implemented here for consistency with GetActiveRequests().
+Handle<Value> GetActiveHandles(const Arguments& args) {
+ HandleScope scope;
+
+ Local<Array> ary = Array::New();
+ ngx_queue_t* q = NULL;
+ int i = 0;
+
+ ngx_queue_foreach(q, &handle_wrap_queue) {
+ HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_);
+ if (w->object_.IsEmpty() || w->unref) continue;
+ ary->Set(i++, w->object_);
+ }
+
+ return scope.Close(ary);
+}
+
+
static Handle<Value> Abort(const Arguments& args) {
abort();
return Undefined();
@@ -2237,6 +2277,8 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
// define various internal methods
+ NODE_SET_METHOD(process, "_getActiveRequests", GetActiveRequests);
+ NODE_SET_METHOD(process, "_getActiveHandles", GetActiveHandles);
NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
NODE_SET_METHOD(process, "reallyExit", Exit);
NODE_SET_METHOD(process, "abort", Abort);
View
9 src/req_wrap.h
@@ -22,11 +22,14 @@
#ifndef REQ_WRAP_H_
#define REQ_WRAP_H_
+#include "ngx-queue.h"
+
namespace node {
// defined in node.cc
extern v8::Persistent<v8::String> process_symbol;
extern v8::Persistent<v8::String> domain_symbol;
+extern ngx_queue_t req_wrap_queue;
template <typename T>
class ReqWrap {
@@ -45,10 +48,13 @@ class ReqWrap {
// fprintf(stderr, "setting domain on ReqWrap\n");
object_->Set(domain_symbol, domain);
}
+
+ ngx_queue_insert_tail(&req_wrap_queue, &req_wrap_queue_);
}
~ReqWrap() {
+ ngx_queue_remove(&req_wrap_queue_);
// Assert that someone has called Dispatched()
assert(req_.data == this);
assert(!object_.IsEmpty());
@@ -62,8 +68,9 @@ class ReqWrap {
}
v8::Persistent<v8::Object> object_;
- T req_;
+ ngx_queue_t req_wrap_queue_;
void* data_;
+ T req_; // *must* be last, GetActiveRequests() in node.cc depends on it
};
View
54 test/simple/test-process-active-wraps.js
@@ -0,0 +1,54 @@
+// 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 net = require('net');
+
+function expect(activeHandles, activeRequests) {
+ assert.equal(process._getActiveHandles().length, activeHandles);
+ assert.equal(process._getActiveRequests().length, activeRequests);
+}
+
+(function() {
+ expect(0, 0);
+ var server = net.createServer().listen(common.PORT);
+ expect(1, 0);
+ server.close();
+ expect(1, 0); // server handle doesn't shut down until next tick
+})();
+
+(function() {
+ expect(1, 0);
+ var conn = net.createConnection(common.PORT);
+ conn.on('error', function() { /* ignore */ });
+ expect(2, 1);
+ conn.destroy();
+ expect(2, 1); // client handle doesn't shut down until next tick
+})();
+
+process.nextTick(function() {
+ process.nextTick(function() {
+ // the handles should be gone but the connect req could still be alive
+ assert.equal(process._getActiveHandles().length, 0);
+ });
+});
Please sign in to comment.
Something went wrong with that request. Please try again.