• 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/v8.h"
6 
7 #include "src/api.h"
8 #include "src/bootstrapper.h"
9 #include "src/debug.h"
10 #include "src/execution.h"
11 #include "src/regexp-stack.h"
12 #include "src/v8threads.h"
13 
14 namespace v8 {
15 
16 
17 // Track whether this V8 instance has ever called v8::Locker. This allows the
18 // API code to verify that the lock is always held when V8 is being entered.
19 bool Locker::active_ = false;
20 
21 
22 // Once the Locker is initialized, the current thread will be guaranteed to have
23 // the lock for a given isolate.
Initialize(v8::Isolate * isolate)24 void Locker::Initialize(v8::Isolate* isolate) {
25   DCHECK(isolate != NULL);
26   has_lock_= false;
27   top_level_ = true;
28   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
29   // Record that the Locker has been used at least once.
30   active_ = true;
31   // Get the big lock if necessary.
32   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
33     isolate_->thread_manager()->Lock();
34     has_lock_ = true;
35 
36     // Make sure that V8 is initialized.  Archiving of threads interferes
37     // with deserialization by adding additional root pointers, so we must
38     // initialize here, before anyone can call ~Locker() or Unlocker().
39     if (!isolate_->IsInitialized()) {
40       isolate_->Enter();
41       V8::Initialize();
42       isolate_->Exit();
43     }
44 
45     // This may be a locker within an unlocker in which case we have to
46     // get the saved state for this thread and restore it.
47     if (isolate_->thread_manager()->RestoreThread()) {
48       top_level_ = false;
49     } else {
50       internal::ExecutionAccess access(isolate_);
51       isolate_->stack_guard()->ClearThread(access);
52       isolate_->stack_guard()->InitThread(access);
53     }
54   }
55   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
56 }
57 
58 
IsLocked(v8::Isolate * isolate)59 bool Locker::IsLocked(v8::Isolate* isolate) {
60   DCHECK(isolate != NULL);
61   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
62   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
63 }
64 
65 
IsActive()66 bool Locker::IsActive() {
67   return active_;
68 }
69 
70 
~Locker()71 Locker::~Locker() {
72   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
73   if (has_lock_) {
74     if (top_level_) {
75       isolate_->thread_manager()->FreeThreadResources();
76     } else {
77       isolate_->thread_manager()->ArchiveThread();
78     }
79     isolate_->thread_manager()->Unlock();
80   }
81 }
82 
83 
Initialize(v8::Isolate * isolate)84 void Unlocker::Initialize(v8::Isolate* isolate) {
85   DCHECK(isolate != NULL);
86   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
87   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
88   isolate_->thread_manager()->ArchiveThread();
89   isolate_->thread_manager()->Unlock();
90 }
91 
92 
~Unlocker()93 Unlocker::~Unlocker() {
94   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
95   isolate_->thread_manager()->Lock();
96   isolate_->thread_manager()->RestoreThread();
97 }
98 
99 
100 namespace internal {
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(per_thread != NULL);
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_ = NULL;
117     per_thread->set_thread_state(NULL);
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 == NULL || per_thread->thread_state() == NULL) {
133     // This is a new thread.
134     isolate_->stack_guard()->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(NULL);
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 
181 
ThreadState(ThreadManager * thread_manager)182 ThreadState::ThreadState(ThreadManager* thread_manager)
183     : id_(ThreadId::Invalid()),
184       terminate_on_restore_(false),
185       data_(NULL),
186       next_(this),
187       previous_(this),
188       thread_manager_(thread_manager) {
189 }
190 
191 
~ThreadState()192 ThreadState::~ThreadState() {
193   DeleteArray<char>(data_);
194 }
195 
196 
AllocateSpace()197 void ThreadState::AllocateSpace() {
198   data_ = NewArray<char>(ArchiveSpacePerThread());
199 }
200 
201 
Unlink()202 void ThreadState::Unlink() {
203   next_->previous_ = previous_;
204   previous_->next_ = next_;
205 }
206 
207 
LinkInto(List list)208 void ThreadState::LinkInto(List list) {
209   ThreadState* flying_anchor =
210       list == FREE_LIST ? thread_manager_->free_anchor_
211                         : thread_manager_->in_use_anchor_;
212   next_ = flying_anchor->next_;
213   previous_ = flying_anchor;
214   flying_anchor->next_ = this;
215   next_->previous_ = this;
216 }
217 
218 
GetFreeThreadState()219 ThreadState* ThreadManager::GetFreeThreadState() {
220   ThreadState* gotten = free_anchor_->next_;
221   if (gotten == free_anchor_) {
222     ThreadState* new_thread_state = new ThreadState(this);
223     new_thread_state->AllocateSpace();
224     return new_thread_state;
225   }
226   return gotten;
227 }
228 
229 
230 // Gets the first in the list of archived threads.
FirstThreadStateInUse()231 ThreadState* ThreadManager::FirstThreadStateInUse() {
232   return in_use_anchor_->Next();
233 }
234 
235 
Next()236 ThreadState* ThreadState::Next() {
237   if (next_ == thread_manager_->in_use_anchor_) return NULL;
238   return next_;
239 }
240 
241 
242 // Thread ids must start with 1, because in TLS having thread id 0 can't
243 // be distinguished from not having a thread id at all (since NULL is
244 // defined as 0.)
ThreadManager()245 ThreadManager::ThreadManager()
246     : mutex_owner_(ThreadId::Invalid()),
247       lazily_archived_thread_(ThreadId::Invalid()),
248       lazily_archived_thread_state_(NULL),
249       free_anchor_(NULL),
250       in_use_anchor_(NULL) {
251   free_anchor_ = new ThreadState(this);
252   in_use_anchor_ = new ThreadState(this);
253 }
254 
255 
~ThreadManager()256 ThreadManager::~ThreadManager() {
257   DeleteThreadStateList(free_anchor_);
258   DeleteThreadStateList(in_use_anchor_);
259 }
260 
261 
DeleteThreadStateList(ThreadState * anchor)262 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
263   // The list starts and ends with the anchor.
264   for (ThreadState* current = anchor->next_; current != anchor;) {
265     ThreadState* next = current->next_;
266     delete current;
267     current = next;
268   }
269   delete anchor;
270 }
271 
272 
ArchiveThread()273 void ThreadManager::ArchiveThread() {
274   DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
275   DCHECK(!IsArchived());
276   DCHECK(IsLockedByCurrentThread());
277   ThreadState* state = GetFreeThreadState();
278   state->Unlink();
279   Isolate::PerIsolateThreadData* per_thread =
280       isolate_->FindOrAllocatePerThreadDataForThisThread();
281   per_thread->set_thread_state(state);
282   lazily_archived_thread_ = ThreadId::Current();
283   lazily_archived_thread_state_ = state;
284   DCHECK(state->id().Equals(ThreadId::Invalid()));
285   state->set_id(CurrentId());
286   DCHECK(!state->id().Equals(ThreadId::Invalid()));
287 }
288 
289 
EagerlyArchiveThread()290 void ThreadManager::EagerlyArchiveThread() {
291   DCHECK(IsLockedByCurrentThread());
292   ThreadState* state = lazily_archived_thread_state_;
293   state->LinkInto(ThreadState::IN_USE_LIST);
294   char* to = state->data();
295   // Ensure that data containing GC roots are archived first, and handle them
296   // in ThreadManager::Iterate(ObjectVisitor*).
297   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
298   to = isolate_->ArchiveThread(to);
299   to = Relocatable::ArchiveState(isolate_, to);
300   to = isolate_->debug()->ArchiveDebug(to);
301   to = isolate_->stack_guard()->ArchiveStackGuard(to);
302   to = isolate_->regexp_stack()->ArchiveStack(to);
303   to = isolate_->bootstrapper()->ArchiveState(to);
304   lazily_archived_thread_ = ThreadId::Invalid();
305   lazily_archived_thread_state_ = NULL;
306 }
307 
308 
FreeThreadResources()309 void ThreadManager::FreeThreadResources() {
310   DCHECK(!isolate_->has_pending_exception());
311   DCHECK(!isolate_->external_caught_exception());
312   DCHECK(isolate_->try_catch_handler() == NULL);
313   isolate_->handle_scope_implementer()->FreeThreadResources();
314   isolate_->FreeThreadResources();
315   isolate_->debug()->FreeThreadResources();
316   isolate_->stack_guard()->FreeThreadResources();
317   isolate_->regexp_stack()->FreeThreadResources();
318   isolate_->bootstrapper()->FreeThreadResources();
319 }
320 
321 
IsArchived()322 bool ThreadManager::IsArchived() {
323   Isolate::PerIsolateThreadData* data =
324       isolate_->FindPerThreadDataForThisThread();
325   return data != NULL && data->thread_state() != NULL;
326 }
327 
328 
Iterate(ObjectVisitor * v)329 void ThreadManager::Iterate(ObjectVisitor* v) {
330   // Expecting no threads during serialization/deserialization
331   for (ThreadState* state = FirstThreadStateInUse();
332        state != NULL;
333        state = state->Next()) {
334     char* data = state->data();
335     data = HandleScopeImplementer::Iterate(v, data);
336     data = isolate_->Iterate(v, data);
337     data = Relocatable::Iterate(v, data);
338   }
339 }
340 
341 
IterateArchivedThreads(ThreadVisitor * v)342 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
343   for (ThreadState* state = FirstThreadStateInUse();
344        state != NULL;
345        state = state->Next()) {
346     char* data = state->data();
347     data += HandleScopeImplementer::ArchiveSpacePerThread();
348     isolate_->IterateThread(v, data);
349   }
350 }
351 
352 
CurrentId()353 ThreadId ThreadManager::CurrentId() {
354   return ThreadId::Current();
355 }
356 
357 
TerminateExecution(ThreadId thread_id)358 void ThreadManager::TerminateExecution(ThreadId thread_id) {
359   for (ThreadState* state = FirstThreadStateInUse();
360        state != NULL;
361        state = state->Next()) {
362     if (thread_id.Equals(state->id())) {
363       state->set_terminate_on_restore(true);
364     }
365   }
366 }
367 
368 
369 }  // namespace internal
370 }  // namespace v8
371