diff options
Diffstat (limited to 'deps/v8/src/v8threads.cc')
-rw-r--r-- | deps/v8/src/v8threads.cc | 301 |
1 files changed, 163 insertions, 138 deletions
diff --git a/deps/v8/src/v8threads.cc b/deps/v8/src/v8threads.cc index 8a5fe6902..978e2ddf3 100644 --- a/deps/v8/src/v8threads.cc +++ b/deps/v8/src/v8threads.cc @@ -36,11 +36,6 @@ namespace v8 { -static internal::Thread::LocalStorageKey thread_state_key = - internal::Thread::CreateThreadLocalKey(); -static internal::Thread::LocalStorageKey thread_id_key = - internal::Thread::CreateThreadLocalKey(); - // Track whether this V8 instance has ever called v8::Locker. This allows the // API code to verify that the lock is always held when V8 is being entered. @@ -48,66 +43,94 @@ bool Locker::active_ = false; // Constructor for the Locker object. Once the Locker is constructed the -// current thread will be guaranteed to have the big V8 lock. -Locker::Locker() : has_lock_(false), top_level_(true) { +// current thread will be guaranteed to have the lock for a given isolate. +Locker::Locker(v8::Isolate* isolate) + : has_lock_(false), + top_level_(false), + isolate_(reinterpret_cast<i::Isolate*>(isolate)) { + if (isolate_ == NULL) { + isolate_ = i::Isolate::GetDefaultIsolateForLocking(); + } // Record that the Locker has been used at least once. active_ = true; // Get the big lock if necessary. - if (!internal::ThreadManager::IsLockedByCurrentThread()) { - internal::ThreadManager::Lock(); + if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { + isolate_->thread_manager()->Lock(); has_lock_ = true; + // Make sure that V8 is initialized. Archiving of threads interferes // with deserialization by adding additional root pointers, so we must // initialize here, before anyone can call ~Locker() or Unlocker(). - if (!internal::V8::IsRunning()) { + if (!isolate_->IsInitialized()) { + isolate_->Enter(); V8::Initialize(); + isolate_->Exit(); } + // This may be a locker within an unlocker in which case we have to // get the saved state for this thread and restore it. - if (internal::ThreadManager::RestoreThread()) { + if (isolate_->thread_manager()->RestoreThread()) { top_level_ = false; } else { - internal::ExecutionAccess access; - internal::StackGuard::ClearThread(access); - internal::StackGuard::InitThread(access); + internal::ExecutionAccess access(isolate_); + isolate_->stack_guard()->ClearThread(access); + isolate_->stack_guard()->InitThread(access); + } + if (isolate_->IsDefaultIsolate()) { + // This only enters if not yet entered. + internal::Isolate::EnterDefaultIsolate(); } } - ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); - - // Make sure this thread is assigned a thread id. - internal::ThreadManager::AssignId(); + ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); } -bool Locker::IsLocked() { - return internal::ThreadManager::IsLockedByCurrentThread(); +bool Locker::IsLocked(v8::Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); + if (internal_isolate == NULL) { + internal_isolate = i::Isolate::GetDefaultIsolateForLocking(); + } + return internal_isolate->thread_manager()->IsLockedByCurrentThread(); } Locker::~Locker() { - ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); + ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); if (has_lock_) { + if (isolate_->IsDefaultIsolate()) { + isolate_->Exit(); + } if (top_level_) { - internal::ThreadManager::FreeThreadResources(); + isolate_->thread_manager()->FreeThreadResources(); } else { - internal::ThreadManager::ArchiveThread(); + isolate_->thread_manager()->ArchiveThread(); } - internal::ThreadManager::Unlock(); + isolate_->thread_manager()->Unlock(); } } -Unlocker::Unlocker() { - ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); - internal::ThreadManager::ArchiveThread(); - internal::ThreadManager::Unlock(); +Unlocker::Unlocker(v8::Isolate* isolate) + : isolate_(reinterpret_cast<i::Isolate*>(isolate)) { + if (isolate_ == NULL) { + isolate_ = i::Isolate::GetDefaultIsolateForLocking(); + } + ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); + if (isolate_->IsDefaultIsolate()) { + isolate_->Exit(); + } + isolate_->thread_manager()->ArchiveThread(); + isolate_->thread_manager()->Unlock(); } Unlocker::~Unlocker() { - ASSERT(!internal::ThreadManager::IsLockedByCurrentThread()); - internal::ThreadManager::Lock(); - internal::ThreadManager::RestoreThread(); + ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread()); + isolate_->thread_manager()->Lock(); + isolate_->thread_manager()->RestoreThread(); + if (isolate_->IsDefaultIsolate()) { + isolate_->Enter(); + } } @@ -125,52 +148,56 @@ namespace internal { bool ThreadManager::RestoreThread() { + ASSERT(IsLockedByCurrentThread()); // First check whether the current thread has been 'lazily archived', ie // not archived at all. If that is the case we put the state storage we // had prepared back in the free list, since we didn't need it after all. - if (lazily_archived_thread_.IsSelf()) { - lazily_archived_thread_.Initialize(ThreadHandle::INVALID); - ASSERT(Thread::GetThreadLocal(thread_state_key) == - lazily_archived_thread_state_); - lazily_archived_thread_state_->set_id(kInvalidId); + if (lazily_archived_thread_.Equals(ThreadId::Current())) { + lazily_archived_thread_ = ThreadId::Invalid(); + Isolate::PerIsolateThreadData* per_thread = + isolate_->FindPerThreadDataForThisThread(); + ASSERT(per_thread != NULL); + ASSERT(per_thread->thread_state() == lazily_archived_thread_state_); + lazily_archived_thread_state_->set_id(ThreadId::Invalid()); lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); lazily_archived_thread_state_ = NULL; - Thread::SetThreadLocal(thread_state_key, NULL); + per_thread->set_thread_state(NULL); return true; } // Make sure that the preemption thread cannot modify the thread state while // it is being archived or restored. - ExecutionAccess access; + ExecutionAccess access(isolate_); // If there is another thread that was lazily archived then we have to really // archive it now. if (lazily_archived_thread_.IsValid()) { EagerlyArchiveThread(); } - ThreadState* state = - reinterpret_cast<ThreadState*>(Thread::GetThreadLocal(thread_state_key)); - if (state == NULL) { + Isolate::PerIsolateThreadData* per_thread = + isolate_->FindPerThreadDataForThisThread(); + if (per_thread == NULL || per_thread->thread_state() == NULL) { // This is a new thread. - StackGuard::InitThread(access); + isolate_->stack_guard()->InitThread(access); return false; } + ThreadState* state = per_thread->thread_state(); char* from = state->data(); - from = HandleScopeImplementer::RestoreThread(from); - from = Top::RestoreThread(from); - from = Relocatable::RestoreState(from); + from = isolate_->handle_scope_implementer()->RestoreThread(from); + from = isolate_->RestoreThread(from); + from = Relocatable::RestoreState(isolate_, from); #ifdef ENABLE_DEBUGGER_SUPPORT - from = Debug::RestoreDebug(from); + from = isolate_->debug()->RestoreDebug(from); #endif - from = StackGuard::RestoreStackGuard(from); - from = RegExpStack::RestoreStack(from); - from = Bootstrapper::RestoreState(from); - Thread::SetThreadLocal(thread_state_key, NULL); + from = isolate_->stack_guard()->RestoreStackGuard(from); + from = isolate_->regexp_stack()->RestoreStack(from); + from = isolate_->bootstrapper()->RestoreState(from); + per_thread->set_thread_state(NULL); if (state->terminate_on_restore()) { - StackGuard::TerminateExecution(); + isolate_->stack_guard()->TerminateExecution(); state->set_terminate_on_restore(false); } - state->set_id(kInvalidId); + state->set_id(ThreadId::Invalid()); state->Unlink(); state->LinkInto(ThreadState::FREE_LIST); return true; @@ -179,20 +206,20 @@ bool ThreadManager::RestoreThread() { void ThreadManager::Lock() { mutex_->Lock(); - mutex_owner_.Initialize(ThreadHandle::SELF); + mutex_owner_ = ThreadId::Current(); ASSERT(IsLockedByCurrentThread()); } void ThreadManager::Unlock() { - mutex_owner_.Initialize(ThreadHandle::INVALID); + mutex_owner_ = ThreadId::Invalid(); mutex_->Unlock(); } static int ArchiveSpacePerThread() { return HandleScopeImplementer::ArchiveSpacePerThread() + - Top::ArchiveSpacePerThread() + + Isolate::ArchiveSpacePerThread() + #ifdef ENABLE_DEBUGGER_SUPPORT Debug::ArchiveSpacePerThread() + #endif @@ -203,13 +230,12 @@ static int ArchiveSpacePerThread() { } -ThreadState* ThreadState::free_anchor_ = new ThreadState(); -ThreadState* ThreadState::in_use_anchor_ = new ThreadState(); - - -ThreadState::ThreadState() : id_(ThreadManager::kInvalidId), - terminate_on_restore_(false), - next_(this), previous_(this) { +ThreadState::ThreadState(ThreadManager* thread_manager) + : id_(ThreadId::Invalid()), + terminate_on_restore_(false), + next_(this), + previous_(this), + thread_manager_(thread_manager) { } @@ -226,7 +252,8 @@ void ThreadState::Unlink() { void ThreadState::LinkInto(List list) { ThreadState* flying_anchor = - list == FREE_LIST ? free_anchor_ : in_use_anchor_; + list == FREE_LIST ? thread_manager_->free_anchor_ + : thread_manager_->in_use_anchor_; next_ = flying_anchor->next_; previous_ = flying_anchor; flying_anchor->next_ = this; @@ -234,10 +261,10 @@ void ThreadState::LinkInto(List list) { } -ThreadState* ThreadState::GetFree() { +ThreadState* ThreadManager::GetFreeThreadState() { ThreadState* gotten = free_anchor_->next_; if (gotten == free_anchor_) { - ThreadState* new_thread_state = new ThreadState(); + ThreadState* new_thread_state = new ThreadState(this); new_thread_state->AllocateSpace(); return new_thread_state; } @@ -246,13 +273,13 @@ ThreadState* ThreadState::GetFree() { // Gets the first in the list of archived threads. -ThreadState* ThreadState::FirstInUse() { +ThreadState* ThreadManager::FirstThreadStateInUse() { return in_use_anchor_->Next(); } ThreadState* ThreadState::Next() { - if (next_ == in_use_anchor_) return NULL; + if (next_ == thread_manager_->in_use_anchor_) return NULL; return next_; } @@ -260,144 +287,140 @@ ThreadState* ThreadState::Next() { // Thread ids must start with 1, because in TLS having thread id 0 can't // be distinguished from not having a thread id at all (since NULL is // defined as 0.) -int ThreadManager::last_id_ = 0; -Mutex* ThreadManager::mutex_ = OS::CreateMutex(); -ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID); -ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID); -ThreadState* ThreadManager::lazily_archived_thread_state_ = NULL; +ThreadManager::ThreadManager() + : mutex_(OS::CreateMutex()), + mutex_owner_(ThreadId::Invalid()), + lazily_archived_thread_(ThreadId::Invalid()), + lazily_archived_thread_state_(NULL), + free_anchor_(NULL), + in_use_anchor_(NULL) { + free_anchor_ = new ThreadState(this); + in_use_anchor_ = new ThreadState(this); +} + + +ThreadManager::~ThreadManager() { + // TODO(isolates): Destroy mutexes. +} void ThreadManager::ArchiveThread() { - ASSERT(!lazily_archived_thread_.IsValid()); + ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); ASSERT(!IsArchived()); - ThreadState* state = ThreadState::GetFree(); + ASSERT(IsLockedByCurrentThread()); + ThreadState* state = GetFreeThreadState(); state->Unlink(); - Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state)); - lazily_archived_thread_.Initialize(ThreadHandle::SELF); + Isolate::PerIsolateThreadData* per_thread = + isolate_->FindOrAllocatePerThreadDataForThisThread(); + per_thread->set_thread_state(state); + lazily_archived_thread_ = ThreadId::Current(); lazily_archived_thread_state_ = state; - ASSERT(state->id() == kInvalidId); + ASSERT(state->id().Equals(ThreadId::Invalid())); state->set_id(CurrentId()); - ASSERT(state->id() != kInvalidId); + ASSERT(!state->id().Equals(ThreadId::Invalid())); } void ThreadManager::EagerlyArchiveThread() { + ASSERT(IsLockedByCurrentThread()); ThreadState* state = lazily_archived_thread_state_; state->LinkInto(ThreadState::IN_USE_LIST); char* to = state->data(); // Ensure that data containing GC roots are archived first, and handle them // in ThreadManager::Iterate(ObjectVisitor*). - to = HandleScopeImplementer::ArchiveThread(to); - to = Top::ArchiveThread(to); - to = Relocatable::ArchiveState(to); + to = isolate_->handle_scope_implementer()->ArchiveThread(to); + to = isolate_->ArchiveThread(to); + to = Relocatable::ArchiveState(isolate_, to); #ifdef ENABLE_DEBUGGER_SUPPORT - to = Debug::ArchiveDebug(to); + to = isolate_->debug()->ArchiveDebug(to); #endif - to = StackGuard::ArchiveStackGuard(to); - to = RegExpStack::ArchiveStack(to); - to = Bootstrapper::ArchiveState(to); - lazily_archived_thread_.Initialize(ThreadHandle::INVALID); + to = isolate_->stack_guard()->ArchiveStackGuard(to); + to = isolate_->regexp_stack()->ArchiveStack(to); + to = isolate_->bootstrapper()->ArchiveState(to); + lazily_archived_thread_ = ThreadId::Invalid(); lazily_archived_thread_state_ = NULL; } void ThreadManager::FreeThreadResources() { - HandleScopeImplementer::FreeThreadResources(); - Top::FreeThreadResources(); + isolate_->handle_scope_implementer()->FreeThreadResources(); + isolate_->FreeThreadResources(); #ifdef ENABLE_DEBUGGER_SUPPORT - Debug::FreeThreadResources(); + isolate_->debug()->FreeThreadResources(); #endif - StackGuard::FreeThreadResources(); - RegExpStack::FreeThreadResources(); - Bootstrapper::FreeThreadResources(); + isolate_->stack_guard()->FreeThreadResources(); + isolate_->regexp_stack()->FreeThreadResources(); + isolate_->bootstrapper()->FreeThreadResources(); } bool ThreadManager::IsArchived() { - return Thread::HasThreadLocal(thread_state_key); + Isolate::PerIsolateThreadData* data = + isolate_->FindPerThreadDataForThisThread(); + return data != NULL && data->thread_state() != NULL; } - void ThreadManager::Iterate(ObjectVisitor* v) { // Expecting no threads during serialization/deserialization - for (ThreadState* state = ThreadState::FirstInUse(); + for (ThreadState* state = FirstThreadStateInUse(); state != NULL; state = state->Next()) { char* data = state->data(); data = HandleScopeImplementer::Iterate(v, data); - data = Top::Iterate(v, data); + data = isolate_->Iterate(v, data); data = Relocatable::Iterate(v, data); } } void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { - for (ThreadState* state = ThreadState::FirstInUse(); + for (ThreadState* state = FirstThreadStateInUse(); state != NULL; state = state->Next()) { char* data = state->data(); data += HandleScopeImplementer::ArchiveSpacePerThread(); - Top::IterateThread(v, data); - } -} - - -int ThreadManager::CurrentId() { - return Thread::GetThreadLocalInt(thread_id_key); -} - - -void ThreadManager::AssignId() { - if (!HasId()) { - ASSERT(Locker::IsLocked()); - int thread_id = ++last_id_; - ASSERT(thread_id > 0); // see the comment near last_id_ definition. - Thread::SetThreadLocalInt(thread_id_key, thread_id); - Top::set_thread_id(thread_id); + isolate_->IterateThread(v, data); } } -bool ThreadManager::HasId() { - return Thread::HasThreadLocal(thread_id_key); +ThreadId ThreadManager::CurrentId() { + return ThreadId::Current(); } -void ThreadManager::TerminateExecution(int thread_id) { - for (ThreadState* state = ThreadState::FirstInUse(); +void ThreadManager::TerminateExecution(ThreadId thread_id) { + for (ThreadState* state = FirstThreadStateInUse(); state != NULL; state = state->Next()) { - if (thread_id == state->id()) { + if (thread_id.Equals(state->id())) { state->set_terminate_on_restore(true); } } } -// This is the ContextSwitcher singleton. There is at most a single thread -// running which delivers preemption events to V8 threads. -ContextSwitcher* ContextSwitcher::singleton_ = NULL; - - -ContextSwitcher::ContextSwitcher(int every_n_ms) +ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms) : Thread("v8:CtxtSwitcher"), keep_going_(true), - sleep_ms_(every_n_ms) { + sleep_ms_(every_n_ms), + isolate_(isolate) { } // Set the scheduling interval of V8 threads. This function starts the // ContextSwitcher thread if needed. void ContextSwitcher::StartPreemption(int every_n_ms) { - ASSERT(Locker::IsLocked()); - if (singleton_ == NULL) { + Isolate* isolate = Isolate::Current(); + ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); + if (isolate->context_switcher() == NULL) { // If the ContextSwitcher thread is not running at the moment start it now. - singleton_ = new ContextSwitcher(every_n_ms); - singleton_->Start(); + isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms)); + isolate->context_switcher()->Start(); } else { // ContextSwitcher thread is already running, so we just change the // scheduling interval. - singleton_->sleep_ms_ = every_n_ms; + isolate->context_switcher()->sleep_ms_ = every_n_ms; } } @@ -405,15 +428,17 @@ void ContextSwitcher::StartPreemption(int every_n_ms) { // Disable preemption of V8 threads. If multiple threads want to use V8 they // must cooperatively schedule amongst them from this point on. void ContextSwitcher::StopPreemption() { - ASSERT(Locker::IsLocked()); - if (singleton_ != NULL) { + Isolate* isolate = Isolate::Current(); + ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); + if (isolate->context_switcher() != NULL) { // The ContextSwitcher thread is running. We need to stop it and release // its resources. - singleton_->keep_going_ = false; - singleton_->Join(); // Wait for the ContextSwitcher thread to exit. + isolate->context_switcher()->keep_going_ = false; + // Wait for the ContextSwitcher thread to exit. + isolate->context_switcher()->Join(); // Thread has exited, now we can delete it. - delete(singleton_); - singleton_ = NULL; + delete(isolate->context_switcher()); + isolate->set_context_switcher(NULL); } } @@ -423,7 +448,7 @@ void ContextSwitcher::StopPreemption() { void ContextSwitcher::Run() { while (keep_going_) { OS::Sleep(sleep_ms_); - StackGuard::Preempt(); + isolate()->stack_guard()->Preempt(); } } |