Created
December 7, 2011 00:16
-
-
Save ry/1440753 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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