@@ -99,51 +99,53 @@ extern char **environ;

namespace node {

static Persistent<Object> process;
static __thread Persistent<Object>* process;

static Persistent<String> errno_symbol;
static Persistent<String> syscall_symbol;
static Persistent<String> errpath_symbol;
static Persistent<String> code_symbol;
static __thread Persistent<String>* errno_symbol;
static __thread Persistent<String>* syscall_symbol;
static __thread Persistent<String>* errpath_symbol;
static __thread Persistent<String>* code_symbol;

static Persistent<String> rss_symbol;
static Persistent<String> heap_total_symbol;
static Persistent<String> heap_used_symbol;
static __thread Persistent<String>* rss_symbol;
static __thread Persistent<String>* heap_total_symbol;
static __thread Persistent<String>* heap_used_symbol;

static Persistent<String> listeners_symbol;
static Persistent<String> uncaught_exception_symbol;
static Persistent<String> emit_symbol;
static __thread Persistent<String>* listeners_symbol;
static __thread Persistent<String>* uncaught_exception_symbol;
static __thread Persistent<String>* emit_symbol;


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 __thread char *eval_string = NULL;
static __thread int option_end_index = 0;
static __thread bool use_debug_agent = false;
static __thread bool debug_wait_connect = false;
static __thread int debug_port=5858;
static __thread 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;
static __thread uv_check_t check_tick_watcher;
static __thread uv_prepare_t prepare_tick_watcher;
static __thread uv_idle_t tick_spinner;
static __thread bool need_tick_cb;
static __thread Persistent<String>* tick_callback_sym;

static __thread Persistent<Object>* binding_cache;
static __thread Persistent<Array>* module_load_list;

#ifdef OPENSSL_NPN_NEGOTIATED
static bool use_npn = true;
static __thread bool use_npn = true;
#else
static bool use_npn = false;
static __thread bool use_npn = false;
#endif

#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
static bool use_sni = true;
static __thread bool use_sni = true;
#else
static bool use_sni = false;
static __thread bool use_sni = false;
#endif

// 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];
static __thread 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
@@ -152,18 +154,18 @@ static char getbuf[PATH_MAX + 1];
//
// 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;
static __thread uv_check_t gc_check;
static __thread uv_idle_t gc_idle;
static __thread uv_timer_t gc_timer;
bool __thread 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 __thread int64_t tick_times[RPM_SAMPLES];
static __thread int tick_time_head;

static void CheckStatus(uv_timer_t* watcher, int status);

@@ -216,6 +218,15 @@ static void Check(uv_check_t* watcher, int status) {
}


inline static void LAZY_INIT(Persistent<String>*& ptr, const char* value)
{
if (!ptr)
ptr = new Persistent<String>(
Persistent<String>::New(
String::NewSymbol(value)));
}


static void Tick(void) {
// Avoid entering a V8 scope.
if (!need_tick_cb) return;
@@ -228,19 +239,16 @@ static void Tick(void) {

HandleScope scope;

if (tick_callback_sym.IsEmpty()) {
// Lazily set the symbol
tick_callback_sym =
Persistent<String>::New(String::NewSymbol("_tickCallback"));
}
if (!tick_callback_sym)
tick_callback_sym = NODE_PPSYMBOL("_tickCallback");

Local<Value> cb_v = process->Get(tick_callback_sym);
Local<Value> cb_v = (*process)->Get(*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(*process, 0, NULL);

if (try_catch.HasCaught()) {
FatalException(try_catch);
@@ -773,11 +781,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 (!syscall_symbol) {
syscall_symbol = NODE_PPSYMBOL("syscall");
errno_symbol = NODE_PPSYMBOL("errno");
errpath_symbol = NODE_PPSYMBOL("path");
code_symbol = NODE_PPSYMBOL("code");
}

if (path) {
@@ -791,10 +799,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(*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));
return e;
}

@@ -889,16 +897,16 @@ void MakeCallback(Handle<Object> object,
void SetErrno(uv_err_t err) {
HandleScope scope;

if (errno_symbol.IsEmpty()) {
errno_symbol = NODE_PSYMBOL("errno");
if (!errno_symbol) {
errno_symbol = NODE_PPSYMBOL("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(*errno_symbol, String::New(errno_buf));
} else {
Context::GetCurrent()->Global()->Set(errno_symbol,
Context::GetCurrent()->Global()->Set(*errno_symbol,
String::NewSymbol(uv_err_name(err)));
}
}
@@ -1478,20 +1486,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 (!rss_symbol) {
rss_symbol = NODE_PPSYMBOL("rss");
heap_total_symbol = NODE_PPSYMBOL("heapTotal");
heap_used_symbol = NODE_PPSYMBOL("heapUsed");
}

info->Set(rss_symbol, Integer::NewFromUnsigned(rss));
info->Set(*rss_symbol, Integer::NewFromUnsigned(rss));

// V8 memory usage
HeapStatistics v8_heap_stats;
V8::GetHeapStatistics(&v8_heap_stats);
info->Set(heap_total_symbol,
info->Set(*heap_total_symbol,
Integer::NewFromUnsigned(v8_heap_stats.total_heap_size()));
info->Set(heap_used_symbol,
info->Set(*heap_used_symbol,
Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));

return scope.Close(info);
@@ -1625,7 +1633,7 @@ static void OnFatalError(const char* location, const char* message) {
exit(1);
}

static int uncaught_exception_counter = 0;
static __thread int uncaught_exception_counter = 0;

void FatalException(TryCatch &try_catch) {
HandleScope scope;
@@ -1636,20 +1644,20 @@ 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 (!listeners_symbol) {
listeners_symbol = NODE_PPSYMBOL("listeners");
uncaught_exception_symbol = NODE_PPSYMBOL("uncaughtException");
emit_symbol = NODE_PPSYMBOL("emit");
}

Local<Value> listeners_v = process->Get(listeners_symbol);
Local<Value> listeners_v = (*process)->Get(*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<Value> argv[1] = { uncaught_exception_symbol_l };
Local<Value> ret = listeners->Call(process, 1, argv);
Local<String> uncaught_exception_symbol_l = Local<String>::New(*uncaught_exception_symbol);
Local<Value> argv[1] = { *uncaught_exception_symbol_l };
Local<Value> ret = listeners->Call(*process, 1, argv);

assert(ret->IsArray());

@@ -1663,22 +1671,22 @@ void FatalException(TryCatch &try_catch) {
}

// Otherwise fire the process "uncaughtException" event
Local<Value> emit_v = process->Get(emit_symbol);
Local<Value> emit_v = (*process)->Get(*emit_symbol);
assert(emit_v->IsFunction());

Local<Function> emit = Local<Function>::Cast(emit_v);

Local<Value> error = try_catch.Exception();
Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
Local<Value> event_argv[2] = { *uncaught_exception_symbol_l, error };

uncaught_exception_counter++;
emit->Call(process, 2, event_argv);
emit->Call(*process, 2, event_argv);
// Decrement so we know if the next exception is a recursion or not
uncaught_exception_counter--;
}


static uv_async_t debug_watcher;
static __thread uv_async_t debug_watcher;

static void DebugMessageCallback(uv_async_t* watcher, int status) {
HandleScope scope;
@@ -1702,54 +1710,52 @@ static void DebugBreakMessageHandler(const Debug::Message& message) {
}


Persistent<Object> binding_cache;
Persistent<Array> module_load_list;

static Handle<Value> Binding(const Arguments& args) {
HandleScope scope;

Local<String> module = args[0]->ToString();
String::Utf8Value module_v(module);
node_module_struct* modp;

if (binding_cache.IsEmpty()) {
binding_cache = Persistent<Object>::New(Object::New());
if (!binding_cache) {
binding_cache = new Persistent<Object>(
Persistent<Object>::New(Object::New()));
}

Local<Object> exports;

if (binding_cache->Has(module)) {
exports = binding_cache->Get(module)->ToObject();
if ((*binding_cache)->Has(module)) {
exports = (*binding_cache)->Get(module)->ToObject();
return scope.Close(exports);
}

// Append a string to process.moduleLoadList
char buf[1024];
snprintf(buf, 1024, "Binding %s", *module_v);
uint32_t l = module_load_list->Length();
module_load_list->Set(l, String::New(buf));
uint32_t l = (*module_load_list)->Length();
(*module_load_list)->Set(l, String::New(buf));

if ((modp = get_builtin_module(*module_v)) != NULL) {
exports = Object::New();
modp->register_func(exports);
binding_cache->Set(module, exports);
(*binding_cache)->Set(module, exports);

} else if (!strcmp(*module_v, "constants")) {
exports = Object::New();
DefineConstants(exports);
binding_cache->Set(module, exports);
(*binding_cache)->Set(module, exports);

#ifdef __POSIX__
} else if (!strcmp(*module_v, "io_watcher")) {
exports = Object::New();
IOWatcher::Initialize(exports);
binding_cache->Set(module, exports);
(*binding_cache)->Set(module, exports);
#endif

} else if (!strcmp(*module_v, "natives")) {
exports = Object::New();
DefineJavaScript(exports);
binding_cache->Set(module, exports);
(*binding_cache)->Set(module, exports);

} else {

@@ -1760,9 +1766,63 @@ static Handle<Value> Binding(const Arguments& args) {
}


static Handle<Value> Print(const Arguments& args) {
for (int i = 0; args[i]->IsString(); ++i) {
String::Utf8Value s(args[i]);
write(1, *s, s.length());
}
write(1, "\n", 1);
return Undefined();
}


static void RunScript(uv_loop_t* loop,
const char* source,
const char* origin) {
TryCatch try_catch;

ScriptOrigin script_origin(String::New(origin));

Local<Script> script = Script::New(String::New(source), &script_origin);
if (script.IsEmpty()) {
ReportException(try_catch, true);
return;
}

Local<Value> v = script->Run();
if (v.IsEmpty()) {
ReportException(try_catch, true);
return;
}

int r = uv_run(loop);
if (r)
abort();
}


static void RunIsolate(void* arg) {
uv_loop_t* loop = uv_loop_new();
Isolate* isolate = Isolate::New(loop);

HandleScope scope;

Persistent<Context> context = Context::New();
Context::Scope context_scope(context);

Local<Object> global = context->Global();
NODE_SET_METHOD(global, "print", Print);

char *argv[] = { "node", "tmp/empty.js", NULL }; // FIXME

Handle<Object> process = SetupProcessObject(ARRAY_SIZE(argv) - 1, argv);
// v8_typed_array::AttachBindings(global); // FIXME

// Create all the objects, load modules, do everything.
// so your next reading stop should be node::Load()!
Load(process);

context.Dispose();
}


@@ -1948,28 +2008,30 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {

Local<FunctionTemplate> process_template = FunctionTemplate::New();

process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
process = new Persistent<Object>(
Persistent<Object>::New(process_template->GetFunction()->NewInstance()));


process->SetAccessor(String::New("title"),
ProcessTitleGetter,
ProcessTitleSetter);
(*process)->SetAccessor(String::New("title"),
ProcessTitleGetter,
ProcessTitleSetter);

// process.version
process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
(*process)->Set(String::NewSymbol("version"), String::New(NODE_VERSION));

#ifdef NODE_PREFIX
// process.installPrefix
process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
(*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);
module_load_list = new Persistent<Array>(
Persistent<Array>::New(Array::New()));
(*process)->Set(String::NewSymbol("moduleLoadList"), *module_load_list);

Local<Object> versions = Object::New();
char buf[20];
process->Set(String::NewSymbol("versions"), versions);
(*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()));
@@ -1996,10 +2058,10 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {


// process.arch
process->Set(String::NewSymbol("arch"), String::New(ARCH));
(*process)->Set(String::NewSymbol("arch"), String::New(ARCH));

// process.platform
process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
(*process)->Set(String::NewSymbol("platform"), String::New(PLATFORM));

// process.argv
Local<Array> arguments = Array::New(argc - option_end_index + 1);
@@ -2009,7 +2071,7 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
arguments->Set(Integer::New(j), arg);
}
// assign it
process->Set(String::NewSymbol("argv"), arguments);
(*process)->Set(String::NewSymbol("argv"), arguments);

// create process.env
Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
@@ -2020,63 +2082,63 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
EnvEnumerator,
Undefined());
Local<Object> env = envTemplate->NewInstance();
process->Set(String::NewSymbol("env"), env);
(*process)->Set(String::NewSymbol("env"), env);

process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
process->Set(String::NewSymbol("features"), GetFeatures());
(*process)->Set(String::NewSymbol("pid"), Integer::New(getpid()));
(*process)->Set(String::NewSymbol("features"), GetFeatures());

// -e, --eval
if (eval_string) {
process->Set(String::NewSymbol("_eval"), String::New(eval_string));
(*process)->Set(String::NewSymbol("_eval"), String::New(eval_string));
}

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]));
(*process)->Set(String::NewSymbol("execPath"), String::New(argv[0]));
} else {
process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
(*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(*process, "_needTickCallback", NeedTickCallback);
NODE_SET_METHOD(*process, "reallyExit", Exit);
NODE_SET_METHOD(*process, "chdir", Chdir);
NODE_SET_METHOD(*process, "cwd", Cwd);

#ifdef _WIN32
NODE_SET_METHOD(process, "_cwdForDrive", CwdForDrive);
NODE_SET_METHOD(*process, "_cwdForDrive", CwdForDrive);
#endif

NODE_SET_METHOD(process, "umask", Umask);
NODE_SET_METHOD(*process, "umask", Umask);

#ifdef __POSIX__
NODE_SET_METHOD(process, "getuid", GetUid);
NODE_SET_METHOD(process, "setuid", SetUid);
NODE_SET_METHOD(*process, "getuid", GetUid);
NODE_SET_METHOD(*process, "setuid", SetUid);

NODE_SET_METHOD(process, "setgid", SetGid);
NODE_SET_METHOD(process, "getgid", GetGid);
NODE_SET_METHOD(*process, "setgid", SetGid);
NODE_SET_METHOD(*process, "getgid", GetGid);
#endif // __POSIX__

NODE_SET_METHOD(process, "_kill", Kill);
NODE_SET_METHOD(*process, "_kill", Kill);

NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
NODE_SET_METHOD(*process, "_debugProcess", DebugProcess);

NODE_SET_METHOD(process, "dlopen", DLOpen);
NODE_SET_METHOD(*process, "dlopen", DLOpen);

NODE_SET_METHOD(process, "uptime", Uptime);
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
NODE_SET_METHOD(process, "uvCounters", UVCounters);
NODE_SET_METHOD(*process, "uptime", Uptime);
NODE_SET_METHOD(*process, "memoryUsage", MemoryUsage);
NODE_SET_METHOD(*process, "uvCounters", UVCounters);

NODE_SET_METHOD(process, "binding", Binding);
NODE_SET_METHOD(*process, "binding", Binding);

NODE_SET_METHOD(process, "_newIsolate", NewIsolate);
NODE_SET_METHOD(process, "_joinIsolate", JoinIsolate);
NODE_SET_METHOD(*process, "_newIsolate", NewIsolate);
NODE_SET_METHOD(*process, "_joinIsolate", JoinIsolate);

return process;
return *process;
}


@@ -100,7 +100,10 @@ void Load(v8::Handle<v8::Object> process);
void EmitExit(v8::Handle<v8::Object> process);

#define NODE_PSYMBOL(s) \
v8::Persistent<v8::String>::New(v8::String::NewSymbol(s))
(v8::Persistent<v8::String>::New(v8::String::NewSymbol(s)))

#define NODE_PPSYMBOL(s) \
(new v8::Persistent<v8::String>(NODE_PSYMBOL(s)))

/* Converts a unixtime to V8 Date */
#define NODE_UNIXTIME_V8(t) v8::Date::New(1000*static_cast<double>(t))
@@ -113,8 +116,8 @@ void EmitExit(v8::Handle<v8::Object> process);
v8::ReadOnly|v8::DontDelete))

#define NODE_SET_METHOD(obj, name, callback) \
obj->Set(v8::String::NewSymbol(name), \
v8::FunctionTemplate::New(callback)->GetFunction())
(obj)->Set(v8::String::NewSymbol((name)), \
v8::FunctionTemplate::New((callback))->GetFunction())

#define NODE_SET_PROTOTYPE_METHOD(templ, name, callback) \
do { \
@@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "node_isolate.h"
#include "v8.h"

#include <stdlib.h>
#include <string.h>
@@ -66,7 +66,10 @@ class Isolate {
*/
void AtExit(AtExitCallback callback, void *arg);

/* Shutdown the isolate. Call this method at thread death. */
/* Shutdown the isolate. Call this method at thread death.
* Calling any methods on the Isolate after Dispose() has
* run will result in undefined behaviour.
*/
void Dispose();

private: