Index: src/v8threads.cc |
=================================================================== |
--- src/v8threads.cc (revision 7267) |
+++ src/v8threads.cc (working copy) |
@@ -36,12 +36,7 @@ |
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. |
bool Locker::active_ = false; |
@@ -50,64 +45,88 @@ |
// 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) { |
+ // TODO(isolates): When Locker has Isolate parameter and it is provided, grab |
+ // that one instead of using the current one. |
+ // We pull default isolate for Locker constructor w/o p[arameter. |
+ // A thread should not enter an isolate before acquiring a lock, |
+ // in cases which mandate using Lockers. |
+ // So getting a lock is the first thing threads do in a scenario where |
+ // multple threads share an isolate. Hence, we need to access |
+ // 'locking isolate' before we can actually enter into default isolate. |
+ internal::Isolate* isolate = internal::Isolate::GetDefaultIsolateForLocking(); |
+ ASSERT(isolate != NULL); |
+ |
// 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; |
+ |
+ if (isolate->IsDefaultIsolate()) { |
+ // This only enters if not yet entered. |
+ internal::Isolate::EnterDefaultIsolate(); |
+ } |
+ |
+ ASSERT(internal::Thread::HasThreadLocal( |
+ internal::Isolate::thread_id_key())); |
+ |
// 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()) { |
V8::Initialize(); |
} |
// 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); |
} |
} |
- 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(); |
+ return internal::Isolate::Current()->thread_manager()-> |
+ IsLockedByCurrentThread(); |
} |
Locker::~Locker() { |
- ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); |
+ // TODO(isolate): this should use a field storing the isolate it |
+ // locked instead. |
+ internal::Isolate* isolate = internal::Isolate::Current(); |
+ ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); |
if (has_lock_) { |
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(); |
+ internal::Isolate* isolate = internal::Isolate::Current(); |
+ ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); |
+ isolate->thread_manager()->ArchiveThread(); |
+ isolate->thread_manager()->Unlock(); |
} |
Unlocker::~Unlocker() { |
- ASSERT(!internal::ThreadManager::IsLockedByCurrentThread()); |
- internal::ThreadManager::Lock(); |
- internal::ThreadManager::RestoreThread(); |
+ // TODO(isolates): check it's the isolate we unlocked. |
+ internal::Isolate* isolate = internal::Isolate::Current(); |
+ ASSERT(!isolate->thread_manager()->IsLockedByCurrentThread()); |
+ isolate->thread_manager()->Lock(); |
+ isolate->thread_manager()->RestoreThread(); |
} |
@@ -130,44 +149,45 @@ |
// 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) == |
+ ASSERT(Isolate::CurrentPerIsolateThreadData()->thread_state() == |
lazily_archived_thread_state_); |
lazily_archived_thread_state_->set_id(kInvalidId); |
lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); |
lazily_archived_thread_state_ = NULL; |
- Thread::SetThreadLocal(thread_state_key, NULL); |
+ Isolate::CurrentPerIsolateThreadData()->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::CurrentPerIsolateThreadData(); |
+ 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 = isolate_->handle_scope_implementer()->RestoreThread(from); |
+ from = isolate_->RestoreThread(from); |
from = Relocatable::RestoreState(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); |
@@ -192,7 +212,7 @@ |
static int ArchiveSpacePerThread() { |
return HandleScopeImplementer::ArchiveSpacePerThread() + |
- Top::ArchiveSpacePerThread() + |
+ Isolate::ArchiveSpacePerThread() + |
#ifdef ENABLE_DEBUGGER_SUPPORT |
Debug::ArchiveSpacePerThread() + |
#endif |
@@ -203,13 +223,12 @@ |
} |
-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_(ThreadManager::kInvalidId), |
+ terminate_on_restore_(false), |
+ next_(this), |
+ previous_(this), |
+ thread_manager_(thread_manager) { |
} |
@@ -226,7 +245,8 @@ |
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 +254,10 @@ |
} |
-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 +266,13 @@ |
// 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,19 +280,29 @@ |
// 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_(ThreadHandle::INVALID), |
+ lazily_archived_thread_(ThreadHandle::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(!IsArchived()); |
- ThreadState* state = ThreadState::GetFree(); |
+ ThreadState* state = GetFreeThreadState(); |
state->Unlink(); |
- Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state)); |
+ Isolate::CurrentPerIsolateThreadData()->set_thread_state(state); |
lazily_archived_thread_.Initialize(ThreadHandle::SELF); |
lazily_archived_thread_state_ = state; |
ASSERT(state->id() == kInvalidId); |
@@ -287,84 +317,69 @@ |
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 = isolate_->handle_scope_implementer()->ArchiveThread(to); |
+ to = isolate_->ArchiveThread(to); |
to = Relocatable::ArchiveState(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); |
+ to = isolate_->stack_guard()->ArchiveStackGuard(to); |
+ to = isolate_->regexp_stack()->ArchiveStack(to); |
+ to = isolate_->bootstrapper()->ArchiveState(to); |
lazily_archived_thread_.Initialize(ThreadHandle::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::CurrentPerIsolateThreadData(); |
+ 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); |
+ isolate_->IterateThread(v, data); |
} |
} |
int ThreadManager::CurrentId() { |
- return Thread::GetThreadLocalInt(thread_id_key); |
+ return Thread::GetThreadLocalInt(Isolate::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); |
- } |
-} |
- |
- |
-bool ThreadManager::HasId() { |
- return Thread::HasThreadLocal(thread_id_key); |
-} |
- |
- |
void ThreadManager::TerminateExecution(int thread_id) { |
- for (ThreadState* state = ThreadState::FirstInUse(); |
+ for (ThreadState* state = FirstThreadStateInUse(); |
state != NULL; |
state = state->Next()) { |
if (thread_id == state->id()) { |
@@ -374,13 +389,8 @@ |
} |
-// 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) |
- : Thread("v8:CtxtSwitcher"), |
+ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms) |
+ : Thread(isolate, "v8:CtxtSwitcher"), |
keep_going_(true), |
sleep_ms_(every_n_ms) { |
} |
@@ -389,15 +399,16 @@ |
// Set the scheduling interval of V8 threads. This function starts the |
// ContextSwitcher thread if needed. |
void ContextSwitcher::StartPreemption(int every_n_ms) { |
+ Isolate* isolate = Isolate::Current(); |
ASSERT(Locker::IsLocked()); |
- if (singleton_ == NULL) { |
+ 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 +416,17 @@ |
// 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() { |
+ Isolate* isolate = Isolate::Current(); |
ASSERT(Locker::IsLocked()); |
- if (singleton_ != NULL) { |
+ 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 +436,7 @@ |
void ContextSwitcher::Run() { |
while (keep_going_) { |
OS::Sleep(sleep_ms_); |
- StackGuard::Preempt(); |
+ isolate()->stack_guard()->Preempt(); |
} |
} |