Skip to content

Instantly share code, notes, and snippets.

@ry
Created December 7, 2011 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ry/1440753 to your computer and use it in GitHub Desktop.
Save ry/1440753 to your computer and use it in GitHub Desktop.
diff --git a/node.gyp b/node.gyp
index 89f5ea7..60f3617 100644
--- a/node.gyp
+++ b/node.gyp
@@ -72,6 +72,7 @@
'src/cares_wrap.cc',
'src/handle_wrap.cc',
'src/node.cc',
+ 'src/node_vars.cc',
'src/node_buffer.cc',
'src/node_constants.cc',
'src/node_extensions.cc',
@@ -94,6 +95,7 @@
# headers to make for a more pleasant IDE experience
'src/handle_wrap.h',
'src/node.h',
+ 'src/node_vars.h',
'src/node_buffer.h',
'src/node_constants.h',
'src/node_crypto.h',
diff --git a/src/node.cc b/src/node.cc
index d0c540f..304ce8a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <node.h>
+#include <node_vars.h>
#include <uv.h>
@@ -97,105 +98,39 @@ extern char **environ;
namespace node {
-static Persistent<Object> process;
-
-static Persistent<String> errno_symbol;
-static Persistent<String> syscall_symbol;
-static Persistent<String> errpath_symbol;
-static Persistent<String> code_symbol;
-
-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;
-
-
-#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 StartGCTimer () {
- if (!uv_is_active((uv_handle_t*) &gc_timer)) {
- uv_timer_start(&node::gc_timer, node::CheckStatus, 5000, 5000);
+ if (!uv_is_active((uv_handle_t*) & NODE_VAR(gc_timer))) {
+ uv_timer_start(& NODE_VAR(gc_timer), node::CheckStatus, 5000, 5000);
}
}
static void StopGCTimer () {
- if (uv_is_active((uv_handle_t*) &gc_timer)) {
- uv_timer_stop(&gc_timer);
+ if (uv_is_active((uv_handle_t*) & NODE_VAR(gc_timer))) {
+ uv_timer_stop(& NODE_VAR(gc_timer));
}
}
static void Idle(uv_idle_t* watcher, int status) {
- assert((uv_idle_t*) watcher == &gc_idle);
+ assert((uv_idle_t*) watcher == & NODE_VAR(gc_idle));
if (V8::IdleNotification()) {
- uv_idle_stop(&gc_idle);
+ uv_idle_stop(& NODE_VAR(gc_idle));
StopGCTimer();
}
}
+#define TICK_TIME(n) NODE_VAR(tick_times)[(NODE_VAR(tick_time_head) - (n)) % RPM_SAMPLES]
+
+
// Called directly after every call to select() (or epoll, or whatever)
static void Check(uv_check_t* watcher, int status) {
assert(watcher == &gc_check);
- tick_times[tick_time_head] = uv_now(uv_default_loop());
- tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
+ NODE_VAR(tick_times)[NODE_VAR(tick_time_head)] = uv_now(uv_default_loop());
+ NODE_VAR(tick_time_head) = (NODE_VAR(tick_time_head) + 1) % RPM_SAMPLES;
StartGCTimer();
@@ -213,35 +148,35 @@ static void Check(uv_check_t* watcher, int status) {
// Otherwise start the gc!
//fprintf(stderr, "start idle 2\n");
- uv_idle_start(&node::gc_idle, node::Idle);
+ uv_idle_start(&NODE_VAR(gc_idle), node::Idle);
}
static void Tick(void) {
// Avoid entering a V8 scope.
- if (!need_tick_cb) return;
+ if (!NODE_VAR(need_tick_cb)) return;
- need_tick_cb = false;
- if (uv_is_active((uv_handle_t*) &tick_spinner)) {
- uv_idle_stop(&tick_spinner);
+ NODE_VAR(need_tick_cb) = false;
+ if (uv_is_active((uv_handle_t*) &NODE_VAR(tick_spinner))) {
+ uv_idle_stop(&NODE_VAR(tick_spinner));
uv_unref(uv_default_loop());
}
HandleScope scope;
- if (tick_callback_sym.IsEmpty()) {
+ if (NODE_VAR(tick_callback_sym).IsEmpty()) {
// Lazily set the symbol
- tick_callback_sym =
+ NODE_VAR(tick_callback_sym) =
Persistent<String>::New(String::NewSymbol("_tickCallback"));
}
- Local<Value> cb_v = process->Get(tick_callback_sym);
+ Local<Value> cb_v = NODE_VAR(process)->Get(NODE_VAR(tick_callback_sym));
if (!cb_v->IsFunction()) return;
Local<Function> cb = Local<Function>::Cast(cb_v);
TryCatch try_catch;
- cb->Call(process, 0, NULL);
+ cb->Call(NODE_VAR(process), 0, NULL);
if (try_catch.HasCaught()) {
FatalException(try_catch);
@@ -250,7 +185,7 @@ static void Tick(void) {
static void Spin(uv_idle_t* handle, int status) {
- assert((uv_idle_t*) handle == &tick_spinner);
+ assert((uv_idle_t*) handle == &NODE_VAR(tick_spinner));
assert(status == 0);
Tick();
}
@@ -258,14 +193,14 @@ static void Spin(uv_idle_t* handle, int status) {
static Handle<Value> NeedTickCallback(const Arguments& args) {
HandleScope scope;
- need_tick_cb = true;
+ NODE_VAR(need_tick_cb) = true;
// TODO: this tick_spinner shouldn't be necessary. An ev_prepare should be
// sufficent, the problem is only in the case of the very last "tick" -
// there is nothing left to do in the event loop and libev will exit. The
// ev_prepare callback isn't called before exiting. Thus we start this
// tick_spinner to keep the event loop alive long enough to handle it.
- if (!uv_is_active((uv_handle_t*) &tick_spinner)) {
- uv_idle_start(&tick_spinner, Spin);
+ if (!uv_is_active((uv_handle_t*) &NODE_VAR(tick_spinner))) {
+ uv_idle_start(&NODE_VAR(tick_spinner), Spin);
uv_ref(uv_default_loop());
}
return Undefined();
@@ -273,14 +208,14 @@ static Handle<Value> NeedTickCallback(const Arguments& args) {
static void PrepareTick(uv_prepare_t* handle, int status) {
- assert(handle == &prepare_tick_watcher);
+ assert(handle == &NODE_VAR(prepare_tick_watcher));
assert(status == 0);
Tick();
}
static void CheckTick(uv_check_t* handle, int status) {
- assert(handle == &check_tick_watcher);
+ assert(handle == &NODE_VAR(check_tick_watcher));
assert(status == 0);
Tick();
}
@@ -774,11 +709,11 @@ Local<Value> ErrnoException(int errorno,
Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
Local<String> cons2 = String::Concat(cons1, message);
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = NODE_PSYMBOL("syscall");
- errno_symbol = NODE_PSYMBOL("errno");
- errpath_symbol = NODE_PSYMBOL("path");
- code_symbol = NODE_PSYMBOL("code");
+ if (NODE_VAR(syscall_symbol).IsEmpty()) {
+ NODE_VAR(syscall_symbol) = NODE_PSYMBOL("syscall");
+ NODE_VAR(errno_symbol) = NODE_PSYMBOL("errno");
+ NODE_VAR(errpath_symbol) = NODE_PSYMBOL("path");
+ NODE_VAR(code_symbol) = NODE_PSYMBOL("code");
}
if (path) {
@@ -792,10 +727,10 @@ Local<Value> ErrnoException(int errorno,
Local<Object> obj = e->ToObject();
- obj->Set(errno_symbol, Integer::New(errorno));
- obj->Set(code_symbol, estring);
- if (path) obj->Set(errpath_symbol, String::New(path));
- if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
+ obj->Set(NODE_VAR(errno_symbol), Integer::New(errorno));
+ obj->Set(NODE_VAR(code_symbol), estring);
+ if (path) obj->Set(NODE_VAR(errpath_symbol), String::New(path));
+ if (syscall) obj->Set(NODE_VAR(syscall_symbol), String::NewSymbol(syscall));
return e;
}
@@ -821,15 +756,12 @@ Local<Value> UVException(int errorno,
const char *syscall,
const char *msg,
const char *path) {
- static Persistent<String> syscall_symbol;
- static Persistent<String> errpath_symbol;
- static Persistent<String> code_symbol;
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = NODE_PSYMBOL("syscall");
- errno_symbol = NODE_PSYMBOL("errno");
- errpath_symbol = NODE_PSYMBOL("path");
- code_symbol = NODE_PSYMBOL("code");
+ if (NODE_VAR(syscall_symbol).IsEmpty()) {
+ NODE_VAR(syscall_symbol) = NODE_PSYMBOL("syscall");
+ NODE_VAR(errno_symbol) = NODE_PSYMBOL("errno");
+ NODE_VAR(errpath_symbol) = NODE_PSYMBOL("path");
+ NODE_VAR(code_symbol) = NODE_PSYMBOL("code");
}
if (!msg || !msg[0])
@@ -868,10 +800,10 @@ Local<Value> UVException(int errorno,
Local<Object> obj = e->ToObject();
// TODO errno should probably go
- obj->Set(errno_symbol, Integer::New(errorno));
- obj->Set(code_symbol, estring);
- if (path) obj->Set(errpath_symbol, path_str);
- if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
+ obj->Set(NODE_VAR(errno_symbol), Integer::New(errorno));
+ obj->Set(NODE_VAR(code_symbol), estring);
+ if (path) obj->Set(NODE_VAR(errpath_symbol), path_str);
+ if (syscall) obj->Set(NODE_VAR(syscall_symbol), String::NewSymbol(syscall));
return e;
}
@@ -887,11 +819,11 @@ Local<Value> WinapiErrnoException(int errorno,
}
Local<String> message = String::NewSymbol(msg);
- if (syscall_symbol.IsEmpty()) {
- syscall_symbol = NODE_PSYMBOL("syscall");
- errno_symbol = NODE_PSYMBOL("errno");
- errpath_symbol = NODE_PSYMBOL("path");
- code_symbol = NODE_PSYMBOL("code");
+ if (NODE_VAR(syscall_symbol).IsEmpty()) {
+ NODE_VAR(syscall_symbol) = NODE_PSYMBOL("syscall");
+ NODE_VAR(errno_symbol) = NODE_PSYMBOL("errno");
+ NODE_VAR(errpath_symbol) = NODE_PSYMBOL("path");
+ NODE_VAR(code_symbol) = NODE_PSYMBOL("code");
}
if (path) {
@@ -905,9 +837,9 @@ Local<Value> WinapiErrnoException(int errorno,
Local<Object> obj = e->ToObject();
- obj->Set(errno_symbol, Integer::New(errorno));
- if (path) obj->Set(errpath_symbol, String::New(path));
- if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
+ obj->Set(NODE_VAR(errno_symbol), Integer::New(errorno));
+ if (path) obj->Set(NODE_VAR(errpath_symbol), String::New(path));
+ if (syscall) obj->Set(NODE_VAR(syscall_symbol), String::NewSymbol(syscall));
return e;
}
#endif
@@ -966,16 +898,17 @@ void MakeCallback(Handle<Object> object,
void SetErrno(uv_err_t err) {
HandleScope scope;
- if (errno_symbol.IsEmpty()) {
- errno_symbol = NODE_PSYMBOL("errno");
+ if (NODE_VAR(errno_symbol).IsEmpty()) {
+ NODE_VAR(errno_symbol) = NODE_PSYMBOL("errno");
}
if (err.code == UV_UNKNOWN) {
char errno_buf[100];
snprintf(errno_buf, 100, "Unknown system errno %d", err.sys_errno_);
- Context::GetCurrent()->Global()->Set(errno_symbol, String::New(errno_buf));
+ Context::GetCurrent()->Global()->Set(NODE_VAR(errno_symbol),
+ String::New(errno_buf));
} else {
- Context::GetCurrent()->Global()->Set(errno_symbol,
+ Context::GetCurrent()->Global()->Set(NODE_VAR(errno_symbol),
String::NewSymbol(uv_err_name(err)));
}
}
@@ -1405,8 +1338,8 @@ static Handle<Value> SetGid(const Arguments& args) {
struct group grp, *grpp = NULL;
int err;
- if ((err = getgrnam_r(*grpnam, &grp, getbuf, ARRAY_SIZE(getbuf), &grpp)) ||
- grpp == NULL) {
+ if ((err = getgrnam_r(*grpnam, &grp, NODE_VAR(getbuf),
+ ARRAY_SIZE(NODE_VAR(getbuf)), &grpp)) || grpp == NULL) {
if (errno == 0)
return ThrowException(Exception::Error(
String::New("setgid group id does not exist")));
@@ -1445,8 +1378,8 @@ static Handle<Value> SetUid(const Arguments& args) {
struct passwd pwd, *pwdp = NULL;
int err;
- if ((err = getpwnam_r(*pwnam, &pwd, getbuf, ARRAY_SIZE(getbuf), &pwdp)) ||
- pwdp == NULL) {
+ if ((err = getpwnam_r(*pwnam, &pwd, NODE_VAR(getbuf),
+ ARRAY_SIZE(NODE_VAR(getbuf)), &pwdp)) || pwdp == NULL) {
if (errno == 0)
return ThrowException(Exception::Error(
String::New("setuid user id does not exist")));
@@ -1482,12 +1415,12 @@ static void CheckStatus(uv_timer_t* watcher, int status) {
assert(watcher == &gc_timer);
// check memory
- if (!uv_is_active((uv_handle_t*) &gc_idle)) {
+ if (!uv_is_active((uv_handle_t*) &NODE_VAR(gc_idle))) {
HeapStatistics stats;
V8::GetHeapStatistics(&stats);
if (stats.total_heap_size() > 1024 * 1024 * 128) {
// larger than 128 megs, just start the idle watcher
- uv_idle_start(&node::gc_idle, node::Idle);
+ uv_idle_start(&NODE_VAR(gc_idle), node::Idle);
return;
}
}
@@ -1498,7 +1431,7 @@ static void CheckStatus(uv_timer_t* watcher, int status) {
if (d >= GC_WAIT_TIME - 1.) {
//fprintf(stderr, "start idle\n");
- uv_idle_start(&node::gc_idle, node::Idle);
+ uv_idle_start(&NODE_VAR(gc_idle), node::Idle);
}
}
@@ -1562,20 +1495,20 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
Local<Object> info = Object::New();
- if (rss_symbol.IsEmpty()) {
- rss_symbol = NODE_PSYMBOL("rss");
- heap_total_symbol = NODE_PSYMBOL("heapTotal");
- heap_used_symbol = NODE_PSYMBOL("heapUsed");
+ if (NODE_VAR(rss_symbol).IsEmpty()) {
+ NODE_VAR(rss_symbol) = NODE_PSYMBOL("rss");
+ NODE_VAR(heap_total_symbol) = NODE_PSYMBOL("heapTotal");
+ NODE_VAR(heap_used_symbol) = NODE_PSYMBOL("heapUsed");
}
- info->Set(rss_symbol, Number::New(rss));
+ info->Set(NODE_VAR(rss_symbol), Number::New(rss));
// V8 memory usage
HeapStatistics v8_heap_stats;
V8::GetHeapStatistics(&v8_heap_stats);
- info->Set(heap_total_symbol,
+ info->Set(NODE_VAR(heap_total_symbol),
Integer::NewFromUnsigned(v8_heap_stats.total_heap_size()));
- info->Set(heap_used_symbol,
+ info->Set(NODE_VAR(heap_used_symbol),
Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));
return scope.Close(info);
@@ -1725,20 +1658,22 @@ void FatalException(TryCatch &try_catch) {
exit(1);
}
- if (listeners_symbol.IsEmpty()) {
- listeners_symbol = NODE_PSYMBOL("listeners");
- uncaught_exception_symbol = NODE_PSYMBOL("uncaughtException");
- emit_symbol = NODE_PSYMBOL("emit");
+ if (NODE_VAR(listeners_symbol).IsEmpty()) {
+ NODE_VAR(listeners_symbol) = NODE_PSYMBOL("listeners");
+ NODE_VAR(uncaught_exception_symbol) = NODE_PSYMBOL("uncaughtException");
+ NODE_VAR(emit_symbol) = NODE_PSYMBOL("emit");
}
- Local<Value> listeners_v = process->Get(listeners_symbol);
+ Local<Value> listeners_v = NODE_VAR(process)->Get(NODE_VAR(listeners_symbol));
assert(listeners_v->IsFunction());
Local<Function> listeners = Local<Function>::Cast(listeners_v);
- Local<String> uncaught_exception_symbol_l = Local<String>::New(uncaught_exception_symbol);
+ Local<String> uncaught_exception_symbol_l =
+ Local<String>::New(NODE_VAR(uncaught_exception_symbol));
+
Local<Value> argv[1] = { uncaught_exception_symbol_l };
- Local<Value> ret = listeners->Call(process, 1, argv);
+ Local<Value> ret = listeners->Call(NODE_VAR(process), 1, argv);
assert(ret->IsArray());
@@ -1752,7 +1687,7 @@ void FatalException(TryCatch &try_catch) {
}
// Otherwise fire the process "uncaughtException" event
- Local<Value> emit_v = process->Get(emit_symbol);
+ Local<Value> emit_v = NODE_VAR(process)->Get(NODE_VAR(emit_symbol));
assert(emit_v->IsFunction());
Local<Function> emit = Local<Function>::Cast(emit_v);
@@ -1761,7 +1696,7 @@ void FatalException(TryCatch &try_catch) {
Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
uncaught_exception_counter++;
- emit->Call(process, 2, event_argv);
+ emit->Call(NODE_VAR(process), 2, event_argv);
// Decrement so we know if the next exception is a recursion or not
uncaught_exception_counter--;
}
@@ -1973,8 +1908,8 @@ static Handle<Object> GetFeatures() {
obj->Set(String::NewSymbol("uv"), True());
obj->Set(String::NewSymbol("ipv6"), True()); // TODO ping libuv
- obj->Set(String::NewSymbol("tls_npn"), Boolean::New(use_npn));
- obj->Set(String::NewSymbol("tls_sni"), Boolean::New(use_sni));
+ obj->Set(String::NewSymbol("tls_npn"), Boolean::New(NODE_VAR(use_npn)));
+ obj->Set(String::NewSymbol("tls_sni"), Boolean::New(NODE_VAR(use_sni)));
obj->Set(String::NewSymbol("tls"),
Boolean::New(get_builtin_module("crypto") != NULL));
@@ -1991,28 +1926,31 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
Local<FunctionTemplate> process_template = FunctionTemplate::New();
- process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
+ NODE_VAR(process) =
+ Persistent<Object>::New(process_template->GetFunction()->NewInstance());
- process->SetAccessor(String::New("title"),
- ProcessTitleGetter,
- ProcessTitleSetter);
+ NODE_VAR(process)->SetAccessor(String::New("title"),
+ ProcessTitleGetter,
+ ProcessTitleSetter);
// process.version
- process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
+ NODE_VAR(process)->Set(String::NewSymbol("version"),
+ String::New(NODE_VERSION));
#ifdef NODE_PREFIX
// process.installPrefix
- process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
+ NODE_VAR(process)->Set(String::NewSymbol("installPrefix"),
+ String::New(NODE_PREFIX));
#endif
// process.moduleLoadList
module_load_list = Persistent<Array>::New(Array::New());
- process->Set(String::NewSymbol("moduleLoadList"), module_load_list);
+ NODE_VAR(process)->Set(String::NewSymbol("moduleLoadList"), module_load_list);
Local<Object> versions = Object::New();
char buf[20];
- process->Set(String::NewSymbol("versions"), versions);
+ NODE_VAR(process)->Set(String::NewSymbol("versions"), versions);
// +1 to get rid of the leading 'v'
versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
@@ -2039,20 +1977,20 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
// process.arch
- process->Set(String::NewSymbol("arch"), String::New(ARCH));
+ NODE_VAR(process)->Set(String::NewSymbol("arch"), String::New(ARCH));
// process.platform
- process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
+ NODE_VAR(process)->Set(String::NewSymbol("platform"), String::New(PLATFORM));
// process.argv
- Local<Array> arguments = Array::New(argc - option_end_index + 1);
+ Local<Array> arguments = Array::New(argc - NODE_VAR(option_end_index) + 1);
arguments->Set(Integer::New(0), String::New(argv[0]));
- for (j = 1, i = option_end_index; i < argc; j++, i++) {
+ for (j = 1, i = NODE_VAR(option_end_index); i < argc; j++, i++) {
Local<String> arg = String::New(argv[i]);
arguments->Set(Integer::New(j), arg);
}
// assign it
- process->Set(String::NewSymbol("argv"), arguments);
+ NODE_VAR(process)->Set(String::NewSymbol("argv"), arguments);
// create process.env
Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
@@ -2063,61 +2001,64 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
EnvEnumerator,
Undefined());
Local<Object> env = envTemplate->NewInstance();
- process->Set(String::NewSymbol("env"), env);
+ NODE_VAR(process)->Set(String::NewSymbol("env"), env);
- process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
- process->Set(String::NewSymbol("features"), GetFeatures());
+ NODE_VAR(process)->Set(String::NewSymbol("pid"), Integer::New(getpid()));
+ NODE_VAR(process)->Set(String::NewSymbol("features"), GetFeatures());
// -e, --eval
- if (eval_string) {
- process->Set(String::NewSymbol("_eval"), String::New(eval_string));
- process->Set(String::NewSymbol("_print_eval"), Boolean::New(print_eval));
+ if (NODE_VAR(eval_string)) {
+ NODE_VAR(process)->Set(String::NewSymbol("_eval"),
+ String::New(NODE_VAR(eval_string)));
+ NODE_VAR(process)->Set(String::NewSymbol("_print_eval"),
+ Boolean::New(NODE_VAR(print_eval)));
}
size_t size = 2*PATH_MAX;
char* execPath = new char[size];
if (uv_exepath(execPath, &size) != 0) {
// as a last ditch effort, fallback on argv[0] ?
- process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
+ NODE_VAR(process)->Set(String::NewSymbol("execPath"), String::New(argv[0]));
} else {
- process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
+ NODE_VAR(process)->Set(String::NewSymbol("execPath"),
+ String::New(execPath, size));
}
delete [] execPath;
// define various internal methods
- NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
- NODE_SET_METHOD(process, "reallyExit", Exit);
- NODE_SET_METHOD(process, "chdir", Chdir);
- NODE_SET_METHOD(process, "cwd", Cwd);
+ NODE_SET_METHOD(NODE_VAR(process), "_needTickCallback", NeedTickCallback);
+ NODE_SET_METHOD(NODE_VAR(process), "reallyExit", Exit);
+ NODE_SET_METHOD(NODE_VAR(process), "chdir", Chdir);
+ NODE_SET_METHOD(NODE_VAR(process), "cwd", Cwd);
#ifdef _WIN32
- NODE_SET_METHOD(process, "_cwdForDrive", CwdForDrive);
+ NODE_SET_METHOD(NODE_VAR(process), "_cwdForDrive", CwdForDrive);
#endif
- NODE_SET_METHOD(process, "umask", Umask);
+ NODE_SET_METHOD(NODE_VAR(process), "umask", Umask);
#ifdef __POSIX__
- NODE_SET_METHOD(process, "getuid", GetUid);
- NODE_SET_METHOD(process, "setuid", SetUid);
+ NODE_SET_METHOD(NODE_VAR(process), "getuid", GetUid);
+ NODE_SET_METHOD(NODE_VAR(process), "setuid", SetUid);
- NODE_SET_METHOD(process, "setgid", SetGid);
- NODE_SET_METHOD(process, "getgid", GetGid);
+ NODE_SET_METHOD(NODE_VAR(process), "setgid", SetGid);
+ NODE_SET_METHOD(NODE_VAR(process), "getgid", GetGid);
#endif // __POSIX__
- NODE_SET_METHOD(process, "_kill", Kill);
+ NODE_SET_METHOD(NODE_VAR(process), "_kill", Kill);
- NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
+ NODE_SET_METHOD(NODE_VAR(process), "_debugProcess", DebugProcess);
- NODE_SET_METHOD(process, "dlopen", DLOpen);
+ NODE_SET_METHOD(NODE_VAR(process), "dlopen", DLOpen);
- NODE_SET_METHOD(process, "uptime", Uptime);
- NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
- NODE_SET_METHOD(process, "uvCounters", UVCounters);
+ NODE_SET_METHOD(NODE_VAR(process), "uptime", Uptime);
+ NODE_SET_METHOD(NODE_VAR(process), "memoryUsage", MemoryUsage);
+ NODE_SET_METHOD(NODE_VAR(process), "uvCounters", UVCounters);
- NODE_SET_METHOD(process, "binding", Binding);
+ NODE_SET_METHOD(NODE_VAR(process), "binding", Binding);
- return process;
+ return NODE_VAR(process);
}
@@ -2181,21 +2122,21 @@ static void PrintHelp();
static void ParseDebugOpt(const char* arg) {
const char *p = 0;
- use_debug_agent = true;
+ NODE_VAR(use_debug_agent) = true;
if (!strcmp (arg, "--debug-brk")) {
- debug_wait_connect = true;
+ NODE_VAR(debug_wait_connect) = true;
return;
} else if (!strcmp(arg, "--debug")) {
return;
} else if (strstr(arg, "--debug-brk=") == arg) {
- debug_wait_connect = true;
+ NODE_VAR(debug_wait_connect) = true;
p = 1 + strchr(arg, '=');
- debug_port = atoi(p);
+ NODE_VAR(debug_port) = atoi(p);
} else if (strstr(arg, "--debug=") == arg) {
p = 1 + strchr(arg, '=');
- debug_port = atoi(p);
+ NODE_VAR(debug_port) = atoi(p);
}
- if (p && debug_port > 1024 && debug_port < 65536)
+ if (p && NODE_VAR(debug_port) > 1024 && NODE_VAR(debug_port) < 65536)
return;
fprintf(stderr, "Bad debug option.\n");
@@ -2255,7 +2196,7 @@ static void ParseArgs(int argc, char **argv) {
} else if (strstr(arg, "--max-stack-size=") == arg) {
const char *p = 0;
p = 1 + strchr(arg, '=');
- max_stack_size = atoi(p);
+ NODE_VAR(max_stack_size) = atoi(p);
argv[i] = const_cast<char*>("");
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
PrintHelp();
@@ -2267,12 +2208,12 @@ static void ParseArgs(int argc, char **argv) {
exit(1);
}
if (arg[1] == 'p') {
- print_eval = true;
+ NODE_VAR(print_eval) = true;
}
argv[i] = const_cast<char*>("");
- eval_string = argv[++i];
+ NODE_VAR(eval_string) = argv[++i];
} else if (strcmp(arg, "--print") == 0 || strcmp(arg, "-p") == 0) {
- print_eval = true;
+ NODE_VAR(print_eval) = true;
argv[i] = const_cast<char*>("");
} else if (strcmp(arg, "--v8-options") == 0) {
argv[i] = const_cast<char*>("--help");
@@ -2281,7 +2222,7 @@ static void ParseArgs(int argc, char **argv) {
}
}
- option_end_index = i;
+ NODE_VAR(option_end_index) = i;
}
@@ -2294,7 +2235,7 @@ static void EnableDebug(bool wait_connect) {
node_isolate->Enter();
// Start the debug thread and it's associated TCP server on port 5858.
- bool r = Debug::EnableAgent("node " NODE_VERSION, debug_port);
+ bool r = Debug::EnableAgent("node " NODE_VERSION, NODE_VAR(debug_port));
if (wait_connect) {
// Set up an empty handler so v8 will not continue until a debugger
@@ -2308,7 +2249,7 @@ static void EnableDebug(bool wait_connect) {
assert(r);
// Print out some information.
- fprintf(stderr, "debugger listening on port %d\n", debug_port);
+ fprintf(stderr, "debugger listening on port %d\n", NODE_VAR(debug_port));
fflush(stderr);
debugger_running = true;
@@ -2522,18 +2463,18 @@ char** Init(int argc, char *argv[]) {
node::ParseArgs(argc, argv);
// Parse the rest of the args (up to the 'option_end_index' (where '--' was
// in the command line))
- int v8argc = node::option_end_index;
+ int v8argc = NODE_VAR(option_end_index);
char **v8argv = argv;
- if (node::debug_wait_connect) {
+ if (NODE_VAR(debug_wait_connect)) {
// v8argv is a copy of argv up to the script file argument +2 if --debug-brk
// to expose the v8 debugger js object so that node.js can set
// a breakpoint on the first line of the startup script
v8argc += 2;
v8argv = new char*[v8argc];
- memcpy(v8argv, argv, sizeof(argv) * node::option_end_index);
- v8argv[node::option_end_index] = const_cast<char*>("--expose_debug_as");
- v8argv[node::option_end_index + 1] = const_cast<char*>("v8debug");
+ memcpy(v8argv, argv, sizeof(argv) * NODE_VAR(option_end_index));
+ v8argv[NODE_VAR(option_end_index)] = const_cast<char*>("--expose_debug_as");
+ v8argv[NODE_VAR(option_end_index) + 1] = const_cast<char*>("v8debug");
}
// For the normal stack which moves from high to low addresses when frames
@@ -2541,11 +2482,11 @@ char** Init(int argc, char *argv[]) {
// the address of a stack variable (e.g. &stack_var) as an approximation
// of the start of the stack (we're assuming that we haven't pushed a lot
// of frames yet).
- if (node::max_stack_size != 0) {
+ if (NODE_VAR(max_stack_size) != 0) {
uint32_t stack_var;
ResourceConstraints constraints;
- uint32_t *stack_limit = &stack_var - (node::max_stack_size / sizeof(uint32_t));
+ uint32_t *stack_limit = &stack_var - (NODE_VAR(max_stack_size) / sizeof(uint32_t));
constraints.set_stack_limit(stack_limit);
SetResourceConstraints(&constraints); // Must be done before V8::Initialize
}
@@ -2558,25 +2499,25 @@ char** Init(int argc, char *argv[]) {
RegisterSignalHandler(SIGTERM, SignalExit);
#endif // __POSIX__
- uv_prepare_init(uv_default_loop(), &node::prepare_tick_watcher);
- uv_prepare_start(&node::prepare_tick_watcher, PrepareTick);
+ uv_prepare_init(uv_default_loop(), &NODE_VAR(prepare_tick_watcher));
+ uv_prepare_start(&NODE_VAR(prepare_tick_watcher), PrepareTick);
uv_unref(uv_default_loop());
- uv_check_init(uv_default_loop(), &node::check_tick_watcher);
- uv_check_start(&node::check_tick_watcher, node::CheckTick);
+ uv_check_init(uv_default_loop(), &NODE_VAR(check_tick_watcher));
+ uv_check_start(&NODE_VAR(check_tick_watcher), node::CheckTick);
uv_unref(uv_default_loop());
- uv_idle_init(uv_default_loop(), &node::tick_spinner);
+ uv_idle_init(uv_default_loop(), &NODE_VAR(tick_spinner));
uv_unref(uv_default_loop());
- uv_check_init(uv_default_loop(), &node::gc_check);
- uv_check_start(&node::gc_check, node::Check);
+ uv_check_init(uv_default_loop(), &NODE_VAR(gc_check));
+ uv_check_start(&NODE_VAR(gc_check), node::Check);
uv_unref(uv_default_loop());
- uv_idle_init(uv_default_loop(), &node::gc_idle);
+ uv_idle_init(uv_default_loop(), &NODE_VAR(gc_idle));
uv_unref(uv_default_loop());
- uv_timer_init(uv_default_loop(), &node::gc_timer);
+ uv_timer_init(uv_default_loop(), &NODE_VAR(gc_timer));
uv_unref(uv_default_loop());
V8::SetFatalErrorHandler(node::OnFatalError);
@@ -2600,8 +2541,8 @@ char** Init(int argc, char *argv[]) {
node_isolate = Isolate::GetCurrent();
// If the --debug flag was specified then initialize the debug thread.
- if (node::use_debug_agent) {
- EnableDebug(debug_wait_connect);
+ if (NODE_VAR(use_debug_agent)) {
+ EnableDebug(NODE_VAR(debug_wait_connect));
} else {
#ifdef _WIN32
RegisterDebugSignalHandler();
diff --git a/src/node_vars.cc b/src/node_vars.cc
new file mode 100644
index 0000000..dbf5364
--- /dev/null
+++ b/src/node_vars.cc
@@ -0,0 +1,42 @@
+#include <node_vars.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.
+
+static struct globals g_struct;
+static struct globals* g_ptr;
+
+
+static void globals_init(struct globals* g) {
+ memset(g, 0, sizeof(struct globals));
+ g->debug_port = 5858;
+
+#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
+}
+
+
+struct globals* globals_get() {
+ if (!g_ptr) {
+ g_ptr = &g_struct;
+ globals_init(g_ptr);
+ }
+ return g_ptr;
+}
+
+} // namespace node
diff --git a/src/node_vars.h b/src/node_vars.h
new file mode 100644
index 0000000..216e341
--- /dev/null
+++ b/src/node_vars.h
@@ -0,0 +1,77 @@
+#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>
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+namespace node {
+
+
+#define NODE_VAR(x) (globals_get()->x)
+
+struct globals {
+ 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;
+
+ bool print_eval;
+ char *eval_string;
+ int option_end_index;
+ bool use_debug_agent;
+ bool debug_wait_connect;
+ int debug_port;
+ int max_stack_size;
+
+ 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;
+};
+
+struct globals* globals_get();
+
+} // namespace node
+#endif // NODE_VARS_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment