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