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 void 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 // 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 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 38 isolate_->thread_manager()->Lock(); 39 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 if (isolate_->thread_manager()->RestoreThread()) { 44 top_level_ = false; 45 } else { 46 internal::ExecutionAccess access(isolate_); 47 isolate_->stack_guard()->ClearThread(access); 48 isolate_->thread_manager()->InitThread(access); 49 } 50 } 51 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 52 } 53 54 55 bool Locker::IsLocked(v8::Isolate* isolate) { 56 DCHECK_NOT_NULL(isolate); 57 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 58 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 59 } 60 61 62 bool Locker::IsActive() { 63 return !!base::Relaxed_Load(&g_locker_was_ever_used_); 64 } 65 66 67 Locker::~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 79 80 void Unlocker::Initialize(v8::Isolate* isolate) { 81 DCHECK_NOT_NULL(isolate); 82 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 83 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 84 isolate_->thread_manager()->ArchiveThread(); 85 isolate_->thread_manager()->Unlock(); 86 } 87 88 89 Unlocker::~Unlocker() { 90 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread()); 91 isolate_->thread_manager()->Lock(); 92 isolate_->thread_manager()->RestoreThread(); 93 } 94 95 96 namespace internal { 97 98 void ThreadManager::InitThread(const ExecutionAccess& lock) { 99 isolate_->stack_guard()->InitThread(lock); 100 isolate_->debug()->InitThread(lock); 101 } 102 103 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 if (lazily_archived_thread_.Equals(ThreadId::Current())) { 109 lazily_archived_thread_ = ThreadId::Invalid(); 110 Isolate::PerIsolateThreadData* per_thread = 111 isolate_->FindPerThreadDataForThisThread(); 112 DCHECK_NOT_NULL(per_thread); 113 DCHECK(per_thread->thread_state() == lazily_archived_thread_state_); 114 lazily_archived_thread_state_->set_id(ThreadId::Invalid()); 115 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 116 lazily_archived_thread_state_ = nullptr; 117 per_thread->set_thread_state(nullptr); 118 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 ExecutionAccess access(isolate_); 124 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 } 130 Isolate::PerIsolateThreadData* per_thread = 131 isolate_->FindPerThreadDataForThisThread(); 132 if (per_thread == nullptr || per_thread->thread_state() == nullptr) { 133 // This is a new thread. 134 InitThread(access); 135 return false; 136 } 137 ThreadState* state = per_thread->thread_state(); 138 char* from = state->data(); 139 from = isolate_->handle_scope_implementer()->RestoreThread(from); 140 from = isolate_->RestoreThread(from); 141 from = Relocatable::RestoreState(isolate_, from); 142 from = isolate_->debug()->RestoreDebug(from); 143 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(nullptr); 147 if (state->terminate_on_restore()) { 148 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 return true; 155 } 156 157 158 void ThreadManager::Lock() { 159 mutex_.Lock(); 160 mutex_owner_ = ThreadId::Current(); 161 DCHECK(IsLockedByCurrentThread()); 162 } 163 164 165 void ThreadManager::Unlock() { 166 mutex_owner_ = ThreadId::Invalid(); 167 mutex_.Unlock(); 168 } 169 170 171 static int ArchiveSpacePerThread() { 172 return HandleScopeImplementer::ArchiveSpacePerThread() + 173 Isolate::ArchiveSpacePerThread() + 174 Debug::ArchiveSpacePerThread() + 175 StackGuard::ArchiveSpacePerThread() + 176 RegExpStack::ArchiveSpacePerThread() + 177 Bootstrapper::ArchiveSpacePerThread() + 178 Relocatable::ArchiveSpacePerThread(); 179 } 180 181 ThreadState::ThreadState(ThreadManager* thread_manager) 182 : id_(ThreadId::Invalid()), 183 terminate_on_restore_(false), 184 data_(nullptr), 185 next_(this), 186 previous_(this), 187 thread_manager_(thread_manager) {} 188 189 ThreadState::~ThreadState() { 190 DeleteArray<char>(data_); 191 } 192 193 194 void ThreadState::AllocateSpace() { 195 data_ = NewArray<char>(ArchiveSpacePerThread()); 196 } 197 198 199 void ThreadState::Unlink() { 200 next_->previous_ = previous_; 201 previous_->next_ = next_; 202 } 203 204 205 void ThreadState::LinkInto(List list) { 206 ThreadState* flying_anchor = 207 list == FREE_LIST ? thread_manager_->free_anchor_ 208 : thread_manager_->in_use_anchor_; 209 next_ = flying_anchor->next_; 210 previous_ = flying_anchor; 211 flying_anchor->next_ = this; 212 next_->previous_ = this; 213 } 214 215 216 ThreadState* ThreadManager::GetFreeThreadState() { 217 ThreadState* gotten = free_anchor_->next_; 218 if (gotten == free_anchor_) { 219 ThreadState* new_thread_state = new ThreadState(this); 220 new_thread_state->AllocateSpace(); 221 return new_thread_state; 222 } 223 return gotten; 224 } 225 226 227 // Gets the first in the list of archived threads. 228 ThreadState* ThreadManager::FirstThreadStateInUse() { 229 return in_use_anchor_->Next(); 230 } 231 232 233 ThreadState* ThreadState::Next() { 234 if (next_ == thread_manager_->in_use_anchor_) return nullptr; 235 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 ThreadManager::ThreadManager() 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 free_anchor_ = new ThreadState(this); 248 in_use_anchor_ = new ThreadState(this); 249 } 250 251 252 ThreadManager::~ThreadManager() { 253 DeleteThreadStateList(free_anchor_); 254 DeleteThreadStateList(in_use_anchor_); 255 } 256 257 258 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) { 259 // The list starts and ends with the anchor. 260 for (ThreadState* current = anchor->next_; current != anchor;) { 261 ThreadState* next = current->next_; 262 delete current; 263 current = next; 264 } 265 delete anchor; 266 } 267 268 269 void ThreadManager::ArchiveThread() { 270 DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid())); 271 DCHECK(!IsArchived()); 272 DCHECK(IsLockedByCurrentThread()); 273 ThreadState* state = GetFreeThreadState(); 274 state->Unlink(); 275 Isolate::PerIsolateThreadData* per_thread = 276 isolate_->FindOrAllocatePerThreadDataForThisThread(); 277 per_thread->set_thread_state(state); 278 lazily_archived_thread_ = ThreadId::Current(); 279 lazily_archived_thread_state_ = state; 280 DCHECK(state->id().Equals(ThreadId::Invalid())); 281 state->set_id(CurrentId()); 282 DCHECK(!state->id().Equals(ThreadId::Invalid())); 283 } 284 285 286 void ThreadManager::EagerlyArchiveThread() { 287 DCHECK(IsLockedByCurrentThread()); 288 ThreadState* state = lazily_archived_thread_state_; 289 state->LinkInto(ThreadState::IN_USE_LIST); 290 char* to = state->data(); 291 // Ensure that data containing GC roots are archived first, and handle them 292 // in ThreadManager::Iterate(RootVisitor*). 293 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 294 to = isolate_->ArchiveThread(to); 295 to = Relocatable::ArchiveState(isolate_, to); 296 to = isolate_->debug()->ArchiveDebug(to); 297 to = isolate_->stack_guard()->ArchiveStackGuard(to); 298 to = isolate_->regexp_stack()->ArchiveStack(to); 299 to = isolate_->bootstrapper()->ArchiveState(to); 300 lazily_archived_thread_ = ThreadId::Invalid(); 301 lazily_archived_thread_state_ = nullptr; 302 } 303 304 305 void ThreadManager::FreeThreadResources() { 306 DCHECK(!isolate_->has_pending_exception()); 307 DCHECK(!isolate_->external_caught_exception()); 308 DCHECK_NULL(isolate_->try_catch_handler()); 309 isolate_->handle_scope_implementer()->FreeThreadResources(); 310 isolate_->FreeThreadResources(); 311 isolate_->debug()->FreeThreadResources(); 312 isolate_->stack_guard()->FreeThreadResources(); 313 isolate_->regexp_stack()->FreeThreadResources(); 314 isolate_->bootstrapper()->FreeThreadResources(); 315 } 316 317 318 bool ThreadManager::IsArchived() { 319 Isolate::PerIsolateThreadData* data = 320 isolate_->FindPerThreadDataForThisThread(); 321 return data != nullptr && data->thread_state() != nullptr; 322 } 323 324 void ThreadManager::Iterate(RootVisitor* v) { 325 // Expecting no threads during serialization/deserialization 326 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr; 327 state = state->Next()) { 328 char* data = state->data(); 329 data = HandleScopeImplementer::Iterate(v, data); 330 data = isolate_->Iterate(v, data); 331 data = Relocatable::Iterate(v, data); 332 } 333 } 334 335 336 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 337 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr; 338 state = state->Next()) { 339 char* data = state->data(); 340 data += HandleScopeImplementer::ArchiveSpacePerThread(); 341 isolate_->IterateThread(v, data); 342 } 343 } 344 345 346 ThreadId ThreadManager::CurrentId() { 347 return ThreadId::Current(); 348 } 349 350 351 void ThreadManager::TerminateExecution(ThreadId thread_id) { 352 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr; 353 state = state->Next()) { 354 if (thread_id.Equals(state->id())) { 355 state->set_terminate_on_restore(true); 356 } 357 } 358 } 359 360 361 } // namespace internal 362 } // namespace v8 363