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/v8.h"
      6 
      7 #include "src/api.h"
      8 #include "src/bootstrapper.h"
      9 #include "src/debug.h"
     10 #include "src/execution.h"
     11 #include "src/regexp-stack.h"
     12 #include "src/v8threads.h"
     13 
     14 namespace v8 {
     15 
     16 
     17 // Track whether this V8 instance has ever called v8::Locker. This allows the
     18 // API code to verify that the lock is always held when V8 is being entered.
     19 bool Locker::active_ = false;
     20 
     21 
     22 // Once the Locker is initialized, the current thread will be guaranteed to have
     23 // the lock for a given isolate.
     24 void Locker::Initialize(v8::Isolate* isolate) {
     25   DCHECK(isolate != NULL);
     26   has_lock_= false;
     27   top_level_ = true;
     28   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     29   // Record that the Locker has been used at least once.
     30   active_ = true;
     31   // Get the big lock if necessary.
     32   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
     33     isolate_->thread_manager()->Lock();
     34     has_lock_ = true;
     35 
     36     // Make sure that V8 is initialized.  Archiving of threads interferes
     37     // with deserialization by adding additional root pointers, so we must
     38     // initialize here, before anyone can call ~Locker() or Unlocker().
     39     if (!isolate_->IsInitialized()) {
     40       isolate_->Enter();
     41       V8::Initialize();
     42       isolate_->Exit();
     43     }
     44 
     45     // This may be a locker within an unlocker in which case we have to
     46     // get the saved state for this thread and restore it.
     47     if (isolate_->thread_manager()->RestoreThread()) {
     48       top_level_ = false;
     49     } else {
     50       internal::ExecutionAccess access(isolate_);
     51       isolate_->stack_guard()->ClearThread(access);
     52       isolate_->stack_guard()->InitThread(access);
     53     }
     54   }
     55   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     56 }
     57 
     58 
     59 bool Locker::IsLocked(v8::Isolate* isolate) {
     60   DCHECK(isolate != NULL);
     61   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
     62   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
     63 }
     64 
     65 
     66 bool Locker::IsActive() {
     67   return active_;
     68 }
     69 
     70 
     71 Locker::~Locker() {
     72   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     73   if (has_lock_) {
     74     if (top_level_) {
     75       isolate_->thread_manager()->FreeThreadResources();
     76     } else {
     77       isolate_->thread_manager()->ArchiveThread();
     78     }
     79     isolate_->thread_manager()->Unlock();
     80   }
     81 }
     82 
     83 
     84 void Unlocker::Initialize(v8::Isolate* isolate) {
     85   DCHECK(isolate != NULL);
     86   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     87   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
     88   isolate_->thread_manager()->ArchiveThread();
     89   isolate_->thread_manager()->Unlock();
     90 }
     91 
     92 
     93 Unlocker::~Unlocker() {
     94   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
     95   isolate_->thread_manager()->Lock();
     96   isolate_->thread_manager()->RestoreThread();
     97 }
     98 
     99 
    100 namespace internal {
    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(per_thread != NULL);
    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_ = NULL;
    117     per_thread->set_thread_state(NULL);
    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 == NULL || per_thread->thread_state() == NULL) {
    133     // This is a new thread.
    134     isolate_->stack_guard()->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(NULL);
    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 
    182 ThreadState::ThreadState(ThreadManager* thread_manager)
    183     : id_(ThreadId::Invalid()),
    184       terminate_on_restore_(false),
    185       data_(NULL),
    186       next_(this),
    187       previous_(this),
    188       thread_manager_(thread_manager) {
    189 }
    190 
    191 
    192 ThreadState::~ThreadState() {
    193   DeleteArray<char>(data_);
    194 }
    195 
    196 
    197 void ThreadState::AllocateSpace() {
    198   data_ = NewArray<char>(ArchiveSpacePerThread());
    199 }
    200 
    201 
    202 void ThreadState::Unlink() {
    203   next_->previous_ = previous_;
    204   previous_->next_ = next_;
    205 }
    206 
    207 
    208 void ThreadState::LinkInto(List list) {
    209   ThreadState* flying_anchor =
    210       list == FREE_LIST ? thread_manager_->free_anchor_
    211                         : thread_manager_->in_use_anchor_;
    212   next_ = flying_anchor->next_;
    213   previous_ = flying_anchor;
    214   flying_anchor->next_ = this;
    215   next_->previous_ = this;
    216 }
    217 
    218 
    219 ThreadState* ThreadManager::GetFreeThreadState() {
    220   ThreadState* gotten = free_anchor_->next_;
    221   if (gotten == free_anchor_) {
    222     ThreadState* new_thread_state = new ThreadState(this);
    223     new_thread_state->AllocateSpace();
    224     return new_thread_state;
    225   }
    226   return gotten;
    227 }
    228 
    229 
    230 // Gets the first in the list of archived threads.
    231 ThreadState* ThreadManager::FirstThreadStateInUse() {
    232   return in_use_anchor_->Next();
    233 }
    234 
    235 
    236 ThreadState* ThreadState::Next() {
    237   if (next_ == thread_manager_->in_use_anchor_) return NULL;
    238   return next_;
    239 }
    240 
    241 
    242 // Thread ids must start with 1, because in TLS having thread id 0 can't
    243 // be distinguished from not having a thread id at all (since NULL is
    244 // defined as 0.)
    245 ThreadManager::ThreadManager()
    246     : mutex_owner_(ThreadId::Invalid()),
    247       lazily_archived_thread_(ThreadId::Invalid()),
    248       lazily_archived_thread_state_(NULL),
    249       free_anchor_(NULL),
    250       in_use_anchor_(NULL) {
    251   free_anchor_ = new ThreadState(this);
    252   in_use_anchor_ = new ThreadState(this);
    253 }
    254 
    255 
    256 ThreadManager::~ThreadManager() {
    257   DeleteThreadStateList(free_anchor_);
    258   DeleteThreadStateList(in_use_anchor_);
    259 }
    260 
    261 
    262 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
    263   // The list starts and ends with the anchor.
    264   for (ThreadState* current = anchor->next_; current != anchor;) {
    265     ThreadState* next = current->next_;
    266     delete current;
    267     current = next;
    268   }
    269   delete anchor;
    270 }
    271 
    272 
    273 void ThreadManager::ArchiveThread() {
    274   DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
    275   DCHECK(!IsArchived());
    276   DCHECK(IsLockedByCurrentThread());
    277   ThreadState* state = GetFreeThreadState();
    278   state->Unlink();
    279   Isolate::PerIsolateThreadData* per_thread =
    280       isolate_->FindOrAllocatePerThreadDataForThisThread();
    281   per_thread->set_thread_state(state);
    282   lazily_archived_thread_ = ThreadId::Current();
    283   lazily_archived_thread_state_ = state;
    284   DCHECK(state->id().Equals(ThreadId::Invalid()));
    285   state->set_id(CurrentId());
    286   DCHECK(!state->id().Equals(ThreadId::Invalid()));
    287 }
    288 
    289 
    290 void ThreadManager::EagerlyArchiveThread() {
    291   DCHECK(IsLockedByCurrentThread());
    292   ThreadState* state = lazily_archived_thread_state_;
    293   state->LinkInto(ThreadState::IN_USE_LIST);
    294   char* to = state->data();
    295   // Ensure that data containing GC roots are archived first, and handle them
    296   // in ThreadManager::Iterate(ObjectVisitor*).
    297   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
    298   to = isolate_->ArchiveThread(to);
    299   to = Relocatable::ArchiveState(isolate_, to);
    300   to = isolate_->debug()->ArchiveDebug(to);
    301   to = isolate_->stack_guard()->ArchiveStackGuard(to);
    302   to = isolate_->regexp_stack()->ArchiveStack(to);
    303   to = isolate_->bootstrapper()->ArchiveState(to);
    304   lazily_archived_thread_ = ThreadId::Invalid();
    305   lazily_archived_thread_state_ = NULL;
    306 }
    307 
    308 
    309 void ThreadManager::FreeThreadResources() {
    310   DCHECK(!isolate_->has_pending_exception());
    311   DCHECK(!isolate_->external_caught_exception());
    312   DCHECK(isolate_->try_catch_handler() == NULL);
    313   isolate_->handle_scope_implementer()->FreeThreadResources();
    314   isolate_->FreeThreadResources();
    315   isolate_->debug()->FreeThreadResources();
    316   isolate_->stack_guard()->FreeThreadResources();
    317   isolate_->regexp_stack()->FreeThreadResources();
    318   isolate_->bootstrapper()->FreeThreadResources();
    319 }
    320 
    321 
    322 bool ThreadManager::IsArchived() {
    323   Isolate::PerIsolateThreadData* data =
    324       isolate_->FindPerThreadDataForThisThread();
    325   return data != NULL && data->thread_state() != NULL;
    326 }
    327 
    328 
    329 void ThreadManager::Iterate(ObjectVisitor* v) {
    330   // Expecting no threads during serialization/deserialization
    331   for (ThreadState* state = FirstThreadStateInUse();
    332        state != NULL;
    333        state = state->Next()) {
    334     char* data = state->data();
    335     data = HandleScopeImplementer::Iterate(v, data);
    336     data = isolate_->Iterate(v, data);
    337     data = Relocatable::Iterate(v, data);
    338   }
    339 }
    340 
    341 
    342 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
    343   for (ThreadState* state = FirstThreadStateInUse();
    344        state != NULL;
    345        state = state->Next()) {
    346     char* data = state->data();
    347     data += HandleScopeImplementer::ArchiveSpacePerThread();
    348     isolate_->IterateThread(v, data);
    349   }
    350 }
    351 
    352 
    353 ThreadId ThreadManager::CurrentId() {
    354   return ThreadId::Current();
    355 }
    356 
    357 
    358 void ThreadManager::TerminateExecution(ThreadId thread_id) {
    359   for (ThreadState* state = FirstThreadStateInUse();
    360        state != NULL;
    361        state = state->Next()) {
    362     if (thread_id.Equals(state->id())) {
    363       state->set_terminate_on_restore(true);
    364     }
    365   }
    366 }
    367 
    368 
    369 }  // namespace internal
    370 }  // namespace v8
    371