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 // Once the Locker is initialized, the current thread will be guaranteed to have 46 // the lock for a given isolate. 47 void Locker::Initialize(v8::Isolate* isolate) { 48 ASSERT(isolate != NULL); 49 has_lock_= false; 50 top_level_ = true; 51 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 52 // Record that the Locker has been used at least once. 53 active_ = true; 54 // Get the big lock if necessary. 55 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { 56 isolate_->thread_manager()->Lock(); 57 has_lock_ = true; 58 59 // Make sure that V8 is initialized. Archiving of threads interferes 60 // with deserialization by adding additional root pointers, so we must 61 // initialize here, before anyone can call ~Locker() or Unlocker(). 62 if (!isolate_->IsInitialized()) { 63 isolate_->Enter(); 64 V8::Initialize(); 65 isolate_->Exit(); 66 } 67 68 // This may be a locker within an unlocker in which case we have to 69 // get the saved state for this thread and restore it. 70 if (isolate_->thread_manager()->RestoreThread()) { 71 top_level_ = false; 72 } else { 73 internal::ExecutionAccess access(isolate_); 74 isolate_->stack_guard()->ClearThread(access); 75 isolate_->stack_guard()->InitThread(access); 76 } 77 if (isolate_->IsDefaultIsolate()) { 78 // This only enters if not yet entered. 79 internal::Isolate::EnterDefaultIsolate(); 80 } 81 } 82 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 83 } 84 85 86 bool Locker::IsLocked(v8::Isolate* isolate) { 87 ASSERT(isolate != NULL); 88 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); 89 return internal_isolate->thread_manager()->IsLockedByCurrentThread(); 90 } 91 92 93 bool Locker::IsActive() { 94 return active_; 95 } 96 97 98 Locker::~Locker() { 99 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 100 if (has_lock_) { 101 if (isolate_->IsDefaultIsolate()) { 102 isolate_->Exit(); 103 } 104 if (top_level_) { 105 isolate_->thread_manager()->FreeThreadResources(); 106 } else { 107 isolate_->thread_manager()->ArchiveThread(); 108 } 109 isolate_->thread_manager()->Unlock(); 110 } 111 } 112 113 114 void Unlocker::Initialize(v8::Isolate* isolate) { 115 ASSERT(isolate != NULL); 116 isolate_ = reinterpret_cast<i::Isolate*>(isolate); 117 ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); 118 if (isolate_->IsDefaultIsolate()) { 119 isolate_->Exit(); 120 } 121 isolate_->thread_manager()->ArchiveThread(); 122 isolate_->thread_manager()->Unlock(); 123 } 124 125 126 Unlocker::~Unlocker() { 127 ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread()); 128 isolate_->thread_manager()->Lock(); 129 isolate_->thread_manager()->RestoreThread(); 130 if (isolate_->IsDefaultIsolate()) { 131 isolate_->Enter(); 132 } 133 } 134 135 136 namespace internal { 137 138 139 bool ThreadManager::RestoreThread() { 140 ASSERT(IsLockedByCurrentThread()); 141 // First check whether the current thread has been 'lazily archived', i.e. 142 // not archived at all. If that is the case we put the state storage we 143 // had prepared back in the free list, since we didn't need it after all. 144 if (lazily_archived_thread_.Equals(ThreadId::Current())) { 145 lazily_archived_thread_ = ThreadId::Invalid(); 146 Isolate::PerIsolateThreadData* per_thread = 147 isolate_->FindPerThreadDataForThisThread(); 148 ASSERT(per_thread != NULL); 149 ASSERT(per_thread->thread_state() == lazily_archived_thread_state_); 150 lazily_archived_thread_state_->set_id(ThreadId::Invalid()); 151 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 152 lazily_archived_thread_state_ = NULL; 153 per_thread->set_thread_state(NULL); 154 return true; 155 } 156 157 // Make sure that the preemption thread cannot modify the thread state while 158 // it is being archived or restored. 159 ExecutionAccess access(isolate_); 160 161 // If there is another thread that was lazily archived then we have to really 162 // archive it now. 163 if (lazily_archived_thread_.IsValid()) { 164 EagerlyArchiveThread(); 165 } 166 Isolate::PerIsolateThreadData* per_thread = 167 isolate_->FindPerThreadDataForThisThread(); 168 if (per_thread == NULL || per_thread->thread_state() == NULL) { 169 // This is a new thread. 170 isolate_->stack_guard()->InitThread(access); 171 return false; 172 } 173 ThreadState* state = per_thread->thread_state(); 174 char* from = state->data(); 175 from = isolate_->handle_scope_implementer()->RestoreThread(from); 176 from = isolate_->RestoreThread(from); 177 from = Relocatable::RestoreState(isolate_, from); 178 #ifdef ENABLE_DEBUGGER_SUPPORT 179 from = isolate_->debug()->RestoreDebug(from); 180 #endif 181 from = isolate_->stack_guard()->RestoreStackGuard(from); 182 from = isolate_->regexp_stack()->RestoreStack(from); 183 from = isolate_->bootstrapper()->RestoreState(from); 184 per_thread->set_thread_state(NULL); 185 if (state->terminate_on_restore()) { 186 isolate_->stack_guard()->TerminateExecution(); 187 state->set_terminate_on_restore(false); 188 } 189 state->set_id(ThreadId::Invalid()); 190 state->Unlink(); 191 state->LinkInto(ThreadState::FREE_LIST); 192 return true; 193 } 194 195 196 void ThreadManager::Lock() { 197 mutex_.Lock(); 198 mutex_owner_ = ThreadId::Current(); 199 ASSERT(IsLockedByCurrentThread()); 200 } 201 202 203 void ThreadManager::Unlock() { 204 mutex_owner_ = ThreadId::Invalid(); 205 mutex_.Unlock(); 206 } 207 208 209 static int ArchiveSpacePerThread() { 210 return HandleScopeImplementer::ArchiveSpacePerThread() + 211 Isolate::ArchiveSpacePerThread() + 212 #ifdef ENABLE_DEBUGGER_SUPPORT 213 Debug::ArchiveSpacePerThread() + 214 #endif 215 StackGuard::ArchiveSpacePerThread() + 216 RegExpStack::ArchiveSpacePerThread() + 217 Bootstrapper::ArchiveSpacePerThread() + 218 Relocatable::ArchiveSpacePerThread(); 219 } 220 221 222 ThreadState::ThreadState(ThreadManager* thread_manager) 223 : id_(ThreadId::Invalid()), 224 terminate_on_restore_(false), 225 data_(NULL), 226 next_(this), 227 previous_(this), 228 thread_manager_(thread_manager) { 229 } 230 231 232 ThreadState::~ThreadState() { 233 DeleteArray<char>(data_); 234 } 235 236 237 void ThreadState::AllocateSpace() { 238 data_ = NewArray<char>(ArchiveSpacePerThread()); 239 } 240 241 242 void ThreadState::Unlink() { 243 next_->previous_ = previous_; 244 previous_->next_ = next_; 245 } 246 247 248 void ThreadState::LinkInto(List list) { 249 ThreadState* flying_anchor = 250 list == FREE_LIST ? thread_manager_->free_anchor_ 251 : thread_manager_->in_use_anchor_; 252 next_ = flying_anchor->next_; 253 previous_ = flying_anchor; 254 flying_anchor->next_ = this; 255 next_->previous_ = this; 256 } 257 258 259 ThreadState* ThreadManager::GetFreeThreadState() { 260 ThreadState* gotten = free_anchor_->next_; 261 if (gotten == free_anchor_) { 262 ThreadState* new_thread_state = new ThreadState(this); 263 new_thread_state->AllocateSpace(); 264 return new_thread_state; 265 } 266 return gotten; 267 } 268 269 270 // Gets the first in the list of archived threads. 271 ThreadState* ThreadManager::FirstThreadStateInUse() { 272 return in_use_anchor_->Next(); 273 } 274 275 276 ThreadState* ThreadState::Next() { 277 if (next_ == thread_manager_->in_use_anchor_) return NULL; 278 return next_; 279 } 280 281 282 // Thread ids must start with 1, because in TLS having thread id 0 can't 283 // be distinguished from not having a thread id at all (since NULL is 284 // defined as 0.) 285 ThreadManager::ThreadManager() 286 : mutex_owner_(ThreadId::Invalid()), 287 lazily_archived_thread_(ThreadId::Invalid()), 288 lazily_archived_thread_state_(NULL), 289 free_anchor_(NULL), 290 in_use_anchor_(NULL) { 291 free_anchor_ = new ThreadState(this); 292 in_use_anchor_ = new ThreadState(this); 293 } 294 295 296 ThreadManager::~ThreadManager() { 297 DeleteThreadStateList(free_anchor_); 298 DeleteThreadStateList(in_use_anchor_); 299 } 300 301 302 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) { 303 // The list starts and ends with the anchor. 304 for (ThreadState* current = anchor->next_; current != anchor;) { 305 ThreadState* next = current->next_; 306 delete current; 307 current = next; 308 } 309 delete anchor; 310 } 311 312 313 void ThreadManager::ArchiveThread() { 314 ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); 315 ASSERT(!IsArchived()); 316 ASSERT(IsLockedByCurrentThread()); 317 ThreadState* state = GetFreeThreadState(); 318 state->Unlink(); 319 Isolate::PerIsolateThreadData* per_thread = 320 isolate_->FindOrAllocatePerThreadDataForThisThread(); 321 per_thread->set_thread_state(state); 322 lazily_archived_thread_ = ThreadId::Current(); 323 lazily_archived_thread_state_ = state; 324 ASSERT(state->id().Equals(ThreadId::Invalid())); 325 state->set_id(CurrentId()); 326 ASSERT(!state->id().Equals(ThreadId::Invalid())); 327 } 328 329 330 void ThreadManager::EagerlyArchiveThread() { 331 ASSERT(IsLockedByCurrentThread()); 332 ThreadState* state = lazily_archived_thread_state_; 333 state->LinkInto(ThreadState::IN_USE_LIST); 334 char* to = state->data(); 335 // Ensure that data containing GC roots are archived first, and handle them 336 // in ThreadManager::Iterate(ObjectVisitor*). 337 to = isolate_->handle_scope_implementer()->ArchiveThread(to); 338 to = isolate_->ArchiveThread(to); 339 to = Relocatable::ArchiveState(isolate_, to); 340 #ifdef ENABLE_DEBUGGER_SUPPORT 341 to = isolate_->debug()->ArchiveDebug(to); 342 #endif 343 to = isolate_->stack_guard()->ArchiveStackGuard(to); 344 to = isolate_->regexp_stack()->ArchiveStack(to); 345 to = isolate_->bootstrapper()->ArchiveState(to); 346 lazily_archived_thread_ = ThreadId::Invalid(); 347 lazily_archived_thread_state_ = NULL; 348 } 349 350 351 void ThreadManager::FreeThreadResources() { 352 isolate_->handle_scope_implementer()->FreeThreadResources(); 353 isolate_->FreeThreadResources(); 354 #ifdef ENABLE_DEBUGGER_SUPPORT 355 isolate_->debug()->FreeThreadResources(); 356 #endif 357 isolate_->stack_guard()->FreeThreadResources(); 358 isolate_->regexp_stack()->FreeThreadResources(); 359 isolate_->bootstrapper()->FreeThreadResources(); 360 } 361 362 363 bool ThreadManager::IsArchived() { 364 Isolate::PerIsolateThreadData* data = 365 isolate_->FindPerThreadDataForThisThread(); 366 return data != NULL && data->thread_state() != NULL; 367 } 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 } // namespace internal 411 } // namespace v8 412