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/v8.h" 6 7 #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" 13 14 namespace v8 { 15 16 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. 19 bool Locker::active_ = false; 20 21 22 // Once the Locker is initialized, the current thread will be guaranteed to have 23 // the lock for a given isolate. 24 void Locker::Initialize(v8::Isolate* isolate) { 25 DCHECK(isolate != NULL); 26 has_lock_= false; 27 top_level_ = true; 28 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 29 // Record that the Locker has been used at least once. 30 active_ = true; 31 // Get the big lock if necessary. 32 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 33 isolate_->thread_manager()->Lock(); 34 has_lock_ = true; 35 36 // 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(). 39 if (!isolate_->IsInitialized()) { 40 isolate_->Enter(); 41 V8::Initialize(); 42 isolate_->Exit(); 43 } 44 45 // 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. 47 if (isolate_->thread_manager()->RestoreThread()) { 48 top_level_ = false; 49 } else { 50 internal::ExecutionAccess access(isolate_); 51 isolate_->stack_guard()->ClearThread(access); 52 isolate_->stack_guard()->InitThread(access); 53 } 54 } 55 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 56 } 57 58 59 bool Locker::IsLocked(v8::Isolate* isolate) { 60 DCHECK(isolate != NULL); 61 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 62 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 63 } 64 65 66 bool Locker::IsActive() { 67 return active_; 68 } 69 70 71 Locker::~Locker() { 72 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 73 if (has_lock_) { 74 if (top_level_) { 75 isolate_->thread_manager()->FreeThreadResources(); 76 } else { 77 isolate_->thread_manager()->ArchiveThread(); 78 } 79 isolate_->thread_manager()->Unlock(); 80 } 81 } 82 83 84 void Unlocker::Initialize(v8::Isolate* isolate) { 85 DCHECK(isolate != NULL); 86 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 87 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); 88 isolate_->thread_manager()->ArchiveThread(); 89 isolate_->thread_manager()->Unlock(); 90 } 91 92 93 Unlocker::~Unlocker() { 94 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread()); 95 isolate_->thread_manager()->Lock(); 96 isolate_->thread_manager()->RestoreThread(); 97 } 98 99 100 namespace internal { 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(per_thread != NULL); 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_ = NULL; 117 per_thread->set_thread_state(NULL); 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 == NULL || per_thread->thread_state() == NULL) { 133 // This is a new thread. 134 isolate_->stack_guard()->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(NULL); 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 182 ThreadState::ThreadState(ThreadManager* thread_manager) 183 : id_(ThreadId::Invalid()), 184 terminate_on_restore_(false), 185 data_(NULL), 186 next_(this), 187 previous_(this), 188 thread_manager_(thread_manager) { 189 } 190 191 192 ThreadState::~ThreadState() { 193 DeleteArray<char>(data_); 194 } 195 196 197 void ThreadState::AllocateSpace() { 198 data_ = NewArray<char>(ArchiveSpacePerThread()); 199 } 200 201 202 void ThreadState::Unlink() { 203 next_->previous_ = previous_; 204 previous_->next_ = next_; 205 } 206 207 208 void ThreadState::LinkInto(List list) { 209 ThreadState* flying_anchor = 210 list == FREE_LIST ? thread_manager_->free_anchor_ 211 : thread_manager_->in_use_anchor_; 212 next_ = flying_anchor->next_; 213 previous_ = flying_anchor; 214 flying_anchor->next_ = this; 215 next_->previous_ = this; 216 } 217 218 219 ThreadState* ThreadManager::GetFreeThreadState() { 220 ThreadState* gotten = free_anchor_->next_; 221 if (gotten == free_anchor_) { 222 ThreadState* new_thread_state = new ThreadState(this); 223 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. 231 ThreadState* ThreadManager::FirstThreadStateInUse() { 232 return in_use_anchor_->Next(); 233 } 234 235 236 ThreadState* ThreadState::Next() { 237 if (next_ == thread_manager_->in_use_anchor_) return NULL; 238 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.) 245 ThreadManager::ThreadManager() 246 : mutex_owner_(ThreadId::Invalid()), 247 lazily_archived_thread_(ThreadId::Invalid()), 248 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 256 ThreadManager::~ThreadManager() { 257 DeleteThreadStateList(free_anchor_); 258 DeleteThreadStateList(in_use_anchor_); 259 } 260 261 262 void 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; 270 } 271 272 273 void ThreadManager::ArchiveThread() { 274 DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid())); 275 DCHECK(!IsArchived()); 276 DCHECK(IsLockedByCurrentThread()); 277 ThreadState* state = GetFreeThreadState(); 278 state->Unlink(); 279 Isolate::PerIsolateThreadData* per_thread = 280 isolate_->FindOrAllocatePerThreadDataForThisThread(); 281 per_thread->set_thread_state(state); 282 lazily_archived_thread_ = ThreadId::Current(); 283 lazily_archived_thread_state_ = state; 284 DCHECK(state->id().Equals(ThreadId::Invalid())); 285 state->set_id(CurrentId()); 286 DCHECK(!state->id().Equals(ThreadId::Invalid())); 287 } 288 289 290 void ThreadManager::EagerlyArchiveThread() { 291 DCHECK(IsLockedByCurrentThread()); 292 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*). 297 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 298 to = isolate_->ArchiveThread(to); 299 to = Relocatable::ArchiveState(isolate_, to); 300 to = isolate_->debug()->ArchiveDebug(to); 301 to = isolate_->stack_guard()->ArchiveStackGuard(to); 302 to = isolate_->regexp_stack()->ArchiveStack(to); 303 to = isolate_->bootstrapper()->ArchiveState(to); 304 lazily_archived_thread_ = ThreadId::Invalid(); 305 lazily_archived_thread_state_ = NULL; 306 } 307 308 309 void ThreadManager::FreeThreadResources() { 310 DCHECK(!isolate_->has_pending_exception()); 311 DCHECK(!isolate_->external_caught_exception()); 312 DCHECK(isolate_->try_catch_handler() == NULL); 313 isolate_->handle_scope_implementer()->FreeThreadResources(); 314 isolate_->FreeThreadResources(); 315 isolate_->debug()->FreeThreadResources(); 316 isolate_->stack_guard()->FreeThreadResources(); 317 isolate_->regexp_stack()->FreeThreadResources(); 318 isolate_->bootstrapper()->FreeThreadResources(); 319 } 320 321 322 bool ThreadManager::IsArchived() { 323 Isolate::PerIsolateThreadData* data = 324 isolate_->FindPerThreadDataForThisThread(); 325 return data != NULL && data->thread_state() != NULL; 326 } 327 328 329 void ThreadManager::Iterate(ObjectVisitor* v) { 330 // Expecting no threads during serialization/deserialization 331 for (ThreadState* state = FirstThreadStateInUse(); 332 state != NULL; 333 state = state->Next()) { 334 char* data = state->data(); 335 data = HandleScopeImplementer::Iterate(v, data); 336 data = isolate_->Iterate(v, data); 337 data = Relocatable::Iterate(v, data); 338 } 339 } 340 341 342 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 343 for (ThreadState* state = FirstThreadStateInUse(); 344 state != NULL; 345 state = state->Next()) { 346 char* data = state->data(); 347 data += HandleScopeImplementer::ArchiveSpacePerThread(); 348 isolate_->IterateThread(v, data); 349 } 350 } 351 352 353 ThreadId ThreadManager::CurrentId() { 354 return ThreadId::Current(); 355 } 356 357 358 void ThreadManager::TerminateExecution(ThreadId thread_id) { 359 for (ThreadState* state = FirstThreadStateInUse(); 360 state != NULL; 361 state = state->Next()) { 362 if (thread_id.Equals(state->id())) { 363 state->set_terminate_on_restore(true); 364 } 365 } 366 } 367 368 369 } // namespace internal 370 } // namespace v8 371