Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8threads.h"
      6 
      7 #include "src/api.h"
      8 #include "src/bootstrapper.h"
      9 #include "src/debug/debug.h"
     10 #include "src/execution.h"
     11 #include "src/isolate-inl.h"
     12 #include "src/regexp/regexp-stack.h"
     13 #include "src/visitors.h"
     14 
     15 namespace v8 {
     16 
     17 
     18 namespace {
     19 
     20 // Track whether this V8 instance has ever called v8::Locker. This allows the
     21 // API code to verify that the lock is always held when V8 is being entered.
     22 base::Atomic32 g_locker_was_ever_used_ = 0;
     23 
     24 }  // namespace
     25 
     26 
     27 // Once the Locker is initialized, the current thread will be guaranteed to have
     28 // the lock for a given isolate.
     29 void Locker::Initialize(v8::Isolate* isolate) {
     30   DCHECK_NOT_NULL(isolate);
     31   has_lock_ = false;
     32   top_level_ = true;
     33   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     34   // Record that the Locker has been used at least once.
     35   base::Relaxed_Store(&g_locker_was_ever_used_, 1);
     36   // Get the big lock if necessary.
     37   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
     38     isolate_->thread_manager()->Lock();
     39     has_lock_ = true;
     40 
     41     // This may be a locker within an unlocker in which case we have to
     42     // get the saved state for this thread and restore it.
     43     if (isolate_->thread_manager()->RestoreThread()) {
     44       top_level_ = false;
     45     } else {
     46       internal::ExecutionAccess access(isolate_);
     47       isolate_->stack_guard()->ClearThread(access);
     48       isolate_->thread_manager()->InitThread(access);
     49     }
     50   }
     51   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     52 }
     53 
     54 
     55 bool Locker::IsLocked(v8::Isolate* isolate) {
     56   DCHECK_NOT_NULL(isolate);
     57   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
     58   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
     59 }
     60 
     61 
     62 bool Locker::IsActive() {
     63   return !!base::Relaxed_Load(&g_locker_was_ever_used_);
     64 }
     65 
     66 
     67 Locker::~Locker() {
     68   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     69   if (has_lock_) {
     70     if (top_level_) {
     71       isolate_->thread_manager()->FreeThreadResources();
     72     } else {
     73       isolate_->thread_manager()->ArchiveThread();
     74     }
     75     isolate_->thread_manager()->Unlock();
     76   }
     77 }
     78 
     79 
     80 void Unlocker::Initialize(v8::Isolate* isolate) {
     81   DCHECK_NOT_NULL(isolate);
     82   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     83   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     84   isolate_->thread_manager()->ArchiveThread();
     85   isolate_->thread_manager()->Unlock();
     86 }
     87 
     88 
     89 Unlocker::~Unlocker() {
     90   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
     91   isolate_->thread_manager()->Lock();
     92   isolate_->thread_manager()->RestoreThread();
     93 }
     94 
     95 
     96 namespace internal {
     97 
     98 void ThreadManager::InitThread(const ExecutionAccess& lock) {
     99   isolate_->stack_guard()->InitThread(lock);
    100   isolate_->debug()->InitThread(lock);
    101 }
    102 
    103 bool ThreadManager::RestoreThread() {
    104   DCHECK(IsLockedByCurrentThread());
    105   // First check whether the current thread has been 'lazily archived', i.e.
    106   // not archived at all.  If that is the case we put the state storage we
    107   // had prepared back in the free list, since we didn't need it after all.
    108   if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    109     lazily_archived_thread_ = ThreadId::Invalid();
    110     Isolate::PerIsolateThreadData* per_thread =
    111         isolate_->FindPerThreadDataForThisThread();
    112     DCHECK_NOT_NULL(per_thread);
    113     DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
    114     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
    115     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
    116     lazily_archived_thread_state_ = nullptr;
    117     per_thread->set_thread_state(nullptr);
    118     return true;
    119   }
    120 
    121   // Make sure that the preemption thread cannot modify the thread state while
    122   // it is being archived or restored.
    123   ExecutionAccess access(isolate_);
    124 
    125   // If there is another thread that was lazily archived then we have to really
    126   // archive it now.
    127   if (lazily_archived_thread_.IsValid()) {
    128     EagerlyArchiveThread();
    129   }
    130   Isolate::PerIsolateThreadData* per_thread =
    131       isolate_->FindPerThreadDataForThisThread();
    132   if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
    133     // This is a new thread.
    134     InitThread(access);
    135     return false;
    136   }
    137   ThreadState* state = per_thread->thread_state();
    138   char* from = state->data();
    139   from = isolate_->handle_scope_implementer()->RestoreThread(from);
    140   from = isolate_->RestoreThread(from);
    141   from = Relocatable::RestoreState(isolate_, from);
    142   from = isolate_->debug()->RestoreDebug(from);
    143   from = isolate_->stack_guard()->RestoreStackGuard(from);
    144   from = isolate_->regexp_stack()->RestoreStack(from);
    145   from = isolate_->bootstrapper()->RestoreState(from);
    146   per_thread->set_thread_state(nullptr);
    147   if (state->terminate_on_restore()) {
    148     isolate_->stack_guard()->RequestTerminateExecution();
    149     state->set_terminate_on_restore(false);
    150   }
    151   state->set_id(ThreadId::Invalid());
    152   state->Unlink();
    153   state->LinkInto(ThreadState::FREE_LIST);
    154   return true;
    155 }
    156 
    157 
    158 void ThreadManager::Lock() {
    159   mutex_.Lock();
    160   mutex_owner_ = ThreadId::Current();
    161   DCHECK(IsLockedByCurrentThread());
    162 }
    163 
    164 
    165 void ThreadManager::Unlock() {
    166   mutex_owner_ = ThreadId::Invalid();
    167   mutex_.Unlock();
    168 }
    169 
    170 
    171 static int ArchiveSpacePerThread() {
    172   return HandleScopeImplementer::ArchiveSpacePerThread() +
    173                         Isolate::ArchiveSpacePerThread() +
    174                           Debug::ArchiveSpacePerThread() +
    175                      StackGuard::ArchiveSpacePerThread() +
    176                     RegExpStack::ArchiveSpacePerThread() +
    177                    Bootstrapper::ArchiveSpacePerThread() +
    178                     Relocatable::ArchiveSpacePerThread();
    179 }
    180 
    181 ThreadState::ThreadState(ThreadManager* thread_manager)
    182     : id_(ThreadId::Invalid()),
    183       terminate_on_restore_(false),
    184       data_(nullptr),
    185       next_(this),
    186       previous_(this),
    187       thread_manager_(thread_manager) {}
    188 
    189 ThreadState::~ThreadState() {
    190   DeleteArray<char>(data_);
    191 }
    192 
    193 
    194 void ThreadState::AllocateSpace() {
    195   data_ = NewArray<char>(ArchiveSpacePerThread());
    196 }
    197 
    198 
    199 void ThreadState::Unlink() {
    200   next_->previous_ = previous_;
    201   previous_->next_ = next_;
    202 }
    203 
    204 
    205 void ThreadState::LinkInto(List list) {
    206   ThreadState* flying_anchor =
    207       list == FREE_LIST ? thread_manager_->free_anchor_
    208                         : thread_manager_->in_use_anchor_;
    209   next_ = flying_anchor->next_;
    210   previous_ = flying_anchor;
    211   flying_anchor->next_ = this;
    212   next_->previous_ = this;
    213 }
    214 
    215 
    216 ThreadState* ThreadManager::GetFreeThreadState() {
    217   ThreadState* gotten = free_anchor_->next_;
    218   if (gotten == free_anchor_) {
    219     ThreadState* new_thread_state = new ThreadState(this);
    220     new_thread_state->AllocateSpace();
    221     return new_thread_state;
    222   }
    223   return gotten;
    224 }
    225 
    226 
    227 // Gets the first in the list of archived threads.
    228 ThreadState* ThreadManager::FirstThreadStateInUse() {
    229   return in_use_anchor_->Next();
    230 }
    231 
    232 
    233 ThreadState* ThreadState::Next() {
    234   if (next_ == thread_manager_->in_use_anchor_) return nullptr;
    235   return next_;
    236 }
    237 
    238 // Thread ids must start with 1, because in TLS having thread id 0 can't
    239 // be distinguished from not having a thread id at all (since NULL is
    240 // defined as 0.)
    241 ThreadManager::ThreadManager()
    242     : mutex_owner_(ThreadId::Invalid()),
    243       lazily_archived_thread_(ThreadId::Invalid()),
    244       lazily_archived_thread_state_(nullptr),
    245       free_anchor_(nullptr),
    246       in_use_anchor_(nullptr) {
    247   free_anchor_ = new ThreadState(this);
    248   in_use_anchor_ = new ThreadState(this);
    249 }
    250 
    251 
    252 ThreadManager::~ThreadManager() {
    253   DeleteThreadStateList(free_anchor_);
    254   DeleteThreadStateList(in_use_anchor_);
    255 }
    256 
    257 
    258 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
    259   // The list starts and ends with the anchor.
    260   for (ThreadState* current = anchor->next_; current != anchor;) {
    261     ThreadState* next = current->next_;
    262     delete current;
    263     current = next;
    264   }
    265   delete anchor;
    266 }
    267 
    268 
    269 void ThreadManager::ArchiveThread() {
    270   DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
    271   DCHECK(!IsArchived());
    272   DCHECK(IsLockedByCurrentThread());
    273   ThreadState* state = GetFreeThreadState();
    274   state->Unlink();
    275   Isolate::PerIsolateThreadData* per_thread =
    276       isolate_->FindOrAllocatePerThreadDataForThisThread();
    277   per_thread->set_thread_state(state);
    278   lazily_archived_thread_ = ThreadId::Current();
    279   lazily_archived_thread_state_ = state;
    280   DCHECK(state->id().Equals(ThreadId::Invalid()));
    281   state->set_id(CurrentId());
    282   DCHECK(!state->id().Equals(ThreadId::Invalid()));
    283 }
    284 
    285 
    286 void ThreadManager::EagerlyArchiveThread() {
    287   DCHECK(IsLockedByCurrentThread());
    288   ThreadState* state = lazily_archived_thread_state_;
    289   state->LinkInto(ThreadState::IN_USE_LIST);
    290   char* to = state->data();
    291   // Ensure that data containing GC roots are archived first, and handle them
    292   // in ThreadManager::Iterate(RootVisitor*).
    293   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
    294   to = isolate_->ArchiveThread(to);
    295   to = Relocatable::ArchiveState(isolate_, to);
    296   to = isolate_->debug()->ArchiveDebug(to);
    297   to = isolate_->stack_guard()->ArchiveStackGuard(to);
    298   to = isolate_->regexp_stack()->ArchiveStack(to);
    299   to = isolate_->bootstrapper()->ArchiveState(to);
    300   lazily_archived_thread_ = ThreadId::Invalid();
    301   lazily_archived_thread_state_ = nullptr;
    302 }
    303 
    304 
    305 void ThreadManager::FreeThreadResources() {
    306   DCHECK(!isolate_->has_pending_exception());
    307   DCHECK(!isolate_->external_caught_exception());
    308   DCHECK_NULL(isolate_->try_catch_handler());
    309   isolate_->handle_scope_implementer()->FreeThreadResources();
    310   isolate_->FreeThreadResources();
    311   isolate_->debug()->FreeThreadResources();
    312   isolate_->stack_guard()->FreeThreadResources();
    313   isolate_->regexp_stack()->FreeThreadResources();
    314   isolate_->bootstrapper()->FreeThreadResources();
    315 }
    316 
    317 
    318 bool ThreadManager::IsArchived() {
    319   Isolate::PerIsolateThreadData* data =
    320       isolate_->FindPerThreadDataForThisThread();
    321   return data != nullptr && data->thread_state() != nullptr;
    322 }
    323 
    324 void ThreadManager::Iterate(RootVisitor* v) {
    325   // Expecting no threads during serialization/deserialization
    326   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
    327        state = state->Next()) {
    328     char* data = state->data();
    329     data = HandleScopeImplementer::Iterate(v, data);
    330     data = isolate_->Iterate(v, data);
    331     data = Relocatable::Iterate(v, data);
    332   }
    333 }
    334 
    335 
    336 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
    337   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
    338        state = state->Next()) {
    339     char* data = state->data();
    340     data += HandleScopeImplementer::ArchiveSpacePerThread();
    341     isolate_->IterateThread(v, data);
    342   }
    343 }
    344 
    345 
    346 ThreadId ThreadManager::CurrentId() {
    347   return ThreadId::Current();
    348 }
    349 
    350 
    351 void ThreadManager::TerminateExecution(ThreadId thread_id) {
    352   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
    353        state = state->Next()) {
    354     if (thread_id.Equals(state->id())) {
    355       state->set_terminate_on_restore(true);
    356     }
    357   }
    358 }
    359 
    360 
    361 }  // namespace internal
    362 }  // namespace v8
    363