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