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