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 8432 : void Locker::Initialize(v8::Isolate* isolate) {
30 : DCHECK_NOT_NULL(isolate);
31 8432 : has_lock_ = false;
32 8432 : top_level_ = true;
33 8432 : 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 28198 : if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
38 13840 : 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 13856 : if (isolate_->thread_manager()->RestoreThread()) {
44 1010 : top_level_ = false;
45 : } else {
46 5918 : internal::ExecutionAccess access(isolate_);
47 5918 : isolate_->stack_guard()->ClearThread(access);
48 11836 : isolate_->thread_manager()->InitThread(access);
49 : }
50 : }
51 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
52 8439 : }
53 :
54 :
55 3056 : bool Locker::IsLocked(v8::Isolate* isolate) {
56 : DCHECK_NOT_NULL(isolate);
57 3056 : i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
58 3056 : return internal_isolate->thread_manager()->IsLockedByCurrentThread();
59 : }
60 :
61 :
62 446882166 : bool Locker::IsActive() {
63 446882166 : return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 : }
65 :
66 :
67 8439 : Locker::~Locker() {
68 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
69 8439 : if (has_lock_) {
70 6928 : if (top_level_) {
71 13856 : isolate_->thread_manager()->FreeThreadResources();
72 : } else {
73 2020 : isolate_->thread_manager()->ArchiveThread();
74 : }
75 13856 : isolate_->thread_manager()->Unlock();
76 : }
77 8439 : }
78 :
79 :
80 25225 : void Unlocker::Initialize(v8::Isolate* isolate) {
81 : DCHECK_NOT_NULL(isolate);
82 25225 : isolate_ = reinterpret_cast<i::Isolate*>(isolate);
83 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
84 50450 : isolate_->thread_manager()->ArchiveThread();
85 50450 : isolate_->thread_manager()->Unlock();
86 25225 : }
87 :
88 :
89 25224 : Unlocker::~Unlocker() {
90 : DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
91 50449 : isolate_->thread_manager()->Lock();
92 50450 : isolate_->thread_manager()->RestoreThread();
93 25225 : }
94 :
95 :
96 : namespace internal {
97 :
98 11836 : void ThreadManager::InitThread(const ExecutionAccess& lock) {
99 23672 : isolate_->stack_guard()->InitThread(lock);
100 11836 : isolate_->debug()->InitThread(lock);
101 11836 : }
102 :
103 32153 : 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 64306 : if (lazily_archived_thread_.Equals(ThreadId::Current())) {
109 1979 : lazily_archived_thread_ = ThreadId::Invalid();
110 : Isolate::PerIsolateThreadData* per_thread =
111 99003 : isolate_->FindPerThreadDataForThisThread();
112 : DCHECK_NOT_NULL(per_thread);
113 : DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
114 1979 : lazily_archived_thread_state_->set_id(ThreadId::Invalid());
115 1979 : lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
116 1979 : lazily_archived_thread_state_ = nullptr;
117 : per_thread->set_thread_state(nullptr);
118 1979 : 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 30174 : ExecutionAccess access(isolate_);
124 :
125 : // If there is another thread that was lazily archived then we have to really
126 : // archive it now.
127 30174 : if (lazily_archived_thread_.IsValid()) {
128 24256 : EagerlyArchiveThread();
129 : }
130 48895 : Isolate::PerIsolateThreadData* per_thread =
131 30174 : isolate_->FindPerThreadDataForThisThread();
132 54813 : if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
133 : // This is a new thread.
134 5918 : InitThread(access);
135 5918 : return false;
136 : }
137 48512 : ThreadState* state = per_thread->thread_state();
138 : char* from = state->data();
139 48512 : from = isolate_->handle_scope_implementer()->RestoreThread(from);
140 24256 : from = isolate_->RestoreThread(from);
141 24256 : from = Relocatable::RestoreState(isolate_, from);
142 48512 : from = isolate_->debug()->RestoreDebug(from);
143 24256 : from = isolate_->stack_guard()->RestoreStackGuard(from);
144 48512 : from = isolate_->regexp_stack()->RestoreStack(from);
145 48512 : from = isolate_->bootstrapper()->RestoreState(from);
146 : per_thread->set_thread_state(nullptr);
147 24256 : 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 24256 : return true;
155 : }
156 :
157 :
158 32143 : void ThreadManager::Lock() {
159 32143 : mutex_.Lock();
160 32153 : mutex_owner_ = ThreadId::Current();
161 : DCHECK(IsLockedByCurrentThread());
162 32153 : }
163 :
164 :
165 32153 : void ThreadManager::Unlock() {
166 32153 : mutex_owner_ = ThreadId::Invalid();
167 32153 : mutex_.Unlock();
168 32153 : }
169 :
170 :
171 1111 : static int ArchiveSpacePerThread() {
172 1111 : return HandleScopeImplementer::ArchiveSpacePerThread() +
173 1111 : Isolate::ArchiveSpacePerThread() +
174 1111 : Debug::ArchiveSpacePerThread() +
175 1111 : StackGuard::ArchiveSpacePerThread() +
176 1111 : RegExpStack::ArchiveSpacePerThread() +
177 1111 : Bootstrapper::ArchiveSpacePerThread() +
178 1111 : 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 126877 : thread_manager_(thread_manager) {}
188 :
189 0 : ThreadState::~ThreadState() {
190 126846 : DeleteArray<char>(data_);
191 0 : }
192 :
193 :
194 1111 : void ThreadState::AllocateSpace() {
195 1111 : data_ = NewArray<char>(ArchiveSpacePerThread());
196 1111 : }
197 :
198 :
199 0 : void ThreadState::Unlink() {
200 50491 : next_->previous_ = previous_;
201 50491 : previous_->next_ = next_;
202 0 : }
203 :
204 :
205 0 : void ThreadState::LinkInto(List list) {
206 : ThreadState* flying_anchor =
207 : list == FREE_LIST ? thread_manager_->free_anchor_
208 50491 : : thread_manager_->in_use_anchor_;
209 50491 : next_ = flying_anchor->next_;
210 50491 : previous_ = flying_anchor;
211 50491 : flying_anchor->next_ = this;
212 50491 : next_->previous_ = this;
213 0 : }
214 :
215 :
216 26235 : ThreadState* ThreadManager::GetFreeThreadState() {
217 26235 : ThreadState* gotten = free_anchor_->next_;
218 26235 : if (gotten == free_anchor_) {
219 1111 : ThreadState* new_thread_state = new ThreadState(this);
220 1111 : new_thread_state->AllocateSpace();
221 1111 : return new_thread_state;
222 : }
223 : return gotten;
224 : }
225 :
226 :
227 : // Gets the first in the list of archived threads.
228 502 : ThreadState* ThreadManager::FirstThreadStateInUse() {
229 389479 : return in_use_anchor_->Next();
230 : }
231 :
232 :
233 0 : ThreadState* ThreadState::Next() {
234 447962 : 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 62882 : 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 188646 : isolate_(isolate) {
248 125765 : free_anchor_ = new ThreadState(this);
249 125766 : in_use_anchor_ = new ThreadState(this);
250 62883 : }
251 :
252 :
253 125735 : ThreadManager::~ThreadManager() {
254 62867 : DeleteThreadStateList(free_anchor_);
255 62868 : DeleteThreadStateList(in_use_anchor_);
256 62868 : }
257 :
258 :
259 125735 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
260 : // The list starts and ends with the anchor.
261 252581 : for (ThreadState* current = anchor->next_; current != anchor;) {
262 1111 : ThreadState* next = current->next_;
263 2222 : delete current;
264 : current = next;
265 : }
266 251470 : delete anchor;
267 125736 : }
268 :
269 :
270 26235 : void ThreadManager::ArchiveThread() {
271 : DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
272 : DCHECK(!IsArchived());
273 : DCHECK(IsLockedByCurrentThread());
274 26235 : ThreadState* state = GetFreeThreadState();
275 : state->Unlink();
276 : Isolate::PerIsolateThreadData* per_thread =
277 26235 : isolate_->FindOrAllocatePerThreadDataForThisThread();
278 : per_thread->set_thread_state(state);
279 26235 : lazily_archived_thread_ = ThreadId::Current();
280 26235 : lazily_archived_thread_state_ = state;
281 : DCHECK(state->id().Equals(ThreadId::Invalid()));
282 : state->set_id(CurrentId());
283 : DCHECK(!state->id().Equals(ThreadId::Invalid()));
284 26235 : }
285 :
286 :
287 24256 : void ThreadManager::EagerlyArchiveThread() {
288 : DCHECK(IsLockedByCurrentThread());
289 48512 : 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 97024 : to = isolate_->handle_scope_implementer()->ArchiveThread(to);
295 24256 : to = isolate_->ArchiveThread(to);
296 24256 : to = Relocatable::ArchiveState(isolate_, to);
297 48512 : to = isolate_->debug()->ArchiveDebug(to);
298 24256 : to = isolate_->stack_guard()->ArchiveStackGuard(to);
299 48512 : to = isolate_->regexp_stack()->ArchiveStack(to);
300 48512 : to = isolate_->bootstrapper()->ArchiveState(to);
301 24256 : lazily_archived_thread_ = ThreadId::Invalid();
302 24256 : lazily_archived_thread_state_ = nullptr;
303 24256 : }
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 17754 : isolate_->handle_scope_implementer()->FreeThreadResources();
311 5918 : isolate_->FreeThreadResources();
312 : isolate_->debug()->FreeThreadResources();
313 5918 : isolate_->stack_guard()->FreeThreadResources();
314 5918 : isolate_->regexp_stack()->FreeThreadResources();
315 11836 : isolate_->bootstrapper()->FreeThreadResources();
316 5918 : }
317 :
318 :
319 0 : bool ThreadManager::IsArchived() {
320 0 : Isolate::PerIsolateThreadData* data =
321 0 : isolate_->FindPerThreadDataForThisThread();
322 0 : return data != nullptr && data->thread_state() != nullptr;
323 : }
324 :
325 307250 : void ThreadManager::Iterate(RootVisitor* v) {
326 : // Expecting no threads during serialization/deserialization
327 620844 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
328 : state = state->Next()) {
329 : char* data = state->data();
330 6344 : data = HandleScopeImplementer::Iterate(v, data);
331 6344 : data = isolate_->Iterate(v, data);
332 6344 : data = Relocatable::Iterate(v, data);
333 : }
334 307250 : }
335 :
336 :
337 81225 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
338 215091 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
339 : state = state->Next()) {
340 : char* data = state->data();
341 52641 : data += HandleScopeImplementer::ArchiveSpacePerThread();
342 52641 : isolate_->IterateThread(v, data);
343 : }
344 81225 : }
345 :
346 :
347 0 : ThreadId ThreadManager::CurrentId() {
348 26235 : 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.Equals(state->id())) {
356 : state->set_terminate_on_restore(true);
357 : }
358 : }
359 0 : }
360 :
361 :
362 : } // namespace internal
363 183867 : } // namespace v8
|