• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
Initialize(v8::Isolate * 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 
IsLocked(v8::Isolate * isolate)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 
IsActive()62 bool Locker::IsActive() {
63   return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 }
65 
66 
~Locker()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 
Initialize(v8::Isolate * isolate)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 
~Unlocker()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 
InitThread(const ExecutionAccess & lock)98 void ThreadManager::InitThread(const ExecutionAccess& lock) {
99   isolate_->stack_guard()->InitThread(lock);
100   isolate_->debug()->InitThread(lock);
101 }
102 
RestoreThread()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 
Lock()158 void ThreadManager::Lock() {
159   mutex_.Lock();
160   mutex_owner_ = ThreadId::Current();
161   DCHECK(IsLockedByCurrentThread());
162 }
163 
164 
Unlock()165 void ThreadManager::Unlock() {
166   mutex_owner_ = ThreadId::Invalid();
167   mutex_.Unlock();
168 }
169 
170 
ArchiveSpacePerThread()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 
ThreadState(ThreadManager * thread_manager)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 
~ThreadState()189 ThreadState::~ThreadState() {
190   DeleteArray<char>(data_);
191 }
192 
193 
AllocateSpace()194 void ThreadState::AllocateSpace() {
195   data_ = NewArray<char>(ArchiveSpacePerThread());
196 }
197 
198 
Unlink()199 void ThreadState::Unlink() {
200   next_->previous_ = previous_;
201   previous_->next_ = next_;
202 }
203 
204 
LinkInto(List list)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 
GetFreeThreadState()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.
FirstThreadStateInUse()228 ThreadState* ThreadManager::FirstThreadStateInUse() {
229   return in_use_anchor_->Next();
230 }
231 
232 
Next()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.)
ThreadManager()241 ThreadManager::ThreadManager()
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   free_anchor_ = new ThreadState(this);
248   in_use_anchor_ = new ThreadState(this);
249 }
250 
251 
~ThreadManager()252 ThreadManager::~ThreadManager() {
253   DeleteThreadStateList(free_anchor_);
254   DeleteThreadStateList(in_use_anchor_);
255 }
256 
257 
DeleteThreadStateList(ThreadState * anchor)258 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
259   // The list starts and ends with the anchor.
260   for (ThreadState* current = anchor->next_; current != anchor;) {
261     ThreadState* next = current->next_;
262     delete current;
263     current = next;
264   }
265   delete anchor;
266 }
267 
268 
ArchiveThread()269 void ThreadManager::ArchiveThread() {
270   DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
271   DCHECK(!IsArchived());
272   DCHECK(IsLockedByCurrentThread());
273   ThreadState* state = GetFreeThreadState();
274   state->Unlink();
275   Isolate::PerIsolateThreadData* per_thread =
276       isolate_->FindOrAllocatePerThreadDataForThisThread();
277   per_thread->set_thread_state(state);
278   lazily_archived_thread_ = ThreadId::Current();
279   lazily_archived_thread_state_ = state;
280   DCHECK(state->id().Equals(ThreadId::Invalid()));
281   state->set_id(CurrentId());
282   DCHECK(!state->id().Equals(ThreadId::Invalid()));
283 }
284 
285 
EagerlyArchiveThread()286 void ThreadManager::EagerlyArchiveThread() {
287   DCHECK(IsLockedByCurrentThread());
288   ThreadState* state = lazily_archived_thread_state_;
289   state->LinkInto(ThreadState::IN_USE_LIST);
290   char* to = state->data();
291   // Ensure that data containing GC roots are archived first, and handle them
292   // in ThreadManager::Iterate(RootVisitor*).
293   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
294   to = isolate_->ArchiveThread(to);
295   to = Relocatable::ArchiveState(isolate_, to);
296   to = isolate_->debug()->ArchiveDebug(to);
297   to = isolate_->stack_guard()->ArchiveStackGuard(to);
298   to = isolate_->regexp_stack()->ArchiveStack(to);
299   to = isolate_->bootstrapper()->ArchiveState(to);
300   lazily_archived_thread_ = ThreadId::Invalid();
301   lazily_archived_thread_state_ = nullptr;
302 }
303 
304 
FreeThreadResources()305 void ThreadManager::FreeThreadResources() {
306   DCHECK(!isolate_->has_pending_exception());
307   DCHECK(!isolate_->external_caught_exception());
308   DCHECK_NULL(isolate_->try_catch_handler());
309   isolate_->handle_scope_implementer()->FreeThreadResources();
310   isolate_->FreeThreadResources();
311   isolate_->debug()->FreeThreadResources();
312   isolate_->stack_guard()->FreeThreadResources();
313   isolate_->regexp_stack()->FreeThreadResources();
314   isolate_->bootstrapper()->FreeThreadResources();
315 }
316 
317 
IsArchived()318 bool ThreadManager::IsArchived() {
319   Isolate::PerIsolateThreadData* data =
320       isolate_->FindPerThreadDataForThisThread();
321   return data != nullptr && data->thread_state() != nullptr;
322 }
323 
Iterate(RootVisitor * v)324 void ThreadManager::Iterate(RootVisitor* v) {
325   // Expecting no threads during serialization/deserialization
326   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
327        state = state->Next()) {
328     char* data = state->data();
329     data = HandleScopeImplementer::Iterate(v, data);
330     data = isolate_->Iterate(v, data);
331     data = Relocatable::Iterate(v, data);
332   }
333 }
334 
335 
IterateArchivedThreads(ThreadVisitor * v)336 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
337   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
338        state = state->Next()) {
339     char* data = state->data();
340     data += HandleScopeImplementer::ArchiveSpacePerThread();
341     isolate_->IterateThread(v, data);
342   }
343 }
344 
345 
CurrentId()346 ThreadId ThreadManager::CurrentId() {
347   return ThreadId::Current();
348 }
349 
350 
TerminateExecution(ThreadId thread_id)351 void ThreadManager::TerminateExecution(ThreadId thread_id) {
352   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
353        state = state->Next()) {
354     if (thread_id.Equals(state->id())) {
355       state->set_terminate_on_restore(true);
356     }
357   }
358 }
359 
360 
361 }  // namespace internal
362 }  // namespace v8
363