}
-struct ThreadInfo {
- uv_thread_t thread_;
- char** argv_;
- int argc_;
-
- ThreadInfo(int argc, char** argv) {
- argc_ = argc;
- argv_ = new char*[argc_ + 1];
-
- for (int i = 0; i < argc_; ++i) {
- size_t size = 1 + strlen(argv[i]);
- argv_[i] = new char[size];
- memcpy(argv_[i], argv[i], size);
- }
- argv_[argc_] = NULL;
- }
-
- ThreadInfo(Handle<Array> args) {
- argc_ = args->Length();
- argv_ = new char*[argc_ + 1];
-
- for (int i = 0; i < argc_; ++i) {
- String::Utf8Value str(args->Get(i));
- size_t size = 1 + strlen(*str);
- argv_[i] = new char[size];
- memcpy(argv_[i], *str, size);
- }
- argv_[argc_] = NULL;
- }
-
- ~ThreadInfo() {
- for (int i = 0; i < argc_; ++i) {
- delete[] argv_[i];
- }
- delete argv_;
- }
-};
-
-
static void RunIsolate(void* arg) {
- ThreadInfo* ti = reinterpret_cast<ThreadInfo*>(arg);
-
- Isolate* isolate = Isolate::New();
-
- StartThread(isolate, ti->argc_, ti->argv_);
+ node::Isolate* isolate = reinterpret_cast<node::Isolate*>(arg);
+ isolate->Enter();
+ StartThread(isolate, isolate->argc_, isolate->argv_);
isolate->Dispose();
-
- delete ti;
delete isolate;
}
Local<Array> argv = args[0].As<Array>();
assert(argv->Length() >= 2);
- ThreadInfo* ti = new ThreadInfo(argv);
+ // Note that isolate lock is aquired in the constructor here. It will not
+ // be unlocked until RunIsolate starts and calls isolate->Enter().
+ Isolate* isolate = new node::Isolate();
- if (uv_thread_create(&ti->thread_, RunIsolate, ti)) {
- delete ti;
+ // Copy over arguments into isolate
+ isolate->argc_ = argv->Length();
+ isolate->argv_ = new char*[isolate->argc_ + 1];
+ for (int i = 0; i < isolate->argc_; ++i) {
+ String::Utf8Value str(argv->Get(i));
+ size_t size = 1 + strlen(*str);
+ isolate->argv_[i] = new char[size];
+ memcpy(isolate->argv_[i], *str, size);
+ }
+ isolate->argv_[isolate->argc_] = NULL;
+
+ if (uv_thread_create(&isolate->tid_, RunIsolate, isolate)) {
+ delete isolate;
return Null();
}
Local<Object> obj = tpl->NewInstance();
obj->SetPointerInInternalField(0, magic_isolate_cookie_);
- obj->SetPointerInInternalField(1, ti);
+ obj->SetPointerInInternalField(1, isolate);
return scope.Close(obj);
}
assert(obj->InternalFieldCount() == 2);
assert(obj->GetPointerFromInternalField(0) == magic_isolate_cookie_);
- ThreadInfo* ti = reinterpret_cast<ThreadInfo*>(
+ Isolate* ti = reinterpret_cast<Isolate*>(
obj->GetPointerFromInternalField(1));
- if (uv_thread_join(&ti->thread_))
+ if (uv_thread_join(&ti->tid_))
return False(); // error
else
return True(); // ok
char** argv) {
HandleScope scope;
- v8::Isolate::Scope isolate_scope(isolate->GetV8Isolate());
- v8::Context::Scope context_scope(isolate->GetV8Context());
+ assert(node::Isolate::GetCurrent() == isolate);
uv_loop_t* loop = isolate->GetLoop();
uv_prepare_init(loop, &prepare_tick_watcher);
v8::V8::Initialize();
v8::HandleScope handle_scope;
+ // Get the id of the this, the main, thread.
+ uv_thread_t tid = uv_thread_self();
+
// Create the main node::Isolate object
node::Isolate::Initialize();
- Isolate* isolate = node::Isolate::New();
+ Isolate* isolate = new node::Isolate();
+ isolate->tid_ = tid;
+ isolate->Enter();
StartThread(isolate, argc, argv);
isolate->Dispose();
+ // The main thread/isolate is done. Wait for all other thread/isolates to
+ // finish.
+ node::Isolate::JoinAll();
+
#ifndef NDEBUG
// Clean up.
V8::Dispose();
}
-Isolate* Isolate::New() {
- return new Isolate();
+int Isolate::Count() {
+ return isolate_count;
}
-int Isolate::Count() {
- return isolate_count;
+void Isolate::JoinAll() {
+ uv_mutex_lock(&list_lock);
+
+ while (ngx_queue_empty(&list_head) == false) {
+ ngx_queue_t* q = ngx_queue_head(&list_head);
+ assert(q);
+ Isolate* isolate = ngx_queue_data(q, Isolate, list_member_);
+ assert(isolate);
+
+ // Unlock the list while we join the thread.
+ uv_mutex_unlock(&list_lock);
+
+ uv_thread_join(&isolate->tid_);
+
+ // Relock to check the next element in the list.
+ uv_mutex_lock(&list_lock);
+ }
+
+ // Unlock the list finally.
+ uv_mutex_unlock(&list_lock);
}
uv_mutex_unlock(&list_lock);
- v8_isolate_ = v8::Isolate::GetCurrent();
- if (v8_isolate_ == NULL) {
- v8_isolate_ = v8::Isolate::New();
- v8_isolate_->Enter();
- }
-
+ v8_isolate_ = v8::Isolate::New();
assert(v8_isolate_->GetData() == NULL);
v8_isolate_->SetData(this);
- v8_context_ = v8::Context::New();
- v8_context_->Enter();
-
- globals_init(&globals_);
+ globals_init_ = false;
}
}
+void Isolate::Enter() {
+ v8_isolate_->Enter();
+
+ if (v8_context_.IsEmpty()) {
+ v8_context_ = v8::Context::New();
+ }
+ v8_context_->Enter();
+
+ if (!globals_init_) {
+ globals_init_ = true;
+ globals_init(&globals_);
+ }
+
+ NODE_ISOLATE_CHECK(this);
+}
+
+
void Isolate::Dispose() {
uv_mutex_lock(&list_lock);
+ NODE_ISOLATE_CHECK(this);
+
struct AtExitCallbackInfo* it;
ngx_queue_t* q;
- NODE_ISOLATE_CHECK(this);
-
- ngx_queue_foreach(q, &at_exit_callbacks_) {
- it = ngx_queue_data(q, struct AtExitCallbackInfo, at_exit_callbacks_);
- it->callback_(it->arg_);
- delete it;
- }
- ngx_queue_init(&at_exit_callbacks_);
assert(v8_context_->InContext());
v8_context_->Exit();
class Isolate {
public:
+ char** argv_;
+ int argc_;
+ uv_thread_t tid_;
+
// Call this before instantiating any Isolate
static void Initialize();
static int Count();
typedef void (*AtExitCallback)(void* arg);
- static Isolate* New();
+ static void JoinAll();
static Isolate* GetCurrent() {
return reinterpret_cast<Isolate*>(v8::Isolate::GetCurrent()->GetData());
*/
void AtExit(AtExitCallback callback, void *arg);
- /* Shutdown the isolate. Call this method at thread death. */
- void Dispose();
-
struct globals* Globals();
unsigned int id_;
-private:
+ // This constructor is used for every non-main thread
Isolate();
+ ~Isolate() {
+ if (argv_) {
+ delete argv_;
+ }
+ }
+
+ void Enter();
+
+ /* Shutdown the isolate. Call this method at thread death. */
+ void Dispose();
+
+private:
+
struct AtExitCallbackInfo {
ngx_queue_t at_exit_callbacks_;
AtExitCallback callback_;
// Global variables for this isolate.
struct globals globals_;
+ bool globals_init_;
};
} // namespace node