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 Locker::Locker() {
     46   Initialize(i::Isolate::GetDefaultIsolateForLocking());
     47 }
     48 
     49 
     50 // Once the Locker is initialized, the current thread will be guaranteed to have
     51 // the lock for a given isolate.
     52 void Locker::Initialize(v8::Isolate* isolate) {
     53   ASSERT(isolate != NULL);
     54   has_lock_= false;
     55   top_level_ = true;
     56   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
     57   // Record that the Locker has been used at least once.
     58   active_ = true;
     59   // Get the big lock if necessary.
     60   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
     61     isolate_->thread_manager()->Lock();
     62     has_lock_ = true;
     63 
     64     // Make sure that V8 is initialized.  Archiving of threads interferes
     65     // with deserialization by adding additional root pointers, so we must
     66     // initialize here, before anyone can call ~Locker() or Unlocker().
     67     if (!isolate_->IsInitialized()) {
     68       isolate_->Enter();
     69       V8::Initialize();
     70       isolate_->Exit();
     71     }
     72 
     73     // This may be a locker within an unlocker in which case we have to
     74     // get the saved state for this thread and restore it.
     75     if (isolate_->thread_manager()->RestoreThread()) {
     76       top_level_ = false;
     77     } else {
     78       internal::ExecutionAccess access(isolate_);
     79       isolate_->stack_guard()->ClearThread(access);
     80       isolate_->stack_guard()->InitThread(access);
     81     }
     82     if (isolate_->IsDefaultIsolate()) {
     83       // This only enters if not yet entered.
     84       internal::Isolate::EnterDefaultIsolate();
     85     }
     86   }
     87   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
     88 }
     89 
     90 
     91 bool Locker::IsLocked(v8::Isolate* isolate) {
     92   ASSERT(isolate != NULL);
     93   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
     94   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
     95 }
     96 
     97 
     98 bool Locker::IsActive() {
     99   return active_;
    100 }
    101 
    102 
    103 Locker::~Locker() {
    104   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
    105   if (has_lock_) {
    106     if (isolate_->IsDefaultIsolate()) {
    107       isolate_->Exit();
    108     }
    109     if (top_level_) {
    110       isolate_->thread_manager()->FreeThreadResources();
    111     } else {
    112       isolate_->thread_manager()->ArchiveThread();
    113     }
    114     isolate_->thread_manager()->Unlock();
    115   }
    116 }
    117 
    118 
    119 Unlocker::Unlocker() {
    120   Initialize(i::Isolate::GetDefaultIsolateForLocking());
    121 }
    122 
    123 
    124 void Unlocker::Initialize(v8::Isolate* isolate) {
    125   ASSERT(isolate != NULL);
    126   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
    127   ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
    128   if (isolate_->IsDefaultIsolate()) {
    129     isolate_->Exit();
    130   }
    131   isolate_->thread_manager()->ArchiveThread();
    132   isolate_->thread_manager()->Unlock();
    133 }
    134 
    135 
    136 Unlocker::~Unlocker() {
    137   ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread());
    138   isolate_->thread_manager()->Lock();
    139   isolate_->thread_manager()->RestoreThread();
    140   if (isolate_->IsDefaultIsolate()) {
    141     isolate_->Enter();
    142   }
    143 }
    144 
    145 
    146 void Locker::StartPreemption(int every_n_ms) {
    147   v8::internal::ContextSwitcher::StartPreemption(every_n_ms);
    148 }
    149 
    150 
    151 void Locker::StopPreemption() {
    152   v8::internal::ContextSwitcher::StopPreemption();
    153 }
    154 
    155 
    156 namespace internal {
    157 
    158 
    159 bool ThreadManager::RestoreThread() {
    160   ASSERT(IsLockedByCurrentThread());
    161   // First check whether the current thread has been 'lazily archived', i.e.
    162   // not archived at all.  If that is the case we put the state storage we
    163   // had prepared back in the free list, since we didn't need it after all.
    164   if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    165     lazily_archived_thread_ = ThreadId::Invalid();
    166     Isolate::PerIsolateThreadData* per_thread =
    167         isolate_->FindPerThreadDataForThisThread();
    168     ASSERT(per_thread != NULL);
    169     ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
    170     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
    171     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
    172     lazily_archived_thread_state_ = NULL;
    173     per_thread->set_thread_state(NULL);
    174     return true;
    175   }
    176 
    177   // Make sure that the preemption thread cannot modify the thread state while
    178   // it is being archived or restored.
    179   ExecutionAccess access(isolate_);
    180 
    181   // If there is another thread that was lazily archived then we have to really
    182   // archive it now.
    183   if (lazily_archived_thread_.IsValid()) {
    184     EagerlyArchiveThread();
    185   }
    186   Isolate::PerIsolateThreadData* per_thread =
    187       isolate_->FindPerThreadDataForThisThread();
    188   if (per_thread == NULL || per_thread->thread_state() == NULL) {
    189     // This is a new thread.
    190     isolate_->stack_guard()->InitThread(access);
    191     return false;
    192   }
    193   ThreadState* state = per_thread->thread_state();
    194   char* from = state->data();
    195   from = isolate_->handle_scope_implementer()->RestoreThread(from);
    196   from = isolate_->RestoreThread(from);
    197   from = Relocatable::RestoreState(isolate_, from);
    198 #ifdef ENABLE_DEBUGGER_SUPPORT
    199   from = isolate_->debug()->RestoreDebug(from);
    200 #endif
    201   from = isolate_->stack_guard()->RestoreStackGuard(from);
    202   from = isolate_->regexp_stack()->RestoreStack(from);
    203   from = isolate_->bootstrapper()->RestoreState(from);
    204   per_thread->set_thread_state(NULL);
    205   if (state->terminate_on_restore()) {
    206     isolate_->stack_guard()->TerminateExecution();
    207     state->set_terminate_on_restore(false);
    208   }
    209   state->set_id(ThreadId::Invalid());
    210   state->Unlink();
    211   state->LinkInto(ThreadState::FREE_LIST);
    212   return true;
    213 }
    214 
    215 
    216 void ThreadManager::Lock() {
    217   mutex_->Lock();
    218   mutex_owner_ = ThreadId::Current();
    219   ASSERT(IsLockedByCurrentThread());
    220 }
    221 
    222 
    223 void ThreadManager::Unlock() {
    224   mutex_owner_ = ThreadId::Invalid();
    225   mutex_->Unlock();
    226 }
    227 
    228 
    229 static int ArchiveSpacePerThread() {
    230   return HandleScopeImplementer::ArchiveSpacePerThread() +
    231                         Isolate::ArchiveSpacePerThread() +
    232 #ifdef ENABLE_DEBUGGER_SUPPORT
    233                           Debug::ArchiveSpacePerThread() +
    234 #endif
    235                      StackGuard::ArchiveSpacePerThread() +
    236                     RegExpStack::ArchiveSpacePerThread() +
    237                    Bootstrapper::ArchiveSpacePerThread() +
    238                     Relocatable::ArchiveSpacePerThread();
    239 }
    240 
    241 
    242 ThreadState::ThreadState(ThreadManager* thread_manager)
    243     : id_(ThreadId::Invalid()),
    244       terminate_on_restore_(false),
    245       data_(NULL),
    246       next_(this),
    247       previous_(this),
    248       thread_manager_(thread_manager) {
    249 }
    250 
    251 
    252 ThreadState::~ThreadState() {
    253   DeleteArray<char>(data_);
    254 }
    255 
    256 
    257 void ThreadState::AllocateSpace() {
    258   data_ = NewArray<char>(ArchiveSpacePerThread());
    259 }
    260 
    261 
    262 void ThreadState::Unlink() {
    263   next_->previous_ = previous_;
    264   previous_->next_ = next_;
    265 }
    266 
    267 
    268 void ThreadState::LinkInto(List list) {
    269   ThreadState* flying_anchor =
    270       list == FREE_LIST ? thread_manager_->free_anchor_
    271                         : thread_manager_->in_use_anchor_;
    272   next_ = flying_anchor->next_;
    273   previous_ = flying_anchor;
    274   flying_anchor->next_ = this;
    275   next_->previous_ = this;
    276 }
    277 
    278 
    279 ThreadState* ThreadManager::GetFreeThreadState() {
    280   ThreadState* gotten = free_anchor_->next_;
    281   if (gotten == free_anchor_) {
    282     ThreadState* new_thread_state = new ThreadState(this);
    283     new_thread_state->AllocateSpace();
    284     return new_thread_state;
    285   }
    286   return gotten;
    287 }
    288 
    289 
    290 // Gets the first in the list of archived threads.
    291 ThreadState* ThreadManager::FirstThreadStateInUse() {
    292   return in_use_anchor_->Next();
    293 }
    294 
    295 
    296 ThreadState* ThreadState::Next() {
    297   if (next_ == thread_manager_->in_use_anchor_) return NULL;
    298   return next_;
    299 }
    300 
    301 
    302 // Thread ids must start with 1, because in TLS having thread id 0 can't
    303 // be distinguished from not having a thread id at all (since NULL is
    304 // defined as 0.)
    305 ThreadManager::ThreadManager()
    306     : mutex_(OS::CreateMutex()),
    307       mutex_owner_(ThreadId::Invalid()),
    308       lazily_archived_thread_(ThreadId::Invalid()),
    309       lazily_archived_thread_state_(NULL),
    310       free_anchor_(NULL),
    311       in_use_anchor_(NULL) {
    312   free_anchor_ = new ThreadState(this);
    313   in_use_anchor_ = new ThreadState(this);
    314 }
    315 
    316 
    317 ThreadManager::~ThreadManager() {
    318   delete mutex_;
    319   DeleteThreadStateList(free_anchor_);
    320   DeleteThreadStateList(in_use_anchor_);
    321 }
    322 
    323 
    324 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
    325   // The list starts and ends with the anchor.
    326   for (ThreadState* current = anchor->next_; current != anchor;) {
    327     ThreadState* next = current->next_;
    328     delete current;
    329     current = next;
    330   }
    331   delete anchor;
    332 }
    333 
    334 
    335 void ThreadManager::ArchiveThread() {
    336   ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
    337   ASSERT(!IsArchived());
    338   ASSERT(IsLockedByCurrentThread());
    339   ThreadState* state = GetFreeThreadState();
    340   state->Unlink();
    341   Isolate::PerIsolateThreadData* per_thread =
    342       isolate_->FindOrAllocatePerThreadDataForThisThread();
    343   per_thread->set_thread_state(state);
    344   lazily_archived_thread_ = ThreadId::Current();
    345   lazily_archived_thread_state_ = state;
    346   ASSERT(state->id().Equals(ThreadId::Invalid()));
    347   state->set_id(CurrentId());
    348   ASSERT(!state->id().Equals(ThreadId::Invalid()));
    349 }
    350 
    351 
    352 void ThreadManager::EagerlyArchiveThread() {
    353   ASSERT(IsLockedByCurrentThread());
    354   ThreadState* state = lazily_archived_thread_state_;
    355   state->LinkInto(ThreadState::IN_USE_LIST);
    356   char* to = state->data();
    357   // Ensure that data containing GC roots are archived first, and handle them
    358   // in ThreadManager::Iterate(ObjectVisitor*).
    359   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
    360   to = isolate_->ArchiveThread(to);
    361   to = Relocatable::ArchiveState(isolate_, to);
    362 #ifdef ENABLE_DEBUGGER_SUPPORT
    363   to = isolate_->debug()->ArchiveDebug(to);
    364 #endif
    365   to = isolate_->stack_guard()->ArchiveStackGuard(to);
    366   to = isolate_->regexp_stack()->ArchiveStack(to);
    367   to = isolate_->bootstrapper()->ArchiveState(to);
    368   lazily_archived_thread_ = ThreadId::Invalid();
    369   lazily_archived_thread_state_ = NULL;
    370 }
    371 
    372 
    373 void ThreadManager::FreeThreadResources() {
    374   isolate_->handle_scope_implementer()->FreeThreadResources();
    375   isolate_->FreeThreadResources();
    376 #ifdef ENABLE_DEBUGGER_SUPPORT
    377   isolate_->debug()->FreeThreadResources();
    378 #endif
    379   isolate_->stack_guard()->FreeThreadResources();
    380   isolate_->regexp_stack()->FreeThreadResources();
    381   isolate_->bootstrapper()->FreeThreadResources();
    382 }
    383 
    384 
    385 bool ThreadManager::IsArchived() {
    386   Isolate::PerIsolateThreadData* data =
    387       isolate_->FindPerThreadDataForThisThread();
    388   return data != NULL && data->thread_state() != NULL;
    389 }
    390 
    391 
    392 void ThreadManager::Iterate(ObjectVisitor* v) {
    393   // Expecting no threads during serialization/deserialization
    394   for (ThreadState* state = FirstThreadStateInUse();
    395        state != NULL;
    396        state = state->Next()) {
    397     char* data = state->data();
    398     data = HandleScopeImplementer::Iterate(v, data);
    399     data = isolate_->Iterate(v, data);
    400     data = Relocatable::Iterate(v, data);
    401   }
    402 }
    403 
    404 
    405 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
    406   for (ThreadState* state = FirstThreadStateInUse();
    407        state != NULL;
    408        state = state->Next()) {
    409     char* data = state->data();
    410     data += HandleScopeImplementer::ArchiveSpacePerThread();
    411     isolate_->IterateThread(v, data);
    412   }
    413 }
    414 
    415 
    416 ThreadId ThreadManager::CurrentId() {
    417   return ThreadId::Current();
    418 }
    419 
    420 
    421 void ThreadManager::TerminateExecution(ThreadId thread_id) {
    422   for (ThreadState* state = FirstThreadStateInUse();
    423        state != NULL;
    424        state = state->Next()) {
    425     if (thread_id.Equals(state->id())) {
    426       state->set_terminate_on_restore(true);
    427     }
    428   }
    429 }
    430 
    431 
    432 ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms)
    433   : Thread("v8:CtxtSwitcher"),
    434     keep_going_(true),
    435     sleep_ms_(every_n_ms),
    436     isolate_(isolate) {
    437 }
    438 
    439 
    440 // Set the scheduling interval of V8 threads. This function starts the
    441 // ContextSwitcher thread if needed.
    442 void ContextSwitcher::StartPreemption(int every_n_ms) {
    443   Isolate* isolate = Isolate::Current();
    444   ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
    445   if (isolate->context_switcher() == NULL) {
    446     // If the ContextSwitcher thread is not running at the moment start it now.
    447     isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms));
    448     isolate->context_switcher()->Start();
    449   } else {
    450     // ContextSwitcher thread is already running, so we just change the
    451     // scheduling interval.
    452     isolate->context_switcher()->sleep_ms_ = every_n_ms;
    453   }
    454 }
    455 
    456 
    457 // Disable preemption of V8 threads. If multiple threads want to use V8 they
    458 // must cooperatively schedule amongst them from this point on.
    459 void ContextSwitcher::StopPreemption() {
    460   Isolate* isolate = Isolate::Current();
    461   ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
    462   if (isolate->context_switcher() != NULL) {
    463     // The ContextSwitcher thread is running. We need to stop it and release
    464     // its resources.
    465     isolate->context_switcher()->keep_going_ = false;
    466     // Wait for the ContextSwitcher thread to exit.
    467     isolate->context_switcher()->Join();
    468     // Thread has exited, now we can delete it.
    469     delete(isolate->context_switcher());
    470     isolate->set_context_switcher(NULL);
    471   }
    472 }
    473 
    474 
    475 // Main loop of the ContextSwitcher thread: Preempt the currently running V8
    476 // thread at regular intervals.
    477 void ContextSwitcher::Run() {
    478   while (keep_going_) {
    479     OS::Sleep(sleep_ms_);
    480     isolate()->stack_guard()->Preempt();
    481   }
    482 }
    483 
    484 
    485 // Acknowledge the preemption by the receiving thread.
    486 void ContextSwitcher::PreemptionReceived() {
    487   ASSERT(Locker::IsLocked(i::Isolate::GetDefaultIsolateForLocking()));
    488   // There is currently no accounting being done for this. But could be in the
    489   // future, which is why we leave this in.
    490 }
    491 
    492 
    493 }  // namespace internal
    494 }  // namespace v8
    495