1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "api.h" 31 #include "bootstrapper.h" 32 #include "debug.h" 33 #include "execution.h" 34 #include "v8threads.h" 35 #include "regexp-stack.h" 36 37 namespace v8 { 38 39 40 // Track whether this V8 instance has ever called v8::Locker. This allows the 41 // API code to verify that the lock is always held when V8 is being entered. 42 bool Locker::active_ = false; 43 44 45 Locker::Locker() { 46 Initialize(i::Isolate::GetDefaultIsolateForLocking()); 47 } 48 49 50 // Once the Locker is initialized, the current thread will be guaranteed to have 51 // the lock for a given isolate. 52 void Locker::Initialize(v8::Isolate* isolate) { 53 ASSERT(isolate != NULL); 54 has_lock_= false; 55 top_level_ = true; 56 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 57 // Record that the Locker has been used at least once. 58 active_ = true; 59 // Get the big lock if necessary. 60 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 61 isolate_->thread_manager()->Lock(); 62 has_lock_ = true; 63 64 // Make sure that V8 is initialized. Archiving of threads interferes 65 // with deserialization by adding additional root pointers, so we must 66 // initialize here, before anyone can call ~Locker() or Unlocker(). 67 if (!isolate_->IsInitialized()) { 68 isolate_->Enter(); 69 V8::Initialize(); 70 isolate_->Exit(); 71 } 72 73 // This may be a locker within an unlocker in which case we have to 74 // get the saved state for this thread and restore it. 75 if (isolate_->thread_manager()->RestoreThread()) { 76 top_level_ = false; 77 } else { 78 internal::ExecutionAccess access(isolate_); 79 isolate_->stack_guard()->ClearThread(access); 80 isolate_->stack_guard()->InitThread(access); 81 } 82 if (isolate_->IsDefaultIsolate()) { 83 // This only enters if not yet entered. 84 internal::Isolate::EnterDefaultIsolate(); 85 } 86 } 87 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 88 } 89 90 91 bool Locker::IsLocked(v8::Isolate* isolate) { 92 ASSERT(isolate != NULL); 93 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 94 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 95 } 96 97 98 bool Locker::IsActive() { 99 return active_; 100 } 101 102 103 Locker::~Locker() { 104 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 105 if (has_lock_) { 106 if (isolate_->IsDefaultIsolate()) { 107 isolate_->Exit(); 108 } 109 if (top_level_) { 110 isolate_->thread_manager()->FreeThreadResources(); 111 } else { 112 isolate_->thread_manager()->ArchiveThread(); 113 } 114 isolate_->thread_manager()->Unlock(); 115 } 116 } 117 118 119 Unlocker::Unlocker() { 120 Initialize(i::Isolate::GetDefaultIsolateForLocking()); 121 } 122 123 124 void Unlocker::Initialize(v8::Isolate* isolate) { 125 ASSERT(isolate != NULL); 126 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 127 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 128 if (isolate_->IsDefaultIsolate()) { 129 isolate_->Exit(); 130 } 131 isolate_->thread_manager()->ArchiveThread(); 132 isolate_->thread_manager()->Unlock(); 133 } 134 135 136 Unlocker::~Unlocker() { 137 ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread()); 138 isolate_->thread_manager()->Lock(); 139 isolate_->thread_manager()->RestoreThread(); 140 if (isolate_->IsDefaultIsolate()) { 141 isolate_->Enter(); 142 } 143 } 144 145 146 void Locker::StartPreemption(int every_n_ms) { 147 v8::internal::ContextSwitcher::StartPreemption(every_n_ms); 148 } 149 150 151 void Locker::StopPreemption() { 152 v8::internal::ContextSwitcher::StopPreemption(); 153 } 154 155 156 namespace internal { 157 158 159 bool ThreadManager::RestoreThread() { 160 ASSERT(IsLockedByCurrentThread()); 161 // First check whether the current thread has been 'lazily archived', i.e. 162 // not archived at all. If that is the case we put the state storage we 163 // had prepared back in the free list, since we didn't need it after all. 164 if (lazily_archived_thread_.Equals(ThreadId::Current())) { 165 lazily_archived_thread_ = ThreadId::Invalid(); 166 Isolate::PerIsolateThreadData* per_thread = 167 isolate_->FindPerThreadDataForThisThread(); 168 ASSERT(per_thread != NULL); 169 ASSERT(per_thread->thread_state() == lazily_archived_thread_state_); 170 lazily_archived_thread_state_->set_id(ThreadId::Invalid()); 171 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 172 lazily_archived_thread_state_ = NULL; 173 per_thread->set_thread_state(NULL); 174 return true; 175 } 176 177 // Make sure that the preemption thread cannot modify the thread state while 178 // it is being archived or restored. 179 ExecutionAccess access(isolate_); 180 181 // If there is another thread that was lazily archived then we have to really 182 // archive it now. 183 if (lazily_archived_thread_.IsValid()) { 184 EagerlyArchiveThread(); 185 } 186 Isolate::PerIsolateThreadData* per_thread = 187 isolate_->FindPerThreadDataForThisThread(); 188 if (per_thread == NULL || per_thread->thread_state() == NULL) { 189 // This is a new thread. 190 isolate_->stack_guard()->InitThread(access); 191 return false; 192 } 193 ThreadState* state = per_thread->thread_state(); 194 char* from = state->data(); 195 from = isolate_->handle_scope_implementer()->RestoreThread(from); 196 from = isolate_->RestoreThread(from); 197 from = Relocatable::RestoreState(isolate_, from); 198 #ifdef ENABLE_DEBUGGER_SUPPORT 199 from = isolate_->debug()->RestoreDebug(from); 200 #endif 201 from = isolate_->stack_guard()->RestoreStackGuard(from); 202 from = isolate_->regexp_stack()->RestoreStack(from); 203 from = isolate_->bootstrapper()->RestoreState(from); 204 per_thread->set_thread_state(NULL); 205 if (state->terminate_on_restore()) { 206 isolate_->stack_guard()->TerminateExecution(); 207 state->set_terminate_on_restore(false); 208 } 209 state->set_id(ThreadId::Invalid()); 210 state->Unlink(); 211 state->LinkInto(ThreadState::FREE_LIST); 212 return true; 213 } 214 215 216 void ThreadManager::Lock() { 217 mutex_->Lock(); 218 mutex_owner_ = ThreadId::Current(); 219 ASSERT(IsLockedByCurrentThread()); 220 } 221 222 223 void ThreadManager::Unlock() { 224 mutex_owner_ = ThreadId::Invalid(); 225 mutex_->Unlock(); 226 } 227 228 229 static int ArchiveSpacePerThread() { 230 return HandleScopeImplementer::ArchiveSpacePerThread() + 231 Isolate::ArchiveSpacePerThread() + 232 #ifdef ENABLE_DEBUGGER_SUPPORT 233 Debug::ArchiveSpacePerThread() + 234 #endif 235 StackGuard::ArchiveSpacePerThread() + 236 RegExpStack::ArchiveSpacePerThread() + 237 Bootstrapper::ArchiveSpacePerThread() + 238 Relocatable::ArchiveSpacePerThread(); 239 } 240 241 242 ThreadState::ThreadState(ThreadManager* thread_manager) 243 : id_(ThreadId::Invalid()), 244 terminate_on_restore_(false), 245 data_(NULL), 246 next_(this), 247 previous_(this), 248 thread_manager_(thread_manager) { 249 } 250 251 252 ThreadState::~ThreadState() { 253 DeleteArray<char>(data_); 254 } 255 256 257 void ThreadState::AllocateSpace() { 258 data_ = NewArray<char>(ArchiveSpacePerThread()); 259 } 260 261 262 void ThreadState::Unlink() { 263 next_->previous_ = previous_; 264 previous_->next_ = next_; 265 } 266 267 268 void ThreadState::LinkInto(List list) { 269 ThreadState* flying_anchor = 270 list == FREE_LIST ? thread_manager_->free_anchor_ 271 : thread_manager_->in_use_anchor_; 272 next_ = flying_anchor->next_; 273 previous_ = flying_anchor; 274 flying_anchor->next_ = this; 275 next_->previous_ = this; 276 } 277 278 279 ThreadState* ThreadManager::GetFreeThreadState() { 280 ThreadState* gotten = free_anchor_->next_; 281 if (gotten == free_anchor_) { 282 ThreadState* new_thread_state = new ThreadState(this); 283 new_thread_state->AllocateSpace(); 284 return new_thread_state; 285 } 286 return gotten; 287 } 288 289 290 // Gets the first in the list of archived threads. 291 ThreadState* ThreadManager::FirstThreadStateInUse() { 292 return in_use_anchor_->Next(); 293 } 294 295 296 ThreadState* ThreadState::Next() { 297 if (next_ == thread_manager_->in_use_anchor_) return NULL; 298 return next_; 299 } 300 301 302 // Thread ids must start with 1, because in TLS having thread id 0 can't 303 // be distinguished from not having a thread id at all (since NULL is 304 // defined as 0.) 305 ThreadManager::ThreadManager() 306 : mutex_(OS::CreateMutex()), 307 mutex_owner_(ThreadId::Invalid()), 308 lazily_archived_thread_(ThreadId::Invalid()), 309 lazily_archived_thread_state_(NULL), 310 free_anchor_(NULL), 311 in_use_anchor_(NULL) { 312 free_anchor_ = new ThreadState(this); 313 in_use_anchor_ = new ThreadState(this); 314 } 315 316 317 ThreadManager::~ThreadManager() { 318 delete mutex_; 319 DeleteThreadStateList(free_anchor_); 320 DeleteThreadStateList(in_use_anchor_); 321 } 322 323 324 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) { 325 // The list starts and ends with the anchor. 326 for (ThreadState* current = anchor->next_; current != anchor;) { 327 ThreadState* next = current->next_; 328 delete current; 329 current = next; 330 } 331 delete anchor; 332 } 333 334 335 void ThreadManager::ArchiveThread() { 336 ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); 337 ASSERT(!IsArchived()); 338 ASSERT(IsLockedByCurrentThread()); 339 ThreadState* state = GetFreeThreadState(); 340 state->Unlink(); 341 Isolate::PerIsolateThreadData* per_thread = 342 isolate_->FindOrAllocatePerThreadDataForThisThread(); 343 per_thread->set_thread_state(state); 344 lazily_archived_thread_ = ThreadId::Current(); 345 lazily_archived_thread_state_ = state; 346 ASSERT(state->id().Equals(ThreadId::Invalid())); 347 state->set_id(CurrentId()); 348 ASSERT(!state->id().Equals(ThreadId::Invalid())); 349 } 350 351 352 void ThreadManager::EagerlyArchiveThread() { 353 ASSERT(IsLockedByCurrentThread()); 354 ThreadState* state = lazily_archived_thread_state_; 355 state->LinkInto(ThreadState::IN_USE_LIST); 356 char* to = state->data(); 357 // Ensure that data containing GC roots are archived first, and handle them 358 // in ThreadManager::Iterate(ObjectVisitor*). 359 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 360 to = isolate_->ArchiveThread(to); 361 to = Relocatable::ArchiveState(isolate_, to); 362 #ifdef ENABLE_DEBUGGER_SUPPORT 363 to = isolate_->debug()->ArchiveDebug(to); 364 #endif 365 to = isolate_->stack_guard()->ArchiveStackGuard(to); 366 to = isolate_->regexp_stack()->ArchiveStack(to); 367 to = isolate_->bootstrapper()->ArchiveState(to); 368 lazily_archived_thread_ = ThreadId::Invalid(); 369 lazily_archived_thread_state_ = NULL; 370 } 371 372 373 void ThreadManager::FreeThreadResources() { 374 isolate_->handle_scope_implementer()->FreeThreadResources(); 375 isolate_->FreeThreadResources(); 376 #ifdef ENABLE_DEBUGGER_SUPPORT 377 isolate_->debug()->FreeThreadResources(); 378 #endif 379 isolate_->stack_guard()->FreeThreadResources(); 380 isolate_->regexp_stack()->FreeThreadResources(); 381 isolate_->bootstrapper()->FreeThreadResources(); 382 } 383 384 385 bool ThreadManager::IsArchived() { 386 Isolate::PerIsolateThreadData* data = 387 isolate_->FindPerThreadDataForThisThread(); 388 return data != NULL && data->thread_state() != NULL; 389 } 390 391 392 void ThreadManager::Iterate(ObjectVisitor* v) { 393 // Expecting no threads during serialization/deserialization 394 for (ThreadState* state = FirstThreadStateInUse(); 395 state != NULL; 396 state = state->Next()) { 397 char* data = state->data(); 398 data = HandleScopeImplementer::Iterate(v, data); 399 data = isolate_->Iterate(v, data); 400 data = Relocatable::Iterate(v, data); 401 } 402 } 403 404 405 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 406 for (ThreadState* state = FirstThreadStateInUse(); 407 state != NULL; 408 state = state->Next()) { 409 char* data = state->data(); 410 data += HandleScopeImplementer::ArchiveSpacePerThread(); 411 isolate_->IterateThread(v, data); 412 } 413 } 414 415 416 ThreadId ThreadManager::CurrentId() { 417 return ThreadId::Current(); 418 } 419 420 421 void ThreadManager::TerminateExecution(ThreadId thread_id) { 422 for (ThreadState* state = FirstThreadStateInUse(); 423 state != NULL; 424 state = state->Next()) { 425 if (thread_id.Equals(state->id())) { 426 state->set_terminate_on_restore(true); 427 } 428 } 429 } 430 431 432 ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms) 433 : Thread("v8:CtxtSwitcher"), 434 keep_going_(true), 435 sleep_ms_(every_n_ms), 436 isolate_(isolate) { 437 } 438 439 440 // Set the scheduling interval of V8 threads. This function starts the 441 // ContextSwitcher thread if needed. 442 void ContextSwitcher::StartPreemption(int every_n_ms) { 443 Isolate* isolate = Isolate::Current(); 444 ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); 445 if (isolate->context_switcher() == NULL) { 446 // If the ContextSwitcher thread is not running at the moment start it now. 447 isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms)); 448 isolate->context_switcher()->Start(); 449 } else { 450 // ContextSwitcher thread is already running, so we just change the 451 // scheduling interval. 452 isolate->context_switcher()->sleep_ms_ = every_n_ms; 453 } 454 } 455 456 457 // Disable preemption of V8 threads. If multiple threads want to use V8 they 458 // must cooperatively schedule amongst them from this point on. 459 void ContextSwitcher::StopPreemption() { 460 Isolate* isolate = Isolate::Current(); 461 ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); 462 if (isolate->context_switcher() != NULL) { 463 // The ContextSwitcher thread is running. We need to stop it and release 464 // its resources. 465 isolate->context_switcher()->keep_going_ = false; 466 // Wait for the ContextSwitcher thread to exit. 467 isolate->context_switcher()->Join(); 468 // Thread has exited, now we can delete it. 469 delete(isolate->context_switcher()); 470 isolate->set_context_switcher(NULL); 471 } 472 } 473 474 475 // Main loop of the ContextSwitcher thread: Preempt the currently running V8 476 // thread at regular intervals. 477 void ContextSwitcher::Run() { 478 while (keep_going_) { 479 OS::Sleep(sleep_ms_); 480 isolate()->stack_guard()->Preempt(); 481 } 482 } 483 484 485 // Acknowledge the preemption by the receiving thread. 486 void ContextSwitcher::PreemptionReceived() { 487 ASSERT(Locker::IsLocked(i::Isolate::GetDefaultIsolateForLocking())); 488 // There is currently no accounting being done for this. But could be in the 489 // future, which is why we leave this in. 490 } 491 492 493 } // namespace internal 494 } // namespace v8 495