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/execution/v8threads.h" 6 7#include "include/v8-locker.h" 8#include "src/api/api.h" 9#include "src/debug/debug.h" 10#include "src/execution/execution.h" 11#include "src/execution/isolate-inl.h" 12#include "src/execution/stack-guard.h" 13#include "src/init/bootstrapper.h" 14#include "src/objects/visitors.h" 15#include "src/regexp/regexp-stack.h" 16 17namespace v8 { 18 19namespace { 20 21// Track whether this V8 instance has ever called v8::Locker. This allows the 22// API code to verify that the lock is always held when V8 is being entered. 23base::AtomicWord g_locker_was_ever_used_ = 0; 24 25} // namespace 26 27// Once the Locker is initialized, the current thread will be guaranteed to have 28// the lock for a given isolate. 29void Locker::Initialize(v8::Isolate* isolate) { 30 DCHECK_NOT_NULL(isolate); 31 has_lock_ = false; 32 top_level_ = true; 33 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 34 35 // Record that the Locker has been used at least once. 36 base::Relaxed_Store(&g_locker_was_ever_used_, 1); 37 isolate_->set_was_locker_ever_used(); 38 39 // Get the big lock if necessary. 40 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 41 isolate_->thread_manager()->Lock(); 42 has_lock_ = true; 43 44 // This may be a locker within an unlocker in which case we have to 45 // get the saved state for this thread and restore it. 46 if (isolate_->thread_manager()->RestoreThread()) { 47 top_level_ = false; 48 } 49 } 50 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 51} 52 53bool Locker::IsLocked(v8::Isolate* isolate) { 54 DCHECK_NOT_NULL(isolate); 55 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 56 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 57} 58 59// static 60bool Locker::IsActive() { return WasEverUsed(); } 61 62// static 63bool Locker::WasEverUsed() { 64 return base::Relaxed_Load(&g_locker_was_ever_used_) != 0; 65} 66 67Locker::~Locker() { 68 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 69 if (has_lock_) { 70 if (top_level_) { 71 isolate_->thread_manager()->FreeThreadResources(); 72 } else { 73 isolate_->thread_manager()->ArchiveThread(); 74 } 75 isolate_->thread_manager()->Unlock(); 76 } 77} 78 79void Unlocker::Initialize(v8::Isolate* isolate) { 80 DCHECK_NOT_NULL(isolate); 81 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 82 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 83 isolate_->thread_manager()->ArchiveThread(); 84 isolate_->thread_manager()->Unlock(); 85} 86 87Unlocker::~Unlocker() { 88 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread()); 89 isolate_->thread_manager()->Lock(); 90 isolate_->thread_manager()->RestoreThread(); 91} 92 93namespace internal { 94 95void ThreadManager::InitThread(const ExecutionAccess& lock) { 96 isolate_->InitializeThreadLocal(); 97 isolate_->stack_guard()->InitThread(lock); 98 isolate_->debug()->InitThread(lock); 99} 100 101bool ThreadManager::RestoreThread() { 102 DCHECK(IsLockedByCurrentThread()); 103 // First check whether the current thread has been 'lazily archived', i.e. 104 // not archived at all. If that is the case we put the state storage we 105 // had prepared back in the free list, since we didn't need it after all. 106 if (lazily_archived_thread_ == ThreadId::Current()) { 107 lazily_archived_thread_ = ThreadId::Invalid(); 108 Isolate::PerIsolateThreadData* per_thread = 109 isolate_->FindPerThreadDataForThisThread(); 110 DCHECK_NOT_NULL(per_thread); 111 DCHECK(per_thread->thread_state() == lazily_archived_thread_state_); 112 lazily_archived_thread_state_->set_id(ThreadId::Invalid()); 113 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 114 lazily_archived_thread_state_ = nullptr; 115 per_thread->set_thread_state(nullptr); 116 return true; 117 } 118 119 // Make sure that the preemption thread cannot modify the thread state while 120 // it is being archived or restored. 121 ExecutionAccess access(isolate_); 122 123 // If there is another thread that was lazily archived then we have to really 124 // archive it now. 125 if (lazily_archived_thread_.IsValid()) { 126 EagerlyArchiveThread(); 127 } 128 Isolate::PerIsolateThreadData* per_thread = 129 isolate_->FindPerThreadDataForThisThread(); 130 if (per_thread == nullptr || per_thread->thread_state() == nullptr) { 131 // This is a new thread. 132 InitThread(access); 133 return false; 134 } 135 ThreadState* state = per_thread->thread_state(); 136 char* from = state->data(); 137 from = isolate_->handle_scope_implementer()->RestoreThread(from); 138 from = isolate_->RestoreThread(from); 139 from = Relocatable::RestoreState(isolate_, from); 140 // Stack guard should be restored before Debug, etc. since Debug etc. might 141 // depend on a correct stack guard. 142 from = isolate_->stack_guard()->RestoreStackGuard(from); 143 from = isolate_->debug()->RestoreDebug(from); 144 from = isolate_->regexp_stack()->RestoreStack(from); 145 from = isolate_->bootstrapper()->RestoreState(from); 146 per_thread->set_thread_state(nullptr); 147 state->set_id(ThreadId::Invalid()); 148 state->Unlink(); 149 state->LinkInto(ThreadState::FREE_LIST); 150 return true; 151} 152 153void ThreadManager::Lock() { 154 mutex_.Lock(); 155 mutex_owner_.store(ThreadId::Current(), std::memory_order_relaxed); 156 DCHECK(IsLockedByCurrentThread()); 157} 158 159void ThreadManager::Unlock() { 160 mutex_owner_.store(ThreadId::Invalid(), std::memory_order_relaxed); 161 mutex_.Unlock(); 162} 163 164static int ArchiveSpacePerThread() { 165 return HandleScopeImplementer::ArchiveSpacePerThread() + 166 Isolate::ArchiveSpacePerThread() + Debug::ArchiveSpacePerThread() + 167 StackGuard::ArchiveSpacePerThread() + 168 RegExpStack::ArchiveSpacePerThread() + 169 Bootstrapper::ArchiveSpacePerThread() + 170 Relocatable::ArchiveSpacePerThread(); 171} 172 173ThreadState::ThreadState(ThreadManager* thread_manager) 174 : id_(ThreadId::Invalid()), 175 data_(nullptr), 176 next_(this), 177 previous_(this), 178 thread_manager_(thread_manager) {} 179 180ThreadState::~ThreadState() { DeleteArray<char>(data_); } 181 182void ThreadState::AllocateSpace() { 183 data_ = NewArray<char>(ArchiveSpacePerThread()); 184} 185 186void ThreadState::Unlink() { 187 next_->previous_ = previous_; 188 previous_->next_ = next_; 189} 190 191void ThreadState::LinkInto(List list) { 192 ThreadState* flying_anchor = list == FREE_LIST 193 ? thread_manager_->free_anchor_ 194 : thread_manager_->in_use_anchor_; 195 next_ = flying_anchor->next_; 196 previous_ = flying_anchor; 197 flying_anchor->next_ = this; 198 next_->previous_ = this; 199} 200 201ThreadState* ThreadManager::GetFreeThreadState() { 202 ThreadState* gotten = free_anchor_->next_; 203 if (gotten == free_anchor_) { 204 ThreadState* new_thread_state = new ThreadState(this); 205 new_thread_state->AllocateSpace(); 206 return new_thread_state; 207 } 208 return gotten; 209} 210 211// Gets the first in the list of archived threads. 212ThreadState* ThreadManager::FirstThreadStateInUse() { 213 return in_use_anchor_->Next(); 214} 215 216ThreadState* ThreadState::Next() { 217 if (next_ == thread_manager_->in_use_anchor_) return nullptr; 218 return next_; 219} 220 221// Thread ids must start with 1, because in TLS having thread id 0 can't 222// be distinguished from not having a thread id at all (since NULL is 223// defined as 0.) 224ThreadManager::ThreadManager(Isolate* isolate) 225 : mutex_owner_(ThreadId::Invalid()), 226 lazily_archived_thread_(ThreadId::Invalid()), 227 lazily_archived_thread_state_(nullptr), 228 free_anchor_(nullptr), 229 in_use_anchor_(nullptr), 230 isolate_(isolate) { 231 free_anchor_ = new ThreadState(this); 232 in_use_anchor_ = new ThreadState(this); 233} 234 235ThreadManager::~ThreadManager() { 236 DeleteThreadStateList(free_anchor_); 237 DeleteThreadStateList(in_use_anchor_); 238} 239 240void ThreadManager::DeleteThreadStateList(ThreadState* anchor) { 241 // The list starts and ends with the anchor. 242 for (ThreadState* current = anchor->next_; current != anchor;) { 243 ThreadState* next = current->next_; 244 delete current; 245 current = next; 246 } 247 delete anchor; 248} 249 250void ThreadManager::ArchiveThread() { 251 DCHECK_EQ(lazily_archived_thread_, ThreadId::Invalid()); 252 DCHECK(!IsArchived()); 253 DCHECK(IsLockedByCurrentThread()); 254 ThreadState* state = GetFreeThreadState(); 255 state->Unlink(); 256 Isolate::PerIsolateThreadData* per_thread = 257 isolate_->FindOrAllocatePerThreadDataForThisThread(); 258 per_thread->set_thread_state(state); 259 lazily_archived_thread_ = ThreadId::Current(); 260 lazily_archived_thread_state_ = state; 261 DCHECK_EQ(state->id(), ThreadId::Invalid()); 262 state->set_id(CurrentId()); 263 DCHECK_NE(state->id(), ThreadId::Invalid()); 264} 265 266void ThreadManager::EagerlyArchiveThread() { 267 DCHECK(IsLockedByCurrentThread()); 268 ThreadState* state = lazily_archived_thread_state_; 269 state->LinkInto(ThreadState::IN_USE_LIST); 270 char* to = state->data(); 271 // Ensure that data containing GC roots are archived first, and handle them 272 // in ThreadManager::Iterate(RootVisitor*). 273 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 274 to = isolate_->ArchiveThread(to); 275 to = Relocatable::ArchiveState(isolate_, to); 276 to = isolate_->stack_guard()->ArchiveStackGuard(to); 277 to = isolate_->debug()->ArchiveDebug(to); 278 to = isolate_->regexp_stack()->ArchiveStack(to); 279 to = isolate_->bootstrapper()->ArchiveState(to); 280 lazily_archived_thread_ = ThreadId::Invalid(); 281 lazily_archived_thread_state_ = nullptr; 282} 283 284void ThreadManager::FreeThreadResources() { 285 DCHECK(!isolate_->has_pending_exception()); 286 DCHECK(!isolate_->external_caught_exception()); 287 DCHECK_NULL(isolate_->try_catch_handler()); 288 isolate_->handle_scope_implementer()->FreeThreadResources(); 289 isolate_->FreeThreadResources(); 290 isolate_->debug()->FreeThreadResources(); 291 isolate_->stack_guard()->FreeThreadResources(); 292 isolate_->regexp_stack()->FreeThreadResources(); 293 isolate_->bootstrapper()->FreeThreadResources(); 294} 295 296bool ThreadManager::IsArchived() { 297 Isolate::PerIsolateThreadData* data = 298 isolate_->FindPerThreadDataForThisThread(); 299 return data != nullptr && data->thread_state() != nullptr; 300} 301 302void ThreadManager::Iterate(RootVisitor* v) { 303 // Expecting no threads during serialization/deserialization 304 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr; 305 state = state->Next()) { 306 char* data = state->data(); 307 data = HandleScopeImplementer::Iterate(v, data); 308 data = isolate_->Iterate(v, data); 309 data = Relocatable::Iterate(v, data); 310 data = StackGuard::Iterate(v, data); 311 data = Debug::Iterate(v, data); 312 } 313} 314 315void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 316 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr; 317 state = state->Next()) { 318 char* data = state->data(); 319 data += HandleScopeImplementer::ArchiveSpacePerThread(); 320 isolate_->IterateThread(v, data); 321 } 322} 323 324ThreadId ThreadManager::CurrentId() { return ThreadId::Current(); } 325 326} // namespace internal 327} // namespace v8 328