v8threads.cc 10.9 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/v8threads.h"
6

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

namespace v8 {

17

18 19
namespace {

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

}  // namespace
25 26


27 28 29
// 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) {
30
  DCHECK_NOT_NULL(isolate);
Benedikt Meurer's avatar
Benedikt Meurer committed
31
  has_lock_ = false;
32 33
  top_level_ = true;
  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
34
  // Record that the Locker has been used at least once.
35
  base::Relaxed_Store(&g_locker_was_ever_used_, 1);
36
  // Get the big lock if necessary.
37 38
  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
    isolate_->thread_manager()->Lock();
39
    has_lock_ = true;
40

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


55
bool Locker::IsLocked(v8::Isolate* isolate) {
56
  DCHECK_NOT_NULL(isolate);
57 58
  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
  return internal_isolate->thread_manager()->IsLockedByCurrentThread();
59 60 61
}


62
bool Locker::IsActive() {
63
  return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 65 66
}


67
Locker::~Locker() {
68
  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
69
  if (has_lock_) {
70
    if (top_level_) {
71
      isolate_->thread_manager()->FreeThreadResources();
72
    } else {
73
      isolate_->thread_manager()->ArchiveThread();
74
    }
75
    isolate_->thread_manager()->Unlock();
76 77 78 79
  }
}


80
void Unlocker::Initialize(v8::Isolate* isolate) {
81
  DCHECK_NOT_NULL(isolate);
82
  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
83
  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
84 85
  isolate_->thread_manager()->ArchiveThread();
  isolate_->thread_manager()->Unlock();
86 87 88 89
}


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


namespace internal {

98 99 100 101
void ThreadManager::InitThread(const ExecutionAccess& lock) {
  isolate_->stack_guard()->InitThread(lock);
  isolate_->debug()->InitThread(lock);
}
102 103

bool ThreadManager::RestoreThread() {
104
  DCHECK(IsLockedByCurrentThread());
105
  // First check whether the current thread has been 'lazily archived', i.e.
106 107
  // 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.
108 109
  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
    lazily_archived_thread_ = ThreadId::Invalid();
110 111
    Isolate::PerIsolateThreadData* per_thread =
        isolate_->FindPerThreadDataForThisThread();
112
    DCHECK_NOT_NULL(per_thread);
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 117
    lazily_archived_thread_state_ = nullptr;
    per_thread->set_thread_state(nullptr);
118 119
    return true;
  }
120

121 122
  // Make sure that the preemption thread cannot modify the thread state while
  // it is being archived or restored.
123
  ExecutionAccess access(isolate_);
124

125 126 127 128 129
  // If there is another thread that was lazily archived then we have to really
  // archive it now.
  if (lazily_archived_thread_.IsValid()) {
    EagerlyArchiveThread();
  }
130
  Isolate::PerIsolateThreadData* per_thread =
131
      isolate_->FindPerThreadDataForThisThread();
132
  if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
133
    // This is a new thread.
134
    InitThread(access);
135 136
    return false;
  }
137
  ThreadState* state = per_thread->thread_state();
138
  char* from = state->data();
139 140
  from = isolate_->handle_scope_implementer()->RestoreThread(from);
  from = isolate_->RestoreThread(from);
141
  from = Relocatable::RestoreState(isolate_, from);
142 143 144 145
  from = isolate_->debug()->RestoreDebug(from);
  from = isolate_->stack_guard()->RestoreStackGuard(from);
  from = isolate_->regexp_stack()->RestoreStack(from);
  from = isolate_->bootstrapper()->RestoreState(from);
146
  per_thread->set_thread_state(nullptr);
147
  if (state->terminate_on_restore()) {
148
    isolate_->stack_guard()->RequestTerminateExecution();
149 150
    state->set_terminate_on_restore(false);
  }
151
  state->set_id(ThreadId::Invalid());
152 153 154 155 156 157 158
  state->Unlink();
  state->LinkInto(ThreadState::FREE_LIST);
  return true;
}


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
ThreadState::ThreadState(ThreadManager* thread_manager)
182
    : id_(ThreadId::Invalid()),
183
      terminate_on_restore_(false),
184
      data_(nullptr),
185 186
      next_(this),
      previous_(this),
187
      thread_manager_(thread_manager) {}
188

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


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


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


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


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


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


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

238 239 240
// 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.)
241
ThreadManager::ThreadManager(Isolate* isolate)
242
    : mutex_owner_(ThreadId::Invalid()),
243
      lazily_archived_thread_(ThreadId::Invalid()),
244 245
      lazily_archived_thread_state_(nullptr),
      free_anchor_(nullptr),
246 247
      in_use_anchor_(nullptr),
      isolate_(isolate) {
248 249 250 251 252 253
  free_anchor_ = new ThreadState(this);
  in_use_anchor_ = new ThreadState(this);
}


ThreadManager::~ThreadManager() {
254 255 256 257 258 259 260 261 262 263 264 265 266
  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;
267
}
268 269 270


void ThreadManager::ArchiveThread() {
271 272 273
  DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
  DCHECK(!IsArchived());
  DCHECK(IsLockedByCurrentThread());
274
  ThreadState* state = GetFreeThreadState();
275
  state->Unlink();
276 277 278
  Isolate::PerIsolateThreadData* per_thread =
      isolate_->FindOrAllocatePerThreadDataForThisThread();
  per_thread->set_thread_state(state);
279
  lazily_archived_thread_ = ThreadId::Current();
280
  lazily_archived_thread_state_ = state;
281
  DCHECK(state->id().Equals(ThreadId::Invalid()));
282
  state->set_id(CurrentId());
283
  DCHECK(!state->id().Equals(ThreadId::Invalid()));
284 285 286 287
}


void ThreadManager::EagerlyArchiveThread() {
288
  DCHECK(IsLockedByCurrentThread());
289 290 291
  ThreadState* state = lazily_archived_thread_state_;
  state->LinkInto(ThreadState::IN_USE_LIST);
  char* to = state->data();
292
  // Ensure that data containing GC roots are archived first, and handle them
293
  // in ThreadManager::Iterate(RootVisitor*).
294 295
  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
  to = isolate_->ArchiveThread(to);
296
  to = Relocatable::ArchiveState(isolate_, to);
297 298 299 300
  to = isolate_->debug()->ArchiveDebug(to);
  to = isolate_->stack_guard()->ArchiveStackGuard(to);
  to = isolate_->regexp_stack()->ArchiveStack(to);
  to = isolate_->bootstrapper()->ArchiveState(to);
301
  lazily_archived_thread_ = ThreadId::Invalid();
302
  lazily_archived_thread_state_ = nullptr;
303 304 305
}


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


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

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


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


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


362 363
}  // namespace internal
}  // namespace v8