Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "api.h"
     31 #include "bootstrapper.h"
     32 #include "debug.h"
     33 #include "execution.h"
     34 #include "v8threads.h"
     35 #include "regexp-stack.h"
     36 
     37 namespace v8 {
     38 
     39 
     40 // Track whether this V8 instance has ever called v8::Locker. This allows the
     41 // API code to verify that the lock is always held when V8 is being entered.
     42 bool Locker::active_ = false;
     43 
     44 
     45 // Once the Locker is initialized, the current thread will be guaranteed to have
     46 // the lock for a given isolate.
     47 void Locker::Initialize(v8::Isolate* isolate) {
     48   ASSERT(isolate != NULL);
     49   has_lock_= false;
     50   top_level_ = true;
     51   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     52   // Record that the Locker has been used at least once.
     53   active_ = true;
     54   // Get the big lock if necessary.
     55   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
     56     isolate_->thread_manager()->Lock();
     57     has_lock_ = true;
     58 
     59     // Make sure that V8 is initialized.  Archiving of threads interferes
     60     // with deserialization by adding additional root pointers, so we must
     61     // initialize here, before anyone can call ~Locker() or Unlocker().
     62     if (!isolate_->IsInitialized()) {
     63       isolate_->Enter();
     64       V8::Initialize();
     65       isolate_->Exit();
     66     }
     67 
     68     // This may be a locker within an unlocker in which case we have to
     69     // get the saved state for this thread and restore it.
     70     if (isolate_->thread_manager()->RestoreThread()) {
     71       top_level_ = false;
     72     } else {
     73       internal::ExecutionAccess access(isolate_);
     74       isolate_->stack_guard()->ClearThread(access);
     75       isolate_->stack_guard()->InitThread(access);
     76     }
     77     if (isolate_->IsDefaultIsolate()) {
     78       // This only enters if not yet entered.
     79       internal::Isolate::EnterDefaultIsolate();
     80     }
     81   }
     82   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
     83 }
     84 
     85 
     86 bool Locker::IsLocked(v8::Isolate* isolate) {
     87   ASSERT(isolate != NULL);
     88   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
     89   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
     90 }
     91 
     92 
     93 bool Locker::IsActive() {
     94   return active_;
     95 }
     96 
     97 
     98 Locker::~Locker() {
     99   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
    100   if (has_lock_) {
    101     if (isolate_->IsDefaultIsolate()) {
    102       isolate_->Exit();
    103     }
    104     if (top_level_) {
    105       isolate_->thread_manager()->FreeThreadResources();
    106     } else {
    107       isolate_->thread_manager()->ArchiveThread();
    108     }
    109     isolate_->thread_manager()->Unlock();
    110   }
    111 }
    112 
    113 
    114 void Unlocker::Initialize(v8::Isolate* isolate) {
    115   ASSERT(isolate != NULL);
    116   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
    117   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
    118   if (isolate_->IsDefaultIsolate()) {
    119     isolate_->Exit();
    120   }
    121   isolate_->thread_manager()->ArchiveThread();
    122   isolate_->thread_manager()->Unlock();
    123 }
    124 
    125 
    126 Unlocker::~Unlocker() {
    127   ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread());
    128   isolate_->thread_manager()->Lock();
    129   isolate_->thread_manager()->RestoreThread();
    130   if (isolate_->IsDefaultIsolate()) {
    131     isolate_->Enter();
    132   }
    133 }
    134 
    135 
    136 namespace internal {
    137 
    138 
    139 bool ThreadManager::RestoreThread() {
    140   ASSERT(IsLockedByCurrentThread());
    141   // First check whether the current thread has been 'lazily archived', i.e.
    142   // not archived at all.  If that is the case we put the state storage we
    143   // had prepared back in the free list, since we didn't need it after all.
    144   if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    145     lazily_archived_thread_ = ThreadId::Invalid();
    146     Isolate::PerIsolateThreadData* per_thread =
    147         isolate_->FindPerThreadDataForThisThread();
    148     ASSERT(per_thread != NULL);
    149     ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
    150     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
    151     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
    152     lazily_archived_thread_state_ = NULL;
    153     per_thread->set_thread_state(NULL);
    154     return true;
    155   }
    156 
    157   // Make sure that the preemption thread cannot modify the thread state while
    158   // it is being archived or restored.
    159   ExecutionAccess access(isolate_);
    160 
    161   // If there is another thread that was lazily archived then we have to really
    162   // archive it now.
    163   if (lazily_archived_thread_.IsValid()) {
    164     EagerlyArchiveThread();
    165   }
    166   Isolate::PerIsolateThreadData* per_thread =
    167       isolate_->FindPerThreadDataForThisThread();
    168   if (per_thread == NULL || per_thread->thread_state() == NULL) {
    169     // This is a new thread.
    170     isolate_->stack_guard()->InitThread(access);
    171     return false;
    172   }
    173   ThreadState* state = per_thread->thread_state();
    174   char* from = state->data();
    175   from = isolate_->handle_scope_implementer()->RestoreThread(from);
    176   from = isolate_->RestoreThread(from);
    177   from = Relocatable::RestoreState(isolate_, from);
    178 #ifdef ENABLE_DEBUGGER_SUPPORT
    179   from = isolate_->debug()->RestoreDebug(from);
    180 #endif
    181   from = isolate_->stack_guard()->RestoreStackGuard(from);
    182   from = isolate_->regexp_stack()->RestoreStack(from);
    183   from = isolate_->bootstrapper()->RestoreState(from);
    184   per_thread->set_thread_state(NULL);
    185   if (state->terminate_on_restore()) {
    186     isolate_->stack_guard()->TerminateExecution();
    187     state->set_terminate_on_restore(false);
    188   }
    189   state->set_id(ThreadId::Invalid());
    190   state->Unlink();
    191   state->LinkInto(ThreadState::FREE_LIST);
    192   return true;
    193 }
    194 
    195 
    196 void ThreadManager::Lock() {
    197   mutex_.Lock();
    198   mutex_owner_ = ThreadId::Current();
    199   ASSERT(IsLockedByCurrentThread());
    200 }
    201 
    202 
    203 void ThreadManager::Unlock() {
    204   mutex_owner_ = ThreadId::Invalid();
    205   mutex_.Unlock();
    206 }
    207 
    208 
    209 static int ArchiveSpacePerThread() {
    210   return HandleScopeImplementer::ArchiveSpacePerThread() +
    211                         Isolate::ArchiveSpacePerThread() +
    212 #ifdef ENABLE_DEBUGGER_SUPPORT
    213                           Debug::ArchiveSpacePerThread() +
    214 #endif
    215                      StackGuard::ArchiveSpacePerThread() +
    216                     RegExpStack::ArchiveSpacePerThread() +
    217                    Bootstrapper::ArchiveSpacePerThread() +
    218                     Relocatable::ArchiveSpacePerThread();
    219 }
    220 
    221 
    222 ThreadState::ThreadState(ThreadManager* thread_manager)
    223     : id_(ThreadId::Invalid()),
    224       terminate_on_restore_(false),
    225       data_(NULL),
    226       next_(this),
    227       previous_(this),
    228       thread_manager_(thread_manager) {
    229 }
    230 
    231 
    232 ThreadState::~ThreadState() {
    233   DeleteArray<char>(data_);
    234 }
    235 
    236 
    237 void ThreadState::AllocateSpace() {
    238   data_ = NewArray<char>(ArchiveSpacePerThread());
    239 }
    240 
    241 
    242 void ThreadState::Unlink() {
    243   next_->previous_ = previous_;
    244   previous_->next_ = next_;
    245 }
    246 
    247 
    248 void ThreadState::LinkInto(List list) {
    249   ThreadState* flying_anchor =
    250       list == FREE_LIST ? thread_manager_->free_anchor_
    251                         : thread_manager_->in_use_anchor_;
    252   next_ = flying_anchor->next_;
    253   previous_ = flying_anchor;
    254   flying_anchor->next_ = this;
    255   next_->previous_ = this;
    256 }
    257 
    258 
    259 ThreadState* ThreadManager::GetFreeThreadState() {
    260   ThreadState* gotten = free_anchor_->next_;
    261   if (gotten == free_anchor_) {
    262     ThreadState* new_thread_state = new ThreadState(this);
    263     new_thread_state->AllocateSpace();
    264     return new_thread_state;
    265   }
    266   return gotten;
    267 }
    268 
    269 
    270 // Gets the first in the list of archived threads.
    271 ThreadState* ThreadManager::FirstThreadStateInUse() {
    272   return in_use_anchor_->Next();
    273 }
    274 
    275 
    276 ThreadState* ThreadState::Next() {
    277   if (next_ == thread_manager_->in_use_anchor_) return NULL;
    278   return next_;
    279 }
    280 
    281 
    282 // Thread ids must start with 1, because in TLS having thread id 0 can't
    283 // be distinguished from not having a thread id at all (since NULL is
    284 // defined as 0.)
    285 ThreadManager::ThreadManager()
    286     : mutex_owner_(ThreadId::Invalid()),
    287       lazily_archived_thread_(ThreadId::Invalid()),
    288       lazily_archived_thread_state_(NULL),
    289       free_anchor_(NULL),
    290       in_use_anchor_(NULL) {
    291   free_anchor_ = new ThreadState(this);
    292   in_use_anchor_ = new ThreadState(this);
    293 }
    294 
    295 
    296 ThreadManager::~ThreadManager() {
    297   DeleteThreadStateList(free_anchor_);
    298   DeleteThreadStateList(in_use_anchor_);
    299 }
    300 
    301 
    302 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
    303   // The list starts and ends with the anchor.
    304   for (ThreadState* current = anchor->next_; current != anchor;) {
    305     ThreadState* next = current->next_;
    306     delete current;
    307     current = next;
    308   }
    309   delete anchor;
    310 }
    311 
    312 
    313 void ThreadManager::ArchiveThread() {
    314   ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
    315   ASSERT(!IsArchived());
    316   ASSERT(IsLockedByCurrentThread());
    317   ThreadState* state = GetFreeThreadState();
    318   state->Unlink();
    319   Isolate::PerIsolateThreadData* per_thread =
    320       isolate_->FindOrAllocatePerThreadDataForThisThread();
    321   per_thread->set_thread_state(state);
    322   lazily_archived_thread_ = ThreadId::Current();
    323   lazily_archived_thread_state_ = state;
    324   ASSERT(state->id().Equals(ThreadId::Invalid()));
    325   state->set_id(CurrentId());
    326   ASSERT(!state->id().Equals(ThreadId::Invalid()));
    327 }
    328 
    329 
    330 void ThreadManager::EagerlyArchiveThread() {
    331   ASSERT(IsLockedByCurrentThread());
    332   ThreadState* state = lazily_archived_thread_state_;
    333   state->LinkInto(ThreadState::IN_USE_LIST);
    334   char* to = state->data();
    335   // Ensure that data containing GC roots are archived first, and handle them
    336   // in ThreadManager::Iterate(ObjectVisitor*).
    337   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
    338   to = isolate_->ArchiveThread(to);
    339   to = Relocatable::ArchiveState(isolate_, to);
    340 #ifdef ENABLE_DEBUGGER_SUPPORT
    341   to = isolate_->debug()->ArchiveDebug(to);
    342 #endif
    343   to = isolate_->stack_guard()->ArchiveStackGuard(to);
    344   to = isolate_->regexp_stack()->ArchiveStack(to);
    345   to = isolate_->bootstrapper()->ArchiveState(to);
    346   lazily_archived_thread_ = ThreadId::Invalid();
    347   lazily_archived_thread_state_ = NULL;
    348 }
    349 
    350 
    351 void ThreadManager::FreeThreadResources() {
    352   isolate_->handle_scope_implementer()->FreeThreadResources();
    353   isolate_->FreeThreadResources();
    354 #ifdef ENABLE_DEBUGGER_SUPPORT
    355   isolate_->debug()->FreeThreadResources();
    356 #endif
    357   isolate_->stack_guard()->FreeThreadResources();
    358   isolate_->regexp_stack()->FreeThreadResources();
    359   isolate_->bootstrapper()->FreeThreadResources();
    360 }
    361 
    362 
    363 bool ThreadManager::IsArchived() {
    364   Isolate::PerIsolateThreadData* data =
    365       isolate_->FindPerThreadDataForThisThread();
    366   return data != NULL && data->thread_state() != NULL;
    367 }
    368 
    369 
    370 void ThreadManager::Iterate(ObjectVisitor* v) {
    371   // Expecting no threads during serialization/deserialization
    372   for (ThreadState* state = FirstThreadStateInUse();
    373        state != NULL;
    374        state = state->Next()) {
    375     char* data = state->data();
    376     data = HandleScopeImplementer::Iterate(v, data);
    377     data = isolate_->Iterate(v, data);
    378     data = Relocatable::Iterate(v, data);
    379   }
    380 }
    381 
    382 
    383 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
    384   for (ThreadState* state = FirstThreadStateInUse();
    385        state != NULL;
    386        state = state->Next()) {
    387     char* data = state->data();
    388     data += HandleScopeImplementer::ArchiveSpacePerThread();
    389     isolate_->IterateThread(v, data);
    390   }
    391 }
    392 
    393 
    394 ThreadId ThreadManager::CurrentId() {
    395   return ThreadId::Current();
    396 }
    397 
    398 
    399 void ThreadManager::TerminateExecution(ThreadId thread_id) {
    400   for (ThreadState* state = FirstThreadStateInUse();
    401        state != NULL;
    402        state = state->Next()) {
    403     if (thread_id.Equals(state->id())) {
    404       state->set_terminate_on_restore(true);
    405     }
    406   }
    407 }
    408 
    409 
    410 }  // namespace internal
    411 }  // namespace v8
    412