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 8430 : void Locker::Initialize(v8::Isolate* isolate) {
30 : DCHECK_NOT_NULL(isolate);
31 8430 : has_lock_ = false;
32 8430 : top_level_ = true;
33 8430 : isolate_ = reinterpret_cast<i::Isolate*>(isolate);
34 : // Record that the Locker has been used at least once.
35 : base::Relaxed_Store(&g_locker_was_ever_used_, 1);
36 : // Get the big lock if necessary.
37 16859 : if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
38 6917 : isolate_->thread_manager()->Lock();
39 6928 : 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 6928 : if (isolate_->thread_manager()->RestoreThread()) {
44 1010 : top_level_ = false;
45 : } else {
46 5918 : internal::ExecutionAccess access(isolate_);
47 11836 : isolate_->stack_guard()->ClearThread(access);
48 5918 : isolate_->thread_manager()->InitThread(access);
49 : }
50 : }
51 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
52 8440 : }
53 :
54 :
55 3056 : bool Locker::IsLocked(v8::Isolate* isolate) {
56 : DCHECK_NOT_NULL(isolate);
57 : i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
58 3056 : return internal_isolate->thread_manager()->IsLockedByCurrentThread();
59 : }
60 :
61 :
62 475228027 : bool Locker::IsActive() {
63 475228027 : return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 : }
65 :
66 :
67 16878 : Locker::~Locker() {
68 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
69 8439 : if (has_lock_) {
70 6928 : if (top_level_) {
71 5918 : isolate_->thread_manager()->FreeThreadResources();
72 : } else {
73 1010 : isolate_->thread_manager()->ArchiveThread();
74 : }
75 6928 : isolate_->thread_manager()->Unlock();
76 : }
77 8439 : }
78 :
79 :
80 33375 : void Unlocker::Initialize(v8::Isolate* isolate) {
81 : DCHECK_NOT_NULL(isolate);
82 33375 : isolate_ = reinterpret_cast<i::Isolate*>(isolate);
83 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
84 33375 : isolate_->thread_manager()->ArchiveThread();
85 33375 : isolate_->thread_manager()->Unlock();
86 33375 : }
87 :
88 :
89 66750 : Unlocker::~Unlocker() {
90 : DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
91 33375 : isolate_->thread_manager()->Lock();
92 33375 : isolate_->thread_manager()->RestoreThread();
93 33375 : }
94 :
95 :
96 : namespace internal {
97 :
98 0 : void ThreadManager::InitThread(const ExecutionAccess& lock) {
99 23672 : isolate_->stack_guard()->InitThread(lock);
100 11836 : isolate_->debug()->InitThread(lock);
101 0 : }
102 :
103 40303 : 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 40303 : if (lazily_archived_thread_ == ThreadId::Current()) {
109 1922 : lazily_archived_thread_ = ThreadId::Invalid();
110 : Isolate::PerIsolateThreadData* per_thread =
111 1922 : isolate_->FindPerThreadDataForThisThread();
112 : DCHECK_NOT_NULL(per_thread);
113 : DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
114 1922 : lazily_archived_thread_state_->set_id(ThreadId::Invalid());
115 1922 : lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
116 1922 : lazily_archived_thread_state_ = nullptr;
117 : per_thread->set_thread_state(nullptr);
118 1922 : 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 38381 : ExecutionAccess access(isolate_);
124 :
125 : // If there is another thread that was lazily archived then we have to really
126 : // archive it now.
127 38381 : if (lazily_archived_thread_.IsValid()) {
128 32463 : EagerlyArchiveThread();
129 : }
130 : Isolate::PerIsolateThreadData* per_thread =
131 38381 : isolate_->FindPerThreadDataForThisThread();
132 38381 : if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
133 : // This is a new thread.
134 : InitThread(access);
135 5918 : return false;
136 : }
137 : ThreadState* state = per_thread->thread_state();
138 : char* from = state->data();
139 32463 : from = isolate_->handle_scope_implementer()->RestoreThread(from);
140 32463 : from = isolate_->RestoreThread(from);
141 32463 : from = Relocatable::RestoreState(isolate_, from);
142 32463 : from = isolate_->debug()->RestoreDebug(from);
143 64926 : from = isolate_->stack_guard()->RestoreStackGuard(from);
144 32463 : from = isolate_->regexp_stack()->RestoreStack(from);
145 32463 : from = isolate_->bootstrapper()->RestoreState(from);
146 : per_thread->set_thread_state(nullptr);
147 32463 : if (state->terminate_on_restore()) {
148 0 : 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 32463 : return true;
155 : }
156 :
157 :
158 40291 : void ThreadManager::Lock() {
159 40291 : mutex_.Lock();
160 : mutex_owner_.store(ThreadId::Current(), std::memory_order_relaxed);
161 : DCHECK(IsLockedByCurrentThread());
162 40303 : }
163 :
164 :
165 0 : void ThreadManager::Unlock() {
166 : mutex_owner_.store(ThreadId::Invalid(), std::memory_order_relaxed);
167 40303 : mutex_.Unlock();
168 0 : }
169 :
170 :
171 1126 : static int ArchiveSpacePerThread() {
172 1126 : return HandleScopeImplementer::ArchiveSpacePerThread() +
173 1126 : Isolate::ArchiveSpacePerThread() +
174 1126 : Debug::ArchiveSpacePerThread() +
175 1126 : StackGuard::ArchiveSpacePerThread() +
176 1126 : RegExpStack::ArchiveSpacePerThread() +
177 1126 : Bootstrapper::ArchiveSpacePerThread() +
178 1126 : Relocatable::ArchiveSpacePerThread();
179 : }
180 :
181 0 : ThreadState::ThreadState(ThreadManager* thread_manager)
182 : : id_(ThreadId::Invalid()),
183 : terminate_on_restore_(false),
184 : data_(nullptr),
185 : next_(this),
186 : previous_(this),
187 125968 : thread_manager_(thread_manager) {}
188 :
189 125939 : ThreadState::~ThreadState() {
190 125939 : DeleteArray<char>(data_);
191 0 : }
192 :
193 :
194 0 : void ThreadState::AllocateSpace() {
195 1126 : data_ = NewArray<char>(ArchiveSpacePerThread());
196 0 : }
197 :
198 :
199 0 : void ThreadState::Unlink() {
200 66848 : next_->previous_ = previous_;
201 66848 : previous_->next_ = next_;
202 0 : }
203 :
204 :
205 0 : void ThreadState::LinkInto(List list) {
206 : ThreadState* flying_anchor =
207 34385 : list == FREE_LIST ? thread_manager_->free_anchor_
208 66848 : : thread_manager_->in_use_anchor_;
209 66848 : next_ = flying_anchor->next_;
210 66848 : previous_ = flying_anchor;
211 66848 : flying_anchor->next_ = this;
212 66848 : next_->previous_ = this;
213 0 : }
214 :
215 :
216 34385 : ThreadState* ThreadManager::GetFreeThreadState() {
217 34385 : ThreadState* gotten = free_anchor_->next_;
218 34385 : if (gotten == free_anchor_) {
219 1126 : ThreadState* new_thread_state = new ThreadState(this);
220 : new_thread_state->AllocateSpace();
221 1126 : return new_thread_state;
222 : }
223 : return gotten;
224 : }
225 :
226 :
227 : // Gets the first in the list of archived threads.
228 522 : ThreadState* ThreadManager::FirstThreadStateInUse() {
229 366728 : return in_use_anchor_->Next();
230 : }
231 :
232 :
233 0 : ThreadState* ThreadState::Next() {
234 372928 : if (next_ == thread_manager_->in_use_anchor_) return nullptr;
235 0 : return next_;
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 62420 : ThreadManager::ThreadManager(Isolate* isolate)
242 : : mutex_owner_(ThreadId::Invalid()),
243 : lazily_archived_thread_(ThreadId::Invalid()),
244 : lazily_archived_thread_state_(nullptr),
245 : free_anchor_(nullptr),
246 : in_use_anchor_(nullptr),
247 124840 : isolate_(isolate) {
248 124841 : free_anchor_ = new ThreadState(this);
249 124842 : in_use_anchor_ = new ThreadState(this);
250 62421 : }
251 :
252 :
253 124813 : ThreadManager::~ThreadManager() {
254 62406 : DeleteThreadStateList(free_anchor_);
255 62407 : DeleteThreadStateList(in_use_anchor_);
256 62407 : }
257 :
258 :
259 124813 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
260 : // The list starts and ends with the anchor.
261 124813 : for (ThreadState* current = anchor->next_; current != anchor;) {
262 1126 : ThreadState* next = current->next_;
263 2252 : delete current;
264 : current = next;
265 : }
266 249626 : delete anchor;
267 124814 : }
268 :
269 :
270 34385 : void ThreadManager::ArchiveThread() {
271 : DCHECK_EQ(lazily_archived_thread_, ThreadId::Invalid());
272 : DCHECK(!IsArchived());
273 : DCHECK(IsLockedByCurrentThread());
274 34385 : ThreadState* state = GetFreeThreadState();
275 : state->Unlink();
276 : Isolate::PerIsolateThreadData* per_thread =
277 34385 : isolate_->FindOrAllocatePerThreadDataForThisThread();
278 : per_thread->set_thread_state(state);
279 34385 : lazily_archived_thread_ = ThreadId::Current();
280 34385 : lazily_archived_thread_state_ = state;
281 : DCHECK_EQ(state->id(), ThreadId::Invalid());
282 : state->set_id(CurrentId());
283 : DCHECK_NE(state->id(), ThreadId::Invalid());
284 34385 : }
285 :
286 :
287 32463 : void ThreadManager::EagerlyArchiveThread() {
288 : DCHECK(IsLockedByCurrentThread());
289 32463 : ThreadState* state = lazily_archived_thread_state_;
290 : state->LinkInto(ThreadState::IN_USE_LIST);
291 : char* to = state->data();
292 : // Ensure that data containing GC roots are archived first, and handle them
293 : // in ThreadManager::Iterate(RootVisitor*).
294 32463 : to = isolate_->handle_scope_implementer()->ArchiveThread(to);
295 32463 : to = isolate_->ArchiveThread(to);
296 32463 : to = Relocatable::ArchiveState(isolate_, to);
297 32463 : to = isolate_->debug()->ArchiveDebug(to);
298 64926 : to = isolate_->stack_guard()->ArchiveStackGuard(to);
299 32463 : to = isolate_->regexp_stack()->ArchiveStack(to);
300 32463 : to = isolate_->bootstrapper()->ArchiveState(to);
301 32463 : lazily_archived_thread_ = ThreadId::Invalid();
302 32463 : lazily_archived_thread_state_ = nullptr;
303 32463 : }
304 :
305 :
306 5918 : void ThreadManager::FreeThreadResources() {
307 : DCHECK(!isolate_->has_pending_exception());
308 : DCHECK(!isolate_->external_caught_exception());
309 : DCHECK_NULL(isolate_->try_catch_handler());
310 5918 : isolate_->handle_scope_implementer()->FreeThreadResources();
311 5918 : isolate_->FreeThreadResources();
312 5918 : isolate_->debug()->FreeThreadResources();
313 5918 : isolate_->stack_guard()->FreeThreadResources();
314 5918 : isolate_->regexp_stack()->FreeThreadResources();
315 5918 : isolate_->bootstrapper()->FreeThreadResources();
316 5918 : }
317 :
318 :
319 0 : bool ThreadManager::IsArchived() {
320 : Isolate::PerIsolateThreadData* data =
321 0 : isolate_->FindPerThreadDataForThisThread();
322 0 : return data != nullptr && data->thread_state() != nullptr;
323 : }
324 :
325 277915 : void ThreadManager::Iterate(RootVisitor* v) {
326 : // Expecting no threads during serialization/deserialization
327 290481 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
328 : state = state->Next()) {
329 : char* data = state->data();
330 6283 : data = HandleScopeImplementer::Iterate(v, data);
331 6283 : data = isolate_->Iterate(v, data);
332 6283 : data = Relocatable::Iterate(v, data);
333 : }
334 277915 : }
335 :
336 :
337 87769 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
338 88647 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
339 : state = state->Next()) {
340 : char* data = state->data();
341 439 : data += HandleScopeImplementer::ArchiveSpacePerThread();
342 439 : isolate_->IterateThread(v, data);
343 : }
344 87769 : }
345 :
346 :
347 0 : ThreadId ThreadManager::CurrentId() {
348 0 : return ThreadId::Current();
349 : }
350 :
351 :
352 0 : void ThreadManager::TerminateExecution(ThreadId thread_id) {
353 0 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
354 : state = state->Next()) {
355 0 : if (thread_id == state->id()) {
356 : state->set_terminate_on_restore(true);
357 : }
358 : }
359 0 : }
360 :
361 :
362 : } // namespace internal
363 121996 : } // namespace v8
|