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.
8 #include "src/bootstrapper.h"
10 #include "src/execution.h"
11 #include "src/regexp-stack.h"
12 #include "src/v8threads.h"
19 // Track whether this V8 instance has ever called v8::Locker. This allows the
20 // API code to verify that the lock is always held when V8 is being entered.
21 base::Atomic32 g_locker_was_ever_used_ = 0;
26 // Once the Locker is initialized, the current thread will be guaranteed to have
27 // the lock for a given isolate.
28 void Locker::Initialize(v8::Isolate* isolate) {
29 DCHECK(isolate != NULL);
32 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
33 // Record that the Locker has been used at least once.
34 base::NoBarrier_Store(&g_locker_was_ever_used_, 1);
35 // Get the big lock if necessary.
36 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
37 isolate_->thread_manager()->Lock();
40 // This may be a locker within an unlocker in which case we have to
41 // get the saved state for this thread and restore it.
42 if (isolate_->thread_manager()->RestoreThread()) {
45 internal::ExecutionAccess access(isolate_);
46 isolate_->stack_guard()->ClearThread(access);
47 isolate_->stack_guard()->InitThread(access);
50 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
54 bool Locker::IsLocked(v8::Isolate* isolate) {
55 DCHECK(isolate != NULL);
56 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
57 return internal_isolate->thread_manager()->IsLockedByCurrentThread();
61 bool Locker::IsActive() {
62 return !!base::NoBarrier_Load(&g_locker_was_ever_used_);
67 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
70 isolate_->thread_manager()->FreeThreadResources();
72 isolate_->thread_manager()->ArchiveThread();
74 isolate_->thread_manager()->Unlock();
79 void Unlocker::Initialize(v8::Isolate* isolate) {
80 DCHECK(isolate != NULL);
81 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
82 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
83 isolate_->thread_manager()->ArchiveThread();
84 isolate_->thread_manager()->Unlock();
88 Unlocker::~Unlocker() {
89 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
90 isolate_->thread_manager()->Lock();
91 isolate_->thread_manager()->RestoreThread();
98 bool ThreadManager::RestoreThread() {
99 DCHECK(IsLockedByCurrentThread());
100 // First check whether the current thread has been 'lazily archived', i.e.
101 // not archived at all. If that is the case we put the state storage we
102 // had prepared back in the free list, since we didn't need it after all.
103 if (lazily_archived_thread_.Equals(ThreadId::Current())) {
104 lazily_archived_thread_ = ThreadId::Invalid();
105 Isolate::PerIsolateThreadData* per_thread =
106 isolate_->FindPerThreadDataForThisThread();
107 DCHECK(per_thread != NULL);
108 DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
109 lazily_archived_thread_state_->set_id(ThreadId::Invalid());
110 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
111 lazily_archived_thread_state_ = NULL;
112 per_thread->set_thread_state(NULL);
116 // Make sure that the preemption thread cannot modify the thread state while
117 // it is being archived or restored.
118 ExecutionAccess access(isolate_);
120 // If there is another thread that was lazily archived then we have to really
122 if (lazily_archived_thread_.IsValid()) {
123 EagerlyArchiveThread();
125 Isolate::PerIsolateThreadData* per_thread =
126 isolate_->FindPerThreadDataForThisThread();
127 if (per_thread == NULL || per_thread->thread_state() == NULL) {
128 // This is a new thread.
129 isolate_->stack_guard()->InitThread(access);
132 ThreadState* state = per_thread->thread_state();
133 char* from = state->data();
134 from = isolate_->handle_scope_implementer()->RestoreThread(from);
135 from = isolate_->RestoreThread(from);
136 from = Relocatable::RestoreState(isolate_, from);
137 from = isolate_->debug()->RestoreDebug(from);
138 from = isolate_->stack_guard()->RestoreStackGuard(from);
139 from = isolate_->regexp_stack()->RestoreStack(from);
140 from = isolate_->bootstrapper()->RestoreState(from);
141 per_thread->set_thread_state(NULL);
142 if (state->terminate_on_restore()) {
143 isolate_->stack_guard()->RequestTerminateExecution();
144 state->set_terminate_on_restore(false);
146 state->set_id(ThreadId::Invalid());
148 state->LinkInto(ThreadState::FREE_LIST);
153 void ThreadManager::Lock() {
155 mutex_owner_ = ThreadId::Current();
156 DCHECK(IsLockedByCurrentThread());
160 void ThreadManager::Unlock() {
161 mutex_owner_ = ThreadId::Invalid();
166 static int ArchiveSpacePerThread() {
167 return HandleScopeImplementer::ArchiveSpacePerThread() +
168 Isolate::ArchiveSpacePerThread() +
169 Debug::ArchiveSpacePerThread() +
170 StackGuard::ArchiveSpacePerThread() +
171 RegExpStack::ArchiveSpacePerThread() +
172 Bootstrapper::ArchiveSpacePerThread() +
173 Relocatable::ArchiveSpacePerThread();
177 ThreadState::ThreadState(ThreadManager* thread_manager)
178 : id_(ThreadId::Invalid()),
179 terminate_on_restore_(false),
183 thread_manager_(thread_manager) {
187 ThreadState::~ThreadState() {
188 DeleteArray<char>(data_);
192 void ThreadState::AllocateSpace() {
193 data_ = NewArray<char>(ArchiveSpacePerThread());
197 void ThreadState::Unlink() {
198 next_->previous_ = previous_;
199 previous_->next_ = next_;
203 void ThreadState::LinkInto(List list) {
204 ThreadState* flying_anchor =
205 list == FREE_LIST ? thread_manager_->free_anchor_
206 : thread_manager_->in_use_anchor_;
207 next_ = flying_anchor->next_;
208 previous_ = flying_anchor;
209 flying_anchor->next_ = this;
210 next_->previous_ = this;
214 ThreadState* ThreadManager::GetFreeThreadState() {
215 ThreadState* gotten = free_anchor_->next_;
216 if (gotten == free_anchor_) {
217 ThreadState* new_thread_state = new ThreadState(this);
218 new_thread_state->AllocateSpace();
219 return new_thread_state;
225 // Gets the first in the list of archived threads.
226 ThreadState* ThreadManager::FirstThreadStateInUse() {
227 return in_use_anchor_->Next();
231 ThreadState* ThreadState::Next() {
232 if (next_ == thread_manager_->in_use_anchor_) return NULL;
237 // Thread ids must start with 1, because in TLS having thread id 0 can't
238 // be distinguished from not having a thread id at all (since NULL is
240 ThreadManager::ThreadManager()
241 : mutex_owner_(ThreadId::Invalid()),
242 lazily_archived_thread_(ThreadId::Invalid()),
243 lazily_archived_thread_state_(NULL),
245 in_use_anchor_(NULL) {
246 free_anchor_ = new ThreadState(this);
247 in_use_anchor_ = new ThreadState(this);
251 ThreadManager::~ThreadManager() {
252 DeleteThreadStateList(free_anchor_);
253 DeleteThreadStateList(in_use_anchor_);
257 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
258 // The list starts and ends with the anchor.
259 for (ThreadState* current = anchor->next_; current != anchor;) {
260 ThreadState* next = current->next_;
268 void ThreadManager::ArchiveThread() {
269 DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
270 DCHECK(!IsArchived());
271 DCHECK(IsLockedByCurrentThread());
272 ThreadState* state = GetFreeThreadState();
274 Isolate::PerIsolateThreadData* per_thread =
275 isolate_->FindOrAllocatePerThreadDataForThisThread();
276 per_thread->set_thread_state(state);
277 lazily_archived_thread_ = ThreadId::Current();
278 lazily_archived_thread_state_ = state;
279 DCHECK(state->id().Equals(ThreadId::Invalid()));
280 state->set_id(CurrentId());
281 DCHECK(!state->id().Equals(ThreadId::Invalid()));
285 void ThreadManager::EagerlyArchiveThread() {
286 DCHECK(IsLockedByCurrentThread());
287 ThreadState* state = lazily_archived_thread_state_;
288 state->LinkInto(ThreadState::IN_USE_LIST);
289 char* to = state->data();
290 // Ensure that data containing GC roots are archived first, and handle them
291 // in ThreadManager::Iterate(ObjectVisitor*).
292 to = isolate_->handle_scope_implementer()->ArchiveThread(to);
293 to = isolate_->ArchiveThread(to);
294 to = Relocatable::ArchiveState(isolate_, to);
295 to = isolate_->debug()->ArchiveDebug(to);
296 to = isolate_->stack_guard()->ArchiveStackGuard(to);
297 to = isolate_->regexp_stack()->ArchiveStack(to);
298 to = isolate_->bootstrapper()->ArchiveState(to);
299 lazily_archived_thread_ = ThreadId::Invalid();
300 lazily_archived_thread_state_ = NULL;
304 void ThreadManager::FreeThreadResources() {
305 DCHECK(!isolate_->has_pending_exception());
306 DCHECK(!isolate_->external_caught_exception());
307 DCHECK(isolate_->try_catch_handler() == NULL);
308 isolate_->handle_scope_implementer()->FreeThreadResources();
309 isolate_->FreeThreadResources();
310 isolate_->debug()->FreeThreadResources();
311 isolate_->stack_guard()->FreeThreadResources();
312 isolate_->regexp_stack()->FreeThreadResources();
313 isolate_->bootstrapper()->FreeThreadResources();
317 bool ThreadManager::IsArchived() {
318 Isolate::PerIsolateThreadData* data =
319 isolate_->FindPerThreadDataForThisThread();
320 return data != NULL && data->thread_state() != NULL;
324 void ThreadManager::Iterate(ObjectVisitor* v) {
325 // Expecting no threads during serialization/deserialization
326 for (ThreadState* state = FirstThreadStateInUse();
328 state = state->Next()) {
329 char* data = state->data();
330 data = HandleScopeImplementer::Iterate(v, data);
331 data = isolate_->Iterate(v, data);
332 data = Relocatable::Iterate(v, data);
337 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
338 for (ThreadState* state = FirstThreadStateInUse();
340 state = state->Next()) {
341 char* data = state->data();
342 data += HandleScopeImplementer::ArchiveSpacePerThread();
343 isolate_->IterateThread(v, data);
348 ThreadId ThreadManager::CurrentId() {
349 return ThreadId::Current();
353 void ThreadManager::TerminateExecution(ThreadId thread_id) {
354 for (ThreadState* state = FirstThreadStateInUse();
356 state = state->Next()) {
357 if (thread_id.Equals(state->id())) {
358 state->set_terminate_on_restore(true);
364 } // namespace internal