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