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 8423 : void Locker::Initialize(v8::Isolate* isolate) {
30 : DCHECK_NOT_NULL(isolate);
31 8423 : has_lock_ = false;
32 8423 : top_level_ = true;
33 8423 : 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 28157 : if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
38 13824 : isolate_->thread_manager()->Lock();
39 6916 : 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 13832 : if (isolate_->thread_manager()->RestoreThread()) {
44 1010 : top_level_ = false;
45 : } else {
46 5906 : internal::ExecutionAccess access(isolate_);
47 5906 : isolate_->stack_guard()->ClearThread(access);
48 11812 : isolate_->thread_manager()->InitThread(access);
49 : }
50 : }
51 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
52 8427 : }
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 444242614 : bool Locker::IsActive() {
63 444242614 : return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 : }
65 :
66 :
67 8427 : Locker::~Locker() {
68 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
69 8427 : if (has_lock_) {
70 6916 : if (top_level_) {
71 13832 : isolate_->thread_manager()->FreeThreadResources();
72 : } else {
73 2020 : isolate_->thread_manager()->ArchiveThread();
74 : }
75 13832 : isolate_->thread_manager()->Unlock();
76 : }
77 8427 : }
78 :
79 :
80 24312 : void Unlocker::Initialize(v8::Isolate* isolate) {
81 : DCHECK_NOT_NULL(isolate);
82 24312 : isolate_ = reinterpret_cast<i::Isolate*>(isolate);
83 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
84 48624 : isolate_->thread_manager()->ArchiveThread();
85 48624 : isolate_->thread_manager()->Unlock();
86 24312 : }
87 :
88 :
89 24312 : Unlocker::~Unlocker() {
90 : DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
91 48624 : isolate_->thread_manager()->Lock();
92 48624 : isolate_->thread_manager()->RestoreThread();
93 24312 : }
94 :
95 :
96 : namespace internal {
97 :
98 11812 : void ThreadManager::InitThread(const ExecutionAccess& lock) {
99 23624 : isolate_->stack_guard()->InitThread(lock);
100 11812 : isolate_->debug()->InitThread(lock);
101 11812 : }
102 :
103 31228 : 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 62456 : if (lazily_archived_thread_.Equals(ThreadId::Current())) {
109 1925 : lazily_archived_thread_ = ThreadId::Invalid();
110 : Isolate::PerIsolateThreadData* per_thread =
111 95513 : isolate_->FindPerThreadDataForThisThread();
112 : DCHECK_NOT_NULL(per_thread);
113 : DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
114 1925 : lazily_archived_thread_state_->set_id(ThreadId::Invalid());
115 1925 : lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
116 1925 : lazily_archived_thread_state_ = nullptr;
117 : per_thread->set_thread_state(nullptr);
118 1925 : 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 29303 : ExecutionAccess access(isolate_);
124 :
125 : // If there is another thread that was lazily archived then we have to really
126 : // archive it now.
127 29303 : if (lazily_archived_thread_.IsValid()) {
128 23397 : EagerlyArchiveThread();
129 : }
130 47177 : Isolate::PerIsolateThreadData* per_thread =
131 29303 : isolate_->FindPerThreadDataForThisThread();
132 53083 : if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
133 : // This is a new thread.
134 5906 : InitThread(access);
135 5906 : return false;
136 : }
137 46794 : ThreadState* state = per_thread->thread_state();
138 : char* from = state->data();
139 46794 : from = isolate_->handle_scope_implementer()->RestoreThread(from);
140 23397 : from = isolate_->RestoreThread(from);
141 23397 : from = Relocatable::RestoreState(isolate_, from);
142 46794 : from = isolate_->debug()->RestoreDebug(from);
143 23397 : from = isolate_->stack_guard()->RestoreStackGuard(from);
144 46794 : from = isolate_->regexp_stack()->RestoreStack(from);
145 46794 : from = isolate_->bootstrapper()->RestoreState(from);
146 : per_thread->set_thread_state(nullptr);
147 23397 : 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 23397 : return true;
155 : }
156 :
157 :
158 31224 : void ThreadManager::Lock() {
159 31224 : mutex_.Lock();
160 31228 : mutex_owner_ = ThreadId::Current();
161 : DCHECK(IsLockedByCurrentThread());
162 31228 : }
163 :
164 :
165 31228 : void ThreadManager::Unlock() {
166 31228 : mutex_owner_ = ThreadId::Invalid();
167 31228 : mutex_.Unlock();
168 31228 : }
169 :
170 :
171 1144 : static int ArchiveSpacePerThread() {
172 1144 : return HandleScopeImplementer::ArchiveSpacePerThread() +
173 1144 : Isolate::ArchiveSpacePerThread() +
174 1144 : Debug::ArchiveSpacePerThread() +
175 1144 : StackGuard::ArchiveSpacePerThread() +
176 1144 : RegExpStack::ArchiveSpacePerThread() +
177 1144 : Bootstrapper::ArchiveSpacePerThread() +
178 1144 : 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 123242 : thread_manager_(thread_manager) {}
188 :
189 0 : ThreadState::~ThreadState() {
190 123212 : DeleteArray<char>(data_);
191 0 : }
192 :
193 :
194 1144 : void ThreadState::AllocateSpace() {
195 1144 : data_ = NewArray<char>(ArchiveSpacePerThread());
196 1144 : }
197 :
198 :
199 0 : void ThreadState::Unlink() {
200 48719 : next_->previous_ = previous_;
201 48719 : 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 48719 : : thread_manager_->in_use_anchor_;
209 48719 : next_ = flying_anchor->next_;
210 48719 : previous_ = flying_anchor;
211 48719 : flying_anchor->next_ = this;
212 48719 : next_->previous_ = this;
213 0 : }
214 :
215 :
216 25322 : ThreadState* ThreadManager::GetFreeThreadState() {
217 25322 : ThreadState* gotten = free_anchor_->next_;
218 25322 : if (gotten == free_anchor_) {
219 1144 : ThreadState* new_thread_state = new ThreadState(this);
220 1144 : new_thread_state->AllocateSpace();
221 1144 : return new_thread_state;
222 : }
223 : return gotten;
224 : }
225 :
226 :
227 : // Gets the first in the list of archived threads.
228 512 : ThreadState* ThreadManager::FirstThreadStateInUse() {
229 358212 : return in_use_anchor_->Next();
230 : }
231 :
232 :
233 0 : ThreadState* ThreadState::Next() {
234 426071 : 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 61048 : 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 183144 : isolate_(isolate) {
248 122097 : free_anchor_ = new ThreadState(this);
249 122098 : in_use_anchor_ = new ThreadState(this);
250 61049 : }
251 :
252 :
253 122068 : ThreadManager::~ThreadManager() {
254 61034 : DeleteThreadStateList(free_anchor_);
255 61034 : DeleteThreadStateList(in_use_anchor_);
256 61034 : }
257 :
258 :
259 122068 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
260 : // The list starts and ends with the anchor.
261 245280 : for (ThreadState* current = anchor->next_; current != anchor;) {
262 1144 : ThreadState* next = current->next_;
263 2288 : delete current;
264 : current = next;
265 : }
266 244136 : delete anchor;
267 122068 : }
268 :
269 :
270 25322 : void ThreadManager::ArchiveThread() {
271 : DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
272 : DCHECK(!IsArchived());
273 : DCHECK(IsLockedByCurrentThread());
274 25322 : ThreadState* state = GetFreeThreadState();
275 : state->Unlink();
276 : Isolate::PerIsolateThreadData* per_thread =
277 25322 : isolate_->FindOrAllocatePerThreadDataForThisThread();
278 : per_thread->set_thread_state(state);
279 25322 : lazily_archived_thread_ = ThreadId::Current();
280 25322 : 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 25322 : }
285 :
286 :
287 23397 : void ThreadManager::EagerlyArchiveThread() {
288 : DCHECK(IsLockedByCurrentThread());
289 46794 : 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 93588 : to = isolate_->handle_scope_implementer()->ArchiveThread(to);
295 23397 : to = isolate_->ArchiveThread(to);
296 23397 : to = Relocatable::ArchiveState(isolate_, to);
297 46794 : to = isolate_->debug()->ArchiveDebug(to);
298 23397 : to = isolate_->stack_guard()->ArchiveStackGuard(to);
299 46794 : to = isolate_->regexp_stack()->ArchiveStack(to);
300 46794 : to = isolate_->bootstrapper()->ArchiveState(to);
301 23397 : lazily_archived_thread_ = ThreadId::Invalid();
302 23397 : lazily_archived_thread_state_ = nullptr;
303 23397 : }
304 :
305 :
306 5906 : void ThreadManager::FreeThreadResources() {
307 : DCHECK(!isolate_->has_pending_exception());
308 : DCHECK(!isolate_->external_caught_exception());
309 : DCHECK_NULL(isolate_->try_catch_handler());
310 17718 : isolate_->handle_scope_implementer()->FreeThreadResources();
311 5906 : isolate_->FreeThreadResources();
312 : isolate_->debug()->FreeThreadResources();
313 5906 : isolate_->stack_guard()->FreeThreadResources();
314 5906 : isolate_->regexp_stack()->FreeThreadResources();
315 11812 : isolate_->bootstrapper()->FreeThreadResources();
316 5906 : }
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 280837 : void ThreadManager::Iterate(RootVisitor* v) {
326 : // Expecting no threads during serialization/deserialization
327 566854 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
328 : state = state->Next()) {
329 : char* data = state->data();
330 5180 : data = HandleScopeImplementer::Iterate(v, data);
331 5180 : data = isolate_->Iterate(v, data);
332 5180 : data = Relocatable::Iterate(v, data);
333 : }
334 280837 : }
335 :
336 :
337 76351 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
338 215893 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
339 : state = state->Next()) {
340 : char* data = state->data();
341 63191 : data += HandleScopeImplementer::ArchiveSpacePerThread();
342 63191 : isolate_->IterateThread(v, data);
343 : }
344 76351 : }
345 :
346 :
347 0 : ThreadId ThreadManager::CurrentId() {
348 25322 : 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 178779 : } // namespace v8
|