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