1 // Copyright 2008 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 // Constructor for the Locker object. Once the Locker is constructed the 46 // current thread will be guaranteed to have the lock for a given isolate. 47 Locker::Locker(v8::Isolate* isolate) 48 : has_lock_(false), 49 top_level_(true), 50 isolate_(reinterpret_cast<i::Isolate*>(isolate)) { 51 if (isolate_ == NULL) { 52 isolate_ = i::Isolate::GetDefaultIsolateForLocking(); 53 } 54 // Record that the Locker has been used at least once. 55 active_ = true; 56 // Get the big lock if necessary. 57 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 58 isolate_->thread_manager()->Lock(); 59 has_lock_ = true; 60 61 // Make sure that V8 is initialized. Archiving of threads interferes 62 // with deserialization by adding additional root pointers, so we must 63 // initialize here, before anyone can call ~Locker() or Unlocker(). 64 if (!isolate_->IsInitialized()) { 65 isolate_->Enter(); 66 V8::Initialize(); 67 isolate_->Exit(); 68 } 69 70 // This may be a locker within an unlocker in which case we have to 71 // get the saved state for this thread and restore it. 72 if (isolate_->thread_manager()->RestoreThread()) { 73 top_level_ = false; 74 } else { 75 internal::ExecutionAccess access(isolate_); 76 isolate_->stack_guard()->ClearThread(access); 77 isolate_->stack_guard()->InitThread(access); 78 } 79 if (isolate_->IsDefaultIsolate()) { 80 // This only enters if not yet entered. 81 internal::Isolate::EnterDefaultIsolate(); 82 } 83 } 84 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 85 } 86 87 88 bool Locker::IsLocked(v8::Isolate* isolate) { 89 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 90 if (internal_isolate == NULL) { 91 internal_isolate = i::Isolate::GetDefaultIsolateForLocking(); 92 } 93 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 94 } 95 96 97 bool Locker::IsActive() { 98 return active_; 99 } 100 101 102 Locker::~Locker() { 103 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 104 if (has_lock_) { 105 if (isolate_->IsDefaultIsolate()) { 106 isolate_->Exit(); 107 } 108 if (top_level_) { 109 isolate_->thread_manager()->FreeThreadResources(); 110 } else { 111 isolate_->thread_manager()->ArchiveThread(); 112 } 113 isolate_->thread_manager()->Unlock(); 114 } 115 } 116 117 118 Unlocker::Unlocker(v8::Isolate* isolate) 119 : isolate_(reinterpret_cast<i::Isolate*>(isolate)) { 120 if (isolate_ == NULL) { 121 isolate_ = i::Isolate::GetDefaultIsolateForLocking(); 122 } 123 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 124 if (isolate_->IsDefaultIsolate()) { 125 isolate_->Exit(); 126 } 127 isolate_->thread_manager()->ArchiveThread(); 128 isolate_->thread_manager()->Unlock(); 129 } 130 131 132 Unlocker::~Unlocker() { 133 ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread()); 134 isolate_->thread_manager()->Lock(); 135 isolate_->thread_manager()->RestoreThread(); 136 if (isolate_->IsDefaultIsolate()) { 137 isolate_->Enter(); 138 } 139 } 140 141 142 void Locker::StartPreemption(int every_n_ms) { 143 v8::internal::ContextSwitcher::StartPreemption(every_n_ms); 144 } 145 146 147 void Locker::StopPreemption() { 148 v8::internal::ContextSwitcher::StopPreemption(); 149 } 150 151 152 namespace internal { 153 154 155 bool ThreadManager::RestoreThread() { 156 ASSERT(IsLockedByCurrentThread()); 157 // First check whether the current thread has been 'lazily archived', i.e. 158 // not archived at all. If that is the case we put the state storage we 159 // had prepared back in the free list, since we didn't need it after all. 160 if (lazily_archived_thread_.Equals(ThreadId::Current())) { 161 lazily_archived_thread_ = ThreadId::Invalid(); 162 Isolate::PerIsolateThreadData* per_thread = 163 isolate_->FindPerThreadDataForThisThread(); 164 ASSERT(per_thread != NULL); 165 ASSERT(per_thread->thread_state() == lazily_archived_thread_state_); 166 lazily_archived_thread_state_->set_id(ThreadId::Invalid()); 167 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 168 lazily_archived_thread_state_ = NULL; 169 per_thread->set_thread_state(NULL); 170 return true; 171 } 172 173 // Make sure that the preemption thread cannot modify the thread state while 174 // it is being archived or restored. 175 ExecutionAccess access(isolate_); 176 177 // If there is another thread that was lazily archived then we have to really 178 // archive it now. 179 if (lazily_archived_thread_.IsValid()) { 180 EagerlyArchiveThread(); 181 } 182 Isolate::PerIsolateThreadData* per_thread = 183 isolate_->FindPerThreadDataForThisThread(); 184 if (per_thread == NULL || per_thread->thread_state() == NULL) { 185 // This is a new thread. 186 isolate_->stack_guard()->InitThread(access); 187 return false; 188 } 189 ThreadState* state = per_thread->thread_state(); 190 char* from = state->data(); 191 from = isolate_->handle_scope_implementer()->RestoreThread(from); 192 from = isolate_->RestoreThread(from); 193 from = Relocatable::RestoreState(isolate_, from); 194 #ifdef ENABLE_DEBUGGER_SUPPORT 195 from = isolate_->debug()->RestoreDebug(from); 196 #endif 197 from = isolate_->stack_guard()->RestoreStackGuard(from); 198 from = isolate_->regexp_stack()->RestoreStack(from); 199 from = isolate_->bootstrapper()->RestoreState(from); 200 per_thread->set_thread_state(NULL); 201 if (state->terminate_on_restore()) { 202 isolate_->stack_guard()->TerminateExecution(); 203 state->set_terminate_on_restore(false); 204 } 205 state->set_id(ThreadId::Invalid()); 206 state->Unlink(); 207 state->LinkInto(ThreadState::FREE_LIST); 208 return true; 209 } 210 211 212 void ThreadManager::Lock() { 213 mutex_->Lock(); 214 mutex_owner_ = ThreadId::Current(); 215 ASSERT(IsLockedByCurrentThread()); 216 } 217 218 219 void ThreadManager::Unlock() { 220 mutex_owner_ = ThreadId::Invalid(); 221 mutex_->Unlock(); 222 } 223 224 225 static int ArchiveSpacePerThread() { 226 return HandleScopeImplementer::ArchiveSpacePerThread() + 227 Isolate::ArchiveSpacePerThread() + 228 #ifdef ENABLE_DEBUGGER_SUPPORT 229 Debug::ArchiveSpacePerThread() + 230 #endif 231 StackGuard::ArchiveSpacePerThread() + 232 RegExpStack::ArchiveSpacePerThread() + 233 Bootstrapper::ArchiveSpacePerThread() + 234 Relocatable::ArchiveSpacePerThread(); 235 } 236 237 238 ThreadState::ThreadState(ThreadManager* thread_manager) 239 : id_(ThreadId::Invalid()), 240 terminate_on_restore_(false), 241 next_(this), 242 previous_(this), 243 thread_manager_(thread_manager) { 244 } 245 246 247 void ThreadState::AllocateSpace() { 248 data_ = NewArray<char>(ArchiveSpacePerThread()); 249 } 250 251 252 void ThreadState::Unlink() { 253 next_->previous_ = previous_; 254 previous_->next_ = next_; 255 } 256 257 258 void ThreadState::LinkInto(List list) { 259 ThreadState* flying_anchor = 260 list == FREE_LIST ? thread_manager_->free_anchor_ 261 : thread_manager_->in_use_anchor_; 262 next_ = flying_anchor->next_; 263 previous_ = flying_anchor; 264 flying_anchor->next_ = this; 265 next_->previous_ = this; 266 } 267 268 269 ThreadState* ThreadManager::GetFreeThreadState() { 270 ThreadState* gotten = free_anchor_->next_; 271 if (gotten == free_anchor_) { 272 ThreadState* new_thread_state = new ThreadState(this); 273 new_thread_state->AllocateSpace(); 274 return new_thread_state; 275 } 276 return gotten; 277 } 278 279 280 // Gets the first in the list of archived threads. 281 ThreadState* ThreadManager::FirstThreadStateInUse() { 282 return in_use_anchor_->Next(); 283 } 284 285 286 ThreadState* ThreadState::Next() { 287 if (next_ == thread_manager_->in_use_anchor_) return NULL; 288 return next_; 289 } 290 291 292 // Thread ids must start with 1, because in TLS having thread id 0 can't 293 // be distinguished from not having a thread id at all (since NULL is 294 // defined as 0.) 295 ThreadManager::ThreadManager() 296 : mutex_(OS::CreateMutex()), 297 mutex_owner_(ThreadId::Invalid()), 298 lazily_archived_thread_(ThreadId::Invalid()), 299 lazily_archived_thread_state_(NULL), 300 free_anchor_(NULL), 301 in_use_anchor_(NULL) { 302 free_anchor_ = new ThreadState(this); 303 in_use_anchor_ = new ThreadState(this); 304 } 305 306 307 ThreadManager::~ThreadManager() { 308 delete mutex_; 309 delete free_anchor_; 310 delete in_use_anchor_; 311 } 312 313 314 void ThreadManager::ArchiveThread() { 315 ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); 316 ASSERT(!IsArchived()); 317 ASSERT(IsLockedByCurrentThread()); 318 ThreadState* state = GetFreeThreadState(); 319 state->Unlink(); 320 Isolate::PerIsolateThreadData* per_thread = 321 isolate_->FindOrAllocatePerThreadDataForThisThread(); 322 per_thread->set_thread_state(state); 323 lazily_archived_thread_ = ThreadId::Current(); 324 lazily_archived_thread_state_ = state; 325 ASSERT(state->id().Equals(ThreadId::Invalid())); 326 state->set_id(CurrentId()); 327 ASSERT(!state->id().Equals(ThreadId::Invalid())); 328 } 329 330 331 void ThreadManager::EagerlyArchiveThread() { 332 ASSERT(IsLockedByCurrentThread()); 333 ThreadState* state = lazily_archived_thread_state_; 334 state->LinkInto(ThreadState::IN_USE_LIST); 335 char* to = state->data(); 336 // Ensure that data containing GC roots are archived first, and handle them 337 // in ThreadManager::Iterate(ObjectVisitor*). 338 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 339 to = isolate_->ArchiveThread(to); 340 to = Relocatable::ArchiveState(isolate_, to); 341 #ifdef ENABLE_DEBUGGER_SUPPORT 342 to = isolate_->debug()->ArchiveDebug(to); 343 #endif 344 to = isolate_->stack_guard()->ArchiveStackGuard(to); 345 to = isolate_->regexp_stack()->ArchiveStack(to); 346 to = isolate_->bootstrapper()->ArchiveState(to); 347 lazily_archived_thread_ = ThreadId::Invalid(); 348 lazily_archived_thread_state_ = NULL; 349 } 350 351 352 void ThreadManager::FreeThreadResources() { 353 isolate_->handle_scope_implementer()->FreeThreadResources(); 354 isolate_->FreeThreadResources(); 355 #ifdef ENABLE_DEBUGGER_SUPPORT 356 isolate_->debug()->FreeThreadResources(); 357 #endif 358 isolate_->stack_guard()->FreeThreadResources(); 359 isolate_->regexp_stack()->FreeThreadResources(); 360 isolate_->bootstrapper()->FreeThreadResources(); 361 } 362 363 364 bool ThreadManager::IsArchived() { 365 Isolate::PerIsolateThreadData* data = 366 isolate_->FindPerThreadDataForThisThread(); 367 return data != NULL && data->thread_state() != NULL; 368 } 369 370 void ThreadManager::Iterate(ObjectVisitor* v) { 371 // Expecting no threads during serialization/deserialization 372 for (ThreadState* state = FirstThreadStateInUse(); 373 state != NULL; 374 state = state->Next()) { 375 char* data = state->data(); 376 data = HandleScopeImplementer::Iterate(v, data); 377 data = isolate_->Iterate(v, data); 378 data = Relocatable::Iterate(v, data); 379 } 380 } 381 382 383 void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) { 384 for (ThreadState* state = FirstThreadStateInUse(); 385 state != NULL; 386 state = state->Next()) { 387 char* data = state->data(); 388 data += HandleScopeImplementer::ArchiveSpacePerThread(); 389 isolate_->IterateThread(v, data); 390 } 391 } 392 393 394 ThreadId ThreadManager::CurrentId() { 395 return ThreadId::Current(); 396 } 397 398 399 void ThreadManager::TerminateExecution(ThreadId thread_id) { 400 for (ThreadState* state = FirstThreadStateInUse(); 401 state != NULL; 402 state = state->Next()) { 403 if (thread_id.Equals(state->id())) { 404 state->set_terminate_on_restore(true); 405 } 406 } 407 } 408 409 410 ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms) 411 : Thread("v8:CtxtSwitcher"), 412 keep_going_(true), 413 sleep_ms_(every_n_ms), 414 isolate_(isolate) { 415 } 416 417 418 // Set the scheduling interval of V8 threads. This function starts the 419 // ContextSwitcher thread if needed. 420 void ContextSwitcher::StartPreemption(int every_n_ms) { 421 Isolate* isolate = Isolate::Current(); 422 ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); 423 if (isolate->context_switcher() == NULL) { 424 // If the ContextSwitcher thread is not running at the moment start it now. 425 isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms)); 426 isolate->context_switcher()->Start(); 427 } else { 428 // ContextSwitcher thread is already running, so we just change the 429 // scheduling interval. 430 isolate->context_switcher()->sleep_ms_ = every_n_ms; 431 } 432 } 433 434 435 // Disable preemption of V8 threads. If multiple threads want to use V8 they 436 // must cooperatively schedule amongst them from this point on. 437 void ContextSwitcher::StopPreemption() { 438 Isolate* isolate = Isolate::Current(); 439 ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate))); 440 if (isolate->context_switcher() != NULL) { 441 // The ContextSwitcher thread is running. We need to stop it and release 442 // its resources. 443 isolate->context_switcher()->keep_going_ = false; 444 // Wait for the ContextSwitcher thread to exit. 445 isolate->context_switcher()->Join(); 446 // Thread has exited, now we can delete it. 447 delete(isolate->context_switcher()); 448 isolate->set_context_switcher(NULL); 449 } 450 } 451 452 453 // Main loop of the ContextSwitcher thread: Preempt the currently running V8 454 // thread at regular intervals. 455 void ContextSwitcher::Run() { 456 while (keep_going_) { 457 OS::Sleep(sleep_ms_); 458 isolate()->stack_guard()->Preempt(); 459 } 460 } 461 462 463 // Acknowledge the preemption by the receiving thread. 464 void ContextSwitcher::PreemptionReceived() { 465 ASSERT(Locker::IsLocked()); 466 // There is currently no accounting being done for this. But could be in the 467 // future, which is why we leave this in. 468 } 469 470 471 } // namespace internal 472 } // namespace v8 473