Revert support for isolates.
It was decided that the performance benefits that isolates offer (faster spin-up times for worker processes, faster inter-worker communication, possibly a lower memory footprint) are not actual bottlenecks for most people and do not outweigh the potential stability issues and intrusive changes to the code base that first-class support for isolates requires. Hence, this commit backs out all isolates-related changes. Good bye, isolates. We hardly knew ye.
This commit is contained in:
parent
a9723df1b7
commit
74a8215a86
6
configure
vendored
6
configure
vendored
@ -32,11 +32,6 @@ parser.add_option("--without-waf",
|
|||||||
dest="without_waf",
|
dest="without_waf",
|
||||||
help="Don\'t install node-waf")
|
help="Don\'t install node-waf")
|
||||||
|
|
||||||
parser.add_option("--without-isolates",
|
|
||||||
action="store_true",
|
|
||||||
dest="without_isolates",
|
|
||||||
help="Build without isolates (no threads, single loop) [Default: False]")
|
|
||||||
|
|
||||||
parser.add_option("--without-ssl",
|
parser.add_option("--without-ssl",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
dest="without_ssl",
|
dest="without_ssl",
|
||||||
@ -172,7 +167,6 @@ def target_arch():
|
|||||||
|
|
||||||
def configure_node(o):
|
def configure_node(o):
|
||||||
# TODO add gdb
|
# TODO add gdb
|
||||||
o['variables']['node_use_isolates'] = b(not options.without_isolates)
|
|
||||||
o['variables']['node_prefix'] = options.prefix if options.prefix else ''
|
o['variables']['node_prefix'] = options.prefix if options.prefix else ''
|
||||||
o['variables']['node_use_dtrace'] = b(options.with_dtrace)
|
o['variables']['node_use_dtrace'] = b(options.with_dtrace)
|
||||||
o['variables']['node_install_npm'] = b(not options.without_npm)
|
o['variables']['node_install_npm'] = b(not options.without_npm)
|
||||||
|
@ -25,7 +25,7 @@ var util = require('util'),
|
|||||||
vm = require('vm'),
|
vm = require('vm'),
|
||||||
repl = require('repl'),
|
repl = require('repl'),
|
||||||
inherits = util.inherits,
|
inherits = util.inherits,
|
||||||
fork = require('child_process').fork;
|
spawn = require('child_process').spawn;
|
||||||
|
|
||||||
exports.start = function(argv, stdin, stdout) {
|
exports.start = function(argv, stdin, stdout) {
|
||||||
argv || (argv = process.argv.slice(2));
|
argv || (argv = process.argv.slice(2));
|
||||||
@ -39,7 +39,7 @@ exports.start = function(argv, stdin, stdout) {
|
|||||||
stdin = stdin || process.openStdin();
|
stdin = stdin || process.openStdin();
|
||||||
stdout = stdout || process.stdout;
|
stdout = stdout || process.stdout;
|
||||||
|
|
||||||
var args = argv,
|
var args = ['--debug-brk'].concat(argv),
|
||||||
interface = new Interface(stdin, stdout, args);
|
interface = new Interface(stdin, stdout, args);
|
||||||
|
|
||||||
stdin.resume();
|
stdin.resume();
|
||||||
@ -169,8 +169,6 @@ function Client() {
|
|||||||
this.scripts = {};
|
this.scripts = {};
|
||||||
this.breakpoints = [];
|
this.breakpoints = [];
|
||||||
|
|
||||||
this.isolates = process.features.isolates;
|
|
||||||
|
|
||||||
// Note that 'Protocol' requires strings instead of Buffers.
|
// Note that 'Protocol' requires strings instead of Buffers.
|
||||||
socket.setEncoding('utf8');
|
socket.setEncoding('utf8');
|
||||||
socket.on('data', function(d) {
|
socket.on('data', function(d) {
|
||||||
@ -1597,51 +1595,20 @@ Interface.prototype.trySpawn = function(cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = self.client = new Client(),
|
|
||||||
connectionAttempts = 0;
|
|
||||||
|
|
||||||
if (!this.child) {
|
if (!this.child) {
|
||||||
if (client.isolates) {
|
this.child = spawn(process.execPath, this.args);
|
||||||
this.child = fork(this.args.shift(), this.args, {
|
|
||||||
thread: true,
|
|
||||||
debug: function(d) {
|
|
||||||
d.onmessage = function(event) {
|
|
||||||
client._onResponse({
|
|
||||||
headers: {},
|
|
||||||
body: JSON.parse(event)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Monkey patch client to send requests directly to debugger
|
this.child.stdout.on('data', this.childPrint.bind(this));
|
||||||
client.req = function(req, cb) {
|
this.child.stderr.on('data', this.childPrint.bind(this));
|
||||||
req.type = 'request';
|
|
||||||
cb.request_seq = req.seq = this.protocol.reqSeq++;
|
|
||||||
this._reqCallbacks.push(cb);
|
|
||||||
|
|
||||||
d.write(JSON.stringify(req));
|
|
||||||
};
|
|
||||||
|
|
||||||
client.emit('ready');
|
|
||||||
|
|
||||||
client._onResponse({
|
|
||||||
headers: { Type: 'connect' },
|
|
||||||
body: {}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
debugBrk: true
|
|
||||||
});
|
|
||||||
this.child.kill = function() {
|
|
||||||
self.error('isolate.kill is not implemented yet!');
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this.child = fork('--debug-brk', this.args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pause();
|
this.pause();
|
||||||
|
|
||||||
|
var client = self.client = new Client(),
|
||||||
|
connectionAttempts = 0;
|
||||||
|
|
||||||
client.once('ready', function() {
|
client.once('ready', function() {
|
||||||
if (!client.isolates) self.stdout.write(' ok\n');
|
self.stdout.write(' ok\n');
|
||||||
|
|
||||||
// Restore breakpoints
|
// Restore breakpoints
|
||||||
breakpoints.forEach(function(bp) {
|
breakpoints.forEach(function(bp) {
|
||||||
@ -1689,14 +1656,11 @@ Interface.prototype.trySpawn = function(cb) {
|
|||||||
function attemptConnect() {
|
function attemptConnect() {
|
||||||
++connectionAttempts;
|
++connectionAttempts;
|
||||||
self.stdout.write('.');
|
self.stdout.write('.');
|
||||||
|
|
||||||
client.connect(port, host);
|
client.connect(port, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!client.isolates) {
|
setTimeout(function() {
|
||||||
setTimeout(function() {
|
self.print('connecting..', true);
|
||||||
self.print('connecting..', true);
|
attemptConnect();
|
||||||
attemptConnect();
|
}, 50);
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -209,11 +209,11 @@ exports.fork = function(modulePath /*, args, options*/) {
|
|||||||
options.env.NODE_CHANNEL_FD = 42;
|
options.env.NODE_CHANNEL_FD = 42;
|
||||||
|
|
||||||
// stdin is the IPC channel.
|
// stdin is the IPC channel.
|
||||||
if (!options.thread) options.stdinStream = createPipe(true);
|
options.stdinStream = createPipe(true);
|
||||||
|
|
||||||
var child = spawn(process.execPath, args, options);
|
var child = spawn(process.execPath, args, options);
|
||||||
|
|
||||||
if (!options.thread) setupChannel(child, options.stdinStream);
|
setupChannel(child, options.stdinStream);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
};
|
};
|
||||||
@ -370,7 +370,7 @@ var spawn = exports.spawn = function(file, args, options) {
|
|||||||
envPairs.push(key + '=' + env[key]);
|
envPairs.push(key + '=' + env[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var child = (options && options.thread) ? (new Isolate) : (new ChildProcess);
|
var child = new ChildProcess();
|
||||||
|
|
||||||
child.spawn({
|
child.spawn({
|
||||||
file: file,
|
file: file,
|
||||||
@ -379,8 +379,7 @@ var spawn = exports.spawn = function(file, args, options) {
|
|||||||
windowsVerbatimArguments: !!(options && options.windowsVerbatimArguments),
|
windowsVerbatimArguments: !!(options && options.windowsVerbatimArguments),
|
||||||
envPairs: envPairs,
|
envPairs: envPairs,
|
||||||
customFds: options ? options.customFds : null,
|
customFds: options ? options.customFds : null,
|
||||||
stdinStream: options ? options.stdinStream : null,
|
stdinStream: options ? options.stdinStream : null
|
||||||
options: options
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
@ -537,63 +536,3 @@ ChildProcess.prototype.kill = function(sig) {
|
|||||||
// TODO: raise error if r == -1?
|
// TODO: raise error if r == -1?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Lazy loaded.
|
|
||||||
var isolates = null;
|
|
||||||
|
|
||||||
|
|
||||||
function Isolate() {
|
|
||||||
if (!process.features.isolates) {
|
|
||||||
throw new Error('Compiled without isolates support.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isolates) {
|
|
||||||
isolates = process.binding('isolates');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._handle = null;
|
|
||||||
}
|
|
||||||
inherits(Isolate, EventEmitter); // maybe inherit from ChildProcess?
|
|
||||||
|
|
||||||
|
|
||||||
Isolate.prototype.spawn = function(options) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (self._handle) throw new Error('Isolate already running.');
|
|
||||||
self._handle = isolates.create(options.args, options.options);
|
|
||||||
if (!self._handle) throw new Error('Cannot create isolate.');
|
|
||||||
|
|
||||||
self._handle.onmessage = function(msg, recvHandle) {
|
|
||||||
msg = JSON.parse('' + msg);
|
|
||||||
|
|
||||||
// Update simultaneous accepts on Windows
|
|
||||||
net._setSimultaneousAccepts(recvHandle);
|
|
||||||
|
|
||||||
self.emit('message', msg, recvHandle);
|
|
||||||
};
|
|
||||||
|
|
||||||
self._handle.onexit = function() {
|
|
||||||
self._handle = null;
|
|
||||||
self.emit('exit');
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Isolate.prototype.kill = function(sig) {
|
|
||||||
if (!this._handle) throw new Error('Isolate not running.');
|
|
||||||
// ignore silently for now, need a way to signal the other thread
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Isolate.prototype.send = function(msg, sendHandle) {
|
|
||||||
if (typeof msg === 'undefined') throw new TypeError('Bad argument.');
|
|
||||||
if (!this._handle) throw new Error('Isolate not running.');
|
|
||||||
msg = JSON.stringify(msg);
|
|
||||||
msg = new Buffer(msg);
|
|
||||||
|
|
||||||
// Update simultaneous accepts on Windows
|
|
||||||
net._setSimultaneousAccepts(sendHandle);
|
|
||||||
|
|
||||||
return this._handle.send(msg, sendHandle);
|
|
||||||
};
|
|
||||||
|
12
node.gyp
12
node.gyp
@ -8,7 +8,6 @@
|
|||||||
'node_use_dtrace': 'false',
|
'node_use_dtrace': 'false',
|
||||||
'node_use_openssl%': 'true',
|
'node_use_openssl%': 'true',
|
||||||
'node_use_system_openssl%': 'false',
|
'node_use_system_openssl%': 'false',
|
||||||
'node_use_isolates%': 'true',
|
|
||||||
'library_files': [
|
'library_files': [
|
||||||
'src/node.js',
|
'src/node.js',
|
||||||
'lib/_debugger.js',
|
'lib/_debugger.js',
|
||||||
@ -73,9 +72,7 @@
|
|||||||
'src/cares_wrap.cc',
|
'src/cares_wrap.cc',
|
||||||
'src/handle_wrap.cc',
|
'src/handle_wrap.cc',
|
||||||
'src/node.cc',
|
'src/node.cc',
|
||||||
'src/node_vars.cc',
|
|
||||||
'src/node_buffer.cc',
|
'src/node_buffer.cc',
|
||||||
'src/node_isolate.cc',
|
|
||||||
'src/node_constants.cc',
|
'src/node_constants.cc',
|
||||||
'src/node_extensions.cc',
|
'src/node_extensions.cc',
|
||||||
'src/node_file.cc',
|
'src/node_file.cc',
|
||||||
@ -95,12 +92,9 @@
|
|||||||
'src/v8_typed_array.cc',
|
'src/v8_typed_array.cc',
|
||||||
'src/udp_wrap.cc',
|
'src/udp_wrap.cc',
|
||||||
# headers to make for a more pleasant IDE experience
|
# headers to make for a more pleasant IDE experience
|
||||||
'src/ngx-queue.h',
|
|
||||||
'src/handle_wrap.h',
|
'src/handle_wrap.h',
|
||||||
'src/node.h',
|
'src/node.h',
|
||||||
'src/node_vars.h',
|
|
||||||
'src/node_buffer.h',
|
'src/node_buffer.h',
|
||||||
'src/node_isolate.h',
|
|
||||||
'src/node_constants.h',
|
'src/node_constants.h',
|
||||||
'src/node_crypto.h',
|
'src/node_crypto.h',
|
||||||
'src/node_extensions.h',
|
'src/node_extensions.h',
|
||||||
@ -133,12 +127,6 @@
|
|||||||
],
|
],
|
||||||
|
|
||||||
'conditions': [
|
'conditions': [
|
||||||
[ 'node_use_isolates=="true"', {
|
|
||||||
'defines': [ 'HAVE_ISOLATES=1' ],
|
|
||||||
}, {
|
|
||||||
'defines': [ 'HAVE_ISOLATES=0' ],
|
|
||||||
}],
|
|
||||||
|
|
||||||
[ 'node_use_openssl=="true"', {
|
[ 'node_use_openssl=="true"', {
|
||||||
'defines': [ 'HAVE_OPENSSL=1' ],
|
'defines': [ 'HAVE_OPENSSL=1' ],
|
||||||
'sources': [ 'src/node_crypto.cc' ],
|
'sources': [ 'src/node_crypto.cc' ],
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -49,11 +48,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
#define oncomplete_sym NODE_VAR(oncomplete_sym)
|
|
||||||
#define ares_channel NODE_VAR(ares_channel)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
namespace cares_wrap {
|
namespace cares_wrap {
|
||||||
@ -75,6 +69,11 @@ using v8::Value;
|
|||||||
|
|
||||||
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
|
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
|
||||||
|
|
||||||
|
static Persistent<String> oncomplete_sym;
|
||||||
|
|
||||||
|
static ares_channel ares_channel;
|
||||||
|
|
||||||
|
|
||||||
static Local<Array> HostentToAddresses(struct hostent* host) {
|
static Local<Array> HostentToAddresses(struct hostent* host) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
Local<Array> addresses = Array::New();
|
Local<Array> addresses = Array::New();
|
||||||
@ -608,7 +607,7 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
|
|||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
// Error
|
// Error
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
argv[0] = Local<Value>::New(Null());
|
argv[0] = Local<Value>::New(Null());
|
||||||
} else {
|
} else {
|
||||||
// Success
|
// Success
|
||||||
@ -711,7 +710,7 @@ static Handle<Value> GetAddrInfo(const Arguments& args) {
|
|||||||
hints.ai_family = fam;
|
hints.ai_family = fam;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
int r = uv_getaddrinfo(Loop(),
|
int r = uv_getaddrinfo(uv_default_loop(),
|
||||||
&req_wrap->req_,
|
&req_wrap->req_,
|
||||||
AfterGetAddrInfo,
|
AfterGetAddrInfo,
|
||||||
*hostname,
|
*hostname,
|
||||||
@ -720,7 +719,7 @@ static Handle<Value> GetAddrInfo(const Arguments& args) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
@ -737,7 +736,7 @@ static void Initialize(Handle<Object> target) {
|
|||||||
assert(r == ARES_SUCCESS);
|
assert(r == ARES_SUCCESS);
|
||||||
|
|
||||||
struct ares_options options;
|
struct ares_options options;
|
||||||
uv_ares_init_options(Loop(), &ares_channel, &options, 0);
|
uv_ares_init_options(uv_default_loop(), &ares_channel, &options, 0);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
|
|
||||||
NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
|
NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@ -110,15 +109,15 @@ Handle<Value> FSEventWrap::Start(const Arguments& args) {
|
|||||||
|
|
||||||
String::Utf8Value path(args[0]->ToString());
|
String::Utf8Value path(args[0]->ToString());
|
||||||
|
|
||||||
int r = uv_fs_event_init(Loop(), &wrap->handle_, *path, OnEvent, 0);
|
int r = uv_fs_event_init(uv_default_loop(), &wrap->handle_, *path, OnEvent, 0);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
// Check for persistent argument
|
// Check for persistent argument
|
||||||
if (!args[1]->IsTrue()) {
|
if (!args[1]->IsTrue()) {
|
||||||
uv_unref(Loop());
|
uv_unref(uv_default_loop());
|
||||||
}
|
}
|
||||||
wrap->initialized_ = true;
|
wrap->initialized_ = true;
|
||||||
} else {
|
} else {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
@ -146,7 +145,7 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
|
|||||||
// assumption that a rename implicitly means an attribute change. Not too
|
// assumption that a rename implicitly means an attribute change. Not too
|
||||||
// unreasonable, right? Still, we should revisit this before v1.0.
|
// unreasonable, right? Still, we should revisit this before v1.0.
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
eventStr = String::Empty();
|
eventStr = String::Empty();
|
||||||
}
|
}
|
||||||
else if (events & UV_RENAME) {
|
else if (events & UV_RENAME) {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
@ -71,7 +70,7 @@ Handle<Value> HandleWrap::Unref(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrap->unref = true;
|
wrap->unref = true;
|
||||||
uv_unref(Loop());
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
return v8::Undefined();
|
return v8::Undefined();
|
||||||
}
|
}
|
||||||
@ -89,7 +88,7 @@ Handle<Value> HandleWrap::Ref(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrap->unref = false;
|
wrap->unref = false;
|
||||||
uv_ref(Loop());
|
uv_ref(uv_default_loop());
|
||||||
|
|
||||||
return v8::Undefined();
|
return v8::Undefined();
|
||||||
}
|
}
|
||||||
|
109
src/ngx-queue.h
109
src/ngx-queue.h
@ -1,109 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Igor Sysoev
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _NGX_QUEUE_H_INCLUDED_
|
|
||||||
#define _NGX_QUEUE_H_INCLUDED_
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# include <stddef.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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_ */
|
|
294
src/node.cc
294
src/node.cc
@ -20,8 +20,6 @@
|
|||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_isolate.h>
|
|
||||||
#include <node_internals.h>
|
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
@ -92,66 +90,82 @@ using namespace v8;
|
|||||||
extern char **environ;
|
extern char **environ;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define check_tick_watcher NODE_VAR(check_tick_watcher)
|
|
||||||
#define code_symbol NODE_VAR(code_symbol)
|
|
||||||
#define emit_symbol NODE_VAR(emit_symbol)
|
|
||||||
#define errno_symbol NODE_VAR(errno_symbol)
|
|
||||||
#define errpath_symbol NODE_VAR(errpath_symbol)
|
|
||||||
#define gc_check NODE_VAR(gc_check)
|
|
||||||
#define gc_idle NODE_VAR(gc_idle)
|
|
||||||
#define gc_timer NODE_VAR(gc_timer)
|
|
||||||
#define getbuf NODE_VAR(getbuf)
|
|
||||||
#define heap_total_symbol NODE_VAR(heap_total_symbol)
|
|
||||||
#define heap_used_symbol NODE_VAR(heap_used_symbol)
|
|
||||||
#define listeners_symbol NODE_VAR(listeners_symbol)
|
|
||||||
#define need_tick_cb NODE_VAR(need_tick_cb)
|
|
||||||
#define prepare_tick_watcher NODE_VAR(prepare_tick_watcher)
|
|
||||||
#define process NODE_VAR(process)
|
|
||||||
#define rss_symbol NODE_VAR(rss_symbol)
|
|
||||||
#define syscall_symbol NODE_VAR(syscall_symbol)
|
|
||||||
#define tick_callback_sym NODE_VAR(tick_callback_sym)
|
|
||||||
#define tick_spinner NODE_VAR(tick_spinner)
|
|
||||||
#define tick_time_head NODE_VAR(tick_time_head)
|
|
||||||
#define tick_times NODE_VAR(tick_times)
|
|
||||||
#define uncaught_exception_symbol NODE_VAR(uncaught_exception_symbol)
|
|
||||||
#define use_npn NODE_VAR(use_npn)
|
|
||||||
#define use_sni NODE_VAR(use_sni)
|
|
||||||
#define uncaught_exception_counter NODE_VAR(uncaught_exception_counter)
|
|
||||||
#define binding_cache NODE_VAR(binding_cache)
|
|
||||||
#define module_load_list NODE_VAR(module_load_list)
|
|
||||||
#define node_isolate NODE_VAR(node_isolate)
|
|
||||||
#define debugger_running NODE_VAR(debugger_running)
|
|
||||||
#define prog_start_time NODE_VAR(prog_start_time)
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
#define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
|
|
||||||
|
|
||||||
static int option_end_index;
|
static Persistent<Object> process;
|
||||||
static unsigned long max_stack_size;
|
|
||||||
static unsigned short debug_port = 5858;
|
static Persistent<String> errno_symbol;
|
||||||
static bool debug_wait_connect;
|
static Persistent<String> syscall_symbol;
|
||||||
static bool use_debug_agent;
|
static Persistent<String> errpath_symbol;
|
||||||
static const char* eval_string;
|
static Persistent<String> code_symbol;
|
||||||
static bool print_eval;
|
|
||||||
|
static Persistent<String> rss_symbol;
|
||||||
|
static Persistent<String> heap_total_symbol;
|
||||||
|
static Persistent<String> heap_used_symbol;
|
||||||
|
|
||||||
|
static Persistent<String> listeners_symbol;
|
||||||
|
static Persistent<String> uncaught_exception_symbol;
|
||||||
|
static Persistent<String> emit_symbol;
|
||||||
|
|
||||||
|
|
||||||
|
static bool print_eval = false;
|
||||||
|
static char *eval_string = NULL;
|
||||||
|
static int option_end_index = 0;
|
||||||
|
static bool use_debug_agent = false;
|
||||||
|
static bool debug_wait_connect = false;
|
||||||
|
static int debug_port=5858;
|
||||||
|
static int max_stack_size = 0;
|
||||||
|
|
||||||
|
static uv_check_t check_tick_watcher;
|
||||||
|
static uv_prepare_t prepare_tick_watcher;
|
||||||
|
static uv_idle_t tick_spinner;
|
||||||
|
static bool need_tick_cb;
|
||||||
|
static Persistent<String> tick_callback_sym;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
static bool use_npn = true;
|
||||||
|
#else
|
||||||
|
static bool use_npn = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||||
|
static bool use_sni = true;
|
||||||
|
#else
|
||||||
|
static bool use_sni = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __POSIX__
|
||||||
|
// Buffer for getpwnam_r(), getgrpam_r() and other misc callers; keep this
|
||||||
|
// scoped at file-level rather than method-level to avoid excess stack usage.
|
||||||
|
static char getbuf[PATH_MAX + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We need to notify V8 when we're idle so that it can run the garbage
|
||||||
|
// collector. The interface to this is V8::IdleNotification(). It returns
|
||||||
|
// true if the heap hasn't be fully compacted, and needs to be run again.
|
||||||
|
// Returning false means that it doesn't have anymore work to do.
|
||||||
|
//
|
||||||
|
// A rather convoluted algorithm has been devised to determine when Node is
|
||||||
|
// idle. You'll have to figure it out for yourself.
|
||||||
|
static uv_check_t gc_check;
|
||||||
|
static uv_idle_t gc_idle;
|
||||||
|
static uv_timer_t gc_timer;
|
||||||
|
bool need_gc;
|
||||||
|
|
||||||
|
// process-relative uptime base, initialized at start-up
|
||||||
|
static double prog_start_time;
|
||||||
|
|
||||||
|
#define FAST_TICK 700.
|
||||||
|
#define GC_WAIT_TIME 5000.
|
||||||
|
#define RPM_SAMPLES 100
|
||||||
|
#define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
|
||||||
|
static int64_t tick_times[RPM_SAMPLES];
|
||||||
|
static int tick_time_head;
|
||||||
|
|
||||||
static void CheckStatus(uv_timer_t* watcher, int status);
|
static void CheckStatus(uv_timer_t* watcher, int status);
|
||||||
|
|
||||||
|
|
||||||
uv_loop_t* Loop() {
|
|
||||||
#if defined(HAVE_ISOLATES) && HAVE_ISOLATES
|
|
||||||
return Isolate::GetCurrent()->GetLoop();
|
|
||||||
#else
|
|
||||||
return uv_default_loop();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void StartGCTimer () {
|
static void StartGCTimer () {
|
||||||
if (!uv_is_active((uv_handle_t*) &gc_timer)) {
|
if (!uv_is_active((uv_handle_t*) &gc_timer)) {
|
||||||
uv_timer_start(&gc_timer, node::CheckStatus, 5000, 5000);
|
uv_timer_start(&gc_timer, node::CheckStatus, 5000, 5000);
|
||||||
@ -178,7 +192,7 @@ static void Idle(uv_idle_t* watcher, int status) {
|
|||||||
static void Check(uv_check_t* watcher, int status) {
|
static void Check(uv_check_t* watcher, int status) {
|
||||||
assert(watcher == &gc_check);
|
assert(watcher == &gc_check);
|
||||||
|
|
||||||
tick_times[tick_time_head] = uv_now(Loop());
|
tick_times[tick_time_head] = uv_now(uv_default_loop());
|
||||||
tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
|
tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
|
||||||
|
|
||||||
StartGCTimer();
|
StartGCTimer();
|
||||||
@ -208,7 +222,7 @@ static void Tick(void) {
|
|||||||
need_tick_cb = false;
|
need_tick_cb = false;
|
||||||
if (uv_is_active((uv_handle_t*) &tick_spinner)) {
|
if (uv_is_active((uv_handle_t*) &tick_spinner)) {
|
||||||
uv_idle_stop(&tick_spinner);
|
uv_idle_stop(&tick_spinner);
|
||||||
uv_unref(Loop());
|
uv_unref(uv_default_loop());
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
@ -250,7 +264,7 @@ static Handle<Value> NeedTickCallback(const Arguments& args) {
|
|||||||
// tick_spinner to keep the event loop alive long enough to handle it.
|
// tick_spinner to keep the event loop alive long enough to handle it.
|
||||||
if (!uv_is_active((uv_handle_t*) &tick_spinner)) {
|
if (!uv_is_active((uv_handle_t*) &tick_spinner)) {
|
||||||
uv_idle_start(&tick_spinner, Spin);
|
uv_idle_start(&tick_spinner, Spin);
|
||||||
uv_ref(Loop());
|
uv_ref(uv_default_loop());
|
||||||
}
|
}
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
@ -1506,7 +1520,7 @@ static void CheckStatus(uv_timer_t* watcher, int status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double d = uv_now(Loop()) - TICK_TIME(3);
|
double d = uv_now(uv_default_loop()) - TICK_TIME(3);
|
||||||
|
|
||||||
//printfb("timer d = %f\n", d);
|
//printfb("timer d = %f\n", d);
|
||||||
|
|
||||||
@ -1535,7 +1549,7 @@ static Handle<Value> Uptime(const Arguments& args) {
|
|||||||
v8::Handle<v8::Value> UVCounters(const v8::Arguments& args) {
|
v8::Handle<v8::Value> UVCounters(const v8::Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
uv_counters_t* c = &Loop()->counters;
|
uv_counters_t* c = &uv_default_loop()->counters;
|
||||||
|
|
||||||
Local<Object> obj = Object::New();
|
Local<Object> obj = Object::New();
|
||||||
|
|
||||||
@ -1730,6 +1744,7 @@ static void OnFatalError(const char* location, const char* message) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uncaught_exception_counter = 0;
|
||||||
|
|
||||||
void FatalException(TryCatch &try_catch) {
|
void FatalException(TryCatch &try_catch) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
@ -1789,6 +1804,9 @@ static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Persistent<Object> binding_cache;
|
||||||
|
Persistent<Array> module_load_list;
|
||||||
|
|
||||||
static Handle<Value> Binding(const Arguments& args) {
|
static Handle<Value> Binding(const Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
@ -1974,15 +1992,6 @@ static Handle<Object> GetFeatures() {
|
|||||||
obj->Set(String::NewSymbol("tls"),
|
obj->Set(String::NewSymbol("tls"),
|
||||||
Boolean::New(get_builtin_module("crypto") != NULL));
|
Boolean::New(get_builtin_module("crypto") != NULL));
|
||||||
|
|
||||||
|
|
||||||
obj->Set(String::NewSymbol("isolates"),
|
|
||||||
#if HAVE_ISOLATES
|
|
||||||
True()
|
|
||||||
#else
|
|
||||||
False()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
return scope.Close(obj);
|
return scope.Close(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1999,6 +2008,7 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
|||||||
|
|
||||||
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
|
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
|
||||||
|
|
||||||
|
|
||||||
process->SetAccessor(String::New("title"),
|
process->SetAccessor(String::New("title"),
|
||||||
ProcessTitleGetter,
|
ProcessTitleGetter,
|
||||||
ProcessTitleSetter);
|
ProcessTitleSetter);
|
||||||
@ -2292,6 +2302,9 @@ static void ParseArgs(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Isolate* node_isolate = NULL;
|
||||||
|
static volatile bool debugger_running = false;
|
||||||
|
|
||||||
static void EnableDebug(bool wait_connect) {
|
static void EnableDebug(bool wait_connect) {
|
||||||
// If we're called from another thread, make sure to enter the right
|
// If we're called from another thread, make sure to enter the right
|
||||||
// v8 isolate.
|
// v8 isolate.
|
||||||
@ -2322,7 +2335,6 @@ static void EnableDebug(bool wait_connect) {
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
// FIXME this is positively unsafe with isolates/threads
|
|
||||||
static void EnableDebugSignalHandler(int signal) {
|
static void EnableDebugSignalHandler(int signal) {
|
||||||
// Break once process will return execution to v8
|
// Break once process will return execution to v8
|
||||||
v8::Debug::DebugBreak(node_isolate);
|
v8::Debug::DebugBreak(node_isolate);
|
||||||
@ -2525,7 +2537,10 @@ static Handle<Value> DebugPause(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char** ProcessInit(int argc, char *argv[]) {
|
char** Init(int argc, char *argv[]) {
|
||||||
|
// Initialize prog_start_time to get relative uptime.
|
||||||
|
uv_uptime(&prog_start_time);
|
||||||
|
|
||||||
// Hack aroung with the argv pointer. Used for process.title = "blah".
|
// Hack aroung with the argv pointer. Used for process.title = "blah".
|
||||||
argv = uv_setup_args(argc, argv);
|
argv = uv_setup_args(argc, argv);
|
||||||
|
|
||||||
@ -2565,11 +2580,48 @@ char** ProcessInit(int argc, char *argv[]) {
|
|||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
// Ignore SIGPIPE
|
// Ignore SIGPIPE
|
||||||
RegisterSignalHandler(SIGPIPE, SIG_IGN);
|
RegisterSignalHandler(SIGPIPE, SIG_IGN);
|
||||||
// TODO decide whether to handle these signals per-process or per-thread
|
|
||||||
RegisterSignalHandler(SIGINT, SignalExit);
|
RegisterSignalHandler(SIGINT, SignalExit);
|
||||||
RegisterSignalHandler(SIGTERM, SignalExit);
|
RegisterSignalHandler(SIGTERM, SignalExit);
|
||||||
#endif // __POSIX__
|
#endif // __POSIX__
|
||||||
|
|
||||||
|
uv_prepare_init(uv_default_loop(), &prepare_tick_watcher);
|
||||||
|
uv_prepare_start(&prepare_tick_watcher, PrepareTick);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
uv_check_init(uv_default_loop(), &check_tick_watcher);
|
||||||
|
uv_check_start(&check_tick_watcher, node::CheckTick);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
uv_idle_init(uv_default_loop(), &tick_spinner);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
uv_check_init(uv_default_loop(), &gc_check);
|
||||||
|
uv_check_start(&gc_check, node::Check);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
uv_idle_init(uv_default_loop(), &gc_idle);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
uv_timer_init(uv_default_loop(), &gc_timer);
|
||||||
|
uv_unref(uv_default_loop());
|
||||||
|
|
||||||
|
V8::SetFatalErrorHandler(node::OnFatalError);
|
||||||
|
|
||||||
|
// Fetch a reference to the main isolate, so we have a reference to it
|
||||||
|
// even when we need it to access it from another (debugger) thread.
|
||||||
|
node_isolate = Isolate::GetCurrent();
|
||||||
|
|
||||||
|
// If the --debug flag was specified then initialize the debug thread.
|
||||||
|
if (use_debug_agent) {
|
||||||
|
EnableDebug(debug_wait_connect);
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
RegisterDebugSignalHandler();
|
||||||
|
#else // Posix
|
||||||
|
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
|
||||||
|
#endif // __POSIX__
|
||||||
|
}
|
||||||
|
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2588,77 +2640,19 @@ void EmitExit(v8::Handle<v8::Object> process_l) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create a new isolate with node::Isolate::New() before you call this function
|
int Start(int argc, char *argv[]) {
|
||||||
void StartThread(node::Isolate* isolate,
|
// This needs to run *before* V8::Initialize()
|
||||||
int argc,
|
argv = Init(argc, argv);
|
||||||
char** argv) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
assert(node::Isolate::GetCurrent() == isolate);
|
v8::V8::Initialize();
|
||||||
|
v8::HandleScope handle_scope;
|
||||||
|
|
||||||
uv_loop_t* loop = isolate->GetLoop();
|
// Create the one and only Context.
|
||||||
uv_prepare_init(loop, &prepare_tick_watcher);
|
Persistent<v8::Context> context = v8::Context::New();
|
||||||
uv_prepare_start(&prepare_tick_watcher, PrepareTick);
|
v8::Context::Scope context_scope(context);
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
uv_check_init(loop, &check_tick_watcher);
|
|
||||||
uv_check_start(&check_tick_watcher, node::CheckTick);
|
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
uv_idle_init(loop, &tick_spinner);
|
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
uv_check_init(loop, &gc_check);
|
|
||||||
uv_check_start(&gc_check, node::Check);
|
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
uv_idle_init(loop, &gc_idle);
|
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
uv_timer_init(loop, &gc_timer);
|
|
||||||
uv_unref(loop);
|
|
||||||
|
|
||||||
V8::SetFatalErrorHandler(node::OnFatalError);
|
|
||||||
|
|
||||||
// Fetch a reference to the main isolate, so we have a reference to it
|
|
||||||
// even when we need it to access it from another (debugger) thread.
|
|
||||||
node_isolate = v8::Isolate::GetCurrent();
|
|
||||||
|
|
||||||
// Only main isolate is allowed to run a debug agent and listen for signals
|
|
||||||
if (isolate->id_ == 1) {
|
|
||||||
// If the --debug flag was specified then initialize the debug thread.
|
|
||||||
if (use_debug_agent) {
|
|
||||||
EnableDebug(debug_wait_connect);
|
|
||||||
} else {
|
|
||||||
#ifdef _WIN32
|
|
||||||
RegisterDebugSignalHandler();
|
|
||||||
#else // Posix
|
|
||||||
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
|
|
||||||
#endif // __POSIX__
|
|
||||||
}
|
|
||||||
} else if (isolate->debug_state != Isolate::kNone) {
|
|
||||||
isolate->debugger_instance->Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Object> process_l = SetupProcessObject(argc, argv);
|
Handle<Object> process_l = SetupProcessObject(argc, argv);
|
||||||
|
v8_typed_array::AttachBindings(context->Global());
|
||||||
process_l->Set(String::NewSymbol("tid"),
|
|
||||||
Integer::NewFromUnsigned(isolate->id_));
|
|
||||||
|
|
||||||
// TODO check (isolate->channel_ != NULL)
|
|
||||||
if (isolate->id_ > 1) {
|
|
||||||
process_l->Set(String::NewSymbol("_send"),
|
|
||||||
FunctionTemplate::New(Isolate::Send)->GetFunction());
|
|
||||||
|
|
||||||
process_l->Set(String::NewSymbol("_exit"),
|
|
||||||
FunctionTemplate::New(Isolate::Unref)->GetFunction());
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME crashes with "CHECK(heap->isolate() == Isolate::Current()) failed"
|
|
||||||
//v8_typed_array::AttachBindings(v8::Context::GetCurrent()->Global());
|
|
||||||
|
|
||||||
// Initialize prog_start_time to get relative uptime.
|
|
||||||
uv_uptime(&prog_start_time);
|
|
||||||
|
|
||||||
// Create all the objects, load modules, do everything.
|
// Create all the objects, load modules, do everything.
|
||||||
// so your next reading stop should be node::Load()!
|
// so your next reading stop should be node::Load()!
|
||||||
@ -2669,29 +2663,13 @@ void StartThread(node::Isolate* isolate,
|
|||||||
// there are no watchers on the loop (except for the ones that were
|
// there are no watchers on the loop (except for the ones that were
|
||||||
// uv_unref'd) then this function exits. As long as there are active
|
// uv_unref'd) then this function exits. As long as there are active
|
||||||
// watchers, it blocks.
|
// watchers, it blocks.
|
||||||
uv_run(loop);
|
uv_run(uv_default_loop());
|
||||||
|
|
||||||
EmitExit(process_l);
|
EmitExit(process_l);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Start(int argc, char *argv[]) {
|
|
||||||
// This needs to run *before* V8::Initialize()
|
|
||||||
argv = ProcessInit(argc, argv);
|
|
||||||
|
|
||||||
v8::V8::Initialize();
|
|
||||||
v8::HandleScope handle_scope;
|
|
||||||
|
|
||||||
// Create the main node::Isolate object
|
|
||||||
node::Isolate::Initialize();
|
|
||||||
Isolate* isolate = new node::Isolate();
|
|
||||||
isolate->tid_ = (uv_thread_t) -1;
|
|
||||||
isolate->Enter();
|
|
||||||
StartThread(isolate, argc, argv);
|
|
||||||
isolate->Dispose();
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Clean up.
|
// Clean up.
|
||||||
|
context.Dispose();
|
||||||
V8::Dispose();
|
V8::Dispose();
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
@ -84,10 +84,6 @@ v8::Handle<v8::Object> SetupProcessObject(int argc, char *argv[]);
|
|||||||
void Load(v8::Handle<v8::Object> process);
|
void Load(v8::Handle<v8::Object> process);
|
||||||
void EmitExit(v8::Handle<v8::Object> process);
|
void EmitExit(v8::Handle<v8::Object> process);
|
||||||
|
|
||||||
// Returns the loop for the current isolate. If compiled with
|
|
||||||
// --without-isolates then this will always return uv_default_loop();
|
|
||||||
uv_loop_t* Loop();
|
|
||||||
|
|
||||||
#define NODE_PSYMBOL(s) \
|
#define NODE_PSYMBOL(s) \
|
||||||
v8::Persistent<v8::String>::New(v8::String::NewSymbol(s))
|
v8::Persistent<v8::String>::New(v8::String::NewSymbol(s))
|
||||||
|
|
||||||
|
32
src/node.js
32
src/node.js
@ -120,33 +120,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.tid === 1) return;
|
|
||||||
|
|
||||||
var net = NativeModule.require('net');
|
|
||||||
|
|
||||||
// isolate initialization
|
|
||||||
process.send = function(msg, sendHandle) {
|
|
||||||
if (typeof msg === 'undefined') throw new TypeError('Bad argument.');
|
|
||||||
msg = JSON.stringify(msg);
|
|
||||||
msg = new Buffer(msg);
|
|
||||||
|
|
||||||
// Update simultaneous accepts on Windows
|
|
||||||
net._setSimultaneousAccepts(sendHandle);
|
|
||||||
|
|
||||||
return process._send(msg, sendHandle);
|
|
||||||
};
|
|
||||||
|
|
||||||
process._onmessage = function(msg, recvHandle) {
|
|
||||||
msg = JSON.parse('' + msg);
|
|
||||||
|
|
||||||
// Update simultaneous accepts on Windows
|
|
||||||
net._setSimultaneousAccepts(recvHandle);
|
|
||||||
|
|
||||||
process.emit('message', msg, recvHandle);
|
|
||||||
};
|
|
||||||
|
|
||||||
process.exit = process._exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startup.globalVariables = function() {
|
startup.globalVariables = function() {
|
||||||
@ -455,11 +428,6 @@
|
|||||||
|
|
||||||
cp._forkChild();
|
cp._forkChild();
|
||||||
assert(process.send);
|
assert(process.send);
|
||||||
} else if (process.tid !== 1) {
|
|
||||||
// Load tcp_wrap to avoid situation where we might immediately receive
|
|
||||||
// a message.
|
|
||||||
// FIXME is this really necessary?
|
|
||||||
process.binding('tcp_wrap');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,12 +36,6 @@
|
|||||||
|
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
#define length_symbol NODE_VAR(length_symbol)
|
|
||||||
#define chars_written_sym NODE_VAR(chars_written_sym)
|
|
||||||
#define write_sym NODE_VAR(write_sym)
|
|
||||||
#define buffer_constructor_template NODE_VAR(buffer_constructor_template)
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
@ -67,6 +61,10 @@ using namespace v8;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Persistent<String> length_symbol;
|
||||||
|
static Persistent<String> chars_written_sym;
|
||||||
|
static Persistent<String> write_sym;
|
||||||
|
Persistent<FunctionTemplate> Buffer::constructor_template;
|
||||||
|
|
||||||
|
|
||||||
static inline size_t base64_decoded_size(const char *src, size_t size) {
|
static inline size_t base64_decoded_size(const char *src, size_t size) {
|
||||||
@ -132,7 +130,7 @@ Buffer* Buffer::New(size_t length) {
|
|||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<Value> arg = Integer::NewFromUnsigned(length);
|
Local<Value> arg = Integer::NewFromUnsigned(length);
|
||||||
Local<Object> b = buffer_constructor_template->GetFunction()->NewInstance(1, &arg);
|
Local<Object> b = constructor_template->GetFunction()->NewInstance(1, &arg);
|
||||||
if (b.IsEmpty()) return NULL;
|
if (b.IsEmpty()) return NULL;
|
||||||
|
|
||||||
return ObjectWrap::Unwrap<Buffer>(b);
|
return ObjectWrap::Unwrap<Buffer>(b);
|
||||||
@ -143,7 +141,7 @@ Buffer* Buffer::New(char* data, size_t length) {
|
|||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<Value> arg = Integer::NewFromUnsigned(0);
|
Local<Value> arg = Integer::NewFromUnsigned(0);
|
||||||
Local<Object> obj = buffer_constructor_template->GetFunction()->NewInstance(1, &arg);
|
Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
|
||||||
|
|
||||||
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
|
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
|
||||||
buffer->Replace(data, length, NULL, NULL);
|
buffer->Replace(data, length, NULL, NULL);
|
||||||
@ -157,7 +155,7 @@ Buffer* Buffer::New(char *data, size_t length,
|
|||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<Value> arg = Integer::NewFromUnsigned(0);
|
Local<Value> arg = Integer::NewFromUnsigned(0);
|
||||||
Local<Object> obj = buffer_constructor_template->GetFunction()->NewInstance(1, &arg);
|
Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
|
||||||
|
|
||||||
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
|
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
|
||||||
buffer->Replace(data, length, callback, hint);
|
buffer->Replace(data, length, callback, hint);
|
||||||
@ -168,7 +166,7 @@ Buffer* Buffer::New(char *data, size_t length,
|
|||||||
|
|
||||||
Handle<Value> Buffer::New(const Arguments &args) {
|
Handle<Value> Buffer::New(const Arguments &args) {
|
||||||
if (!args.IsConstructCall()) {
|
if (!args.IsConstructCall()) {
|
||||||
return FromConstructorTemplate(buffer_constructor_template, args);
|
return FromConstructorTemplate(constructor_template, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
@ -470,7 +468,7 @@ Handle<Value> Buffer::Utf8Write(const Arguments &args) {
|
|||||||
int length = s->Length();
|
int length = s->Length();
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(0));
|
Integer::New(0));
|
||||||
return scope.Close(Integer::New(0));
|
return scope.Close(Integer::New(0));
|
||||||
}
|
}
|
||||||
@ -494,7 +492,7 @@ Handle<Value> Buffer::Utf8Write(const Arguments &args) {
|
|||||||
(String::HINT_MANY_WRITES_EXPECTED |
|
(String::HINT_MANY_WRITES_EXPECTED |
|
||||||
String::NO_NULL_TERMINATION));
|
String::NO_NULL_TERMINATION));
|
||||||
|
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(char_written));
|
Integer::New(char_written));
|
||||||
|
|
||||||
return scope.Close(Integer::New(written));
|
return scope.Close(Integer::New(written));
|
||||||
@ -532,7 +530,7 @@ Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
|
|||||||
(String::HINT_MANY_WRITES_EXPECTED |
|
(String::HINT_MANY_WRITES_EXPECTED |
|
||||||
String::NO_NULL_TERMINATION));
|
String::NO_NULL_TERMINATION));
|
||||||
|
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(written));
|
Integer::New(written));
|
||||||
|
|
||||||
return scope.Close(Integer::New(written * 2));
|
return scope.Close(Integer::New(written * 2));
|
||||||
@ -571,7 +569,7 @@ Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
|
|||||||
(String::HINT_MANY_WRITES_EXPECTED |
|
(String::HINT_MANY_WRITES_EXPECTED |
|
||||||
String::NO_NULL_TERMINATION));
|
String::NO_NULL_TERMINATION));
|
||||||
|
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(written));
|
Integer::New(written));
|
||||||
|
|
||||||
return scope.Close(Integer::New(written));
|
return scope.Close(Integer::New(written));
|
||||||
@ -661,7 +659,7 @@ Handle<Value> Buffer::Base64Write(const Arguments &args) {
|
|||||||
*dst++ = ((c & 0x03) << 6) | (d & 0x3F);
|
*dst++ = ((c & 0x03) << 6) | (d & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(s.length()));
|
Integer::New(s.length()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(dst - start));
|
return scope.Close(Integer::New(dst - start));
|
||||||
@ -695,7 +693,7 @@ Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
|
|||||||
|
|
||||||
int written = DecodeWrite(p, max_length, s, BINARY);
|
int written = DecodeWrite(p, max_length, s, BINARY);
|
||||||
|
|
||||||
buffer_constructor_template->GetFunction()->Set(chars_written_sym,
|
constructor_template->GetFunction()->Set(chars_written_sym,
|
||||||
Integer::New(written));
|
Integer::New(written));
|
||||||
|
|
||||||
return scope.Close(Integer::New(written));
|
return scope.Close(Integer::New(written));
|
||||||
@ -747,7 +745,7 @@ bool Buffer::HasInstance(v8::Handle<v8::Value> val) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Also check for SlowBuffers that are empty.
|
// Also check for SlowBuffers that are empty.
|
||||||
if (buffer_constructor_template->HasInstance(obj))
|
if (constructor_template->HasInstance(obj))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -761,35 +759,35 @@ void Buffer::Initialize(Handle<Object> target) {
|
|||||||
chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
|
chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
|
||||||
buffer_constructor_template = Persistent<FunctionTemplate>::New(t);
|
constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||||
buffer_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
buffer_constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
|
constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
|
||||||
|
|
||||||
// copy free
|
// copy free
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "binarySlice", Buffer::BinarySlice);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "asciiSlice", Buffer::AsciiSlice);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "base64Slice", Buffer::Base64Slice);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
|
||||||
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
|
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
|
||||||
// copy
|
// copy
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "utf8Slice", Buffer::Utf8Slice);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "utf8Write", Buffer::Utf8Write);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "asciiWrite", Buffer::AsciiWrite);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "binaryWrite", Buffer::BinaryWrite);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "base64Write", Buffer::Base64Write);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "ucs2Write", Buffer::Ucs2Write);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "fill", Buffer::Fill);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill);
|
||||||
NODE_SET_PROTOTYPE_METHOD(buffer_constructor_template, "copy", Buffer::Copy);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
|
||||||
|
|
||||||
NODE_SET_METHOD(buffer_constructor_template->GetFunction(),
|
NODE_SET_METHOD(constructor_template->GetFunction(),
|
||||||
"byteLength",
|
"byteLength",
|
||||||
Buffer::ByteLength);
|
Buffer::ByteLength);
|
||||||
NODE_SET_METHOD(buffer_constructor_template->GetFunction(),
|
NODE_SET_METHOD(constructor_template->GetFunction(),
|
||||||
"makeFastBuffer",
|
"makeFastBuffer",
|
||||||
Buffer::MakeFastBuffer);
|
Buffer::MakeFastBuffer);
|
||||||
|
|
||||||
target->Set(String::NewSymbol("SlowBuffer"), buffer_constructor_template->GetFunction());
|
target->Set(String::NewSymbol("SlowBuffer"), constructor_template->GetFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ namespace node {
|
|||||||
|
|
||||||
class NODE_EXTERN Buffer: public ObjectWrap {
|
class NODE_EXTERN Buffer: public ObjectWrap {
|
||||||
public:
|
public:
|
||||||
|
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||||
|
|
||||||
static bool HasInstance(v8::Handle<v8::Value> val);
|
static bool HasInstance(v8::Handle<v8::Value> val);
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <node_root_certs.h>
|
#include <node_root_certs.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -64,34 +63,29 @@ static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL
|
|||||||
| XN_FLAG_SEP_MULTILINE
|
| XN_FLAG_SEP_MULTILINE
|
||||||
| XN_FLAG_FN_SN;
|
| XN_FLAG_FN_SN;
|
||||||
|
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define on_headers_sym NODE_VAR(on_headers_sym)
|
|
||||||
#define errno_symbol NODE_VAR(errno_symbol)
|
|
||||||
#define syscall_symbol NODE_VAR(syscall_symbol)
|
|
||||||
#define subject_symbol NODE_VAR(subject_symbol)
|
|
||||||
#define subjectaltname_symbol NODE_VAR(subjectaltname_symbol)
|
|
||||||
#define modulus_symbol NODE_VAR(modulus_symbol)
|
|
||||||
#define exponent_symbol NODE_VAR(exponent_symbol)
|
|
||||||
#define issuer_symbol NODE_VAR(issuer_symbol)
|
|
||||||
#define valid_from_symbol NODE_VAR(valid_from_symbol)
|
|
||||||
#define valid_to_symbol NODE_VAR(valid_to_symbol)
|
|
||||||
#define fingerprint_symbol NODE_VAR(fingerprint_symbol)
|
|
||||||
#define name_symbol NODE_VAR(name_symbol)
|
|
||||||
#define version_symbol NODE_VAR(version_symbol)
|
|
||||||
#define ext_key_usage_symbol NODE_VAR(ext_key_usage_symbol)
|
|
||||||
#define secure_context_constructor NODE_VAR(secure_context_constructor)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
namespace crypto {
|
namespace crypto {
|
||||||
|
|
||||||
static uv_rwlock_t* locks;
|
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
|
||||||
|
static Persistent<String> errno_symbol;
|
||||||
|
static Persistent<String> syscall_symbol;
|
||||||
|
static Persistent<String> subject_symbol;
|
||||||
|
static Persistent<String> subjectaltname_symbol;
|
||||||
|
static Persistent<String> modulus_symbol;
|
||||||
|
static Persistent<String> exponent_symbol;
|
||||||
|
static Persistent<String> issuer_symbol;
|
||||||
|
static Persistent<String> valid_from_symbol;
|
||||||
|
static Persistent<String> valid_to_symbol;
|
||||||
|
static Persistent<String> fingerprint_symbol;
|
||||||
|
static Persistent<String> name_symbol;
|
||||||
|
static Persistent<String> version_symbol;
|
||||||
|
static Persistent<String> ext_key_usage_symbol;
|
||||||
|
|
||||||
|
static Persistent<FunctionTemplate> secure_context_constructor;
|
||||||
|
|
||||||
|
static uv_rwlock_t* locks;
|
||||||
|
|
||||||
|
|
||||||
static unsigned long crypto_id_cb(void) {
|
static unsigned long crypto_id_cb(void) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -4165,8 +4159,7 @@ PBKDF2(const Arguments& args) {
|
|||||||
|
|
||||||
req = new uv_work_t();
|
req = new uv_work_t();
|
||||||
req->data = request;
|
req->data = request;
|
||||||
uv_queue_work(Loop(), req, EIO_PBKDF2, EIO_PBKDF2After);
|
uv_queue_work(uv_default_loop(), req, EIO_PBKDF2, EIO_PBKDF2After);
|
||||||
|
|
||||||
return Undefined();
|
return Undefined();
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -4288,7 +4281,7 @@ Handle<Value> RandomBytes(const Arguments& args) {
|
|||||||
Local<Function> callback_v = Local<Function>(Function::Cast(*args[1]));
|
Local<Function> callback_v = Local<Function>(Function::Cast(*args[1]));
|
||||||
req->callback_ = Persistent<Function>::New(callback_v);
|
req->callback_ = Persistent<Function>::New(callback_v);
|
||||||
|
|
||||||
uv_queue_work(Loop(),
|
uv_queue_work(uv_default_loop(),
|
||||||
&req->work_req_,
|
&req->work_req_,
|
||||||
RandomBytesWork<generator>,
|
RandomBytesWork<generator>,
|
||||||
RandomBytesAfter<generator>);
|
RandomBytesAfter<generator>);
|
||||||
|
@ -35,10 +35,6 @@ NODE_EXT_LIST_ITEM(node_signal_watcher)
|
|||||||
NODE_EXT_LIST_ITEM(node_os)
|
NODE_EXT_LIST_ITEM(node_os)
|
||||||
NODE_EXT_LIST_ITEM(node_zlib)
|
NODE_EXT_LIST_ITEM(node_zlib)
|
||||||
|
|
||||||
#if defined(HAVE_ISOLATES) && HAVE_ISOLATES
|
|
||||||
NODE_EXT_LIST_ITEM(node_isolates)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// libuv rewrite
|
// libuv rewrite
|
||||||
NODE_EXT_LIST_ITEM(node_timer_wrap)
|
NODE_EXT_LIST_ITEM(node_timer_wrap)
|
||||||
NODE_EXT_LIST_ITEM(node_tcp_wrap)
|
NODE_EXT_LIST_ITEM(node_tcp_wrap)
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "node_file.h"
|
#include "node_file.h"
|
||||||
#include "node_buffer.h"
|
#include "node_buffer.h"
|
||||||
#include <node_vars.h>
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
# include "node_stat_watcher.h"
|
# include "node_stat_watcher.h"
|
||||||
#endif
|
#endif
|
||||||
@ -41,30 +40,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define on_headers_sym NODE_VAR(on_headers_sym)
|
|
||||||
#define encoding_symbol NODE_VAR(encoding_symbol)
|
|
||||||
#define errno_symbol NODE_VAR(errno_symbol)
|
|
||||||
#define buf_symbol NODE_VAR(buf_symbol)
|
|
||||||
#define oncomplete_sym NODE_VAR(oncomplete_sym)
|
|
||||||
#define stats_constructor_template NODE_VAR(stats_constructor_template)
|
|
||||||
#define dev_symbol NODE_VAR(dev_symbol)
|
|
||||||
#define ino_symbol NODE_VAR(ino_symbol)
|
|
||||||
#define mode_symbol NODE_VAR(mode_symbol)
|
|
||||||
#define nlink_symbol NODE_VAR(nlink_symbol)
|
|
||||||
#define uid_symbol NODE_VAR(uid_symbol)
|
|
||||||
#define gid_symbol NODE_VAR(gid_symbol)
|
|
||||||
#define rdev_symbol NODE_VAR(rdev_symbol)
|
|
||||||
#define size_symbol NODE_VAR(size_symbol)
|
|
||||||
#define blksize_symbol NODE_VAR(blksize_symbol)
|
|
||||||
#define blocks_symbol NODE_VAR(blocks_symbol)
|
|
||||||
#define atime_symbol NODE_VAR(atime_symbol)
|
|
||||||
#define mtime_symbol NODE_VAR(mtime_symbol)
|
|
||||||
#define ctime_symbol NODE_VAR(ctime_symbol)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
@ -78,6 +53,11 @@ using namespace v8;
|
|||||||
|
|
||||||
typedef class ReqWrap<uv_fs_t> FSReqWrap;
|
typedef class ReqWrap<uv_fs_t> FSReqWrap;
|
||||||
|
|
||||||
|
static Persistent<String> encoding_symbol;
|
||||||
|
static Persistent<String> errno_symbol;
|
||||||
|
static Persistent<String> buf_symbol;
|
||||||
|
static Persistent<String> oncomplete_sym;
|
||||||
|
|
||||||
|
|
||||||
#ifdef _LARGEFILE_SOURCE
|
#ifdef _LARGEFILE_SOURCE
|
||||||
static inline int IsInt64(double x) {
|
static inline int IsInt64(double x) {
|
||||||
@ -229,7 +209,7 @@ struct fs_req_wrap {
|
|||||||
|
|
||||||
#define ASYNC_CALL(func, callback, ...) \
|
#define ASYNC_CALL(func, callback, ...) \
|
||||||
FSReqWrap* req_wrap = new FSReqWrap(); \
|
FSReqWrap* req_wrap = new FSReqWrap(); \
|
||||||
int r = uv_fs_##func(Loop(), &req_wrap->req_, \
|
int r = uv_fs_##func(uv_default_loop(), &req_wrap->req_, \
|
||||||
__VA_ARGS__, After); \
|
__VA_ARGS__, After); \
|
||||||
req_wrap->object_->Set(oncomplete_sym, callback); \
|
req_wrap->object_->Set(oncomplete_sym, callback); \
|
||||||
req_wrap->Dispatched(); \
|
req_wrap->Dispatched(); \
|
||||||
@ -237,16 +217,16 @@ struct fs_req_wrap {
|
|||||||
uv_fs_t* req = &req_wrap->req_; \
|
uv_fs_t* req = &req_wrap->req_; \
|
||||||
req->result = r; \
|
req->result = r; \
|
||||||
req->path = NULL; \
|
req->path = NULL; \
|
||||||
req->errorno = uv_last_error(Loop()).code; \
|
req->errorno = uv_last_error(uv_default_loop()).code; \
|
||||||
After(req); \
|
After(req); \
|
||||||
} \
|
} \
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
|
|
||||||
#define SYNC_CALL(func, path, ...) \
|
#define SYNC_CALL(func, path, ...) \
|
||||||
fs_req_wrap req_wrap; \
|
fs_req_wrap req_wrap; \
|
||||||
int result = uv_fs_##func(Loop(), &req_wrap.req, __VA_ARGS__, NULL); \
|
int result = uv_fs_##func(uv_default_loop(), &req_wrap.req, __VA_ARGS__, NULL); \
|
||||||
if (result < 0) { \
|
if (result < 0) { \
|
||||||
int code = uv_last_error(Loop()).code; \
|
int code = uv_last_error(uv_default_loop()).code; \
|
||||||
return ThrowException(UVException(code, #func, "", path)); \
|
return ThrowException(UVException(code, #func, "", path)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +253,22 @@ static Handle<Value> Close(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Persistent<FunctionTemplate> stats_constructor_template;
|
||||||
|
|
||||||
|
static Persistent<String> dev_symbol;
|
||||||
|
static Persistent<String> ino_symbol;
|
||||||
|
static Persistent<String> mode_symbol;
|
||||||
|
static Persistent<String> nlink_symbol;
|
||||||
|
static Persistent<String> uid_symbol;
|
||||||
|
static Persistent<String> gid_symbol;
|
||||||
|
static Persistent<String> rdev_symbol;
|
||||||
|
static Persistent<String> size_symbol;
|
||||||
|
static Persistent<String> blksize_symbol;
|
||||||
|
static Persistent<String> blocks_symbol;
|
||||||
|
static Persistent<String> atime_symbol;
|
||||||
|
static Persistent<String> mtime_symbol;
|
||||||
|
static Persistent<String> ctime_symbol;
|
||||||
|
|
||||||
Local<Object> BuildStatsObject(NODE_STAT_STRUCT *s) {
|
Local<Object> BuildStatsObject(NODE_STAT_STRUCT *s) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
|
@ -47,57 +47,61 @@
|
|||||||
// allocations.
|
// allocations.
|
||||||
|
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define on_headers_sym NODE_VAR(on_headers_sym)
|
|
||||||
#define on_headers_complete_sym NODE_VAR(on_headers_complete_sym)
|
|
||||||
#define on_body_sym NODE_VAR(on_body_sym)
|
|
||||||
#define on_message_complete_sym NODE_VAR(on_message_complete_sym)
|
|
||||||
#define delete_sym NODE_VAR(delete_sym)
|
|
||||||
#define get_sym NODE_VAR(get_sym)
|
|
||||||
#define head_sym NODE_VAR(head_sym)
|
|
||||||
#define post_sym NODE_VAR(post_sym)
|
|
||||||
#define put_sym NODE_VAR(put_sym)
|
|
||||||
#define connect_sym NODE_VAR(connect_sym)
|
|
||||||
#define options_sym NODE_VAR(options_sym)
|
|
||||||
#define trace_sym NODE_VAR(trace_sym)
|
|
||||||
#define patch_sym NODE_VAR(patch_sym)
|
|
||||||
#define copy_sym NODE_VAR(copy_sym)
|
|
||||||
#define lock_sym NODE_VAR(lock_sym)
|
|
||||||
#define mkcol_sym NODE_VAR(mkcol_sym)
|
|
||||||
#define move_sym NODE_VAR(move_sym)
|
|
||||||
#define propfind_sym NODE_VAR(propfind_sym)
|
|
||||||
#define proppatch_sym NODE_VAR(proppatch_sym)
|
|
||||||
#define unlock_sym NODE_VAR(unlock_sym)
|
|
||||||
#define report_sym NODE_VAR(report_sym)
|
|
||||||
#define mkactivity_sym NODE_VAR(mkactivity_sym)
|
|
||||||
#define checkout_sym NODE_VAR(checkout_sym)
|
|
||||||
#define merge_sym NODE_VAR(merge_sym)
|
|
||||||
#define msearch_sym NODE_VAR(msearch_sym)
|
|
||||||
#define notify_sym NODE_VAR(notify_sym)
|
|
||||||
#define subscribe_sym NODE_VAR(subscribe_sym)
|
|
||||||
#define unsubscribe_sym NODE_VAR(unsubscribe_sym)
|
|
||||||
#define unknown_method_sym NODE_VAR(unknown_method_sym)
|
|
||||||
#define method_sym NODE_VAR(method_sym)
|
|
||||||
#define status_code_sym NODE_VAR(status_code_sym)
|
|
||||||
#define http_version_sym NODE_VAR(http_version_sym)
|
|
||||||
#define version_major_sym NODE_VAR(version_major_sym)
|
|
||||||
#define version_minor_sym NODE_VAR(version_minor_sym)
|
|
||||||
#define should_keep_alive_sym NODE_VAR(should_keep_alive_sym)
|
|
||||||
#define upgrade_sym NODE_VAR(upgrade_sym)
|
|
||||||
#define headers_sym NODE_VAR(headers_sym)
|
|
||||||
#define url_sym NODE_VAR(url_sym)
|
|
||||||
#define settings NODE_VAR(settings)
|
|
||||||
#define current_buffer NODE_VAR(current_buffer)
|
|
||||||
#define current_buffer_data NODE_VAR(current_buffer_data)
|
|
||||||
#define current_buffer_len NODE_VAR(current_buffer_len)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
|
||||||
|
static Persistent<String> on_headers_sym;
|
||||||
|
static Persistent<String> on_headers_complete_sym;
|
||||||
|
static Persistent<String> on_body_sym;
|
||||||
|
static Persistent<String> on_message_complete_sym;
|
||||||
|
|
||||||
|
static Persistent<String> delete_sym;
|
||||||
|
static Persistent<String> get_sym;
|
||||||
|
static Persistent<String> head_sym;
|
||||||
|
static Persistent<String> post_sym;
|
||||||
|
static Persistent<String> put_sym;
|
||||||
|
static Persistent<String> connect_sym;
|
||||||
|
static Persistent<String> options_sym;
|
||||||
|
static Persistent<String> trace_sym;
|
||||||
|
static Persistent<String> patch_sym;
|
||||||
|
static Persistent<String> copy_sym;
|
||||||
|
static Persistent<String> lock_sym;
|
||||||
|
static Persistent<String> mkcol_sym;
|
||||||
|
static Persistent<String> move_sym;
|
||||||
|
static Persistent<String> propfind_sym;
|
||||||
|
static Persistent<String> proppatch_sym;
|
||||||
|
static Persistent<String> unlock_sym;
|
||||||
|
static Persistent<String> report_sym;
|
||||||
|
static Persistent<String> mkactivity_sym;
|
||||||
|
static Persistent<String> checkout_sym;
|
||||||
|
static Persistent<String> merge_sym;
|
||||||
|
static Persistent<String> msearch_sym;
|
||||||
|
static Persistent<String> notify_sym;
|
||||||
|
static Persistent<String> subscribe_sym;
|
||||||
|
static Persistent<String> unsubscribe_sym;
|
||||||
|
static Persistent<String> unknown_method_sym;
|
||||||
|
|
||||||
|
static Persistent<String> method_sym;
|
||||||
|
static Persistent<String> status_code_sym;
|
||||||
|
static Persistent<String> http_version_sym;
|
||||||
|
static Persistent<String> version_major_sym;
|
||||||
|
static Persistent<String> version_minor_sym;
|
||||||
|
static Persistent<String> should_keep_alive_sym;
|
||||||
|
static Persistent<String> upgrade_sym;
|
||||||
|
static Persistent<String> headers_sym;
|
||||||
|
static Persistent<String> url_sym;
|
||||||
|
|
||||||
|
static struct http_parser_settings settings;
|
||||||
|
|
||||||
|
|
||||||
|
// This is a hack to get the current_buffer to the callbacks with the least
|
||||||
|
// amount of overhead. Nothing else will run while http_parser_execute()
|
||||||
|
// runs, therefore this pointer can be set and used for the execution.
|
||||||
|
static Local<Value>* current_buffer;
|
||||||
|
static char* current_buffer_data;
|
||||||
|
static size_t current_buffer_len;
|
||||||
|
|
||||||
|
|
||||||
#define HTTP_CB(name) \
|
#define HTTP_CB(name) \
|
||||||
static int name(http_parser* p_) { \
|
static int name(http_parser* p_) { \
|
||||||
|
@ -24,13 +24,6 @@
|
|||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
// This function starts an Isolate. This function is defined in node.cc
|
|
||||||
// currently so that we minimize the diff between master and v0.6 for easy
|
|
||||||
// merging. In the future, when v0.6 is extinct, StartThread should be moved
|
|
||||||
// to node_isolate.cc.
|
|
||||||
class Isolate;
|
|
||||||
void StartThread(Isolate* isolate, int argc, char** argv);
|
|
||||||
|
|
||||||
#ifndef offset_of
|
#ifndef offset_of
|
||||||
// g++ in strict mode complains loudly about the system offsetof() macro
|
// g++ in strict mode complains loudly about the system offsetof() macro
|
||||||
// because it uses NULL as the base address.
|
// because it uses NULL as the base address.
|
||||||
@ -47,14 +40,6 @@ void StartThread(Isolate* isolate, int argc, char** argv);
|
|||||||
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
|
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
|
||||||
TypeName(const TypeName&); \
|
|
||||||
void operator=(const TypeName&)
|
|
||||||
|
|
||||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
|
||||||
TypeName(); \
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // SRC_NODE_INTERNALS_H_
|
#endif // SRC_NODE_INTERNALS_H_
|
||||||
|
@ -1,815 +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.
|
|
||||||
|
|
||||||
#include <v8.h>
|
|
||||||
#include <v8-debug.h>
|
|
||||||
#include <node.h>
|
|
||||||
#include <node_buffer.h>
|
|
||||||
#include <node_isolate.h>
|
|
||||||
#include <node_internals.h>
|
|
||||||
#include <node_object_wrap.h>
|
|
||||||
#include <tcp_wrap.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define isolate_debugger_constructor NODE_VAR(isolate_debugger_constructor)
|
|
||||||
|
|
||||||
#define ISOLATEMESSAGE_SHARED_STREAM 0x0001
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
|
||||||
|
|
||||||
using v8::Arguments;
|
|
||||||
using v8::Array;
|
|
||||||
using v8::Context;
|
|
||||||
using v8::False;
|
|
||||||
using v8::Function;
|
|
||||||
using v8::FunctionTemplate;
|
|
||||||
using v8::Handle;
|
|
||||||
using v8::HandleScope;
|
|
||||||
using v8::Integer;
|
|
||||||
using v8::Local;
|
|
||||||
using v8::Null;
|
|
||||||
using v8::Object;
|
|
||||||
using v8::ObjectTemplate;
|
|
||||||
using v8::Persistent;
|
|
||||||
using v8::String;
|
|
||||||
using v8::True;
|
|
||||||
using v8::Undefined;
|
|
||||||
using v8::Value;
|
|
||||||
using v8::Undefined;
|
|
||||||
|
|
||||||
static volatile bool initialized;
|
|
||||||
static volatile int id;
|
|
||||||
static volatile int isolate_count;
|
|
||||||
static ngx_queue_t isolate_list;
|
|
||||||
static uv_mutex_t isolate_mutex;
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
# define IF_DEBUG(expr)
|
|
||||||
#else
|
|
||||||
# define IF_DEBUG(expr) expr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class Queue {
|
|
||||||
public:
|
|
||||||
Queue() {
|
|
||||||
if (uv_mutex_init(&mutex_)) abort();
|
|
||||||
ngx_queue_init(&queue_);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Queue() {
|
|
||||||
IF_DEBUG({
|
|
||||||
uv_mutex_lock(&mutex_);
|
|
||||||
assert(ngx_queue_empty(&queue_));
|
|
||||||
uv_mutex_unlock(&mutex_);
|
|
||||||
})
|
|
||||||
uv_mutex_destroy(&mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Produce(T item) {
|
|
||||||
Message* m = new Message;
|
|
||||||
m->item_ = item;
|
|
||||||
|
|
||||||
uv_mutex_lock(&mutex_);
|
|
||||||
ngx_queue_insert_tail(&queue_, &m->queue_);
|
|
||||||
uv_mutex_unlock(&mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Consume(T& item) {
|
|
||||||
ngx_queue_t* q = NULL;
|
|
||||||
|
|
||||||
uv_mutex_lock(&mutex_);
|
|
||||||
if (!ngx_queue_empty(&queue_)) {
|
|
||||||
q = ngx_queue_head(&queue_);
|
|
||||||
ngx_queue_remove(q);
|
|
||||||
}
|
|
||||||
uv_mutex_unlock(&mutex_);
|
|
||||||
|
|
||||||
if (q == NULL) return false;
|
|
||||||
|
|
||||||
Message* m = ngx_queue_data(q, Message, queue_);
|
|
||||||
item = m->item_;
|
|
||||||
delete m;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Message {
|
|
||||||
ngx_queue_t queue_;
|
|
||||||
T item_;
|
|
||||||
};
|
|
||||||
|
|
||||||
ngx_queue_t queue_;
|
|
||||||
uv_mutex_t mutex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class Channel {
|
|
||||||
public:
|
|
||||||
typedef void (*Callback)(T item, void* arg);
|
|
||||||
|
|
||||||
Channel(uv_loop_t* loop, Callback callback, void* arg) {
|
|
||||||
callback_ = callback;
|
|
||||||
arg_ = arg;
|
|
||||||
uv_async_init(loop, &async_, OnMessage);
|
|
||||||
uv_unref(loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Channel() {
|
|
||||||
uv_ref(async_.loop);
|
|
||||||
uv_close(reinterpret_cast<uv_handle_t*>(&async_), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Send(T item) {
|
|
||||||
queue_.Produce(item);
|
|
||||||
uv_async_send(&async_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void OnMessage(uv_async_t* handle, int status) {
|
|
||||||
Channel* c = container_of(handle, Channel, async_);
|
|
||||||
c->OnMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnMessage() {
|
|
||||||
T item;
|
|
||||||
while (queue_.Consume(item)) callback_(item, arg_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* arg_;
|
|
||||||
Callback callback_;
|
|
||||||
uv_async_t async_;
|
|
||||||
Queue<T> queue_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct IsolateMessage {
|
|
||||||
int flags;
|
|
||||||
struct {
|
|
||||||
size_t size_;
|
|
||||||
char* buffer_;
|
|
||||||
} data_;
|
|
||||||
uv_stream_info_t shared_stream_info_;
|
|
||||||
|
|
||||||
IsolateMessage(const char* buffer, size_t size,
|
|
||||||
uv_stream_info_t* shared_stream_info) {
|
|
||||||
flags = 0;
|
|
||||||
|
|
||||||
// make a copy for now
|
|
||||||
data_.size_ = size;
|
|
||||||
data_.buffer_ = new char[size];
|
|
||||||
memcpy(data_.buffer_, buffer, size);
|
|
||||||
|
|
||||||
if (shared_stream_info) {
|
|
||||||
flags |= ISOLATEMESSAGE_SHARED_STREAM;
|
|
||||||
shared_stream_info_ = *shared_stream_info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~IsolateMessage() {
|
|
||||||
delete[] data_.buffer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Free(char* data, void* arg) {
|
|
||||||
IsolateMessage* msg = static_cast<IsolateMessage*>(arg);
|
|
||||||
assert(data == msg->data_.buffer_);
|
|
||||||
delete msg;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class IsolateChannel: public Channel<IsolateMessage*> {
|
|
||||||
public:
|
|
||||||
IsolateChannel(uv_loop_t* loop, Callback callback, void* arg)
|
|
||||||
: Channel<IsolateMessage*>(loop, callback, arg)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> Isolate::Send(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
|
||||||
assert(Buffer::HasInstance(args[0]));
|
|
||||||
assert(isolate->send_channel_ != NULL);
|
|
||||||
|
|
||||||
Local<Object> obj = args[0]->ToObject();
|
|
||||||
const char* data = Buffer::Data(obj);
|
|
||||||
size_t size = Buffer::Length(obj);
|
|
||||||
|
|
||||||
IsolateMessage* msg;
|
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
|
||||||
uv_stream_info_t stream_info;
|
|
||||||
|
|
||||||
Local<Object> send_stream_obj = args[1]->ToObject();
|
|
||||||
assert(send_stream_obj->InternalFieldCount() > 0);
|
|
||||||
StreamWrap* send_stream_wrap = static_cast<StreamWrap*>(
|
|
||||||
send_stream_obj->GetPointerFromInternalField(0));
|
|
||||||
uv_stream_t* send_stream = send_stream_wrap->GetStream();
|
|
||||||
int r = uv_export(send_stream, &stream_info);
|
|
||||||
assert(r == 0);
|
|
||||||
msg = new IsolateMessage(data, size, &stream_info);
|
|
||||||
} else {
|
|
||||||
msg = new IsolateMessage(data, size, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
isolate->send_channel_->Send(msg);
|
|
||||||
|
|
||||||
return Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> Isolate::Unref(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
|
||||||
uv_unref(isolate->loop_);
|
|
||||||
|
|
||||||
return Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::OnMessage(IsolateMessage* msg, void* arg) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Isolate* self = static_cast<Isolate*>(arg);
|
|
||||||
NODE_ISOLATE_CHECK(self);
|
|
||||||
|
|
||||||
Buffer* buf = Buffer::New(msg->data_.buffer_, msg->data_.size_,
|
|
||||||
IsolateMessage::Free, msg);
|
|
||||||
|
|
||||||
int argc = 1;
|
|
||||||
Handle<Value> argv[2] = {
|
|
||||||
buf->handle_
|
|
||||||
};
|
|
||||||
|
|
||||||
if (msg->flags & ISOLATEMESSAGE_SHARED_STREAM) {
|
|
||||||
// Instantiate the client javascript object and handle.
|
|
||||||
Local<Object> pending_obj = TCPWrap::Instantiate();
|
|
||||||
|
|
||||||
// Unwrap the client javascript object.
|
|
||||||
assert(pending_obj->InternalFieldCount() > 0);
|
|
||||||
TCPWrap* pending_wrap =
|
|
||||||
static_cast<TCPWrap*>(pending_obj->GetPointerFromInternalField(0));
|
|
||||||
|
|
||||||
int r = uv_import(pending_wrap->GetStream(), &msg->shared_stream_info_);
|
|
||||||
assert(r == 0);
|
|
||||||
|
|
||||||
argv[1] = pending_obj;
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
MakeCallback(self->globals_.process, "_onmessage", argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::Initialize() {
|
|
||||||
if (initialized) return;
|
|
||||||
if (uv_mutex_init(&isolate_mutex)) abort();
|
|
||||||
ngx_queue_init(&isolate_list);
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Isolate::Count() {
|
|
||||||
int count;
|
|
||||||
uv_mutex_lock(&isolate_mutex);
|
|
||||||
count = isolate_count;
|
|
||||||
uv_mutex_unlock(&isolate_mutex);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Isolate::Isolate() {
|
|
||||||
send_channel_ = NULL; // set (and deleted) by the parent isolate
|
|
||||||
recv_channel_ = NULL;
|
|
||||||
|
|
||||||
uv_mutex_lock(&isolate_mutex);
|
|
||||||
assert(initialized && "node::Isolate::Initialize() hasn't been called");
|
|
||||||
ngx_queue_insert_tail(&isolate_list, &isolate_list_);
|
|
||||||
isolate_count++;
|
|
||||||
id_ = ++id;
|
|
||||||
uv_mutex_unlock(&isolate_mutex);
|
|
||||||
|
|
||||||
if (id_ == 1) {
|
|
||||||
loop_ = uv_default_loop();
|
|
||||||
} else {
|
|
||||||
loop_ = uv_loop_new();
|
|
||||||
// Artificially ref the isolate loop so that the child
|
|
||||||
// isolate stays alive by default. process.exit will
|
|
||||||
// unref the loop (see Isolate::Unref).
|
|
||||||
uv_ref(loop_);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_state = kNone;
|
|
||||||
debugger_instance = NULL;
|
|
||||||
|
|
||||||
ngx_queue_init(&at_exit_callbacks_);
|
|
||||||
|
|
||||||
v8_isolate_ = v8::Isolate::New();
|
|
||||||
assert(v8_isolate_->GetData() == NULL);
|
|
||||||
v8_isolate_->SetData(this);
|
|
||||||
|
|
||||||
globals_init_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Isolate::~Isolate() {
|
|
||||||
if (!argv_) return;
|
|
||||||
for (size_t i = 0; argv_[i]; ++i) delete[] argv_[i];
|
|
||||||
delete[] argv_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct globals* Isolate::Globals() {
|
|
||||||
return &globals_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::AtExit(AtExitCallback callback, void* arg) {
|
|
||||||
struct AtExitCallbackInfo* it = new AtExitCallbackInfo;
|
|
||||||
|
|
||||||
//NODE_ISOLATE_CHECK(this);
|
|
||||||
|
|
||||||
it->callback_ = callback;
|
|
||||||
it->arg_ = arg;
|
|
||||||
|
|
||||||
ngx_queue_insert_head(&at_exit_callbacks_, &it->queue_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::Enter() {
|
|
||||||
v8_isolate_->Enter();
|
|
||||||
|
|
||||||
if (v8_context_.IsEmpty()) {
|
|
||||||
v8_context_ = Context::New();
|
|
||||||
}
|
|
||||||
v8_context_->Enter();
|
|
||||||
|
|
||||||
if (!globals_init_) {
|
|
||||||
globals_init_ = true;
|
|
||||||
globals_init(&globals_);
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::Exit() {
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
v8_context_->Exit();
|
|
||||||
v8_isolate_->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Isolate::Dispose() {
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
|
|
||||||
while (!ngx_queue_empty(&at_exit_callbacks_)) {
|
|
||||||
ngx_queue_t* q = ngx_queue_head(&at_exit_callbacks_);
|
|
||||||
ngx_queue_remove(q);
|
|
||||||
|
|
||||||
AtExitCallbackInfo* it = ngx_queue_data(q, AtExitCallbackInfo, queue_);
|
|
||||||
it->callback_(it->arg_);
|
|
||||||
|
|
||||||
delete it;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(v8_context_->InContext());
|
|
||||||
v8_context_->Exit();
|
|
||||||
v8_context_.Clear();
|
|
||||||
v8_context_.Dispose();
|
|
||||||
|
|
||||||
v8_isolate_->Exit();
|
|
||||||
v8_isolate_->Dispose();
|
|
||||||
v8_isolate_ = NULL;
|
|
||||||
|
|
||||||
uv_mutex_lock(&isolate_mutex);
|
|
||||||
isolate_count--;
|
|
||||||
ngx_queue_remove(&isolate_list_);
|
|
||||||
assert(isolate_count >= 0);
|
|
||||||
assert((isolate_count == 0 && ngx_queue_empty(&isolate_list))
|
|
||||||
|| (isolate_count > 0 && !ngx_queue_empty(&isolate_list)));
|
|
||||||
uv_mutex_unlock(&isolate_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct IsolateWrap: public ObjectWrap {
|
|
||||||
public:
|
|
||||||
IsolateWrap(Isolate* parent_isolate) {
|
|
||||||
parent_isolate_ = parent_isolate;
|
|
||||||
|
|
||||||
uv_loop_t* parent_loop = parent_isolate->GetLoop();
|
|
||||||
recv_channel_ = new IsolateChannel(
|
|
||||||
parent_loop, IsolateWrap::OnMessage, this);
|
|
||||||
|
|
||||||
isolate_ = new Isolate;
|
|
||||||
send_channel_ = new IsolateChannel(
|
|
||||||
isolate_->loop_, Isolate::OnMessage, isolate_);
|
|
||||||
|
|
||||||
isolate_->send_channel_ = recv_channel_;
|
|
||||||
isolate_->recv_channel_ = send_channel_;
|
|
||||||
|
|
||||||
// TODO this could be folded into the regular channel
|
|
||||||
uv_async_init(parent_loop, &child_exit_, AfterChildExit);
|
|
||||||
isolate_->AtExit(AtChildExit, this);
|
|
||||||
|
|
||||||
HandleScope scope;
|
|
||||||
Local<ObjectTemplate> tpl = ObjectTemplate::New();
|
|
||||||
tpl->SetInternalFieldCount(1);
|
|
||||||
|
|
||||||
Local<Object> obj = tpl->NewInstance();
|
|
||||||
Wrap(obj);
|
|
||||||
Ref(); // unref'd when the child isolate exits
|
|
||||||
|
|
||||||
obj->Set(String::NewSymbol("tid"),
|
|
||||||
Integer::New(isolate_->id_));
|
|
||||||
|
|
||||||
obj->Set(String::NewSymbol("send"),
|
|
||||||
FunctionTemplate::New(Send)->GetFunction());
|
|
||||||
}
|
|
||||||
|
|
||||||
~IsolateWrap() {
|
|
||||||
delete isolate_;
|
|
||||||
delete recv_channel_;
|
|
||||||
delete send_channel_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Isolate* GetIsolate() {
|
|
||||||
return isolate_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// runs in the child thread
|
|
||||||
static void AtChildExit(void* arg) {
|
|
||||||
IsolateWrap* self = static_cast<IsolateWrap*>(arg);
|
|
||||||
uv_async_send(&self->child_exit_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// runs in the parent thread
|
|
||||||
static void AfterChildExit(uv_async_t* handle, int status) {
|
|
||||||
IsolateWrap* self = container_of(handle, IsolateWrap, child_exit_);
|
|
||||||
self->OnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnExit() {
|
|
||||||
if (uv_thread_join(&isolate_->tid_)) abort();
|
|
||||||
uv_close(reinterpret_cast<uv_handle_t*>(&child_exit_), NULL);
|
|
||||||
MakeCallback(handle_, "onexit", 0, NULL);
|
|
||||||
Unref(); // child is dead, it's safe to GC the JS object now
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnMessage(IsolateMessage* msg, void* arg) {
|
|
||||||
IsolateWrap* self = static_cast<IsolateWrap*>(arg);
|
|
||||||
self->OnMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnMessage(IsolateMessage* msg) {
|
|
||||||
NODE_ISOLATE_CHECK(parent_isolate_);
|
|
||||||
HandleScope scope;
|
|
||||||
Buffer* buf = Buffer::New(
|
|
||||||
msg->data_.buffer_, msg->data_.size_, IsolateMessage::Free, msg);
|
|
||||||
|
|
||||||
int argc = 1;
|
|
||||||
Handle<Value> argv[2] = {
|
|
||||||
buf->handle_
|
|
||||||
};
|
|
||||||
|
|
||||||
if (msg->flags & ISOLATEMESSAGE_SHARED_STREAM) {
|
|
||||||
// Instantiate the client javascript object and handle.
|
|
||||||
Local<Object> pending_obj = TCPWrap::Instantiate();
|
|
||||||
|
|
||||||
// Unwrap the client javascript object.
|
|
||||||
assert(pending_obj->InternalFieldCount() > 0);
|
|
||||||
TCPWrap* pending_wrap =
|
|
||||||
static_cast<TCPWrap*>(pending_obj->GetPointerFromInternalField(0));
|
|
||||||
|
|
||||||
int r = uv_import(pending_wrap->GetStream(), &msg->shared_stream_info_);
|
|
||||||
assert(r == 0);
|
|
||||||
|
|
||||||
argv[1] = pending_obj;
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
MakeCallback(handle_, "onmessage", argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO merge with Isolate::Send(), it's almost identical
|
|
||||||
static Handle<Value> Send(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
IsolateWrap* self = Unwrap<IsolateWrap>(args.This());
|
|
||||||
assert(Buffer::HasInstance(args[0]));
|
|
||||||
|
|
||||||
Local<Object> obj = args[0]->ToObject();
|
|
||||||
const char* data = Buffer::Data(obj);
|
|
||||||
size_t size = Buffer::Length(obj);
|
|
||||||
|
|
||||||
IsolateMessage* msg;
|
|
||||||
|
|
||||||
if (args[1]->IsObject()) {
|
|
||||||
uv_stream_info_t stream_info;
|
|
||||||
|
|
||||||
Local<Object> send_stream_obj = args[1]->ToObject();
|
|
||||||
assert(send_stream_obj->InternalFieldCount() > 0);
|
|
||||||
StreamWrap* send_stream_wrap = static_cast<StreamWrap*>(
|
|
||||||
send_stream_obj->GetPointerFromInternalField(0));
|
|
||||||
uv_stream_t* send_stream = send_stream_wrap->GetStream();
|
|
||||||
int r = uv_export(send_stream, &stream_info);
|
|
||||||
assert(r == 0);
|
|
||||||
msg = new IsolateMessage(data, size, &stream_info);
|
|
||||||
} else {
|
|
||||||
msg = new IsolateMessage(data, size, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
self->send_channel_->Send(msg);
|
|
||||||
return Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(IsolateWrap);
|
|
||||||
Isolate* isolate_;
|
|
||||||
Isolate* parent_isolate_;
|
|
||||||
IsolateChannel* send_channel_;
|
|
||||||
IsolateChannel* recv_channel_;
|
|
||||||
uv_async_t child_exit_; // side effect: keeps the parent's event loop alive
|
|
||||||
// until the child exits
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void RunIsolate(void* arg) {
|
|
||||||
Isolate* isolate = static_cast<Isolate*>(arg);
|
|
||||||
isolate->Enter();
|
|
||||||
StartThread(isolate, isolate->argc_, isolate->argv_);
|
|
||||||
isolate->Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Handle<Value> CreateIsolate(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
assert(args[0]->IsArray());
|
|
||||||
|
|
||||||
Local<Array> argv = args[0].As<Array>();
|
|
||||||
assert(argv->Length() >= 2);
|
|
||||||
|
|
||||||
Isolate* current_isolate = node::Isolate::GetCurrent();
|
|
||||||
IsolateWrap* wrap = new IsolateWrap(current_isolate);
|
|
||||||
Isolate* isolate = wrap->GetIsolate();
|
|
||||||
|
|
||||||
// Copy over arguments into isolate
|
|
||||||
isolate->argc_ = argv->Length();
|
|
||||||
isolate->argv_ = new char*[isolate->argc_ + 1];
|
|
||||||
for (int i = 0; i < isolate->argc_; ++i) {
|
|
||||||
String::Utf8Value str(argv->Get(i));
|
|
||||||
size_t size = 1 + strlen(*str);
|
|
||||||
isolate->argv_[i] = new char[size];
|
|
||||||
memcpy(isolate->argv_[i], *str, size);
|
|
||||||
}
|
|
||||||
isolate->argv_[isolate->argc_] = NULL;
|
|
||||||
|
|
||||||
// If options object was provided
|
|
||||||
if (args.Length() > 1) {
|
|
||||||
Local<Object> options = args[1].As<Object>();
|
|
||||||
Local<Value> opt_debug = options->Get(String::New("debug"));
|
|
||||||
Local<Value> opt_debug_brk = options->Get(String::New("debugBrk"));
|
|
||||||
|
|
||||||
// Handle .debug = true case
|
|
||||||
if (opt_debug->IsFunction()) {
|
|
||||||
isolate->debug_state = opt_debug_brk->IsTrue() ?
|
|
||||||
Isolate::kDebugBrk
|
|
||||||
:
|
|
||||||
Isolate::kDebug;
|
|
||||||
isolate->debugger_instance = IsolateDebugger::New(opt_debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uv_thread_create(&isolate->tid_, RunIsolate, isolate))
|
|
||||||
return Null(); // wrap is collected by the GC
|
|
||||||
else
|
|
||||||
return wrap->handle_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Handle<Value> CountIsolate(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
return scope.Close(Integer::New(Isolate::Count()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InitIsolates(Handle<Object> target) {
|
|
||||||
HandleScope scope;
|
|
||||||
NODE_SET_METHOD(target, "create", CreateIsolate);
|
|
||||||
NODE_SET_METHOD(target, "count", CountIsolate);
|
|
||||||
|
|
||||||
IsolateDebugger::Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class IsolateDebuggerMessage {
|
|
||||||
public:
|
|
||||||
IsolateDebugger* d_;
|
|
||||||
uint16_t* value_;
|
|
||||||
int len_;
|
|
||||||
|
|
||||||
IsolateDebuggerMessage(IsolateDebugger* d, uint16_t* value, int len) {
|
|
||||||
d_ = d;
|
|
||||||
value_ = new uint16_t[len];
|
|
||||||
len_ = len;
|
|
||||||
memcpy(value_, value, len * sizeof(value_[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
~IsolateDebuggerMessage() {
|
|
||||||
delete[] value_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void IsolateDebugger::Initialize() {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(IsolateDebugger::New);
|
|
||||||
isolate_debugger_constructor = Persistent<FunctionTemplate>::New(t);
|
|
||||||
|
|
||||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
||||||
t->SetClassName(String::NewSymbol("IsolateDebugger"));
|
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "write", IsolateDebugger::Write);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IsolateDebugger::IsolateDebugger(Handle<Value> init) {
|
|
||||||
debuggee_ = NULL;
|
|
||||||
initialized_ = false;
|
|
||||||
host_ = Isolate::GetCurrent();
|
|
||||||
host_loop_ = host_->GetLoop();
|
|
||||||
init_callback_fn_ = Persistent<Value>::New(init);
|
|
||||||
|
|
||||||
// Init async handle to invoke js callback once
|
|
||||||
// debugger will be initialized
|
|
||||||
uv_async_init(host_loop_,
|
|
||||||
&init_callback_,
|
|
||||||
IsolateDebugger::InitCallback);
|
|
||||||
init_callback_.data = reinterpret_cast<void*>(this);
|
|
||||||
|
|
||||||
msg_channel_ = new Channel<IsolateDebuggerMessage*>(
|
|
||||||
host_loop_, MessageCallback, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IsolateDebugger::~IsolateDebugger() {
|
|
||||||
init_callback_fn_.Clear();
|
|
||||||
init_callback_fn_.Dispose();
|
|
||||||
delete msg_channel_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void IsolateDebugger::Init(void) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
|
||||||
|
|
||||||
debuggee_ = isolate;
|
|
||||||
debuggee_v8_ = isolate->GetV8Isolate();
|
|
||||||
v8::Debug::SetMessageHandler2(IsolateDebugger::DebugMessageHandler);
|
|
||||||
|
|
||||||
// Expose v8debug for isolate
|
|
||||||
|
|
||||||
if (isolate->debug_state == Isolate::kDebugBrk) {
|
|
||||||
Local<Context> debugContext = v8::Debug::GetDebugContext();
|
|
||||||
|
|
||||||
debugContext->SetSecurityToken(
|
|
||||||
isolate->GetV8Context()->GetSecurityToken()
|
|
||||||
);
|
|
||||||
isolate->GetV8Context()->Global()->Set(
|
|
||||||
String::New("v8debug"),
|
|
||||||
debugContext->Global()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized_ = true;
|
|
||||||
|
|
||||||
uv_async_send(&init_callback_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void IsolateDebugger::InitCallback(uv_async_t* c, int status) {
|
|
||||||
assert(c->data != NULL);
|
|
||||||
|
|
||||||
IsolateDebugger* d = reinterpret_cast<IsolateDebugger*>(c->data);
|
|
||||||
|
|
||||||
d->host_->Enter();
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Handle<Value> argv[1] = { d->handle_ };
|
|
||||||
Function::Cast(*d->init_callback_fn_)->Call(d->handle_, 1, argv);
|
|
||||||
|
|
||||||
d->host_->Exit();
|
|
||||||
|
|
||||||
// Unreference loop
|
|
||||||
uv_unref(d->host_loop_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> IsolateDebugger::New(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
IsolateDebugger* d = new IsolateDebugger(args[0]);
|
|
||||||
d->Wrap(args.Holder());
|
|
||||||
|
|
||||||
return args.This();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IsolateDebugger* IsolateDebugger::New(Handle<Value> init) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
Handle<Value> argv[1] = { init };
|
|
||||||
Handle<Object> i = isolate_debugger_constructor->GetFunction()->NewInstance(
|
|
||||||
1,
|
|
||||||
argv
|
|
||||||
);
|
|
||||||
|
|
||||||
return ObjectWrap::Unwrap<IsolateDebugger>(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> IsolateDebugger::Write(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (args.Length() != 1) {
|
|
||||||
return ThrowException(String::New(
|
|
||||||
"IsolateDebugger::Write requires one argument"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
IsolateDebugger* d = ObjectWrap::Unwrap<IsolateDebugger>(args.This());
|
|
||||||
assert(d->initialized_);
|
|
||||||
|
|
||||||
String::Value v(args[0]->ToString());
|
|
||||||
v8::Debug::SendCommand(*v,
|
|
||||||
v.length(),
|
|
||||||
NULL,
|
|
||||||
d->debuggee_v8_);
|
|
||||||
|
|
||||||
return Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void IsolateDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
|
|
||||||
IsolateDebugger* d = Isolate::GetCurrent()->debugger_instance;
|
|
||||||
|
|
||||||
String::Value v(message.GetJSON());
|
|
||||||
d->msg_channel_->Send(new IsolateDebuggerMessage(d, *v, v.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void IsolateDebugger::MessageCallback(IsolateDebuggerMessage* msg, void*) {
|
|
||||||
assert(msg != NULL);
|
|
||||||
|
|
||||||
IsolateDebugger *d = msg->d_;
|
|
||||||
// Enter parent isolate context
|
|
||||||
d->host_->Enter();
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
// debugger.onmessage should be a function!
|
|
||||||
Handle<Value> argv[] = { String::New(msg->value_, msg->len_) };
|
|
||||||
MakeCallback(d->handle_, "onmessage", ARRAY_SIZE(argv), argv);
|
|
||||||
|
|
||||||
// Free memory allocated for message
|
|
||||||
delete msg;
|
|
||||||
|
|
||||||
// And leave isolate
|
|
||||||
d->host_->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace node
|
|
||||||
|
|
||||||
|
|
||||||
NODE_MODULE(node_isolates, node::InitIsolates)
|
|
@ -1,185 +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.
|
|
||||||
|
|
||||||
#ifndef SRC_NODE_ISOLATE_H_
|
|
||||||
#define SRC_NODE_ISOLATE_H_
|
|
||||||
|
|
||||||
#include "v8.h"
|
|
||||||
#include "v8-debug.h"
|
|
||||||
#include "uv.h"
|
|
||||||
#include "node_vars.h"
|
|
||||||
#include "node_object_wrap.h"
|
|
||||||
#include "ngx-queue.h"
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
# define NODE_ISOLATE_CHECK(ptr) ((void) (ptr))
|
|
||||||
#else
|
|
||||||
# include <assert.h>
|
|
||||||
# define NODE_ISOLATE_CHECK(ptr) \
|
|
||||||
do { \
|
|
||||||
node::Isolate* data_ = node::Isolate::GetCurrent(); \
|
|
||||||
assert(data_ == (ptr)); \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
|
|
||||||
class Channel;
|
|
||||||
|
|
||||||
class IsolateWrap;
|
|
||||||
class IsolateChannel;
|
|
||||||
class IsolateMessage;
|
|
||||||
class IsolateDebugger;
|
|
||||||
class IsolateDebuggerMessage;
|
|
||||||
|
|
||||||
class Isolate {
|
|
||||||
public:
|
|
||||||
char** argv_;
|
|
||||||
int argc_;
|
|
||||||
uv_thread_t tid_;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
kNone,
|
|
||||||
kDebug,
|
|
||||||
kDebugBrk
|
|
||||||
} debug_state;
|
|
||||||
IsolateDebugger* debugger_instance;
|
|
||||||
|
|
||||||
// Call this before instantiating any Isolate
|
|
||||||
static void Initialize();
|
|
||||||
static int Count();
|
|
||||||
|
|
||||||
typedef void (*AtExitCallback)(void* arg);
|
|
||||||
|
|
||||||
static v8::Handle<v8::Value> Send(const v8::Arguments& args);
|
|
||||||
static v8::Handle<v8::Value> Unref(const v8::Arguments& args);
|
|
||||||
|
|
||||||
static Isolate* GetCurrent() {
|
|
||||||
return reinterpret_cast<Isolate*>(v8::Isolate::GetCurrent()->GetData());
|
|
||||||
}
|
|
||||||
|
|
||||||
uv_loop_t* GetLoop() {
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
return loop_;
|
|
||||||
}
|
|
||||||
|
|
||||||
v8::Isolate* GetV8Isolate() {
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
return v8_isolate_;
|
|
||||||
}
|
|
||||||
|
|
||||||
v8::Handle<v8::Context> GetV8Context() {
|
|
||||||
NODE_ISOLATE_CHECK(this);
|
|
||||||
return v8_context_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register a handler that should run when the current isolate exits.
|
|
||||||
* Handlers run in LIFO order.
|
|
||||||
*/
|
|
||||||
void AtExit(AtExitCallback callback, void *arg);
|
|
||||||
|
|
||||||
struct globals* Globals();
|
|
||||||
|
|
||||||
unsigned int id_;
|
|
||||||
|
|
||||||
// This constructor is used for every non-main thread
|
|
||||||
Isolate();
|
|
||||||
~Isolate();
|
|
||||||
|
|
||||||
void Enter();
|
|
||||||
void Exit();
|
|
||||||
|
|
||||||
/* Shutdown the isolate. Call this method at thread death. */
|
|
||||||
void Dispose();
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class IsolateWrap;
|
|
||||||
|
|
||||||
struct AtExitCallbackInfo {
|
|
||||||
AtExitCallback callback_;
|
|
||||||
ngx_queue_t queue_;
|
|
||||||
void* arg_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void OnMessage(IsolateMessage*, void*);
|
|
||||||
|
|
||||||
// Forbid implicit constructors and copy constructors
|
|
||||||
void operator=(const Isolate&) {}
|
|
||||||
Isolate(const Isolate&) {}
|
|
||||||
|
|
||||||
ngx_queue_t isolate_list_; // linked list of all isolates
|
|
||||||
ngx_queue_t at_exit_callbacks_;
|
|
||||||
v8::Persistent<v8::Context> v8_context_;
|
|
||||||
v8::Isolate* v8_isolate_;
|
|
||||||
IsolateChannel* send_channel_;
|
|
||||||
IsolateChannel* recv_channel_;
|
|
||||||
uv_loop_t* loop_;
|
|
||||||
|
|
||||||
// Global variables for this isolate.
|
|
||||||
struct globals globals_;
|
|
||||||
bool globals_init_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IsolateDebugger : ObjectWrap {
|
|
||||||
public:
|
|
||||||
static void Initialize();
|
|
||||||
void Init();
|
|
||||||
static void InitCallback(uv_async_t* c, int status);
|
|
||||||
|
|
||||||
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
|
||||||
static IsolateDebugger* New(v8::Handle<v8::Value> init);
|
|
||||||
|
|
||||||
static v8::Handle<v8::Value> Write(const v8::Arguments& args);
|
|
||||||
|
|
||||||
static void DebugMessageHandler(const v8::Debug::Message& message);
|
|
||||||
static void MessageCallback(IsolateDebuggerMessage* msg, void*);
|
|
||||||
|
|
||||||
IsolateDebugger(v8::Handle<v8::Value> init);
|
|
||||||
~IsolateDebugger();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Isolate* host_;
|
|
||||||
uv_loop_t* host_loop_;
|
|
||||||
|
|
||||||
uv_async_t init_callback_;
|
|
||||||
v8::Persistent<v8::Value> init_callback_fn_;
|
|
||||||
|
|
||||||
bool initialized_;
|
|
||||||
Isolate* debuggee_;
|
|
||||||
v8::Isolate* debuggee_v8_;
|
|
||||||
|
|
||||||
struct debug_msg_s {
|
|
||||||
uint16_t* value;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
IsolateDebugger* d;
|
|
||||||
};
|
|
||||||
|
|
||||||
Channel<IsolateDebuggerMessage*>* msg_channel_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace node
|
|
||||||
|
|
||||||
#endif // SRC_NODE_ISOLATE_H_
|
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_script.h>
|
#include <node_script.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
@ -44,8 +43,6 @@ using v8::Integer;
|
|||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
|
|
||||||
#define wrapped_context_constructor NODE_VAR(wrapped_context_constructor)
|
|
||||||
#define wrapped_script_constructor NODE_VAR(wrapped_script_constructor)
|
|
||||||
|
|
||||||
class WrappedContext : ObjectWrap {
|
class WrappedContext : ObjectWrap {
|
||||||
public:
|
public:
|
||||||
@ -58,6 +55,8 @@ class WrappedContext : ObjectWrap {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
static Persistent<FunctionTemplate> constructor_template;
|
||||||
|
|
||||||
WrappedContext();
|
WrappedContext();
|
||||||
~WrappedContext();
|
~WrappedContext();
|
||||||
|
|
||||||
@ -65,6 +64,9 @@ class WrappedContext : ObjectWrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Persistent<FunctionTemplate> WrappedContext::constructor_template;
|
||||||
|
|
||||||
|
|
||||||
class WrappedScript : ObjectWrap {
|
class WrappedScript : ObjectWrap {
|
||||||
public:
|
public:
|
||||||
static void Initialize(Handle<Object> target);
|
static void Initialize(Handle<Object> target);
|
||||||
@ -79,6 +81,8 @@ class WrappedScript : ObjectWrap {
|
|||||||
static Handle<Value> EvalMachine(const Arguments& args);
|
static Handle<Value> EvalMachine(const Arguments& args);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static Persistent<FunctionTemplate> constructor_template;
|
||||||
|
|
||||||
WrappedScript() : ObjectWrap() {}
|
WrappedScript() : ObjectWrap() {}
|
||||||
~WrappedScript();
|
~WrappedScript();
|
||||||
|
|
||||||
@ -131,17 +135,17 @@ void WrappedContext::Initialize(Handle<Object> target) {
|
|||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::New);
|
||||||
wrapped_context_constructor = Persistent<FunctionTemplate>::New(t);
|
constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||||
wrapped_context_constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
wrapped_context_constructor->SetClassName(String::NewSymbol("Context"));
|
constructor_template->SetClassName(String::NewSymbol("Context"));
|
||||||
|
|
||||||
target->Set(String::NewSymbol("Context"),
|
target->Set(String::NewSymbol("Context"),
|
||||||
wrapped_context_constructor->GetFunction());
|
constructor_template->GetFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WrappedContext::InstanceOf(Handle<Value> value) {
|
bool WrappedContext::InstanceOf(Handle<Value> value) {
|
||||||
return !value.IsEmpty() && wrapped_context_constructor->HasInstance(value);
|
return !value.IsEmpty() && constructor_template->HasInstance(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,7 +170,7 @@ WrappedContext::~WrappedContext() {
|
|||||||
|
|
||||||
|
|
||||||
Local<Object> WrappedContext::NewInstance() {
|
Local<Object> WrappedContext::NewInstance() {
|
||||||
Local<Object> context = wrapped_context_constructor->GetFunction()->NewInstance();
|
Local<Object> context = constructor_template->GetFunction()->NewInstance();
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,57 +180,60 @@ Persistent<Context> WrappedContext::GetV8Context() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Persistent<FunctionTemplate> WrappedScript::constructor_template;
|
||||||
|
|
||||||
|
|
||||||
void WrappedScript::Initialize(Handle<Object> target) {
|
void WrappedScript::Initialize(Handle<Object> target) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New);
|
||||||
wrapped_script_constructor = Persistent<FunctionTemplate>::New(t);
|
constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||||
wrapped_script_constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
// Note: We use 'NodeScript' instead of 'Script' so that we do not
|
// Note: We use 'NodeScript' instead of 'Script' so that we do not
|
||||||
// conflict with V8's Script class defined in v8/src/messages.js
|
// conflict with V8's Script class defined in v8/src/messages.js
|
||||||
// See GH-203 https://github.com/joyent/node/issues/203
|
// See GH-203 https://github.com/joyent/node/issues/203
|
||||||
wrapped_script_constructor->SetClassName(String::NewSymbol("NodeScript"));
|
constructor_template->SetClassName(String::NewSymbol("NodeScript"));
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(wrapped_script_constructor,
|
NODE_SET_PROTOTYPE_METHOD(constructor_template,
|
||||||
"createContext",
|
"createContext",
|
||||||
WrappedScript::CreateContext);
|
WrappedScript::CreateContext);
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(wrapped_script_constructor,
|
NODE_SET_PROTOTYPE_METHOD(constructor_template,
|
||||||
"runInContext",
|
"runInContext",
|
||||||
WrappedScript::RunInContext);
|
WrappedScript::RunInContext);
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(wrapped_script_constructor,
|
NODE_SET_PROTOTYPE_METHOD(constructor_template,
|
||||||
"runInThisContext",
|
"runInThisContext",
|
||||||
WrappedScript::RunInThisContext);
|
WrappedScript::RunInThisContext);
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(wrapped_script_constructor,
|
NODE_SET_PROTOTYPE_METHOD(constructor_template,
|
||||||
"runInNewContext",
|
"runInNewContext",
|
||||||
WrappedScript::RunInNewContext);
|
WrappedScript::RunInNewContext);
|
||||||
|
|
||||||
NODE_SET_METHOD(wrapped_script_constructor,
|
NODE_SET_METHOD(constructor_template,
|
||||||
"createContext",
|
"createContext",
|
||||||
WrappedScript::CreateContext);
|
WrappedScript::CreateContext);
|
||||||
|
|
||||||
NODE_SET_METHOD(wrapped_script_constructor,
|
NODE_SET_METHOD(constructor_template,
|
||||||
"runInContext",
|
"runInContext",
|
||||||
WrappedScript::CompileRunInContext);
|
WrappedScript::CompileRunInContext);
|
||||||
|
|
||||||
NODE_SET_METHOD(wrapped_script_constructor,
|
NODE_SET_METHOD(constructor_template,
|
||||||
"runInThisContext",
|
"runInThisContext",
|
||||||
WrappedScript::CompileRunInThisContext);
|
WrappedScript::CompileRunInThisContext);
|
||||||
|
|
||||||
NODE_SET_METHOD(wrapped_script_constructor,
|
NODE_SET_METHOD(constructor_template,
|
||||||
"runInNewContext",
|
"runInNewContext",
|
||||||
WrappedScript::CompileRunInNewContext);
|
WrappedScript::CompileRunInNewContext);
|
||||||
|
|
||||||
target->Set(String::NewSymbol("NodeScript"),
|
target->Set(String::NewSymbol("NodeScript"),
|
||||||
wrapped_script_constructor->GetFunction());
|
constructor_template->GetFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> WrappedScript::New(const Arguments& args) {
|
Handle<Value> WrappedScript::New(const Arguments& args) {
|
||||||
if (!args.IsConstructCall()) {
|
if (!args.IsConstructCall()) {
|
||||||
return FromConstructorTemplate(wrapped_script_constructor, args);
|
return FromConstructorTemplate(constructor_template, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
@ -22,27 +22,26 @@
|
|||||||
#include <node_signal_watcher.h>
|
#include <node_signal_watcher.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
#define callback_symbol NODE_VAR(callback_symbol)
|
|
||||||
#define signal_watcher_constructor_template NODE_VAR(signal_watcher_constructor_template)
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
|
||||||
|
Persistent<FunctionTemplate> SignalWatcher::constructor_template;
|
||||||
|
static Persistent<String> callback_symbol;
|
||||||
|
|
||||||
void SignalWatcher::Initialize(Handle<Object> target) {
|
void SignalWatcher::Initialize(Handle<Object> target) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(SignalWatcher::New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(SignalWatcher::New);
|
||||||
signal_watcher_constructor_template = Persistent<FunctionTemplate>::New(t);
|
constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||||
signal_watcher_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
signal_watcher_constructor_template->SetClassName(String::NewSymbol("SignalWatcher"));
|
constructor_template->SetClassName(String::NewSymbol("SignalWatcher"));
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(signal_watcher_constructor_template, "start", SignalWatcher::Start);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "start", SignalWatcher::Start);
|
||||||
NODE_SET_PROTOTYPE_METHOD(signal_watcher_constructor_template, "stop", SignalWatcher::Stop);
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "stop", SignalWatcher::Stop);
|
||||||
|
|
||||||
target->Set(String::NewSymbol("SignalWatcher"),
|
target->Set(String::NewSymbol("SignalWatcher"),
|
||||||
signal_watcher_constructor_template->GetFunction());
|
constructor_template->GetFunction());
|
||||||
|
|
||||||
callback_symbol = NODE_PSYMBOL("callback");
|
callback_symbol = NODE_PSYMBOL("callback");
|
||||||
}
|
}
|
||||||
@ -74,7 +73,7 @@ void SignalWatcher::Callback(EV_P_ ev_signal *watcher, int revents) {
|
|||||||
|
|
||||||
Handle<Value> SignalWatcher::New(const Arguments& args) {
|
Handle<Value> SignalWatcher::New(const Arguments& args) {
|
||||||
if (!args.IsConstructCall()) {
|
if (!args.IsConstructCall()) {
|
||||||
return FromConstructorTemplate(signal_watcher_constructor_template, args);
|
return FromConstructorTemplate(constructor_template, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
#include <node_vars.h>
|
|
||||||
#include <node_isolate.h>
|
|
||||||
#if HAVE_OPENSSL
|
|
||||||
# include <node_crypto.h>
|
|
||||||
#endif
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace node {
|
|
||||||
|
|
||||||
// For now we just statically initialize the globals structure. Later there
|
|
||||||
// will be one struct globals for each isolate.
|
|
||||||
|
|
||||||
void globals_init(struct globals* g) {
|
|
||||||
memset(g, 0, sizeof(struct globals));
|
|
||||||
|
|
||||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
|
||||||
g->use_npn = true;
|
|
||||||
#else
|
|
||||||
g->use_npn = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
|
||||||
g->use_sni = true;
|
|
||||||
#else
|
|
||||||
g->use_sni = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_ISOLATES
|
|
||||||
struct globals* globals_get() {
|
|
||||||
node::Isolate* isolate = node::Isolate::GetCurrent();
|
|
||||||
return isolate->Globals();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static struct globals g_struct;
|
|
||||||
static struct globals* g_ptr;
|
|
||||||
|
|
||||||
struct globals* globals_get() {
|
|
||||||
if (!g_ptr) {
|
|
||||||
g_ptr = &g_struct;
|
|
||||||
globals_init(g_ptr);
|
|
||||||
}
|
|
||||||
return g_ptr;
|
|
||||||
}
|
|
||||||
#endif // HAVE_ISOLATES
|
|
||||||
|
|
||||||
} // namespace node
|
|
197
src/node_vars.h
197
src/node_vars.h
@ -1,197 +0,0 @@
|
|||||||
#ifndef NODE_VARS_H
|
|
||||||
#define NODE_VARS_H
|
|
||||||
|
|
||||||
// This file contains all Isolate-local variables. We allow people to
|
|
||||||
// compile Node either with Isolates or without. In the case that they
|
|
||||||
// compile without isolates, these will be static variables.
|
|
||||||
|
|
||||||
#include <v8.h>
|
|
||||||
#include <uv.h>
|
|
||||||
#include <http_parser.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# define PATH_MAX MAX_PATH
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
|
||||||
# define PATH_MAX 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace node {
|
|
||||||
|
|
||||||
|
|
||||||
#define NODE_VAR(x) (globals_get()->x)
|
|
||||||
|
|
||||||
struct globals {
|
|
||||||
// node.cc
|
|
||||||
v8::Persistent<v8::Object> process;
|
|
||||||
v8::Persistent<v8::String> errno_symbol;
|
|
||||||
v8::Persistent<v8::String> syscall_symbol;
|
|
||||||
v8::Persistent<v8::String> errpath_symbol;
|
|
||||||
v8::Persistent<v8::String> code_symbol;
|
|
||||||
v8::Persistent<v8::String> rss_symbol;
|
|
||||||
v8::Persistent<v8::String> heap_total_symbol;
|
|
||||||
v8::Persistent<v8::String> heap_used_symbol;
|
|
||||||
v8::Persistent<v8::String> listeners_symbol;
|
|
||||||
v8::Persistent<v8::String> uncaught_exception_symbol;
|
|
||||||
v8::Persistent<v8::String> emit_symbol;
|
|
||||||
uv_check_t check_tick_watcher;
|
|
||||||
uv_prepare_t prepare_tick_watcher;
|
|
||||||
uv_idle_t tick_spinner;
|
|
||||||
bool need_tick_cb;
|
|
||||||
v8::Persistent<v8::String> tick_callback_sym;
|
|
||||||
bool use_npn;
|
|
||||||
bool use_sni;
|
|
||||||
// Buffer for getpwnam_r(), getgrpam_r() and other misc callers; keep this
|
|
||||||
// scoped at file-level rather than method-level to avoid excess stack usage.
|
|
||||||
char getbuf[PATH_MAX + 1];
|
|
||||||
// We need to notify V8 when we're idle so that it can run the garbage
|
|
||||||
// collector. The interface to this is V8::IdleNotification(). It returns
|
|
||||||
// true if the heap hasn't be fully compacted, and needs to be run again.
|
|
||||||
// Returning false means that it doesn't have anymore work to do.
|
|
||||||
//
|
|
||||||
// A rather convoluted algorithm has been devised to determine when Node is
|
|
||||||
// idle. You'll have to figure it out for yourself.
|
|
||||||
uv_check_t gc_check;
|
|
||||||
uv_idle_t gc_idle;
|
|
||||||
uv_timer_t gc_timer;
|
|
||||||
bool need_gc;
|
|
||||||
# define FAST_TICK 700.
|
|
||||||
# define GC_WAIT_TIME 5000.
|
|
||||||
# define RPM_SAMPLES 100
|
|
||||||
int64_t tick_times[RPM_SAMPLES];
|
|
||||||
int tick_time_head;
|
|
||||||
int uncaught_exception_counter;
|
|
||||||
v8::Persistent<v8::Object> binding_cache;
|
|
||||||
v8::Persistent<v8::Array> module_load_list;
|
|
||||||
v8::Isolate* node_isolate;
|
|
||||||
volatile bool debugger_running;
|
|
||||||
double prog_start_time;
|
|
||||||
|
|
||||||
// stream_wrap.cc
|
|
||||||
size_t slab_used;
|
|
||||||
uv_stream_t* handle_that_last_alloced;
|
|
||||||
v8::Persistent<v8::String> slab_sym;
|
|
||||||
v8::Persistent<v8::String> buffer_sym;
|
|
||||||
v8::Persistent<v8::String> write_queue_size_sym;
|
|
||||||
bool stream_wrap_initialized;
|
|
||||||
|
|
||||||
// tcp_wrap.cc
|
|
||||||
v8::Persistent<v8::Function> tcpConstructor;
|
|
||||||
v8::Persistent<v8::String> family_symbol;
|
|
||||||
v8::Persistent<v8::String> address_symbol;
|
|
||||||
v8::Persistent<v8::String> port_symbol;
|
|
||||||
|
|
||||||
// node_http_parser.cc
|
|
||||||
v8::Persistent<v8::String> on_headers_sym;
|
|
||||||
v8::Persistent<v8::String> on_headers_complete_sym;
|
|
||||||
v8::Persistent<v8::String> on_body_sym;
|
|
||||||
v8::Persistent<v8::String> on_message_complete_sym;
|
|
||||||
v8::Persistent<v8::String> delete_sym;
|
|
||||||
v8::Persistent<v8::String> get_sym;
|
|
||||||
v8::Persistent<v8::String> head_sym;
|
|
||||||
v8::Persistent<v8::String> post_sym;
|
|
||||||
v8::Persistent<v8::String> put_sym;
|
|
||||||
v8::Persistent<v8::String> connect_sym;
|
|
||||||
v8::Persistent<v8::String> options_sym;
|
|
||||||
v8::Persistent<v8::String> trace_sym;
|
|
||||||
v8::Persistent<v8::String> patch_sym;
|
|
||||||
v8::Persistent<v8::String> copy_sym;
|
|
||||||
v8::Persistent<v8::String> lock_sym;
|
|
||||||
v8::Persistent<v8::String> mkcol_sym;
|
|
||||||
v8::Persistent<v8::String> move_sym;
|
|
||||||
v8::Persistent<v8::String> propfind_sym;
|
|
||||||
v8::Persistent<v8::String> proppatch_sym;
|
|
||||||
v8::Persistent<v8::String> unlock_sym;
|
|
||||||
v8::Persistent<v8::String> report_sym;
|
|
||||||
v8::Persistent<v8::String> mkactivity_sym;
|
|
||||||
v8::Persistent<v8::String> checkout_sym;
|
|
||||||
v8::Persistent<v8::String> merge_sym;
|
|
||||||
v8::Persistent<v8::String> msearch_sym;
|
|
||||||
v8::Persistent<v8::String> notify_sym;
|
|
||||||
v8::Persistent<v8::String> subscribe_sym;
|
|
||||||
v8::Persistent<v8::String> unsubscribe_sym;
|
|
||||||
v8::Persistent<v8::String> unknown_method_sym;
|
|
||||||
v8::Persistent<v8::String> method_sym;
|
|
||||||
v8::Persistent<v8::String> status_code_sym;
|
|
||||||
v8::Persistent<v8::String> http_version_sym;
|
|
||||||
v8::Persistent<v8::String> version_major_sym;
|
|
||||||
v8::Persistent<v8::String> version_minor_sym;
|
|
||||||
v8::Persistent<v8::String> should_keep_alive_sym;
|
|
||||||
v8::Persistent<v8::String> upgrade_sym;
|
|
||||||
v8::Persistent<v8::String> headers_sym;
|
|
||||||
v8::Persistent<v8::String> url_sym;
|
|
||||||
struct http_parser_settings settings;
|
|
||||||
// This is a hack to get the current_buffer to the callbacks with the least
|
|
||||||
// amount of overhead. Nothing else will run while http_parser_execute()
|
|
||||||
// runs, therefore this pointer can be set and used for the execution.
|
|
||||||
v8::Local<v8::Value>* current_buffer;
|
|
||||||
char* current_buffer_data;
|
|
||||||
size_t current_buffer_len;
|
|
||||||
|
|
||||||
// node_file.cc
|
|
||||||
v8::Persistent<v8::String> encoding_symbol;
|
|
||||||
v8::Persistent<v8::String> buf_symbol;
|
|
||||||
v8::Persistent<v8::String> oncomplete_sym;
|
|
||||||
v8::Persistent<v8::FunctionTemplate> stats_constructor_template;
|
|
||||||
v8::Persistent<v8::String> dev_symbol;
|
|
||||||
v8::Persistent<v8::String> ino_symbol;
|
|
||||||
v8::Persistent<v8::String> mode_symbol;
|
|
||||||
v8::Persistent<v8::String> nlink_symbol;
|
|
||||||
v8::Persistent<v8::String> uid_symbol;
|
|
||||||
v8::Persistent<v8::String> gid_symbol;
|
|
||||||
v8::Persistent<v8::String> rdev_symbol;
|
|
||||||
v8::Persistent<v8::String> size_symbol;
|
|
||||||
v8::Persistent<v8::String> blksize_symbol;
|
|
||||||
v8::Persistent<v8::String> blocks_symbol;
|
|
||||||
v8::Persistent<v8::String> atime_symbol;
|
|
||||||
v8::Persistent<v8::String> mtime_symbol;
|
|
||||||
v8::Persistent<v8::String> ctime_symbol;
|
|
||||||
|
|
||||||
// node_zlib.cc
|
|
||||||
v8::Persistent<v8::String> callback_sym;
|
|
||||||
|
|
||||||
// node_crypto.cc
|
|
||||||
v8::Persistent<v8::String> subject_symbol;
|
|
||||||
v8::Persistent<v8::String> subjectaltname_symbol;
|
|
||||||
v8::Persistent<v8::String> modulus_symbol;
|
|
||||||
v8::Persistent<v8::String> exponent_symbol;
|
|
||||||
v8::Persistent<v8::String> issuer_symbol;
|
|
||||||
v8::Persistent<v8::String> valid_from_symbol;
|
|
||||||
v8::Persistent<v8::String> valid_to_symbol;
|
|
||||||
v8::Persistent<v8::String> fingerprint_symbol;
|
|
||||||
v8::Persistent<v8::String> name_symbol;
|
|
||||||
v8::Persistent<v8::String> version_symbol;
|
|
||||||
v8::Persistent<v8::String> ext_key_usage_symbol;
|
|
||||||
v8::Persistent<v8::FunctionTemplate> secure_context_constructor;
|
|
||||||
|
|
||||||
// node_buffer.cc
|
|
||||||
v8::Persistent<v8::String> length_symbol;
|
|
||||||
v8::Persistent<v8::String> chars_written_sym;
|
|
||||||
v8::Persistent<v8::String> write_sym;
|
|
||||||
v8::Persistent<v8::FunctionTemplate> buffer_constructor_template;
|
|
||||||
|
|
||||||
// node_script.cc
|
|
||||||
v8::Persistent<v8::FunctionTemplate> wrapped_context_constructor;
|
|
||||||
v8::Persistent<v8::FunctionTemplate> wrapped_script_constructor;
|
|
||||||
|
|
||||||
// node_isolate.cc
|
|
||||||
v8::Persistent<v8::FunctionTemplate> isolate_debugger_constructor;
|
|
||||||
|
|
||||||
// node_signal_watcher.cc
|
|
||||||
v8::Persistent<v8::String> callback_symbol;
|
|
||||||
v8::Persistent<v8::FunctionTemplate> signal_watcher_constructor_template;
|
|
||||||
|
|
||||||
// cares_wrap.cc
|
|
||||||
::ares_channel ares_channel;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize globals struct.
|
|
||||||
void globals_init(struct globals*);
|
|
||||||
|
|
||||||
// Get the globals struct for the current Isolate. The returned pointer is
|
|
||||||
// already initialized.
|
|
||||||
struct globals* globals_get();
|
|
||||||
|
|
||||||
} // namespace node
|
|
||||||
#endif // NODE_VARS_H
|
|
@ -29,16 +29,14 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define callback_sym NODE_VAR(callback_sym)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
|
||||||
|
|
||||||
|
static Persistent<String> callback_sym;
|
||||||
|
|
||||||
enum node_zlib_mode {
|
enum node_zlib_mode {
|
||||||
DEFLATE = 1,
|
DEFLATE = 1,
|
||||||
INFLATE,
|
INFLATE,
|
||||||
@ -127,7 +125,7 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
|||||||
// set this so that later on, I can easily tell how much was written.
|
// set this so that later on, I can easily tell how much was written.
|
||||||
ctx->chunk_size_ = out_len;
|
ctx->chunk_size_ = out_len;
|
||||||
|
|
||||||
uv_queue_work(Loop(),
|
uv_queue_work(uv_default_loop(),
|
||||||
work_req,
|
work_req,
|
||||||
ZCtx<mode>::Process,
|
ZCtx<mode>::Process,
|
||||||
ZCtx<mode>::After);
|
ZCtx<mode>::After);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <stream_wrap.h>
|
#include <stream_wrap.h>
|
||||||
@ -124,7 +123,7 @@ Handle<Value> PipeWrap::New(const Arguments& args) {
|
|||||||
|
|
||||||
PipeWrap::PipeWrap(Handle<Object> object, bool ipc)
|
PipeWrap::PipeWrap(Handle<Object> object, bool ipc)
|
||||||
: StreamWrap(object, (uv_stream_t*) &handle_) {
|
: StreamWrap(object, (uv_stream_t*) &handle_) {
|
||||||
int r = uv_pipe_init(Loop(), &handle_, ipc);
|
int r = uv_pipe_init(uv_default_loop(), &handle_, ipc);
|
||||||
assert(r == 0); // How do we proxy this error up to javascript?
|
assert(r == 0); // How do we proxy this error up to javascript?
|
||||||
// Suggestion: uv_pipe_init() returns void.
|
// Suggestion: uv_pipe_init() returns void.
|
||||||
handle_.data = reinterpret_cast<void*>(this);
|
handle_.data = reinterpret_cast<void*>(this);
|
||||||
@ -142,7 +141,7 @@ Handle<Value> PipeWrap::Bind(const Arguments& args) {
|
|||||||
int r = uv_pipe_bind(&wrap->handle_, *name);
|
int r = uv_pipe_bind(&wrap->handle_, *name);
|
||||||
|
|
||||||
// Error starting the pipe.
|
// Error starting the pipe.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -173,7 +172,7 @@ Handle<Value> PipeWrap::Listen(const Arguments& args) {
|
|||||||
int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection);
|
int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection);
|
||||||
|
|
||||||
// Error starting the pipe.
|
// Error starting the pipe.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -226,7 +225,7 @@ void PipeWrap::AfterConnect(uv_connect_t* req, int status) {
|
|||||||
assert(wrap->object_.IsEmpty() == false);
|
assert(wrap->object_.IsEmpty() == false);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> argv[3] = {
|
Local<Value> argv[3] = {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <pipe_wrap.h>
|
#include <pipe_wrap.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -176,10 +175,10 @@ class ProcessWrap : public HandleWrap {
|
|||||||
Get(String::NewSymbol("windowsVerbatimArguments"))->IsTrue();
|
Get(String::NewSymbol("windowsVerbatimArguments"))->IsTrue();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int r = uv_spawn(Loop(), &wrap->process_, options);
|
int r = uv_spawn(uv_default_loop(), &wrap->process_, options);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
wrap->SetHandle((uv_handle_t*)&wrap->process_);
|
wrap->SetHandle((uv_handle_t*)&wrap->process_);
|
||||||
@ -212,7 +211,7 @@ class ProcessWrap : public HandleWrap {
|
|||||||
|
|
||||||
int r = uv_process_kill(&wrap->process_, signal);
|
int r = uv_process_kill(&wrap->process_, signal);
|
||||||
|
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
|
@ -21,24 +21,11 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <stream_wrap.h>
|
#include <stream_wrap.h>
|
||||||
#include <tcp_wrap.h>
|
#include <tcp_wrap.h>
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define slab_used NODE_VAR(slab_used)
|
|
||||||
#define slab_sym NODE_VAR(slab_sym)
|
|
||||||
#define handle_that_last_alloced NODE_VAR(handle_that_last_alloced)
|
|
||||||
#define buffer_sym NODE_VAR(buffer_sym)
|
|
||||||
#define buffer_constructor_template NODE_VAR(buffer_constructor_template)
|
|
||||||
#define write_queue_size_sym NODE_VAR(write_queue_size_sym)
|
|
||||||
#define stream_wrap_initialized NODE_VAR(stream_wrap_initialized)
|
|
||||||
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
@ -79,11 +66,19 @@ typedef class ReqWrap<uv_shutdown_t> ShutdownWrap;
|
|||||||
typedef class ReqWrap<uv_write_t> WriteWrap;
|
typedef class ReqWrap<uv_write_t> WriteWrap;
|
||||||
|
|
||||||
|
|
||||||
|
static size_t slab_used;
|
||||||
|
static uv_stream_t* handle_that_last_alloced;
|
||||||
|
static Persistent<String> slab_sym;
|
||||||
|
static Persistent<String> buffer_sym;
|
||||||
|
static Persistent<String> write_queue_size_sym;
|
||||||
|
static bool initialized;
|
||||||
|
|
||||||
|
|
||||||
void StreamWrap::Initialize(Handle<Object> target) {
|
void StreamWrap::Initialize(Handle<Object> target) {
|
||||||
if (stream_wrap_initialized) {
|
if (initialized) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
stream_wrap_initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
@ -134,7 +129,7 @@ Handle<Value> StreamWrap::ReadStart(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Error starting the tcp.
|
// Error starting the tcp.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -148,7 +143,7 @@ Handle<Value> StreamWrap::ReadStop(const Arguments& args) {
|
|||||||
int r = uv_read_stop(wrap->stream_);
|
int r = uv_read_stop(wrap->stream_);
|
||||||
|
|
||||||
// Error starting the tcp.
|
// Error starting the tcp.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -158,7 +153,7 @@ char* StreamWrap::NewSlab(Handle<Object> global,
|
|||||||
Handle<Object> wrap_obj) {
|
Handle<Object> wrap_obj) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
Local<Value> arg = Integer::NewFromUnsigned(SLAB_SIZE);
|
Local<Value> arg = Integer::NewFromUnsigned(SLAB_SIZE);
|
||||||
Local<Object> b = buffer_constructor_template->GetFunction()->
|
Local<Object> b = Buffer::constructor_template->GetFunction()->
|
||||||
NewInstance(1, &arg);
|
NewInstance(1, &arg);
|
||||||
if (b.IsEmpty()) return NULL;
|
if (b.IsEmpty()) return NULL;
|
||||||
global->SetHiddenValue(slab_sym, b);
|
global->SetHiddenValue(slab_sym, b);
|
||||||
@ -231,7 +226,7 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
|
|||||||
slab_used -= buf.len;
|
slab_used -= buf.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
MakeCallback(wrap->object_, "onread", 0, NULL);
|
MakeCallback(wrap->object_, "onread", 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -344,7 +339,7 @@ Handle<Value> StreamWrap::Write(const Arguments& args) {
|
|||||||
wrap->UpdateWriteQueueSize();
|
wrap->UpdateWriteQueueSize();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
@ -364,7 +359,7 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
|
|||||||
assert(wrap->object_.IsEmpty() == false);
|
assert(wrap->object_.IsEmpty() == false);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap->UpdateWriteQueueSize();
|
wrap->UpdateWriteQueueSize();
|
||||||
@ -394,7 +389,7 @@ Handle<Value> StreamWrap::Shutdown(const Arguments& args) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
@ -414,7 +409,7 @@ void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
|
|||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> argv[3] = {
|
Local<Value> argv[3] = {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <stream_wrap.h>
|
#include <stream_wrap.h>
|
||||||
@ -56,15 +55,6 @@
|
|||||||
return scope.Close(Integer::New(-1)); \
|
return scope.Close(Integer::New(-1)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
// We do the following to minimize the detal between v0.6 branch. We want to
|
|
||||||
// use the variables as they were being used before.
|
|
||||||
#define tcpConstructor NODE_VAR(tcpConstructor)
|
|
||||||
#define family_symbol NODE_VAR(family_symbol)
|
|
||||||
#define address_symbol NODE_VAR(address_symbol)
|
|
||||||
#define port_symbol NODE_VAR(port_symbol)
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
@ -82,6 +72,12 @@ using v8::Arguments;
|
|||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
using v8::Undefined;
|
using v8::Undefined;
|
||||||
|
|
||||||
|
static Persistent<Function> tcpConstructor;
|
||||||
|
static Persistent<String> family_symbol;
|
||||||
|
static Persistent<String> address_symbol;
|
||||||
|
static Persistent<String> port_symbol;
|
||||||
|
|
||||||
|
|
||||||
typedef class ReqWrap<uv_connect_t> ConnectWrap;
|
typedef class ReqWrap<uv_connect_t> ConnectWrap;
|
||||||
|
|
||||||
|
|
||||||
@ -155,7 +151,7 @@ Handle<Value> TCPWrap::New(const Arguments& args) {
|
|||||||
|
|
||||||
TCPWrap::TCPWrap(Handle<Object> object)
|
TCPWrap::TCPWrap(Handle<Object> object)
|
||||||
: StreamWrap(object, (uv_stream_t*) &handle_) {
|
: StreamWrap(object, (uv_stream_t*) &handle_) {
|
||||||
int r = uv_tcp_init(Loop(), &handle_);
|
int r = uv_tcp_init(uv_default_loop(), &handle_);
|
||||||
assert(r == 0); // How do we proxy this error up to javascript?
|
assert(r == 0); // How do we proxy this error up to javascript?
|
||||||
// Suggestion: uv_tcp_init() returns void.
|
// Suggestion: uv_tcp_init() returns void.
|
||||||
UpdateWriteQueueSize();
|
UpdateWriteQueueSize();
|
||||||
@ -183,7 +179,7 @@ Handle<Value> TCPWrap::GetSockName(const Arguments& args) {
|
|||||||
|
|
||||||
Local<Object> sockname = Object::New();
|
Local<Object> sockname = Object::New();
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
} else {
|
} else {
|
||||||
family = address.ss_family;
|
family = address.ss_family;
|
||||||
|
|
||||||
@ -225,7 +221,7 @@ Handle<Value> TCPWrap::GetPeerName(const Arguments& args) {
|
|||||||
|
|
||||||
Local<Object> sockname = Object::New();
|
Local<Object> sockname = Object::New();
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
} else {
|
} else {
|
||||||
family = address.ss_family;
|
family = address.ss_family;
|
||||||
|
|
||||||
@ -258,7 +254,7 @@ Handle<Value> TCPWrap::SetNoDelay(const Arguments& args) {
|
|||||||
|
|
||||||
int r = uv_tcp_nodelay(&wrap->handle_, 1);
|
int r = uv_tcp_nodelay(&wrap->handle_, 1);
|
||||||
if (r)
|
if (r)
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
@ -274,7 +270,7 @@ Handle<Value> TCPWrap::SetKeepAlive(const Arguments& args) {
|
|||||||
|
|
||||||
int r = uv_tcp_keepalive(&wrap->handle_, enable, delay);
|
int r = uv_tcp_keepalive(&wrap->handle_, enable, delay);
|
||||||
if (r)
|
if (r)
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
@ -290,7 +286,7 @@ Handle<Value> TCPWrap::SetSimultaneousAccepts(const Arguments& args) {
|
|||||||
|
|
||||||
int r = uv_tcp_simultaneous_accepts(&wrap->handle_, enable ? 1 : 0);
|
int r = uv_tcp_simultaneous_accepts(&wrap->handle_, enable ? 1 : 0);
|
||||||
if (r)
|
if (r)
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
@ -309,7 +305,7 @@ Handle<Value> TCPWrap::Bind(const Arguments& args) {
|
|||||||
int r = uv_tcp_bind(&wrap->handle_, address);
|
int r = uv_tcp_bind(&wrap->handle_, address);
|
||||||
|
|
||||||
// Error starting the tcp.
|
// Error starting the tcp.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -327,7 +323,7 @@ Handle<Value> TCPWrap::Bind6(const Arguments& args) {
|
|||||||
int r = uv_tcp_bind6(&wrap->handle_, address);
|
int r = uv_tcp_bind6(&wrap->handle_, address);
|
||||||
|
|
||||||
// Error starting the tcp.
|
// Error starting the tcp.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -343,7 +339,7 @@ Handle<Value> TCPWrap::Listen(const Arguments& args) {
|
|||||||
int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection);
|
int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection);
|
||||||
|
|
||||||
// Error starting the tcp.
|
// Error starting the tcp.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -378,7 +374,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
|
|||||||
// Successful accept. Call the onconnection callback in JavaScript land.
|
// Successful accept. Call the onconnection callback in JavaScript land.
|
||||||
argv[0] = client_obj;
|
argv[0] = client_obj;
|
||||||
} else {
|
} else {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
argv[0] = v8::Null();
|
argv[0] = v8::Null();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +393,7 @@ void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
|
|||||||
assert(wrap->object_.IsEmpty() == false);
|
assert(wrap->object_.IsEmpty() == false);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> argv[3] = {
|
Local<Value> argv[3] = {
|
||||||
@ -433,7 +429,7 @@ Handle<Value> TCPWrap::Connect(const Arguments& args) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
@ -460,7 +456,7 @@ Handle<Value> TCPWrap::Connect6(const Arguments& args) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return scope.Close(v8::Null());
|
return scope.Close(v8::Null());
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
#define UNWRAP \
|
#define UNWRAP \
|
||||||
assert(!args.Holder().IsEmpty()); \
|
assert(!args.Holder().IsEmpty()); \
|
||||||
@ -92,7 +91,7 @@ class TimerWrap : public HandleWrap {
|
|||||||
: HandleWrap(object, (uv_handle_t*) &handle_) {
|
: HandleWrap(object, (uv_handle_t*) &handle_) {
|
||||||
active_ = false;
|
active_ = false;
|
||||||
|
|
||||||
int r = uv_timer_init(Loop(), &handle_);
|
int r = uv_timer_init(uv_default_loop(), &handle_);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
|
|
||||||
handle_.data = this;
|
handle_.data = this;
|
||||||
@ -100,11 +99,11 @@ class TimerWrap : public HandleWrap {
|
|||||||
// uv_timer_init adds a loop reference. (That is, it calls uv_ref.) This
|
// uv_timer_init adds a loop reference. (That is, it calls uv_ref.) This
|
||||||
// is not the behavior we want in Node. Timers should not increase the
|
// is not the behavior we want in Node. Timers should not increase the
|
||||||
// ref count of the loop except when active.
|
// ref count of the loop except when active.
|
||||||
uv_unref(Loop());
|
uv_unref(uv_default_loop());
|
||||||
}
|
}
|
||||||
|
|
||||||
~TimerWrap() {
|
~TimerWrap() {
|
||||||
if (!active_) uv_ref(Loop());
|
if (!active_) uv_ref(uv_default_loop());
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateChange() {
|
void StateChange() {
|
||||||
@ -114,11 +113,11 @@ class TimerWrap : public HandleWrap {
|
|||||||
if (!was_active && active_) {
|
if (!was_active && active_) {
|
||||||
// If our state is changing from inactive to active, we
|
// If our state is changing from inactive to active, we
|
||||||
// increase the loop's reference count.
|
// increase the loop's reference count.
|
||||||
uv_ref(Loop());
|
uv_ref(uv_default_loop());
|
||||||
} else if (was_active && !active_) {
|
} else if (was_active && !active_) {
|
||||||
// If our state is changing from active to inactive, we
|
// If our state is changing from active to inactive, we
|
||||||
// decrease the loop's reference count.
|
// decrease the loop's reference count.
|
||||||
uv_unref(Loop());
|
uv_unref(uv_default_loop());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +132,7 @@ class TimerWrap : public HandleWrap {
|
|||||||
int r = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat);
|
int r = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat);
|
||||||
|
|
||||||
// Error starting the timer.
|
// Error starting the timer.
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
wrap->StateChange();
|
wrap->StateChange();
|
||||||
|
|
||||||
@ -147,7 +146,7 @@ class TimerWrap : public HandleWrap {
|
|||||||
|
|
||||||
int r = uv_timer_stop(&wrap->handle_);
|
int r = uv_timer_stop(&wrap->handle_);
|
||||||
|
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
wrap->StateChange();
|
wrap->StateChange();
|
||||||
|
|
||||||
@ -161,7 +160,7 @@ class TimerWrap : public HandleWrap {
|
|||||||
|
|
||||||
int r = uv_timer_again(&wrap->handle_);
|
int r = uv_timer_again(&wrap->handle_);
|
||||||
|
|
||||||
if (r) SetErrno(uv_last_error(Loop()));
|
if (r) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
wrap->StateChange();
|
wrap->StateChange();
|
||||||
|
|
||||||
@ -187,7 +186,7 @@ class TimerWrap : public HandleWrap {
|
|||||||
|
|
||||||
int64_t repeat = uv_timer_get_repeat(&wrap->handle_);
|
int64_t repeat = uv_timer_get_repeat(&wrap->handle_);
|
||||||
|
|
||||||
if (repeat < 0) SetErrno(uv_last_error(Loop()));
|
if (repeat < 0) SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(repeat));
|
return scope.Close(Integer::New(repeat));
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
#include <stream_wrap.h>
|
#include <stream_wrap.h>
|
||||||
@ -125,7 +124,7 @@ class TTYWrap : StreamWrap {
|
|||||||
int r = uv_tty_get_winsize(&wrap->handle_, &width, &height);
|
int r = uv_tty_get_winsize(&wrap->handle_, &width, &height);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
return v8::Undefined();
|
return v8::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ class TTYWrap : StreamWrap {
|
|||||||
int r = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue());
|
int r = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue());
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
@ -170,7 +169,7 @@ class TTYWrap : StreamWrap {
|
|||||||
|
|
||||||
TTYWrap(Handle<Object> object, int fd, bool readable)
|
TTYWrap(Handle<Object> object, int fd, bool readable)
|
||||||
: StreamWrap(object, (uv_stream_t*)&handle_) {
|
: StreamWrap(object, (uv_stream_t*)&handle_) {
|
||||||
uv_tty_init(Loop(), &handle_, fd, readable);
|
uv_tty_init(uv_default_loop(), &handle_, fd, readable);
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_tty_t handle_;
|
uv_tty_t handle_;
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include <node_buffer.h>
|
#include <node_buffer.h>
|
||||||
#include <node_vars.h>
|
|
||||||
|
|
||||||
#include <req_wrap.h>
|
#include <req_wrap.h>
|
||||||
#include <handle_wrap.h>
|
#include <handle_wrap.h>
|
||||||
@ -124,7 +123,7 @@ private:
|
|||||||
|
|
||||||
UDPWrap::UDPWrap(Handle<Object> object): HandleWrap(object,
|
UDPWrap::UDPWrap(Handle<Object> object): HandleWrap(object,
|
||||||
(uv_handle_t*)&handle_) {
|
(uv_handle_t*)&handle_) {
|
||||||
int r = uv_udp_init(Loop(), &handle_);
|
int r = uv_udp_init(uv_default_loop(), &handle_);
|
||||||
assert(r == 0); // can't fail anyway
|
assert(r == 0); // can't fail anyway
|
||||||
handle_.data = reinterpret_cast<void*>(this);
|
handle_.data = reinterpret_cast<void*>(this);
|
||||||
}
|
}
|
||||||
@ -203,7 +202,7 @@ Handle<Value> UDPWrap::DoBind(const Arguments& args, int family) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
|
||||||
return scope.Close(Integer::New(r));
|
return scope.Close(Integer::New(r));
|
||||||
}
|
}
|
||||||
@ -314,7 +313,7 @@ Handle<Value> UDPWrap::DoSend(const Arguments& args, int family) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
delete req_wrap;
|
delete req_wrap;
|
||||||
return Null();
|
return Null();
|
||||||
}
|
}
|
||||||
@ -341,8 +340,8 @@ Handle<Value> UDPWrap::RecvStart(const Arguments& args) {
|
|||||||
|
|
||||||
// UV_EALREADY means that the socket is already bound but that's okay
|
// UV_EALREADY means that the socket is already bound but that's okay
|
||||||
int r = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
|
int r = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
|
||||||
if (r && uv_last_error(Loop()).code != UV_EALREADY) {
|
if (r && uv_last_error(uv_default_loop()).code != UV_EALREADY) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
return False();
|
return False();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +377,7 @@ Handle<Value> UDPWrap::GetSockName(const Arguments& args) {
|
|||||||
return scope.Close(sockname);
|
return scope.Close(sockname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
return Null();
|
return Null();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,7 +396,7 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
|
|||||||
assert(wrap->object_.IsEmpty() == false);
|
assert(wrap->object_.IsEmpty() == false);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> argv[4] = {
|
Local<Value> argv[4] = {
|
||||||
@ -475,7 +474,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (nread == -1) {
|
if (nread == -1) {
|
||||||
SetErrno(uv_last_error(Loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Local<Object> rinfo = Object::New();
|
Local<Object> rinfo = Object::New();
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
#include <node.h>
|
|
||||||
#include <v8.h>
|
|
||||||
#include <uv.h>
|
|
||||||
|
|
||||||
using namespace v8;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
void init(Handle<Object> target);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
|
||||||
static uint8_t buf[BUFSIZE];
|
|
||||||
static uv_mutex_t lock;
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> Get(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
int index = args[0]->Uint32Value();
|
|
||||||
|
|
||||||
if (index < 0 || BUFSIZE <= index) {
|
|
||||||
return ThrowException(Exception::Error(String::New("out of bounds")));
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(Integer::New(buf[index]));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> Set(const Arguments& args) {
|
|
||||||
uv_mutex_lock(&lock);
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
int index = args[0]->Uint32Value();
|
|
||||||
|
|
||||||
if (index < 0 || BUFSIZE <= index) {
|
|
||||||
return ThrowException(Exception::Error(String::New("out of bounds")));
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[index] = args[1]->Uint32Value();
|
|
||||||
|
|
||||||
Local<Integer> val = Integer::New(buf[index]);
|
|
||||||
|
|
||||||
uv_mutex_unlock(&lock);
|
|
||||||
|
|
||||||
return scope.Close(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void init(Handle<Object> target) {
|
|
||||||
NODE_SET_METHOD(target, "get", Get);
|
|
||||||
NODE_SET_METHOD(target, "set", Set);
|
|
||||||
target->Set(String::New("length"), Integer::New(BUFSIZE));
|
|
||||||
uv_mutex_init(&lock);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'binding',
|
|
||||||
'sources': [ 'binding.cc' ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
var assert = require('assert');
|
|
||||||
var binding = require('./out/Release/binding');
|
|
||||||
var isolates = process.binding('isolates');
|
|
||||||
|
|
||||||
console.log("binding.length =", binding.length);
|
|
||||||
|
|
||||||
if (process.tid === 1) {
|
|
||||||
var isolate = isolates.create(process.argv);
|
|
||||||
for (var i = 0; i < binding.length; i++) {
|
|
||||||
console.log('parent',
|
|
||||||
'binding.set(' + i + ', ' + i + ')',
|
|
||||||
binding.set(i, i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (var i = 0; i < binding.length; i++) {
|
|
||||||
console.log('child', 'binding.get(' + i + ')', binding.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -24,13 +24,7 @@ var common = require('../common');
|
|||||||
var fork = require('child_process').fork;
|
var fork = require('child_process').fork;
|
||||||
var args = ['foo', 'bar'];
|
var args = ['foo', 'bar'];
|
||||||
|
|
||||||
var options = {
|
var n = fork(common.fixturesDir + '/child-process-spawn-node.js', args);
|
||||||
thread: process.TEST_ISOLATE ? true : false
|
|
||||||
};
|
|
||||||
|
|
||||||
var n = fork(common.fixturesDir + '/child-process-spawn-node.js',
|
|
||||||
args,
|
|
||||||
options);
|
|
||||||
assert.deepEqual(args, ['foo', 'bar']);
|
assert.deepEqual(args, ['foo', 'bar']);
|
||||||
|
|
||||||
var messageCount = 0;
|
var messageCount = 0;
|
||||||
|
@ -27,11 +27,7 @@ var net = require('net');
|
|||||||
var socketCloses = 0;
|
var socketCloses = 0;
|
||||||
var N = 10;
|
var N = 10;
|
||||||
|
|
||||||
var options = {
|
var n = fork(common.fixturesDir + '/fork2.js');
|
||||||
thread: process.TEST_ISOLATE ? true : false
|
|
||||||
};
|
|
||||||
|
|
||||||
var n = fork(common.fixturesDir + '/fork2.js', [], options);
|
|
||||||
|
|
||||||
var messageCount = 0;
|
var messageCount = 0;
|
||||||
|
|
||||||
|
@ -25,12 +25,8 @@ var fork = require('child_process').fork;
|
|||||||
|
|
||||||
var filename = common.fixturesDir + '/destroy-stdin.js';
|
var filename = common.fixturesDir + '/destroy-stdin.js';
|
||||||
|
|
||||||
var options = {
|
|
||||||
thread: process.TEST_ISOLATE ? true : false
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ensure that we don't accidentally close fd 0 and
|
// Ensure that we don't accidentally close fd 0 and
|
||||||
// reuse it for something else, it causes all kinds
|
// reuse it for something else, it causes all kinds
|
||||||
// of obscure bugs.
|
// of obscure bugs.
|
||||||
process.stdin.destroy();
|
process.stdin.destroy();
|
||||||
fork(filename, [], options).stdin.on('end', process.exit);
|
fork(filename).stdin.on('end', process.exit);
|
||||||
|
@ -76,19 +76,12 @@ function addTest(input, output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial lines
|
// Initial lines
|
||||||
if (process.features.isolates) {
|
addTest(null, [
|
||||||
addTest(null, [
|
/listening on port 5858/,
|
||||||
/break in .*:1/,
|
/connecting... ok/,
|
||||||
/1/, /2/, /3/
|
/break in .*:1/,
|
||||||
]);
|
/1/, /2/, /3/
|
||||||
} else {
|
]);
|
||||||
addTest(null, [
|
|
||||||
/listening on port 5858/,
|
|
||||||
/connecting... ok/,
|
|
||||||
/break in .*:1/,
|
|
||||||
/1/, /2/, /3/
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next
|
// Next
|
||||||
addTest('n', [
|
addTest('n', [
|
||||||
|
@ -81,19 +81,12 @@ function addTest(input, output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial lines
|
// Initial lines
|
||||||
if (process.features.isolates) {
|
addTest(null, [
|
||||||
addTest(null, [
|
/listening on port 5858/,
|
||||||
/break in .*:1/,
|
/connecting... ok/,
|
||||||
/1/, /2/, /3/
|
/break in .*:1/,
|
||||||
]);
|
/1/, /2/, /3/
|
||||||
} else {
|
]);
|
||||||
addTest(null, [
|
|
||||||
/listening on port 5858/,
|
|
||||||
/connecting... ok/,
|
|
||||||
/break in .*:1/,
|
|
||||||
/1/, /2/, /3/
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next
|
// Next
|
||||||
addTest('n', [
|
addTest('n', [
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
var isolates = process.binding('isolates');
|
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
var N_ISOLATES = 4;
|
|
||||||
var N_MESSAGES = 20;
|
|
||||||
var N_MESSAGES_PER_TICK = 4;
|
|
||||||
|
|
||||||
assert(N_MESSAGES % N_MESSAGES_PER_TICK == 0);
|
|
||||||
|
|
||||||
if (process.tid === 1)
|
|
||||||
master();
|
|
||||||
else
|
|
||||||
child();
|
|
||||||
|
|
||||||
function master() {
|
|
||||||
for (var i = 0; i < N_ISOLATES; ++i) spawn();
|
|
||||||
|
|
||||||
function spawn() {
|
|
||||||
var isolate = isolates.create(process.argv);
|
|
||||||
|
|
||||||
var gotExit = false; // exit event emitted?
|
|
||||||
var msgId = 0; // message IDs seen so far
|
|
||||||
var tick = 0;
|
|
||||||
|
|
||||||
isolate.onexit = function() {
|
|
||||||
gotExit = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
isolate.onmessage = function(buf) {
|
|
||||||
var msg = JSON.parse(buf);
|
|
||||||
assert.equal(msg.id, msgId + 1); // verify that messages arrive in order
|
|
||||||
assert.equal(msg.tick, tick); // and on the proper tick (=full mq drain)
|
|
||||||
msgId = msg.id;
|
|
||||||
if (msgId % N_MESSAGES_PER_TICK == 0) tick++;
|
|
||||||
isolate.send(buf);
|
|
||||||
};
|
|
||||||
|
|
||||||
process.on('exit', function() {
|
|
||||||
assert.equal(gotExit, true);
|
|
||||||
assert.equal(msgId, N_MESSAGES);
|
|
||||||
assert.equal(tick, N_MESSAGES / N_MESSAGES_PER_TICK);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function child() {
|
|
||||||
var msgId = 0;
|
|
||||||
var tick = 0;
|
|
||||||
|
|
||||||
function send() {
|
|
||||||
// Send multiple messages, verify that the message queue
|
|
||||||
// is completely drained on each tick of the event loop.
|
|
||||||
for (var i = 0; i < N_MESSAGES_PER_TICK; ++i) {
|
|
||||||
process.send({tick:tick, id:++msgId});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msgId < N_MESSAGES) {
|
|
||||||
setTimeout(send, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
tick++;
|
|
||||||
}
|
|
||||||
|
|
||||||
send();
|
|
||||||
|
|
||||||
process._onmessage = function(m) {
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
var fs = require('fs');
|
|
||||||
var http = require('http');
|
|
||||||
var isolates = process.binding('isolates');
|
|
||||||
|
|
||||||
console.log("count: %d", isolates.count());
|
|
||||||
|
|
||||||
if (process.tid === 1) {
|
|
||||||
var isolate = isolates.create(process.argv, {
|
|
||||||
debug: function init(d) {
|
|
||||||
d.onmessage = function(data) {
|
|
||||||
data = JSON.parse(data);
|
|
||||||
if (data.event === 'break') {
|
|
||||||
d.write(JSON.stringify({
|
|
||||||
type: 'request',
|
|
||||||
seq: 1,
|
|
||||||
command: 'continue'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
isolate.onmessage = function() {
|
|
||||||
console.error("onmessage");
|
|
||||||
};
|
|
||||||
isolate.onexit = function() {
|
|
||||||
console.error("onexit");
|
|
||||||
};
|
|
||||||
|
|
||||||
console.error("master");
|
|
||||||
fs.stat(__dirname, function(err, stat) {
|
|
||||||
if (err) throw err;
|
|
||||||
console.error('thread 1', stat.mtime);
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
fs.stat(__dirname, function(err, stat) {
|
|
||||||
if (err) throw err;
|
|
||||||
console.error('thread 1', stat.mtime);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
console.log("thread 1 count: %d", isolates.count());
|
|
||||||
} else {
|
|
||||||
console.error("slave");
|
|
||||||
fs.stat(__dirname, function(err, stat) {
|
|
||||||
if (err) throw err;
|
|
||||||
console.error('thread 2', stat.mtime);
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
fs.stat(__dirname, function(err, stat) {
|
|
||||||
if (err) throw err;
|
|
||||||
console.error('thread 2', stat.mtime);
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
console.error("thread 2 count: %d", isolates.count());
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
// Skip this test if Node is not compiled with isolates support.
|
|
||||||
if (!process.features.isolates) return;
|
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
// This is the same test as test-child-process-fork except it uses isolates
|
|
||||||
// instead of processes. process.TEST_ISOLATE is a ghetto method of passing
|
|
||||||
// some information into the other test.
|
|
||||||
process.TEST_ISOLATE = true;
|
|
||||||
require('./test-child-process-fork');
|
|
||||||
|
|
||||||
var numThreads = process.binding('isolates').count();
|
|
||||||
assert.ok(numThreads > 1);
|
|
@ -1,13 +0,0 @@
|
|||||||
// Skip this test if Node is not compiled with isolates support.
|
|
||||||
if (!process.features.isolates) return;
|
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
// This is the same test as test-child-process-fork2 except it uses isolates
|
|
||||||
// instead of processes. process.TEST_ISOLATE is a ghetto method of passing
|
|
||||||
// some information into the other test.
|
|
||||||
process.TEST_ISOLATE = true;
|
|
||||||
require('./test-child-process-fork2');
|
|
||||||
|
|
||||||
var numThreads = process.binding('isolates').count();
|
|
||||||
assert.ok(numThreads > 1);
|
|
@ -1,13 +0,0 @@
|
|||||||
// Skip this test if Node is not compiled with isolates support.
|
|
||||||
if (!process.features.isolates) return;
|
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
// This is the same test as test-child-process-fork3 except it uses isolates
|
|
||||||
// instead of processes. process.TEST_ISOLATE is a ghetto method of passing
|
|
||||||
// some information into the other test.
|
|
||||||
process.TEST_ISOLATE = true;
|
|
||||||
require('./test-child-process-fork3');
|
|
||||||
|
|
||||||
var numThreads = process.binding('isolates').count();
|
|
||||||
assert.ok(numThreads > 1);
|
|
Loading…
x
Reference in New Issue
Block a user