V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
v8threads.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8threads.h"
6 
7 #include "src/api.h"
8 #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 namespace v8 {
16 
17 
18 namespace {
19 
20 // Track whether this V8 instance has ever called v8::Locker. This allows the
21 // API code to verify that the lock is always held when V8 is being entered.
22 base::Atomic32 g_locker_was_ever_used_ = 0;
23 
24 } // namespace
25 
26 
27 // Once the Locker is initialized, the current thread will be guaranteed to have
28 // the lock for a given isolate.
29 void Locker::Initialize(v8::Isolate* isolate) {
30  DCHECK_NOT_NULL(isolate);
31  has_lock_ = false;
32  top_level_ = true;
33  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  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
38  isolate_->thread_manager()->Lock();
39  has_lock_ = true;
40 
41  // This may be a locker within an unlocker in which case we have to
42  // get the saved state for this thread and restore it.
43  if (isolate_->thread_manager()->RestoreThread()) {
44  top_level_ = false;
45  } else {
46  internal::ExecutionAccess access(isolate_);
47  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  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
58  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  isolate_->thread_manager()->ArchiveThread();
85  isolate_->thread_manager()->Unlock();
86 }
87 
88 
89 Unlocker::~Unlocker() {
90  DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
91  isolate_->thread_manager()->Lock();
92  isolate_->thread_manager()->RestoreThread();
93 }
94 
95 
96 namespace internal {
97 
98 void ThreadManager::InitThread(const ExecutionAccess& lock) {
99  isolate_->stack_guard()->InitThread(lock);
100  isolate_->debug()->InitThread(lock);
101 }
102 
103 bool ThreadManager::RestoreThread() {
104  DCHECK(IsLockedByCurrentThread());
105  // First check whether the current thread has been 'lazily archived', i.e.
106  // not archived at all. If that is the case we put the state storage we
107  // had prepared back in the free list, since we didn't need it after all.
108  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
109  lazily_archived_thread_ = ThreadId::Invalid();
110  Isolate::PerIsolateThreadData* per_thread =
111  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  lazily_archived_thread_state_ = nullptr;
117  per_thread->set_thread_state(nullptr);
118  return true;
119  }
120 
121  // Make sure that the preemption thread cannot modify the thread state while
122  // it is being archived or restored.
123  ExecutionAccess access(isolate_);
124 
125  // If there is another thread that was lazily archived then we have to really
126  // archive it now.
127  if (lazily_archived_thread_.IsValid()) {
128  EagerlyArchiveThread();
129  }
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  return false;
136  }
137  ThreadState* state = per_thread->thread_state();
138  char* from = state->data();
139  from = isolate_->handle_scope_implementer()->RestoreThread(from);
140  from = isolate_->RestoreThread(from);
141  from = Relocatable::RestoreState(isolate_, from);
142  from = isolate_->debug()->RestoreDebug(from);
143  from = isolate_->stack_guard()->RestoreStackGuard(from);
144  from = isolate_->regexp_stack()->RestoreStack(from);
145  from = isolate_->bootstrapper()->RestoreState(from);
146  per_thread->set_thread_state(nullptr);
147  if (state->terminate_on_restore()) {
148  isolate_->stack_guard()->RequestTerminateExecution();
149  state->set_terminate_on_restore(false);
150  }
151  state->set_id(ThreadId::Invalid());
152  state->Unlink();
153  state->LinkInto(ThreadState::FREE_LIST);
154  return true;
155 }
156 
157 
158 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  next_(this),
186  previous_(this),
187  thread_manager_(thread_manager) {}
188 
189 ThreadState::~ThreadState() {
190  DeleteArray<char>(data_);
191 }
192 
193 
194 void ThreadState::AllocateSpace() {
195  data_ = NewArray<char>(ArchiveSpacePerThread());
196 }
197 
198 
199 void ThreadState::Unlink() {
200  next_->previous_ = previous_;
201  previous_->next_ = next_;
202 }
203 
204 
205 void ThreadState::LinkInto(List list) {
206  ThreadState* flying_anchor =
207  list == FREE_LIST ? thread_manager_->free_anchor_
208  : thread_manager_->in_use_anchor_;
209  next_ = flying_anchor->next_;
210  previous_ = flying_anchor;
211  flying_anchor->next_ = this;
212  next_->previous_ = this;
213 }
214 
215 
216 ThreadState* ThreadManager::GetFreeThreadState() {
217  ThreadState* gotten = free_anchor_->next_;
218  if (gotten == free_anchor_) {
219  ThreadState* new_thread_state = new ThreadState(this);
220  new_thread_state->AllocateSpace();
221  return new_thread_state;
222  }
223  return gotten;
224 }
225 
226 
227 // Gets the first in the list of archived threads.
228 ThreadState* ThreadManager::FirstThreadStateInUse() {
229  return in_use_anchor_->Next();
230 }
231 
232 
233 ThreadState* ThreadState::Next() {
234  if (next_ == thread_manager_->in_use_anchor_) return nullptr;
235  return next_;
236 }
237 
238 // Thread ids must start with 1, because in TLS having thread id 0 can't
239 // be distinguished from not having a thread id at all (since NULL is
240 // defined as 0.)
241 ThreadManager::ThreadManager(Isolate* isolate)
242  : mutex_owner_(ThreadId::Invalid()),
243  lazily_archived_thread_(ThreadId::Invalid()),
244  lazily_archived_thread_state_(nullptr),
245  free_anchor_(nullptr),
246  in_use_anchor_(nullptr),
247  isolate_(isolate) {
248  free_anchor_ = new ThreadState(this);
249  in_use_anchor_ = new ThreadState(this);
250 }
251 
252 
253 ThreadManager::~ThreadManager() {
254  DeleteThreadStateList(free_anchor_);
255  DeleteThreadStateList(in_use_anchor_);
256 }
257 
258 
259 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
260  // The list starts and ends with the anchor.
261  for (ThreadState* current = anchor->next_; current != anchor;) {
262  ThreadState* next = current->next_;
263  delete current;
264  current = next;
265  }
266  delete anchor;
267 }
268 
269 
270 void ThreadManager::ArchiveThread() {
271  DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
272  DCHECK(!IsArchived());
273  DCHECK(IsLockedByCurrentThread());
274  ThreadState* state = GetFreeThreadState();
275  state->Unlink();
276  Isolate::PerIsolateThreadData* per_thread =
277  isolate_->FindOrAllocatePerThreadDataForThisThread();
278  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  ThreadState* state = lazily_archived_thread_state_;
290  state->LinkInto(ThreadState::IN_USE_LIST);
291  char* to = state->data();
292  // Ensure that data containing GC roots are archived first, and handle them
293  // in ThreadManager::Iterate(RootVisitor*).
294  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
295  to = isolate_->ArchiveThread(to);
296  to = Relocatable::ArchiveState(isolate_, to);
297  to = isolate_->debug()->ArchiveDebug(to);
298  to = isolate_->stack_guard()->ArchiveStackGuard(to);
299  to = isolate_->regexp_stack()->ArchiveStack(to);
300  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  DCHECK(!isolate_->has_pending_exception());
308  DCHECK(!isolate_->external_caught_exception());
309  DCHECK_NULL(isolate_->try_catch_handler());
310  isolate_->handle_scope_implementer()->FreeThreadResources();
311  isolate_->FreeThreadResources();
312  isolate_->debug()->FreeThreadResources();
313  isolate_->stack_guard()->FreeThreadResources();
314  isolate_->regexp_stack()->FreeThreadResources();
315  isolate_->bootstrapper()->FreeThreadResources();
316 }
317 
318 
319 bool ThreadManager::IsArchived() {
320  Isolate::PerIsolateThreadData* data =
321  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  state = state->Next()) {
329  char* data = state->data();
330  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  state = state->Next()) {
340  char* data = state->data();
341  data += HandleScopeImplementer::ArchiveSpacePerThread();
342  isolate_->IterateThread(v, data);
343  }
344 }
345 
346 
347 ThreadId ThreadManager::CurrentId() {
348  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  state->set_terminate_on_restore(true);
357  }
358  }
359 }
360 
361 
362 } // namespace internal
363 } // namespace v8
Definition: libplatform.h:13