v8threads.cc 12.6 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "api.h"
31
#include "bootstrapper.h"
32 33 34
#include "debug.h"
#include "execution.h"
#include "v8threads.h"
35
#include "regexp-stack.h"
36 37 38

namespace v8 {

39 40 41 42 43 44

// Track whether this V8 instance has ever called v8::Locker. This allows the
// API code to verify that the lock is always held when V8 is being entered.
bool Locker::active_ = false;


45 46 47 48 49 50 51
// Once the Locker is initialized, the current thread will be guaranteed to have
// the lock for a given isolate.
void Locker::Initialize(v8::Isolate* isolate) {
  ASSERT(isolate != NULL);
  has_lock_= false;
  top_level_ = true;
  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
52 53
  // Record that the Locker has been used at least once.
  active_ = true;
54
  // Get the big lock if necessary.
55 56
  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
    isolate_->thread_manager()->Lock();
57
    has_lock_ = true;
58

59 60 61
    // Make sure that V8 is initialized.  Archiving of threads interferes
    // with deserialization by adding additional root pointers, so we must
    // initialize here, before anyone can call ~Locker() or Unlocker().
62 63
    if (!isolate_->IsInitialized()) {
      isolate_->Enter();
64
      V8::Initialize();
65
      isolate_->Exit();
66
    }
67

68 69
    // This may be a locker within an unlocker in which case we have to
    // get the saved state for this thread and restore it.
70
    if (isolate_->thread_manager()->RestoreThread()) {
71
      top_level_ = false;
72
    } else {
73 74 75 76 77 78 79
      internal::ExecutionAccess access(isolate_);
      isolate_->stack_guard()->ClearThread(access);
      isolate_->stack_guard()->InitThread(access);
    }
    if (isolate_->IsDefaultIsolate()) {
      // This only enters if not yet entered.
      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 89
  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
  return internal_isolate->thread_manager()->IsLockedByCurrentThread();
90 91 92
}


93 94 95 96 97
bool Locker::IsActive() {
  return active_;
}


98
Locker::~Locker() {
99
  ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
100
  if (has_lock_) {
101 102 103
    if (isolate_->IsDefaultIsolate()) {
      isolate_->Exit();
    }
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 115 116
void Unlocker::Initialize(v8::Isolate* isolate) {
  ASSERT(isolate != NULL);
  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
117 118 119 120 121 122
  ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
  if (isolate_->IsDefaultIsolate()) {
    isolate_->Exit();
  }
  isolate_->thread_manager()->ArchiveThread();
  isolate_->thread_manager()->Unlock();
123 124 125 126
}


Unlocker::~Unlocker() {
127 128 129 130 131 132
  ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread());
  isolate_->thread_manager()->Lock();
  isolate_->thread_manager()->RestoreThread();
  if (isolate_->IsDefaultIsolate()) {
    isolate_->Enter();
  }
133 134 135 136 137 138 139
}


namespace internal {


bool ThreadManager::RestoreThread() {
140
  ASSERT(IsLockedByCurrentThread());
141
  // First check whether the current thread has been 'lazily archived', i.e.
142 143
  // not archived at all.  If that is the case we put the state storage we
  // had prepared back in the free list, since we didn't need it after all.
144 145
  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    lazily_archived_thread_ = ThreadId::Invalid();
146 147 148 149
    Isolate::PerIsolateThreadData* per_thread =
        isolate_->FindPerThreadDataForThisThread();
    ASSERT(per_thread != NULL);
    ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
150
    lazily_archived_thread_state_->set_id(ThreadId::Invalid());
151 152
    lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
    lazily_archived_thread_state_ = NULL;
153
    per_thread->set_thread_state(NULL);
154 155
    return true;
  }
156

157 158
  // Make sure that the preemption thread cannot modify the thread state while
  // it is being archived or restored.
159
  ExecutionAccess access(isolate_);
160

161 162 163 164 165
  // If there is another thread that was lazily archived then we have to really
  // archive it now.
  if (lazily_archived_thread_.IsValid()) {
    EagerlyArchiveThread();
  }
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 172
    return false;
  }
173
  ThreadState* state = per_thread->thread_state();
174
  char* from = state->data();
175 176
  from = isolate_->handle_scope_implementer()->RestoreThread(from);
  from = isolate_->RestoreThread(from);
177
  from = Relocatable::RestoreState(isolate_, from);
178
#ifdef ENABLE_DEBUGGER_SUPPORT
179
  from = isolate_->debug()->RestoreDebug(from);
180
#endif
181 182 183 184
  from = isolate_->stack_guard()->RestoreStackGuard(from);
  from = isolate_->regexp_stack()->RestoreStack(from);
  from = isolate_->bootstrapper()->RestoreState(from);
  per_thread->set_thread_state(NULL);
185
  if (state->terminate_on_restore()) {
186
    isolate_->stack_guard()->TerminateExecution();
187 188
    state->set_terminate_on_restore(false);
  }
189
  state->set_id(ThreadId::Invalid());
190 191 192 193 194 195 196
  state->Unlink();
  state->LinkInto(ThreadState::FREE_LIST);
  return true;
}


void ThreadManager::Lock() {
197
  mutex_.Lock();
198
  mutex_owner_ = ThreadId::Current();
199 200 201 202 203
  ASSERT(IsLockedByCurrentThread());
}


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 227 228
      next_(this),
      previous_(this),
      thread_manager_(thread_manager) {
229 230 231
}


232 233 234 235 236
ThreadState::~ThreadState() {
  DeleteArray<char>(data_);
}


237
void ThreadState::AllocateSpace() {
238
  data_ = NewArray<char>(ArchiveSpacePerThread());
239 240 241 242 243 244 245 246 247 248 249
}


void ThreadState::Unlink() {
  next_->previous_ = previous_;
  previous_->next_ = next_;
}


void ThreadState::LinkInto(List list) {
  ThreadState* flying_anchor =
250 251
      list == FREE_LIST ? thread_manager_->free_anchor_
                        : thread_manager_->in_use_anchor_;
252 253 254 255 256 257 258
  next_ = flying_anchor->next_;
  previous_ = flying_anchor;
  flying_anchor->next_ = this;
  next_->previous_ = this;
}


259
ThreadState* ThreadManager::GetFreeThreadState() {
260 261
  ThreadState* gotten = free_anchor_->next_;
  if (gotten == free_anchor_) {
262
    ThreadState* new_thread_state = new ThreadState(this);
263 264 265 266 267 268 269 270
    new_thread_state->AllocateSpace();
    return new_thread_state;
  }
  return gotten;
}


// Gets the first in the list of archived threads.
271
ThreadState* ThreadManager::FirstThreadStateInUse() {
272 273 274 275 276
  return in_use_anchor_->Next();
}


ThreadState* ThreadState::Next() {
277
  if (next_ == thread_manager_->in_use_anchor_) return NULL;
278 279 280 281
  return next_;
}


282 283 284
// Thread ids must start with 1, because in TLS having thread id 0 can't
// be distinguished from not having a thread id at all (since NULL is
// defined as 0.)
285
ThreadManager::ThreadManager()
286
    : mutex_owner_(ThreadId::Invalid()),
287
      lazily_archived_thread_(ThreadId::Invalid()),
288 289 290 291 292 293 294 295 296
      lazily_archived_thread_state_(NULL),
      free_anchor_(NULL),
      in_use_anchor_(NULL) {
  free_anchor_ = new ThreadState(this);
  in_use_anchor_ = new ThreadState(this);
}


ThreadManager::~ThreadManager() {
297 298 299 300 301 302 303 304 305 306 307 308 309
  DeleteThreadStateList(free_anchor_);
  DeleteThreadStateList(in_use_anchor_);
}


void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
  // The list starts and ends with the anchor.
  for (ThreadState* current = anchor->next_; current != anchor;) {
    ThreadState* next = current->next_;
    delete current;
    current = next;
  }
  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 320 321
  Isolate::PerIsolateThreadData* per_thread =
      isolate_->FindOrAllocatePerThreadDataForThisThread();
  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 333 334
  ThreadState* state = lazily_archived_thread_state_;
  state->LinkInto(ThreadState::IN_USE_LIST);
  char* to = state->data();
335 336
  // Ensure that data containing GC roots are archived first, and handle them
  // in ThreadManager::Iterate(ObjectVisitor*).
337 338
  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
  to = isolate_->ArchiveThread(to);
339
  to = Relocatable::ArchiveState(isolate_, to);
340
#ifdef ENABLE_DEBUGGER_SUPPORT
341
  to = isolate_->debug()->ArchiveDebug(to);
342
#endif
343 344 345
  to = isolate_->stack_guard()->ArchiveStackGuard(to);
  to = isolate_->regexp_stack()->ArchiveStack(to);
  to = isolate_->bootstrapper()->ArchiveState(to);
346
  lazily_archived_thread_ = ThreadId::Invalid();
347 348 349 350
  lazily_archived_thread_state_ = NULL;
}


351
void ThreadManager::FreeThreadResources() {
352 353
  isolate_->handle_scope_implementer()->FreeThreadResources();
  isolate_->FreeThreadResources();
354
#ifdef ENABLE_DEBUGGER_SUPPORT
355
  isolate_->debug()->FreeThreadResources();
356
#endif
357 358 359
  isolate_->stack_guard()->FreeThreadResources();
  isolate_->regexp_stack()->FreeThreadResources();
  isolate_->bootstrapper()->FreeThreadResources();
360 361 362
}


363
bool ThreadManager::IsArchived() {
364 365
  Isolate::PerIsolateThreadData* data =
      isolate_->FindPerThreadDataForThisThread();
366
  return data != NULL && data->thread_state() != NULL;
367 368
}

369

370 371
void ThreadManager::Iterate(ObjectVisitor* v) {
  // Expecting no threads during serialization/deserialization
372
  for (ThreadState* state = FirstThreadStateInUse();
373 374 375 376
       state != NULL;
       state = state->Next()) {
    char* data = state->data();
    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 386 387 388
       state != NULL;
       state = state->Next()) {
    char* data = state->data();
    data += HandleScopeImplementer::ArchiveSpacePerThread();
389
    isolate_->IterateThread(v, data);
390 391 392 393
  }
}


394 395
ThreadId ThreadManager::CurrentId() {
  return ThreadId::Current();
396 397 398
}


399
void ThreadManager::TerminateExecution(ThreadId thread_id) {
400
  for (ThreadState* state = FirstThreadStateInUse();
401 402
       state != NULL;
       state = state->Next()) {
403
    if (thread_id.Equals(state->id())) {
404 405
      state->set_terminate_on_restore(true);
    }
406 407 408 409
  }
}


410 411
}  // namespace internal
}  // namespace v8