v8threads.cc 10.7 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/v8.h"
6

7 8 9 10 11
#include "src/api.h"
#include "src/bootstrapper.h"
#include "src/debug.h"
#include "src/execution.h"
#include "src/regexp-stack.h"
12
#include "src/v8threads.h"
13 14 15

namespace v8 {

16

17 18
namespace {

19 20
// 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.
21 22 23
base::Atomic32 g_locker_was_ever_used_ = 0;

}  // namespace
24 25


26 27 28
// 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) {
29
  DCHECK(isolate != NULL);
Benedikt Meurer's avatar
Benedikt Meurer committed
30
  has_lock_ = false;
31 32
  top_level_ = true;
  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 37
  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
    isolate_->thread_manager()->Lock();
38
    has_lock_ = true;
39

40 41
    // This may be a locker within an unlocker in which case we have to
    // get the saved state for this thread and restore it.
42
    if (isolate_->thread_manager()->RestoreThread()) {
43
      top_level_ = false;
44
    } else {
45 46 47 48
      internal::ExecutionAccess access(isolate_);
      isolate_->stack_guard()->ClearThread(access);
      isolate_->stack_guard()->InitThread(access);
    }
49
  }
50
  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
51 52 53
}


54
bool Locker::IsLocked(v8::Isolate* isolate) {
55
  DCHECK(isolate != NULL);
56 57
  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
  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 84
  isolate_->thread_manager()->ArchiveThread();
  isolate_->thread_manager()->Unlock();
85 86 87 88
}


Unlocker::~Unlocker() {
89
  DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
90 91
  isolate_->thread_manager()->Lock();
  isolate_->thread_manager()->RestoreThread();
92 93 94 95 96 97 98
}


namespace internal {


bool ThreadManager::RestoreThread() {
99
  DCHECK(IsLockedByCurrentThread());
100
  // First check whether the current thread has been 'lazily archived', i.e.
101 102
  // 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.
103 104
  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    lazily_archived_thread_ = ThreadId::Invalid();
105 106
    Isolate::PerIsolateThreadData* per_thread =
        isolate_->FindPerThreadDataForThisThread();
107 108
    DCHECK(per_thread != NULL);
    DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
109
    lazily_archived_thread_state_->set_id(ThreadId::Invalid());
110 111
    lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
    lazily_archived_thread_state_ = NULL;
112
    per_thread->set_thread_state(NULL);
113 114
    return true;
  }
115

116 117
  // Make sure that the preemption thread cannot modify the thread state while
  // it is being archived or restored.
118
  ExecutionAccess access(isolate_);
119

120 121 122 123 124
  // If there is another thread that was lazily archived then we have to really
  // archive it now.
  if (lazily_archived_thread_.IsValid()) {
    EagerlyArchiveThread();
  }
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 131
    return false;
  }
132
  ThreadState* state = per_thread->thread_state();
133
  char* from = state->data();
134 135
  from = isolate_->handle_scope_implementer()->RestoreThread(from);
  from = isolate_->RestoreThread(from);
136
  from = Relocatable::RestoreState(isolate_, from);
137 138 139 140 141
  from = isolate_->debug()->RestoreDebug(from);
  from = isolate_->stack_guard()->RestoreStackGuard(from);
  from = isolate_->regexp_stack()->RestoreStack(from);
  from = isolate_->bootstrapper()->RestoreState(from);
  per_thread->set_thread_state(NULL);
142
  if (state->terminate_on_restore()) {
143
    isolate_->stack_guard()->RequestTerminateExecution();
144 145
    state->set_terminate_on_restore(false);
  }
146
  state->set_id(ThreadId::Invalid());
147 148 149 150 151 152 153
  state->Unlink();
  state->LinkInto(ThreadState::FREE_LIST);
  return true;
}


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 182 183
      next_(this),
      previous_(this),
      thread_manager_(thread_manager) {
184 185 186
}


187 188 189 190 191
ThreadState::~ThreadState() {
  DeleteArray<char>(data_);
}


192
void ThreadState::AllocateSpace() {
193
  data_ = NewArray<char>(ArchiveSpacePerThread());
194 195 196 197 198 199 200 201 202 203 204
}


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


void ThreadState::LinkInto(List list) {
  ThreadState* flying_anchor =
205 206
      list == FREE_LIST ? thread_manager_->free_anchor_
                        : thread_manager_->in_use_anchor_;
207 208 209 210 211 212 213
  next_ = flying_anchor->next_;
  previous_ = flying_anchor;
  flying_anchor->next_ = this;
  next_->previous_ = this;
}


214
ThreadState* ThreadManager::GetFreeThreadState() {
215 216
  ThreadState* gotten = free_anchor_->next_;
  if (gotten == free_anchor_) {
217
    ThreadState* new_thread_state = new ThreadState(this);
218 219 220 221 222 223 224 225
    new_thread_state->AllocateSpace();
    return new_thread_state;
  }
  return gotten;
}


// Gets the first in the list of archived threads.
226
ThreadState* ThreadManager::FirstThreadStateInUse() {
227 228 229 230 231
  return in_use_anchor_->Next();
}


ThreadState* ThreadState::Next() {
232
  if (next_ == thread_manager_->in_use_anchor_) return NULL;
233 234 235 236
  return next_;
}


237 238 239
// 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.)
240
ThreadManager::ThreadManager()
241
    : mutex_owner_(ThreadId::Invalid()),
242
      lazily_archived_thread_(ThreadId::Invalid()),
243 244 245 246 247 248 249 250 251
      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() {
252 253 254 255 256 257 258 259 260 261 262 263 264
  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;
265
}
266 267 268


void ThreadManager::ArchiveThread() {
269 270 271
  DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
  DCHECK(!IsArchived());
  DCHECK(IsLockedByCurrentThread());
272
  ThreadState* state = GetFreeThreadState();
273
  state->Unlink();
274 275 276
  Isolate::PerIsolateThreadData* per_thread =
      isolate_->FindOrAllocatePerThreadDataForThisThread();
  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 288 289
  ThreadState* state = lazily_archived_thread_state_;
  state->LinkInto(ThreadState::IN_USE_LIST);
  char* to = state->data();
290 291
  // Ensure that data containing GC roots are archived first, and handle them
  // in ThreadManager::Iterate(ObjectVisitor*).
292 293
  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
  to = isolate_->ArchiveThread(to);
294
  to = Relocatable::ArchiveState(isolate_, to);
295 296 297 298
  to = isolate_->debug()->ArchiveDebug(to);
  to = isolate_->stack_guard()->ArchiveStackGuard(to);
  to = isolate_->regexp_stack()->ArchiveStack(to);
  to = isolate_->bootstrapper()->ArchiveState(to);
299
  lazily_archived_thread_ = ThreadId::Invalid();
300 301 302 303
  lazily_archived_thread_state_ = NULL;
}


304
void ThreadManager::FreeThreadResources() {
305 306 307
  DCHECK(!isolate_->has_pending_exception());
  DCHECK(!isolate_->external_caught_exception());
  DCHECK(isolate_->try_catch_handler() == NULL);
308 309 310 311 312 313
  isolate_->handle_scope_implementer()->FreeThreadResources();
  isolate_->FreeThreadResources();
  isolate_->debug()->FreeThreadResources();
  isolate_->stack_guard()->FreeThreadResources();
  isolate_->regexp_stack()->FreeThreadResources();
  isolate_->bootstrapper()->FreeThreadResources();
314 315 316
}


317
bool ThreadManager::IsArchived() {
318 319
  Isolate::PerIsolateThreadData* data =
      isolate_->FindPerThreadDataForThisThread();
320
  return data != NULL && data->thread_state() != NULL;
321 322
}

323

324 325
void ThreadManager::Iterate(ObjectVisitor* v) {
  // Expecting no threads during serialization/deserialization
326
  for (ThreadState* state = FirstThreadStateInUse();
327 328 329 330
       state != NULL;
       state = state->Next()) {
    char* data = state->data();
    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 340 341 342
       state != NULL;
       state = state->Next()) {
    char* data = state->data();
    data += HandleScopeImplementer::ArchiveSpacePerThread();
343
    isolate_->IterateThread(v, data);
344 345 346 347
  }
}


348 349
ThreadId ThreadManager::CurrentId() {
  return ThreadId::Current();
350 351 352
}


353
void ThreadManager::TerminateExecution(ThreadId thread_id) {
354
  for (ThreadState* state = FirstThreadStateInUse();
355 356
       state != NULL;
       state = state->Next()) {
357
    if (thread_id.Equals(state->id())) {
358 359
      state->set_terminate_on_restore(true);
    }
360 361 362 363
  }
}


364 365
}  // namespace internal
}  // namespace v8