Skip to content

Commit 068b733

Browse files
committed
Land Cantrill's DTrace patch
only works on solaris
1 parent 91cc2d8 commit 068b733

9 files changed

Lines changed: 358 additions & 2 deletions

File tree

lib/http.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ OutgoingMessage.prototype.end = function(data, encoding) {
599599
}
600600

601601
this.finished = true;
602+
DTRACE_HTTP_SERVER_RESPONSE(this.connection);
602603

603604
// There is the first message on the outgoing queue, and we've sent
604605
// everything to the socket.
@@ -866,6 +867,7 @@ function connectionListener(socket) {
866867
var res = new ServerResponse(req);
867868
debug('server response shouldKeepAlive: ' + shouldKeepAlive);
868869
res.shouldKeepAlive = shouldKeepAlive;
870+
DTRACE_HTTP_SERVER_REQUEST(req, socket);
869871

870872
if (socket._httpMessage) {
871873
// There are already pending outgoing res, append.

lib/net.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ Socket.prototype._shutdown = function() {
789789
Socket.prototype.end = function(data, encoding) {
790790
if (this.writable) {
791791
if (this._writeQueueLast() !== END_OF_FILE) {
792+
DTRACE_NET_STREAM_END(this);
792793
if (data) this.write(data, encoding);
793794
this._writeQueue.push(END_OF_FILE);
794795
if (!this._connecting) {
@@ -868,6 +869,7 @@ function Server(/* [ options, ] listener */) {
868869
s.server = self;
869870
s.resume();
870871

872+
DTRACE_NET_SERVER_CONNECTION(s);
871873
self.emit('connection', s);
872874

873875
// The 'connect' event probably should be removed for server-side

src/node.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <node.h>
44

55
#include <v8-debug.h>
6+
#include <node_dtrace.h>
67

78
#include <locale.h>
89
#include <stdio.h>
@@ -2028,6 +2029,8 @@ static void Load(int argc, char *argv[]) {
20282029
Local<Object> global = v8::Context::GetCurrent()->Global();
20292030
Local<Value> args[1] = { Local<Value>::New(process) };
20302031

2032+
InitDTrace(global);
2033+
20312034
f->Call(global, 1, args);
20322035

20332036
if (try_catch.HasCaught()) {

src/node.d

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* This is the DTrace library file for the node provider, which includes
3+
* the necessary translators to get from the args[] to something useful.
4+
* Be warned: the mechanics here are seriously ugly -- and one must always
5+
* keep in mind that clean abstractions often require filthy systems.
6+
*/
7+
#pragma D depends_on library procfs.d
8+
9+
typedef struct {
10+
int32_t fd;
11+
int32_t port;
12+
uint32_t remote;
13+
} node_dtrace_connection_t;
14+
15+
typedef struct {
16+
int32_t fd;
17+
int32_t port;
18+
uint64_t remote;
19+
} node_dtrace_connection64_t;
20+
21+
typedef struct {
22+
int fd;
23+
string remoteAddress;
24+
int remotePort;
25+
} node_connection_t;
26+
27+
translator node_connection_t <node_dtrace_connection_t *nc> {
28+
fd = *(int32_t *)copyin((uintptr_t)&nc->fd, sizeof (int32_t));
29+
remotePort =
30+
*(int32_t *)copyin((uintptr_t)&nc->port, sizeof (int32_t));
31+
remoteAddress = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
32+
copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nc->remote,
33+
sizeof (int32_t))) :
34+
copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t)
35+
&((node_dtrace_connection64_t *)nc)->remote, sizeof (int64_t)));
36+
};
37+
38+
typedef struct {
39+
uint32_t url;
40+
uint32_t method;
41+
} node_dtrace_http_request_t;
42+
43+
typedef struct {
44+
uint64_t url;
45+
uint64_t method;
46+
} node_dtrace_http_request64_t;
47+
48+
typedef struct {
49+
string url;
50+
string method;
51+
} node_http_request_t;
52+
53+
translator node_http_request_t <node_dtrace_http_request_t *nd> {
54+
url = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
55+
copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nd->url,
56+
sizeof (int32_t))) :
57+
copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t)
58+
&((node_dtrace_http_request64_t *)nd)->url, sizeof (int64_t)));
59+
method = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
60+
copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nd->method,
61+
sizeof (int32_t))) :
62+
copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t)
63+
&((node_dtrace_http_request64_t *)nd)->method, sizeof (int64_t)));
64+
};

src/node_dtrace.cc

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include <node_dtrace.h>
2+
3+
#ifdef HAVE_DTRACE
4+
#include "node_provider.h"
5+
#else
6+
#define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
7+
#define NODE_HTTP_SERVER_REQUEST_ENABLED() (0)
8+
#define NODE_HTTP_SERVER_RESPONSE(arg0)
9+
#define NODE_HTTP_SERVER_RESPONSE_ENABLED() (0)
10+
#define NODE_NET_SERVER_CONNECTION(arg0)
11+
#define NODE_NET_SERVER_CONNECTION_ENABLED() (0)
12+
#define NODE_NET_STREAM_END(arg0)
13+
#define NODE_NET_STREAM_END_ENABLED() (0)
14+
#endif
15+
16+
namespace node {
17+
18+
using namespace v8;
19+
20+
#define SLURP_STRING(obj, member, valp) \
21+
String::Utf8Value _##member(obj->Get(String::New(#member))->ToString()); \
22+
if ((*(const char **)valp = *_##member) == NULL) \
23+
*(const char **)valp = "<unknown>";
24+
25+
#define SLURP_INT(obj, member, valp) \
26+
*valp = obj->Get(String::New(#member))->ToInteger()->Value();
27+
28+
#define SLURP_CONNECTION(arg, conn) \
29+
node_dtrace_connection_t conn; \
30+
Local<Object> _##conn = Local<Object>::Cast(arg); \
31+
SLURP_INT(_##conn, fd, &conn.fd); \
32+
SLURP_STRING(_##conn, remoteAddress, &conn.remote); \
33+
SLURP_INT(_##conn, remotePort, &conn.port);
34+
35+
Handle<Value> DTRACE_NET_SERVER_CONNECTION(const Arguments& args) {
36+
if (!NODE_NET_SERVER_CONNECTION_ENABLED())
37+
return Undefined();
38+
39+
HandleScope scope;
40+
41+
SLURP_CONNECTION(args[0], conn);
42+
NODE_NET_SERVER_CONNECTION(&conn);
43+
44+
return Undefined();
45+
}
46+
47+
Handle<Value> DTRACE_NET_STREAM_END(const Arguments& args) {
48+
if (!NODE_NET_STREAM_END_ENABLED())
49+
return Undefined();
50+
51+
HandleScope scope;
52+
53+
SLURP_CONNECTION(args[0], conn);
54+
NODE_NET_STREAM_END(&conn);
55+
56+
return Undefined();
57+
}
58+
59+
Handle<Value> DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) {
60+
node_dtrace_http_request_t req;
61+
62+
if (!NODE_HTTP_SERVER_REQUEST_ENABLED())
63+
return Undefined();
64+
65+
HandleScope scope;
66+
67+
Local<Object> arg0 = Local<Object>::Cast(args[0]);
68+
Local<Object> arg1 = Local<Object>::Cast(args[1]);
69+
70+
SLURP_STRING(arg0, url, &req.url);
71+
SLURP_STRING(arg0, method, &req.method);
72+
73+
SLURP_CONNECTION(args[1], conn);
74+
75+
NODE_HTTP_SERVER_REQUEST(&req, &conn);
76+
return Undefined();
77+
}
78+
79+
Handle<Value> DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) {
80+
if (!NODE_HTTP_SERVER_RESPONSE_ENABLED())
81+
return Undefined();
82+
83+
HandleScope scope;
84+
85+
SLURP_CONNECTION(args[0], conn);
86+
NODE_HTTP_SERVER_RESPONSE(&conn);
87+
88+
return Undefined();
89+
}
90+
91+
#define NODE_PROBE(name) #name, name
92+
93+
void InitDTrace(Handle<Object> target) {
94+
static struct {
95+
const char *name;
96+
Handle<Value> (*func)(const Arguments&);
97+
Persistent<FunctionTemplate> templ;
98+
} tab[] = {
99+
{ NODE_PROBE(DTRACE_NET_SERVER_CONNECTION) },
100+
{ NODE_PROBE(DTRACE_NET_STREAM_END) },
101+
{ NODE_PROBE(DTRACE_HTTP_SERVER_REQUEST) },
102+
{ NODE_PROBE(DTRACE_HTTP_SERVER_RESPONSE) },
103+
{ NULL }
104+
};
105+
106+
for (int i = 0; tab[i].name != NULL; i++) {
107+
tab[i].templ = Persistent<FunctionTemplate>::New(
108+
FunctionTemplate::New(tab[i].func));
109+
target->Set(String::NewSymbol(tab[i].name), tab[i].templ->GetFunction());
110+
}
111+
}
112+
113+
}

src/node_dtrace.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef NODE_DTRACE_H_
2+
#define NODE_DTRACE_H_
3+
4+
#include <node.h>
5+
#include <v8.h>
6+
7+
extern "C" {
8+
9+
typedef struct {
10+
int32_t fd;
11+
int32_t port;
12+
char *remote;
13+
} node_dtrace_connection_t;
14+
15+
typedef struct {
16+
char *url;
17+
char *method;
18+
} node_dtrace_http_request_t;
19+
20+
}
21+
22+
namespace node {
23+
24+
void InitDTrace(v8::Handle<v8::Object> target);
25+
26+
}
27+
28+
#endif

src/node_provider.d

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* DTrace provider for node.js.
3+
*/
4+
5+
/*
6+
* In order to have the information we need here to create the provider,
7+
* we must declare bogus definitions for our depended-upon structures. And
8+
* yes, the fact that we need to do this represents a shortcoming in DTrace,
9+
* one that would be resolved by that elusive El Dorado: dynamic translators.
10+
*/
11+
12+
typedef struct {
13+
int dummy;
14+
} node_dtrace_connection_t;
15+
16+
typedef struct {
17+
int dummy;
18+
} node_connection_t;
19+
20+
typedef struct {
21+
int dummy;
22+
} node_dtrace_http_request_t;
23+
24+
typedef struct {
25+
int dummy;
26+
} node_http_request_t;
27+
28+
provider node {
29+
probe net__server__connection(node_dtrace_connection_t *c) :
30+
(node_connection_t *c);
31+
probe net__stream__end(node_dtrace_connection_t *c) :
32+
(node_connection_t *c);
33+
probe http__server__request(node_dtrace_http_request_t *h,
34+
node_dtrace_connection_t *c) :
35+
(node_http_request_t *h, node_connection_t *c);
36+
probe http__server__response(node_dtrace_connection_t *c) :
37+
(node_connection_t *c);
38+
};
39+
40+
#pragma D attributes Evolving/Evolving/ISA provider node provider
41+
#pragma D attributes Private/Private/Unknown provider node module
42+
#pragma D attributes Private/Private/Unknown provider node function
43+
#pragma D attributes Private/Private/ISA provider node name
44+
#pragma D attributes Evolving/Evolving/ISA provider node args

test/common.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ process.on('exit', function() {
3939
process,
4040
global];
4141

42+
if (DTRACE_HTTP_SERVER_RESPONSE) {
43+
knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
44+
knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
45+
knownGlobals.push(DTRACE_NET_STREAM_END);
46+
knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
47+
}
48+
4249
for (var x in global) {
4350
var found = false;
4451

0 commit comments

Comments
 (0)