blob: a46b289ba1374b9e17dc3e18e823c86214784159 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/api.h"
8#include "src/bootstrapper.h"
9#include "src/debug.h"
10#include "src/execution.h"
11#include "src/regexp-stack.h"
12#include "src/v8threads.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000013
14namespace v8 {
15
Steve Blocka7e24c12009-10-30 11:49:00 +000016
17// Track whether this V8 instance has ever called v8::Locker. This allows the
18// API code to verify that the lock is always held when V8 is being entered.
19bool Locker::active_ = false;
20
21
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022// Once the Locker is initialized, the current thread will be guaranteed to have
23// the lock for a given isolate.
24void Locker::Initialize(v8::Isolate* isolate) {
25 DCHECK(isolate != NULL);
26 has_lock_= false;
27 top_level_ = true;
28 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000029 // Record that the Locker has been used at least once.
30 active_ = true;
31 // Get the big lock if necessary.
Ben Murdoch257744e2011-11-30 15:57:28 +000032 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
33 isolate_->thread_manager()->Lock();
Steve Blocka7e24c12009-10-30 11:49:00 +000034 has_lock_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +010035
Steve Blocka7e24c12009-10-30 11:49:00 +000036 // Make sure that V8 is initialized. Archiving of threads interferes
37 // with deserialization by adding additional root pointers, so we must
38 // initialize here, before anyone can call ~Locker() or Unlocker().
Ben Murdoch257744e2011-11-30 15:57:28 +000039 if (!isolate_->IsInitialized()) {
40 isolate_->Enter();
Steve Blocka7e24c12009-10-30 11:49:00 +000041 V8::Initialize();
Ben Murdoch257744e2011-11-30 15:57:28 +000042 isolate_->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000043 }
Ben Murdoch257744e2011-11-30 15:57:28 +000044
Steve Blocka7e24c12009-10-30 11:49:00 +000045 // This may be a locker within an unlocker in which case we have to
46 // get the saved state for this thread and restore it.
Ben Murdoch257744e2011-11-30 15:57:28 +000047 if (isolate_->thread_manager()->RestoreThread()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000048 top_level_ = false;
49 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +000050 internal::ExecutionAccess access(isolate_);
51 isolate_->stack_guard()->ClearThread(access);
52 isolate_->stack_guard()->InitThread(access);
53 }
Steve Blocka7e24c12009-10-30 11:49:00 +000054 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
Steve Blocka7e24c12009-10-30 11:49:00 +000056}
57
58
Ben Murdoch257744e2011-11-30 15:57:28 +000059bool Locker::IsLocked(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 DCHECK(isolate != NULL);
Ben Murdoch257744e2011-11-30 15:57:28 +000061 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000062 return internal_isolate->thread_manager()->IsLockedByCurrentThread();
Steve Blocka7e24c12009-10-30 11:49:00 +000063}
64
65
Ben Murdoch69a99ed2011-11-30 16:03:39 +000066bool Locker::IsActive() {
67 return active_;
68}
69
70
Steve Blocka7e24c12009-10-30 11:49:00 +000071Locker::~Locker() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
Steve Blocka7e24c12009-10-30 11:49:00 +000073 if (has_lock_) {
Ben Murdoch257744e2011-11-30 15:57:28 +000074 if (top_level_) {
75 isolate_->thread_manager()->FreeThreadResources();
76 } else {
77 isolate_->thread_manager()->ArchiveThread();
78 }
79 isolate_->thread_manager()->Unlock();
Steve Blocka7e24c12009-10-30 11:49:00 +000080 }
81}
82
83
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084void Unlocker::Initialize(v8::Isolate* isolate) {
85 DCHECK(isolate != NULL);
86 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
87 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
Ben Murdoch257744e2011-11-30 15:57:28 +000088 isolate_->thread_manager()->ArchiveThread();
89 isolate_->thread_manager()->Unlock();
Steve Blocka7e24c12009-10-30 11:49:00 +000090}
91
92
93Unlocker::~Unlocker() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
Ben Murdoch257744e2011-11-30 15:57:28 +000095 isolate_->thread_manager()->Lock();
96 isolate_->thread_manager()->RestoreThread();
Steve Blocka7e24c12009-10-30 11:49:00 +000097}
98
99
100namespace internal {
101
102
103bool ThreadManager::RestoreThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 DCHECK(IsLockedByCurrentThread());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100105 // First check whether the current thread has been 'lazily archived', i.e.
Steve Blocka7e24c12009-10-30 11:49:00 +0000106 // 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.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100108 if (lazily_archived_thread_.Equals(ThreadId::Current())) {
109 lazily_archived_thread_ = ThreadId::Invalid();
Ben Murdoch257744e2011-11-30 15:57:28 +0000110 Isolate::PerIsolateThreadData* per_thread =
111 isolate_->FindPerThreadDataForThisThread();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 DCHECK(per_thread != NULL);
113 DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100114 lazily_archived_thread_state_->set_id(ThreadId::Invalid());
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
116 lazily_archived_thread_state_ = NULL;
Ben Murdoch257744e2011-11-30 15:57:28 +0000117 per_thread->set_thread_state(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 return true;
119 }
120
121 // Make sure that the preemption thread cannot modify the thread state while
122 // it is being archived or restored.
Steve Block44f0eee2011-05-26 01:26:41 +0100123 ExecutionAccess access(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
125 // If there is another thread that was lazily archived then we have to really
126 // archive it now.
127 if (lazily_archived_thread_.IsValid()) {
128 EagerlyArchiveThread();
129 }
Steve Block44f0eee2011-05-26 01:26:41 +0100130 Isolate::PerIsolateThreadData* per_thread =
Ben Murdoch257744e2011-11-30 15:57:28 +0000131 isolate_->FindPerThreadDataForThisThread();
Steve Block44f0eee2011-05-26 01:26:41 +0100132 if (per_thread == NULL || per_thread->thread_state() == NULL) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 // This is a new thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100134 isolate_->stack_guard()->InitThread(access);
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 return false;
136 }
Steve Block44f0eee2011-05-26 01:26:41 +0100137 ThreadState* state = per_thread->thread_state();
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 char* from = state->data();
Steve Block44f0eee2011-05-26 01:26:41 +0100139 from = isolate_->handle_scope_implementer()->RestoreThread(from);
140 from = isolate_->RestoreThread(from);
Ben Murdoch257744e2011-11-30 15:57:28 +0000141 from = Relocatable::RestoreState(isolate_, from);
Steve Block44f0eee2011-05-26 01:26:41 +0100142 from = isolate_->debug()->RestoreDebug(from);
Steve Block44f0eee2011-05-26 01:26:41 +0100143 from = isolate_->stack_guard()->RestoreStackGuard(from);
144 from = isolate_->regexp_stack()->RestoreStack(from);
145 from = isolate_->bootstrapper()->RestoreState(from);
146 per_thread->set_thread_state(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 if (state->terminate_on_restore()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 isolate_->stack_guard()->RequestTerminateExecution();
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 state->set_terminate_on_restore(false);
150 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100151 state->set_id(ThreadId::Invalid());
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 state->Unlink();
153 state->LinkInto(ThreadState::FREE_LIST);
154 return true;
155}
156
157
158void ThreadManager::Lock() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 mutex_.Lock();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100160 mutex_owner_ = ThreadId::Current();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 DCHECK(IsLockedByCurrentThread());
Steve Blocka7e24c12009-10-30 11:49:00 +0000162}
163
164
165void ThreadManager::Unlock() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100166 mutex_owner_ = ThreadId::Invalid();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 mutex_.Unlock();
Steve Blocka7e24c12009-10-30 11:49:00 +0000168}
169
170
171static int ArchiveSpacePerThread() {
172 return HandleScopeImplementer::ArchiveSpacePerThread() +
Steve Block44f0eee2011-05-26 01:26:41 +0100173 Isolate::ArchiveSpacePerThread() +
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 Debug::ArchiveSpacePerThread() +
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 StackGuard::ArchiveSpacePerThread() +
176 RegExpStack::ArchiveSpacePerThread() +
177 Bootstrapper::ArchiveSpacePerThread() +
178 Relocatable::ArchiveSpacePerThread();
179}
180
181
Steve Block44f0eee2011-05-26 01:26:41 +0100182ThreadState::ThreadState(ThreadManager* thread_manager)
Ben Murdoch8b112d22011-06-08 16:22:53 +0100183 : id_(ThreadId::Invalid()),
Steve Block44f0eee2011-05-26 01:26:41 +0100184 terminate_on_restore_(false),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 data_(NULL),
Steve Block44f0eee2011-05-26 01:26:41 +0100186 next_(this),
187 previous_(this),
188 thread_manager_(thread_manager) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000189}
190
191
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192ThreadState::~ThreadState() {
193 DeleteArray<char>(data_);
194}
195
196
Steve Blocka7e24c12009-10-30 11:49:00 +0000197void ThreadState::AllocateSpace() {
198 data_ = NewArray<char>(ArchiveSpacePerThread());
199}
200
201
202void ThreadState::Unlink() {
203 next_->previous_ = previous_;
204 previous_->next_ = next_;
205}
206
207
208void ThreadState::LinkInto(List list) {
209 ThreadState* flying_anchor =
Steve Block44f0eee2011-05-26 01:26:41 +0100210 list == FREE_LIST ? thread_manager_->free_anchor_
211 : thread_manager_->in_use_anchor_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 next_ = flying_anchor->next_;
213 previous_ = flying_anchor;
214 flying_anchor->next_ = this;
215 next_->previous_ = this;
216}
217
218
Steve Block44f0eee2011-05-26 01:26:41 +0100219ThreadState* ThreadManager::GetFreeThreadState() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000220 ThreadState* gotten = free_anchor_->next_;
221 if (gotten == free_anchor_) {
Steve Block44f0eee2011-05-26 01:26:41 +0100222 ThreadState* new_thread_state = new ThreadState(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 new_thread_state->AllocateSpace();
224 return new_thread_state;
225 }
226 return gotten;
227}
228
229
230// Gets the first in the list of archived threads.
Steve Block44f0eee2011-05-26 01:26:41 +0100231ThreadState* ThreadManager::FirstThreadStateInUse() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 return in_use_anchor_->Next();
233}
234
235
236ThreadState* ThreadState::Next() {
Steve Block44f0eee2011-05-26 01:26:41 +0100237 if (next_ == thread_manager_->in_use_anchor_) return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 return next_;
239}
240
241
242// Thread ids must start with 1, because in TLS having thread id 0 can't
243// be distinguished from not having a thread id at all (since NULL is
244// defined as 0.)
Steve Block44f0eee2011-05-26 01:26:41 +0100245ThreadManager::ThreadManager()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 : mutex_owner_(ThreadId::Invalid()),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100247 lazily_archived_thread_(ThreadId::Invalid()),
Steve Block44f0eee2011-05-26 01:26:41 +0100248 lazily_archived_thread_state_(NULL),
249 free_anchor_(NULL),
250 in_use_anchor_(NULL) {
251 free_anchor_ = new ThreadState(this);
252 in_use_anchor_ = new ThreadState(this);
253}
254
255
256ThreadManager::~ThreadManager() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 DeleteThreadStateList(free_anchor_);
258 DeleteThreadStateList(in_use_anchor_);
259}
260
261
262void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
263 // The list starts and ends with the anchor.
264 for (ThreadState* current = anchor->next_; current != anchor;) {
265 ThreadState* next = current->next_;
266 delete current;
267 current = next;
268 }
269 delete anchor;
Steve Block44f0eee2011-05-26 01:26:41 +0100270}
Steve Blocka7e24c12009-10-30 11:49:00 +0000271
272
273void ThreadManager::ArchiveThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
275 DCHECK(!IsArchived());
276 DCHECK(IsLockedByCurrentThread());
Steve Block44f0eee2011-05-26 01:26:41 +0100277 ThreadState* state = GetFreeThreadState();
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 state->Unlink();
Ben Murdoch257744e2011-11-30 15:57:28 +0000279 Isolate::PerIsolateThreadData* per_thread =
280 isolate_->FindOrAllocatePerThreadDataForThisThread();
281 per_thread->set_thread_state(state);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100282 lazily_archived_thread_ = ThreadId::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 lazily_archived_thread_state_ = state;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 DCHECK(state->id().Equals(ThreadId::Invalid()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 state->set_id(CurrentId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 DCHECK(!state->id().Equals(ThreadId::Invalid()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000287}
288
289
290void ThreadManager::EagerlyArchiveThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 DCHECK(IsLockedByCurrentThread());
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 ThreadState* state = lazily_archived_thread_state_;
293 state->LinkInto(ThreadState::IN_USE_LIST);
294 char* to = state->data();
295 // Ensure that data containing GC roots are archived first, and handle them
296 // in ThreadManager::Iterate(ObjectVisitor*).
Steve Block44f0eee2011-05-26 01:26:41 +0100297 to = isolate_->handle_scope_implementer()->ArchiveThread(to);
298 to = isolate_->ArchiveThread(to);
Ben Murdoch257744e2011-11-30 15:57:28 +0000299 to = Relocatable::ArchiveState(isolate_, to);
Steve Block44f0eee2011-05-26 01:26:41 +0100300 to = isolate_->debug()->ArchiveDebug(to);
Steve Block44f0eee2011-05-26 01:26:41 +0100301 to = isolate_->stack_guard()->ArchiveStackGuard(to);
302 to = isolate_->regexp_stack()->ArchiveStack(to);
303 to = isolate_->bootstrapper()->ArchiveState(to);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100304 lazily_archived_thread_ = ThreadId::Invalid();
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 lazily_archived_thread_state_ = NULL;
306}
307
308
309void ThreadManager::FreeThreadResources() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 DCHECK(!isolate_->has_pending_exception());
311 DCHECK(!isolate_->external_caught_exception());
312 DCHECK(isolate_->try_catch_handler() == NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100313 isolate_->handle_scope_implementer()->FreeThreadResources();
314 isolate_->FreeThreadResources();
Steve Block44f0eee2011-05-26 01:26:41 +0100315 isolate_->debug()->FreeThreadResources();
Steve Block44f0eee2011-05-26 01:26:41 +0100316 isolate_->stack_guard()->FreeThreadResources();
317 isolate_->regexp_stack()->FreeThreadResources();
318 isolate_->bootstrapper()->FreeThreadResources();
Steve Blocka7e24c12009-10-30 11:49:00 +0000319}
320
321
322bool ThreadManager::IsArchived() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000323 Isolate::PerIsolateThreadData* data =
324 isolate_->FindPerThreadDataForThisThread();
Steve Block44f0eee2011-05-26 01:26:41 +0100325 return data != NULL && data->thread_state() != NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000326}
327
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328
Steve Blocka7e24c12009-10-30 11:49:00 +0000329void ThreadManager::Iterate(ObjectVisitor* v) {
330 // Expecting no threads during serialization/deserialization
Steve Block44f0eee2011-05-26 01:26:41 +0100331 for (ThreadState* state = FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 state != NULL;
333 state = state->Next()) {
334 char* data = state->data();
335 data = HandleScopeImplementer::Iterate(v, data);
Steve Block44f0eee2011-05-26 01:26:41 +0100336 data = isolate_->Iterate(v, data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000337 data = Relocatable::Iterate(v, data);
338 }
339}
340
341
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100342void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +0100343 for (ThreadState* state = FirstThreadStateInUse();
Steve Block6ded16b2010-05-10 14:33:55 +0100344 state != NULL;
345 state = state->Next()) {
346 char* data = state->data();
347 data += HandleScopeImplementer::ArchiveSpacePerThread();
Steve Block44f0eee2011-05-26 01:26:41 +0100348 isolate_->IterateThread(v, data);
Steve Block6ded16b2010-05-10 14:33:55 +0100349 }
350}
351
352
Ben Murdoch8b112d22011-06-08 16:22:53 +0100353ThreadId ThreadManager::CurrentId() {
354 return ThreadId::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +0000355}
356
357
Ben Murdoch8b112d22011-06-08 16:22:53 +0100358void ThreadManager::TerminateExecution(ThreadId thread_id) {
Steve Block44f0eee2011-05-26 01:26:41 +0100359 for (ThreadState* state = FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +0000360 state != NULL;
361 state = state->Next()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100362 if (thread_id.Equals(state->id())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 state->set_terminate_on_restore(true);
364 }
365 }
366}
367
368
Steve Blocka7e24c12009-10-30 11:49:00 +0000369} // namespace internal
370} // namespace v8