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/v8threads.h" 12 #include "src/regexp-stack.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 ASSERT(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 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 56 } 57 58 59 bool Locker::IsLocked(v8::Isolate* isolate) { 60 ASSERT(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 ASSERT(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 ASSERT(isolate != NULL); 86 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 87 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 88 isolate_->thread_manager()->ArchiveThread(); 89 isolate_->thread_manager()->Unlock(); 90 } 91 92 93 Unlocker::~Unlocker() { 94 ASSERT(!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 ASSERT(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 ASSERT(per_thread != NULL); 113 ASSERT(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 ASSERT(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 ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); 275 ASSERT(!IsArchived()); 276 ASSERT(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 ASSERT(state->id().Equals(ThreadId::Invalid())); 285 state->set_id(CurrentId()); 286 ASSERT(!state->id().Equals(ThreadId::Invalid())); 287 } 288 289 290 void ThreadManager::EagerlyArchiveThread() { 291 ASSERT(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 isolate_->handle_scope_implementer()->FreeThreadResources(); 311 isolate_->FreeThreadResources(); 312 isolate_->debug()->FreeThreadResources(); 313 isolate_->stack_guard()->FreeThreadResources(); 314 isolate_->regexp_stack()->FreeThreadResources(); 315 isolate_->bootstrapper()->FreeThreadResources(); 316 } 317 318 319 bool ThreadManager::IsArchived() { 320 Isolate::PerIsolateThreadData* data = 321 isolate_->FindPerThreadDataForThisThread(); 322 return data != NULL && data->thread_state() != NULL; 323 } 324 325 326 void ThreadManager::Iterate(ObjectVisitor* v) { 327 // Expecting no threads during serialization/deserialization 328 for (ThreadState* state = FirstThreadStateInUse(); 329 state != NULL; 330 state = state->Next()) { 331 char* data = state->data(); 332 data = HandleScopeImplementer::Iterate(v, data); 333 data = isolate_->Iterate(v, data); 334 data = Relocatable::Iterate(v, data); 335 } 336 } 337 338 339 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 340 for (ThreadState* state = FirstThreadStateInUse(); 341 state != NULL; 342 state = state->Next()) { 343 char* data = state->data(); 344 data += HandleScopeImplementer::ArchiveSpacePerThread(); 345 isolate_->IterateThread(v, data); 346 } 347 } 348 349 350 ThreadId ThreadManager::CurrentId() { 351 return ThreadId::Current(); 352 } 353 354 355 void ThreadManager::TerminateExecution(ThreadId thread_id) { 356 for (ThreadState* state = FirstThreadStateInUse(); 357 state != NULL; 358 state = state->Next()) { 359 if (thread_id.Equals(state->id())) { 360 state->set_terminate_on_restore(true); 361 } 362 } 363 } 364 365 366 } // namespace internal 367 } // namespace v8 368