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