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 14 namespace v8 { 15 16 17 namespace { 18 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; 22 23 } // namespace 24 25 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); 30 has_lock_ = false; 31 top_level_ = true; 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(); 38 has_lock_ = true; 39 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()) { 43 top_level_ = false; 44 } else { 45 internal::ExecutionAccess access(isolate_); 46 isolate_->stack_guard()->ClearThread(access); 47 isolate_->stack_guard()->InitThread(access); 48 } 49 } 50 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 51 } 52 53 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(); 58 } 59 60 61 bool Locker::IsActive() { 62 return !!base::NoBarrier_Load(&g_locker_was_ever_used_); 63 } 64 65 66 Locker::~Locker() { 67 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 68 if (has_lock_) { 69 if (top_level_) { 70 isolate_->thread_manager()->FreeThreadResources(); 71 } else { 72 isolate_->thread_manager()->ArchiveThread(); 73 } 74 isolate_->thread_manager()->Unlock(); 75 } 76 } 77 78 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(); 85 } 86 87 88 Unlocker::~Unlocker() { 89 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread()); 90 isolate_->thread_manager()->Lock(); 91 isolate_->thread_manager()->RestoreThread(); 92 } 93 94 95 namespace internal { 96 97 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); 113 return true; 114 } 115 116 // Make sure that the preemption thread cannot modify the thread state while 117 // it is being archived or restored. 118 ExecutionAccess access(isolate_); 119 120 // If there is another thread that was lazily archived then we have to really 121 // archive it now. 122 if (lazily_archived_thread_.IsValid()) { 123 EagerlyArchiveThread(); 124 } 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); 130 return false; 131 } 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); 145 } 146 state->set_id(ThreadId::Invalid()); 147 state->Unlink(); 148 state->LinkInto(ThreadState::FREE_LIST); 149 return true; 150 } 151 152 153 void ThreadManager::Lock() { 154 mutex_.Lock(); 155 mutex_owner_ = ThreadId::Current(); 156 DCHECK(IsLockedByCurrentThread()); 157 } 158 159 160 void ThreadManager::Unlock() { 161 mutex_owner_ = ThreadId::Invalid(); 162 mutex_.Unlock(); 163 } 164 165 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(); 174 } 175 176 177 ThreadState::ThreadState(ThreadManager* thread_manager) 178 : id_(ThreadId::Invalid()), 179 terminate_on_restore_(false), 180 data_(NULL), 181 next_(this), 182 previous_(this), 183 thread_manager_(thread_manager) { 184 } 185 186 187 ThreadState::~ThreadState() { 188 DeleteArray<char>(data_); 189 } 190 191 192 void ThreadState::AllocateSpace() { 193 data_ = NewArray<char>(ArchiveSpacePerThread()); 194 } 195 196 197 void ThreadState::Unlink() { 198 next_->previous_ = previous_; 199 previous_->next_ = next_; 200 } 201 202 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; 211 } 212 213 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; 220 } 221 return gotten; 222 } 223 224 225 // Gets the first in the list of archived threads. 226 ThreadState* ThreadManager::FirstThreadStateInUse() { 227 return in_use_anchor_->Next(); 228 } 229 230 231 ThreadState* ThreadState::Next() { 232 if (next_ == thread_manager_->in_use_anchor_) return NULL; 233 return next_; 234 } 235 236 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 239 // defined as 0.) 240 ThreadManager::ThreadManager() 241 : mutex_owner_(ThreadId::Invalid()), 242 lazily_archived_thread_(ThreadId::Invalid()), 243 lazily_archived_thread_state_(NULL), 244 free_anchor_(NULL), 245 in_use_anchor_(NULL) { 246 free_anchor_ = new ThreadState(this); 247 in_use_anchor_ = new ThreadState(this); 248 } 249 250 251 ThreadManager::~ThreadManager() { 252 DeleteThreadStateList(free_anchor_); 253 DeleteThreadStateList(in_use_anchor_); 254 } 255 256 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_; 261 delete current; 262 current = next; 263 } 264 delete anchor; 265 } 266 267 268 void ThreadManager::ArchiveThread() { 269 DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid())); 270 DCHECK(!IsArchived()); 271 DCHECK(IsLockedByCurrentThread()); 272 ThreadState* state = GetFreeThreadState(); 273 state->Unlink(); 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())); 282 } 283 284 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; 301 } 302 303 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(); 314 } 315 316 317 bool ThreadManager::IsArchived() { 318 Isolate::PerIsolateThreadData* data = 319 isolate_->FindPerThreadDataForThisThread(); 320 return data != NULL && data->thread_state() != NULL; 321 } 322 323 324 void ThreadManager::Iterate(ObjectVisitor* v) { 325 // Expecting no threads during serialization/deserialization 326 for (ThreadState* state = FirstThreadStateInUse(); 327 state != NULL; 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); 333 } 334 } 335 336 337 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 338 for (ThreadState* state = FirstThreadStateInUse(); 339 state != NULL; 340 state = state->Next()) { 341 char* data = state->data(); 342 data += HandleScopeImplementer::ArchiveSpacePerThread(); 343 isolate_->IterateThread(v, data); 344 } 345 } 346 347 348 ThreadId ThreadManager::CurrentId() { 349 return ThreadId::Current(); 350 } 351 352 353 void ThreadManager::TerminateExecution(ThreadId thread_id) { 354 for (ThreadState* state = FirstThreadStateInUse(); 355 state != NULL; 356 state = state->Next()) { 357 if (thread_id.Equals(state->id())) { 358 state->set_terminate_on_restore(true); 359 } 360 } 361 } 362 363 364 } // namespace internal 365 } // namespace v8 366