From c16a1ca83e892f33faa84081fddfcca19868a97e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 29 Nov 2011 00:55:24 +0100 Subject: [PATCH] WIP --- src/node.cc | 243 ++++++++++++++++++++++++++++++-------------- src/node.h | 6 +- src/node_isolate.cc | 1 + src/node_isolate.h | 5 +- 4 files changed, 177 insertions(+), 78 deletions(-) diff --git a/src/node.cc b/src/node.cc index 6dc8bf70394..a59067deaaf 100644 --- a/src/node.cc +++ b/src/node.cc @@ -99,51 +99,129 @@ extern char **environ; namespace node { -static Persistent process; +#if HAVE_ISOLATES -static Persistent errno_symbol; -static Persistent syscall_symbol; -static Persistent errpath_symbol; -static Persistent code_symbol; +# define TLS(type, name) __thread type* __tls_##name +# define VAR(name) (*__tls_##name) +# define EMPTY(name) (__tls_##name == NULL) -static Persistent rss_symbol; -static Persistent heap_total_symbol; -static Persistent heap_used_symbol; +# define NODE_PPSYMBOL(s) \ + P(NODE_PSYMBOL(s)) -static Persistent listeners_symbol; -static Persistent uncaught_exception_symbol; -static Persistent emit_symbol; +# define ASSIGN(name, val) \ + ((__tls_##name) = P(val)) +# define LAZY_ASSIGN(name, val) \ + do if (!__tls_##name) ((__tls_##name) = P(val)); while (0) -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; +template v8::Persistent* P(v8::Handle v) +{ + return new v8::Persistent(v8::Persistent::New(v)); +} + +v8::Persistent* P(const char* symbol) +{ + return new v8::Persistent( + v8::Persistent::New( + String::NewSymbol(symbol))); +} + +#else /* !HAVE_ISOLATES */ + +# define TLS(type, name) type name +# define VAR(name) (name) +# define EMPTY(name) ((name).IsEmpty()) + +# define NODE_PPSYMBOL(s) \ + NODE_PSYMBOL(s) + +# define ASSIGN(name, val) \ + ((name) = P(val)) + +# define LAZY_ASSIGN(name, val) \ + do if ((name).IsEmpty()) (name) = P(val); while (0) + +template v8::Persistent P(v8::Handle v) +{ + return v8::Persistent(v); +} + +v8::Persistent P(const char* symbol) +{ + return v8::Persistent::New(String::NewSymbol(symbol)); +} + +#endif /* HAVE_ISOLATES */ + +static TLS(Persistent, process); +#define process VAR(process) + +static TLS(Persistent, errno_symbol); +#define errno_symbol VAR(errno_symbol) + +static TLS(Persistent, syscall_symbol); +#define syscall_symbol VAR(syscall_symbol) + +static TLS(Persistent, errpath_symbol); +#define errpath_symbol VAR(errpath_symbol) + +static TLS(Persistent, code_symbol); +#define code_symbol VAR(code_symbol) + +static TLS(Persistent, rss_symbol); +#define rss_symbol VAR(rss_symbol) + +static TLS(Persistent, heap_total_symbol); +#define heap_total_symbol VAR(heap_total_symbol) + +static TLS(Persistent, heap_used_symbol); +#define heap_used_symbol VAR(heap_used_symbol) + +static TLS(Persistent, listeners_symbol); +#define listeners_symbol VAR(listeners_symbol) + +static TLS(Persistent, uncaught_exception_symbol); +#define uncaught_exception_symbol VAR(uncaught_exception_symbol) + +static TLS(Persistent, emit_symbol); +#define emit_symbol VAR(emit_symbol) + +static TLS(Persistent, tick_callback_sym); +#define tick_callback_sym VAR(tick_callback_sym) + +static TLS(Persistent, binding_cache); +#define binding_cache VAR(binding_cache) + +static TLS(Persistent, module_load_list); +#define module_load_list VAR(module_load_list) -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 tick_callback_sym; +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 __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; #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 +230,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); @@ -228,11 +306,7 @@ static void Tick(void) { HandleScope scope; - if (tick_callback_sym.IsEmpty()) { - // Lazily set the symbol - tick_callback_sym = - Persistent::New(String::NewSymbol("_tickCallback")); - } + LAZY_ASSIGN(tick_callback_sym, "_tickCallback"); Local cb_v = process->Get(tick_callback_sym); if (!cb_v->IsFunction()) return; @@ -773,11 +847,11 @@ Local ErrnoException(int errorno, Local cons1 = String::Concat(estring, String::NewSymbol(", ")); Local 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 (EMPTY(syscall_symbol)) { + ASSIGN(syscall_symbol, "syscall"); + ASSIGN(errno_symbol, "errno"); + ASSIGN(errpath_symbol, "path"); + ASSIGN(code_symbol, "code"); } if (path) { @@ -889,9 +963,7 @@ void MakeCallback(Handle object, void SetErrno(uv_err_t err) { HandleScope scope; - if (errno_symbol.IsEmpty()) { - errno_symbol = NODE_PSYMBOL("errno"); - } + LAZY_ASSIGN(errno_symbol, "errno"); if (err.code == UV_UNKNOWN) { char errno_buf[100]; @@ -1478,10 +1550,10 @@ v8::Handle MemoryUsage(const v8::Arguments& args) { Local 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 (EMPTY(rss_symbol)) { + ASSIGN(rss_symbol, "rss"); + ASSIGN(heap_total_symbol, "heapTotal"); + ASSIGN(heap_used_symbol, "heapUsed"); } info->Set(rss_symbol, Integer::NewFromUnsigned(rss)); @@ -1625,7 +1697,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,10 +1708,10 @@ 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 (EMPTY(listeners_symbol)) { + ASSIGN(listeners_symbol, "listeners"); + ASSIGN(uncaught_exception_symbol, "uncaughtException"); + ASSIGN(emit_symbol, "emit"); } Local listeners_v = process->Get(listeners_symbol); @@ -1678,7 +1750,7 @@ void FatalException(TryCatch &try_catch) { } -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,9 +1774,6 @@ static void DebugBreakMessageHandler(const Debug::Message& message) { } -Persistent binding_cache; -Persistent module_load_list; - static Handle Binding(const Arguments& args) { HandleScope scope; @@ -1712,9 +1781,7 @@ static Handle Binding(const Arguments& args) { String::Utf8Value module_v(module); node_module_struct* modp; - if (binding_cache.IsEmpty()) { - binding_cache = Persistent::New(Object::New()); - } + LAZY_ASSIGN(binding_cache, Object::New()); Local exports; @@ -1760,9 +1827,38 @@ static Handle Binding(const Arguments& args) { } +static Handle 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 RunIsolate(void* arg) { uv_loop_t* loop = uv_loop_new(); Isolate* isolate = Isolate::New(loop); + + HandleScope scope; + + Persistent context = Context::New(); + Context::Scope context_scope(context); + + Local global = context->Global(); + NODE_SET_METHOD(global, "print", Print); + + char *argv[] = { "node", "tmp/empty.js", NULL }; // FIXME + + Handle process_object = 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_object); + + context.Dispose(); } @@ -1948,12 +2044,11 @@ Handle SetupProcessObject(int argc, char *argv[]) { Local process_template = FunctionTemplate::New(); - process = Persistent::New(process_template->GetFunction()->NewInstance()); - + ASSIGN(process, process_template->GetFunction()->NewInstance()); process->SetAccessor(String::New("title"), - ProcessTitleGetter, - ProcessTitleSetter); + ProcessTitleGetter, + ProcessTitleSetter); // process.version process->Set(String::NewSymbol("version"), String::New(NODE_VERSION)); @@ -1964,7 +2059,7 @@ Handle SetupProcessObject(int argc, char *argv[]) { #endif // process.moduleLoadList - module_load_list = Persistent::New(Array::New()); + ASSIGN(module_load_list, Array::New()); process->Set(String::NewSymbol("moduleLoadList"), module_load_list); Local versions = Object::New(); @@ -2091,7 +2186,7 @@ static void SignalExit(int signal) { } -void Load(Handle process) { +void Load(Handle process_object) { // Compile, execute the src/node.js file. (Which was included as static C // string in node_natives.h. 'natve_node' is the string containing that // source code.) @@ -2121,7 +2216,7 @@ void Load(Handle process) { // Add a reference to the global object Local global = v8::Context::GetCurrent()->Global(); - Local args[1] = { Local::New(process) }; + Local args[1] = { Local::New(process_object) }; #ifdef HAVE_DTRACE InitDTrace(global); @@ -2564,14 +2659,14 @@ char** Init(int argc, char *argv[]) { } -void EmitExit(v8::Handle process) { +void EmitExit(v8::Handle process_object) { // process.emit('exit') Local emit_v = process->Get(String::New("emit")); assert(emit_v->IsFunction()); Local emit = Local::Cast(emit_v); Local args[] = { String::New("exit") }; TryCatch try_catch; - emit->Call(process, 1, args); + emit->Call(process_object, 1, args); if (try_catch.HasCaught()) { FatalException(try_catch); } @@ -2592,12 +2687,12 @@ int Start(int argc, char *argv[]) { // Create the main node::Isolate object Isolate* isolate = Isolate::New(uv_default_loop()); - Handle process = SetupProcessObject(argc, argv); + Handle process_object = SetupProcessObject(argc, argv); v8_typed_array::AttachBindings(context->Global()); // Create all the objects, load modules, do everything. // so your next reading stop should be node::Load()! - Load(process); + Load(process_object); // All our arguments are loaded. We've evaluated all of the scripts. We // might even have created TCP servers. Now we enter the main eventloop. If @@ -2606,7 +2701,7 @@ int Start(int argc, char *argv[]) { // watchers, it blocks. uv_run(NODE_LOOP()); - EmitExit(process); + EmitExit(process_object); isolate->Dispose(); diff --git a/src/node.h b/src/node.h index 7aa1a8af33d..c19c4b49f0c 100644 --- a/src/node.h +++ b/src/node.h @@ -100,7 +100,7 @@ void Load(v8::Handle process); void EmitExit(v8::Handle process); #define NODE_PSYMBOL(s) \ - v8::Persistent::New(v8::String::NewSymbol(s)) + (v8::Persistent::New(v8::String::NewSymbol(s))) /* Converts a unixtime to V8 Date */ #define NODE_UNIXTIME_V8(t) v8::Date::New(1000*static_cast(t)) @@ -113,8 +113,8 @@ void EmitExit(v8::Handle 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 { \ diff --git a/src/node_isolate.cc b/src/node_isolate.cc index 808a87265fa..193c5ee00e9 100644 --- a/src/node_isolate.cc +++ b/src/node_isolate.cc @@ -20,6 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "node_isolate.h" +#include "v8.h" #include #include diff --git a/src/node_isolate.h b/src/node_isolate.h index 415f69525fc..fd48c8ed489 100644 --- a/src/node_isolate.h +++ b/src/node_isolate.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: