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 8355 : void Locker::Initialize(v8::Isolate* isolate) {
30 : DCHECK_NOT_NULL(isolate);
31 8355 : has_lock_ = false;
32 8355 : top_level_ = true;
33 8355 : 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 22074 : if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
38 13706 : isolate_->thread_manager()->Lock();
39 6866 : 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 13732 : if (isolate_->thread_manager()->RestoreThread()) {
44 1010 : top_level_ = false;
45 : } else {
46 5856 : internal::ExecutionAccess access(isolate_);
47 5856 : isolate_->stack_guard()->ClearThread(access);
48 5856 : isolate_->stack_guard()->InitThread(access);
49 : }
50 : }
51 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
52 8378 : }
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 608367614 : bool Locker::IsActive() {
63 608367614 : return !!base::Relaxed_Load(&g_locker_was_ever_used_);
64 : }
65 :
66 :
67 8377 : Locker::~Locker() {
68 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
69 8377 : if (has_lock_) {
70 6866 : if (top_level_) {
71 13732 : isolate_->thread_manager()->FreeThreadResources();
72 : } else {
73 2020 : isolate_->thread_manager()->ArchiveThread();
74 : }
75 13732 : isolate_->thread_manager()->Unlock();
76 : }
77 8377 : }
78 :
79 :
80 25139 : void Unlocker::Initialize(v8::Isolate* isolate) {
81 : DCHECK_NOT_NULL(isolate);
82 25139 : isolate_ = reinterpret_cast<i::Isolate*>(isolate);
83 : DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
84 50278 : isolate_->thread_manager()->ArchiveThread();
85 50278 : isolate_->thread_manager()->Unlock();
86 25139 : }
87 :
88 :
89 25139 : Unlocker::~Unlocker() {
90 : DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
91 50278 : isolate_->thread_manager()->Lock();
92 50278 : isolate_->thread_manager()->RestoreThread();
93 25139 : }
94 :
95 :
96 : namespace internal {
97 :
98 :
99 32005 : 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 64010 : if (lazily_archived_thread_.Equals(ThreadId::Current())) {
105 1986 : lazily_archived_thread_ = ThreadId::Invalid();
106 : Isolate::PerIsolateThreadData* per_thread =
107 98638 : isolate_->FindPerThreadDataForThisThread();
108 : DCHECK_NOT_NULL(per_thread);
109 : DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
110 1986 : lazily_archived_thread_state_->set_id(ThreadId::Invalid());
111 1986 : lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
112 1986 : lazily_archived_thread_state_ = nullptr;
113 : per_thread->set_thread_state(nullptr);
114 1986 : 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 30019 : ExecutionAccess access(isolate_);
120 :
121 : // If there is another thread that was lazily archived then we have to really
122 : // archive it now.
123 30019 : if (lazily_archived_thread_.IsValid()) {
124 24163 : EagerlyArchiveThread();
125 : }
126 48676 : Isolate::PerIsolateThreadData* per_thread =
127 30019 : isolate_->FindPerThreadDataForThisThread();
128 54532 : if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
129 : // This is a new thread.
130 5856 : isolate_->stack_guard()->InitThread(access);
131 5856 : return false;
132 : }
133 48326 : ThreadState* state = per_thread->thread_state();
134 : char* from = state->data();
135 48326 : from = isolate_->handle_scope_implementer()->RestoreThread(from);
136 24163 : from = isolate_->RestoreThread(from);
137 24163 : from = Relocatable::RestoreState(isolate_, from);
138 48326 : from = isolate_->debug()->RestoreDebug(from);
139 24163 : from = isolate_->stack_guard()->RestoreStackGuard(from);
140 48326 : from = isolate_->regexp_stack()->RestoreStack(from);
141 48326 : from = isolate_->bootstrapper()->RestoreState(from);
142 : per_thread->set_thread_state(nullptr);
143 24163 : 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 24163 : return true;
151 : }
152 :
153 :
154 31992 : void ThreadManager::Lock() {
155 31992 : mutex_.Lock();
156 32005 : mutex_owner_ = ThreadId::Current();
157 : DCHECK(IsLockedByCurrentThread());
158 32005 : }
159 :
160 :
161 32005 : void ThreadManager::Unlock() {
162 32005 : mutex_owner_ = ThreadId::Invalid();
163 32005 : mutex_.Unlock();
164 32005 : }
165 :
166 :
167 1118 : static int ArchiveSpacePerThread() {
168 1118 : return HandleScopeImplementer::ArchiveSpacePerThread() +
169 1118 : Isolate::ArchiveSpacePerThread() +
170 1118 : Debug::ArchiveSpacePerThread() +
171 1118 : StackGuard::ArchiveSpacePerThread() +
172 1118 : RegExpStack::ArchiveSpacePerThread() +
173 1118 : Bootstrapper::ArchiveSpacePerThread() +
174 1118 : Relocatable::ArchiveSpacePerThread();
175 : }
176 :
177 0 : ThreadState::ThreadState(ThreadManager* thread_manager)
178 : : id_(ThreadId::Invalid()),
179 : terminate_on_restore_(false),
180 : data_(nullptr),
181 : next_(this),
182 : previous_(this),
183 111116 : thread_manager_(thread_manager) {}
184 :
185 0 : ThreadState::~ThreadState() {
186 107848 : DeleteArray<char>(data_);
187 0 : }
188 :
189 :
190 1118 : void ThreadState::AllocateSpace() {
191 1118 : data_ = NewArray<char>(ArchiveSpacePerThread());
192 1118 : }
193 :
194 :
195 0 : void ThreadState::Unlink() {
196 50312 : next_->previous_ = previous_;
197 50312 : previous_->next_ = next_;
198 0 : }
199 :
200 :
201 0 : void ThreadState::LinkInto(List list) {
202 : ThreadState* flying_anchor =
203 : list == FREE_LIST ? thread_manager_->free_anchor_
204 50312 : : thread_manager_->in_use_anchor_;
205 50312 : next_ = flying_anchor->next_;
206 50312 : previous_ = flying_anchor;
207 50312 : flying_anchor->next_ = this;
208 50312 : next_->previous_ = this;
209 0 : }
210 :
211 :
212 26149 : ThreadState* ThreadManager::GetFreeThreadState() {
213 26149 : ThreadState* gotten = free_anchor_->next_;
214 26149 : if (gotten == free_anchor_) {
215 1118 : ThreadState* new_thread_state = new ThreadState(this);
216 1118 : new_thread_state->AllocateSpace();
217 1118 : return new_thread_state;
218 : }
219 : return gotten;
220 : }
221 :
222 :
223 : // Gets the first in the list of archived threads.
224 161 : ThreadState* ThreadManager::FirstThreadStateInUse() {
225 308090 : return in_use_anchor_->Next();
226 : }
227 :
228 :
229 0 : ThreadState* ThreadState::Next() {
230 406449 : if (next_ == thread_manager_->in_use_anchor_) return nullptr;
231 0 : return next_;
232 : }
233 :
234 : // Thread ids must start with 1, because in TLS having thread id 0 can't
235 : // be distinguished from not having a thread id at all (since NULL is
236 : // defined as 0.)
237 54999 : ThreadManager::ThreadManager()
238 : : mutex_owner_(ThreadId::Invalid()),
239 : lazily_archived_thread_(ThreadId::Invalid()),
240 : lazily_archived_thread_state_(nullptr),
241 : free_anchor_(nullptr),
242 164997 : in_use_anchor_(nullptr) {
243 109998 : free_anchor_ = new ThreadState(this);
244 109998 : in_use_anchor_ = new ThreadState(this);
245 54999 : }
246 :
247 :
248 106730 : ThreadManager::~ThreadManager() {
249 53365 : DeleteThreadStateList(free_anchor_);
250 53365 : DeleteThreadStateList(in_use_anchor_);
251 53365 : }
252 :
253 :
254 106730 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
255 : // The list starts and ends with the anchor.
256 214578 : for (ThreadState* current = anchor->next_; current != anchor;) {
257 1118 : ThreadState* next = current->next_;
258 2236 : delete current;
259 : current = next;
260 : }
261 213460 : delete anchor;
262 106730 : }
263 :
264 :
265 26149 : void ThreadManager::ArchiveThread() {
266 : DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
267 : DCHECK(!IsArchived());
268 : DCHECK(IsLockedByCurrentThread());
269 26149 : ThreadState* state = GetFreeThreadState();
270 : state->Unlink();
271 : Isolate::PerIsolateThreadData* per_thread =
272 26149 : isolate_->FindOrAllocatePerThreadDataForThisThread();
273 : per_thread->set_thread_state(state);
274 26149 : lazily_archived_thread_ = ThreadId::Current();
275 26149 : lazily_archived_thread_state_ = state;
276 : DCHECK(state->id().Equals(ThreadId::Invalid()));
277 : state->set_id(CurrentId());
278 : DCHECK(!state->id().Equals(ThreadId::Invalid()));
279 26149 : }
280 :
281 :
282 24163 : void ThreadManager::EagerlyArchiveThread() {
283 : DCHECK(IsLockedByCurrentThread());
284 48326 : ThreadState* state = lazily_archived_thread_state_;
285 : state->LinkInto(ThreadState::IN_USE_LIST);
286 : char* to = state->data();
287 : // Ensure that data containing GC roots are archived first, and handle them
288 : // in ThreadManager::Iterate(RootVisitor*).
289 96652 : to = isolate_->handle_scope_implementer()->ArchiveThread(to);
290 24163 : to = isolate_->ArchiveThread(to);
291 24163 : to = Relocatable::ArchiveState(isolate_, to);
292 48326 : to = isolate_->debug()->ArchiveDebug(to);
293 24163 : to = isolate_->stack_guard()->ArchiveStackGuard(to);
294 48326 : to = isolate_->regexp_stack()->ArchiveStack(to);
295 48326 : to = isolate_->bootstrapper()->ArchiveState(to);
296 24163 : lazily_archived_thread_ = ThreadId::Invalid();
297 24163 : lazily_archived_thread_state_ = nullptr;
298 24163 : }
299 :
300 :
301 5856 : void ThreadManager::FreeThreadResources() {
302 : DCHECK(!isolate_->has_pending_exception());
303 : DCHECK(!isolate_->external_caught_exception());
304 : DCHECK_NULL(isolate_->try_catch_handler());
305 17568 : isolate_->handle_scope_implementer()->FreeThreadResources();
306 5856 : isolate_->FreeThreadResources();
307 : isolate_->debug()->FreeThreadResources();
308 5856 : isolate_->stack_guard()->FreeThreadResources();
309 5856 : isolate_->regexp_stack()->FreeThreadResources();
310 11712 : isolate_->bootstrapper()->FreeThreadResources();
311 5856 : }
312 :
313 :
314 0 : bool ThreadManager::IsArchived() {
315 0 : Isolate::PerIsolateThreadData* data =
316 0 : isolate_->FindPerThreadDataForThisThread();
317 0 : return data != nullptr && data->thread_state() != nullptr;
318 : }
319 :
320 232423 : void ThreadManager::Iterate(RootVisitor* v) {
321 : // Expecting no threads during serialization/deserialization
322 470840 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
323 : state = state->Next()) {
324 : char* data = state->data();
325 5994 : data = HandleScopeImplementer::Iterate(v, data);
326 5994 : data = isolate_->Iterate(v, data);
327 5994 : data = Relocatable::Iterate(v, data);
328 : }
329 232423 : }
330 :
331 :
332 75345 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
333 243216 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
334 : state = state->Next()) {
335 : char* data = state->data();
336 92526 : data += HandleScopeImplementer::ArchiveSpacePerThread();
337 92526 : isolate_->IterateThread(v, data);
338 : }
339 75345 : }
340 :
341 :
342 0 : ThreadId ThreadManager::CurrentId() {
343 26149 : return ThreadId::Current();
344 : }
345 :
346 :
347 0 : void ThreadManager::TerminateExecution(ThreadId thread_id) {
348 0 : for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
349 : state = state->Next()) {
350 0 : if (thread_id.Equals(state->id())) {
351 : state->set_terminate_on_restore(true);
352 : }
353 : }
354 0 : }
355 :
356 :
357 : } // namespace internal
358 : } // namespace v8
|