• 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/execution/v8threads.h"
6 
7 #include "include/v8-locker.h"
8 #include "src/api/api.h"
9 #include "src/debug/debug.h"
10 #include "src/execution/execution.h"
11 #include "src/execution/isolate-inl.h"
12 #include "src/execution/stack-guard.h"
13 #include "src/init/bootstrapper.h"
14 #include "src/objects/visitors.h"
15 #include "src/regexp/regexp-stack.h"
16 
17 namespace v8 {
18 
19 namespace {
20 
21 // Track whether this V8 instance has ever called v8::Locker. This allows the
22 // API code to verify that the lock is always held when V8 is being entered.
23 base::AtomicWord g_locker_was_ever_used_ = 0;
24 
25 }  // namespace
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 
35   // Record that the Locker has been used at least once.
36   base::Relaxed_Store(&g_locker_was_ever_used_, 1);
37   isolate_->set_was_locker_ever_used();
38 
39   // Get the big lock if necessary.
40   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
41     isolate_->thread_manager()->Lock();
42     has_lock_ = true;
43 
44     // This may be a locker within an unlocker in which case we have to
45     // get the saved state for this thread and restore it.
46     if (isolate_->thread_manager()->RestoreThread()) {
47       top_level_ = false;
48     }
49   }
50   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
51 }
52 
IsLocked(v8::Isolate * isolate)53 bool Locker::IsLocked(v8::Isolate* isolate) {
54   DCHECK_NOT_NULL(isolate);
55   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
56   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
57 }
58 
59 // static
IsActive()60 bool Locker::IsActive() { return WasEverUsed(); }
61 
62 // static
WasEverUsed()63 bool Locker::WasEverUsed() {
64   return base::Relaxed_Load(&g_locker_was_ever_used_) != 0;
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 
Initialize(v8::Isolate * isolate)79 void Unlocker::Initialize(v8::Isolate* isolate) {
80   DCHECK_NOT_NULL(isolate);
81   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
82   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
83   isolate_->thread_manager()->ArchiveThread();
84   isolate_->thread_manager()->Unlock();
85 }
86 
~Unlocker()87 Unlocker::~Unlocker() {
88   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
89   isolate_->thread_manager()->Lock();
90   isolate_->thread_manager()->RestoreThread();
91 }
92 
93 namespace internal {
94 
InitThread(const ExecutionAccess & lock)95 void ThreadManager::InitThread(const ExecutionAccess& lock) {
96   isolate_->InitializeThreadLocal();
97   isolate_->stack_guard()->InitThread(lock);
98   isolate_->debug()->InitThread(lock);
99 }
100 
RestoreThread()101 bool ThreadManager::RestoreThread() {
102   DCHECK(IsLockedByCurrentThread());
103   // First check whether the current thread has been 'lazily archived', i.e.
104   // not archived at all.  If that is the case we put the state storage we
105   // had prepared back in the free list, since we didn't need it after all.
106   if (lazily_archived_thread_ == ThreadId::Current()) {
107     lazily_archived_thread_ = ThreadId::Invalid();
108     Isolate::PerIsolateThreadData* per_thread =
109         isolate_->FindPerThreadDataForThisThread();
110     DCHECK_NOT_NULL(per_thread);
111     DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
112     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
113     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
114     lazily_archived_thread_state_ = nullptr;
115     per_thread->set_thread_state(nullptr);
116     return true;
117   }
118 
119   // Make sure that the preemption thread cannot modify the thread state while
120   // it is being archived or restored.
121   ExecutionAccess access(isolate_);
122 
123   // If there is another thread that was lazily archived then we have to really
124   // archive it now.
125   if (lazily_archived_thread_.IsValid()) {
126     EagerlyArchiveThread();
127   }
128   Isolate::PerIsolateThreadData* per_thread =
129       isolate_->FindPerThreadDataForThisThread();
130   if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
131     // This is a new thread.
132     InitThread(access);
133     return false;
134   }
135   ThreadState* state = per_thread->thread_state();
136   char* from = state->data();
137   from = isolate_->handle_scope_implementer()->RestoreThread(from);
138   from = isolate_->RestoreThread(from);
139   from = Relocatable::RestoreState(isolate_, from);
140   // Stack guard should be restored before Debug, etc. since Debug etc. might
141   // depend on a correct stack guard.
142   from = isolate_->stack_guard()->RestoreStackGuard(from);
143   from = isolate_->debug()->RestoreDebug(from);
144   from = isolate_->regexp_stack()->RestoreStack(from);
145   from = isolate_->bootstrapper()->RestoreState(from);
146   per_thread->set_thread_state(nullptr);
147   state->set_id(ThreadId::Invalid());
148   state->Unlink();
149   state->LinkInto(ThreadState::FREE_LIST);
150   return true;
151 }
152 
Lock()153 void ThreadManager::Lock() {
154   mutex_.Lock();
155   mutex_owner_.store(ThreadId::Current(), std::memory_order_relaxed);
156   DCHECK(IsLockedByCurrentThread());
157 }
158 
Unlock()159 void ThreadManager::Unlock() {
160   mutex_owner_.store(ThreadId::Invalid(), std::memory_order_relaxed);
161   mutex_.Unlock();
162 }
163 
ArchiveSpacePerThread()164 static int ArchiveSpacePerThread() {
165   return HandleScopeImplementer::ArchiveSpacePerThread() +
166          Isolate::ArchiveSpacePerThread() + Debug::ArchiveSpacePerThread() +
167          StackGuard::ArchiveSpacePerThread() +
168          RegExpStack::ArchiveSpacePerThread() +
169          Bootstrapper::ArchiveSpacePerThread() +
170          Relocatable::ArchiveSpacePerThread();
171 }
172 
ThreadState(ThreadManager * thread_manager)173 ThreadState::ThreadState(ThreadManager* thread_manager)
174     : id_(ThreadId::Invalid()),
175       data_(nullptr),
176       next_(this),
177       previous_(this),
178       thread_manager_(thread_manager) {}
179 
~ThreadState()180 ThreadState::~ThreadState() { DeleteArray<char>(data_); }
181 
AllocateSpace()182 void ThreadState::AllocateSpace() {
183   data_ = NewArray<char>(ArchiveSpacePerThread());
184 }
185 
Unlink()186 void ThreadState::Unlink() {
187   next_->previous_ = previous_;
188   previous_->next_ = next_;
189 }
190 
LinkInto(List list)191 void ThreadState::LinkInto(List list) {
192   ThreadState* flying_anchor = list == FREE_LIST
193                                    ? thread_manager_->free_anchor_
194                                    : thread_manager_->in_use_anchor_;
195   next_ = flying_anchor->next_;
196   previous_ = flying_anchor;
197   flying_anchor->next_ = this;
198   next_->previous_ = this;
199 }
200 
GetFreeThreadState()201 ThreadState* ThreadManager::GetFreeThreadState() {
202   ThreadState* gotten = free_anchor_->next_;
203   if (gotten == free_anchor_) {
204     ThreadState* new_thread_state = new ThreadState(this);
205     new_thread_state->AllocateSpace();
206     return new_thread_state;
207   }
208   return gotten;
209 }
210 
211 // Gets the first in the list of archived threads.
FirstThreadStateInUse()212 ThreadState* ThreadManager::FirstThreadStateInUse() {
213   return in_use_anchor_->Next();
214 }
215 
Next()216 ThreadState* ThreadState::Next() {
217   if (next_ == thread_manager_->in_use_anchor_) return nullptr;
218   return next_;
219 }
220 
221 // Thread ids must start with 1, because in TLS having thread id 0 can't
222 // be distinguished from not having a thread id at all (since NULL is
223 // defined as 0.)
ThreadManager(Isolate * isolate)224 ThreadManager::ThreadManager(Isolate* isolate)
225     : mutex_owner_(ThreadId::Invalid()),
226       lazily_archived_thread_(ThreadId::Invalid()),
227       lazily_archived_thread_state_(nullptr),
228       free_anchor_(nullptr),
229       in_use_anchor_(nullptr),
230       isolate_(isolate) {
231   free_anchor_ = new ThreadState(this);
232   in_use_anchor_ = new ThreadState(this);
233 }
234 
~ThreadManager()235 ThreadManager::~ThreadManager() {
236   DeleteThreadStateList(free_anchor_);
237   DeleteThreadStateList(in_use_anchor_);
238 }
239 
DeleteThreadStateList(ThreadState * anchor)240 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
241   // The list starts and ends with the anchor.
242   for (ThreadState* current = anchor->next_; current != anchor;) {
243     ThreadState* next = current->next_;
244     delete current;
245     current = next;
246   }
247   delete anchor;
248 }
249 
ArchiveThread()250 void ThreadManager::ArchiveThread() {
251   DCHECK_EQ(lazily_archived_thread_, ThreadId::Invalid());
252   DCHECK(!IsArchived());
253   DCHECK(IsLockedByCurrentThread());
254   ThreadState* state = GetFreeThreadState();
255   state->Unlink();
256   Isolate::PerIsolateThreadData* per_thread =
257       isolate_->FindOrAllocatePerThreadDataForThisThread();
258   per_thread->set_thread_state(state);
259   lazily_archived_thread_ = ThreadId::Current();
260   lazily_archived_thread_state_ = state;
261   DCHECK_EQ(state->id(), ThreadId::Invalid());
262   state->set_id(CurrentId());
263   DCHECK_NE(state->id(), ThreadId::Invalid());
264 }
265 
EagerlyArchiveThread()266 void ThreadManager::EagerlyArchiveThread() {
267   DCHECK(IsLockedByCurrentThread());
268   ThreadState* state = lazily_archived_thread_state_;
269   state->LinkInto(ThreadState::IN_USE_LIST);
270   char* to = state->data();
271   // Ensure that data containing GC roots are archived first, and handle them
272   // in ThreadManager::Iterate(RootVisitor*).
273   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
274   to = isolate_->ArchiveThread(to);
275   to = Relocatable::ArchiveState(isolate_, to);
276   to = isolate_->stack_guard()->ArchiveStackGuard(to);
277   to = isolate_->debug()->ArchiveDebug(to);
278   to = isolate_->regexp_stack()->ArchiveStack(to);
279   to = isolate_->bootstrapper()->ArchiveState(to);
280   lazily_archived_thread_ = ThreadId::Invalid();
281   lazily_archived_thread_state_ = nullptr;
282 }
283 
FreeThreadResources()284 void ThreadManager::FreeThreadResources() {
285   DCHECK(!isolate_->has_pending_exception());
286   DCHECK(!isolate_->external_caught_exception());
287   DCHECK_NULL(isolate_->try_catch_handler());
288   isolate_->handle_scope_implementer()->FreeThreadResources();
289   isolate_->FreeThreadResources();
290   isolate_->debug()->FreeThreadResources();
291   isolate_->stack_guard()->FreeThreadResources();
292   isolate_->regexp_stack()->FreeThreadResources();
293   isolate_->bootstrapper()->FreeThreadResources();
294 }
295 
IsArchived()296 bool ThreadManager::IsArchived() {
297   Isolate::PerIsolateThreadData* data =
298       isolate_->FindPerThreadDataForThisThread();
299   return data != nullptr && data->thread_state() != nullptr;
300 }
301 
Iterate(RootVisitor * v)302 void ThreadManager::Iterate(RootVisitor* v) {
303   // Expecting no threads during serialization/deserialization
304   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
305        state = state->Next()) {
306     char* data = state->data();
307     data = HandleScopeImplementer::Iterate(v, data);
308     data = isolate_->Iterate(v, data);
309     data = Relocatable::Iterate(v, data);
310     data = StackGuard::Iterate(v, data);
311     data = Debug::Iterate(v, data);
312   }
313 }
314 
IterateArchivedThreads(ThreadVisitor * v)315 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
316   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
317        state = state->Next()) {
318     char* data = state->data();
319     data += HandleScopeImplementer::ArchiveSpacePerThread();
320     isolate_->IterateThread(v, data);
321   }
322 }
323 
CurrentId()324 ThreadId ThreadManager::CurrentId() { return ThreadId::Current(); }
325 
326 }  // namespace internal
327 }  // namespace v8
328