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 14namespace 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. 19bool 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. 24void 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 59bool 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 66bool Locker::IsActive() { 67 return active_; 68} 69 70 71Locker::~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 84void 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 93Unlocker::~Unlocker() { 94 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread()); 95 isolate_->thread_manager()->Lock(); 96 isolate_->thread_manager()->RestoreThread(); 97} 98 99 100namespace internal { 101 102 103bool 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 158void ThreadManager::Lock() { 159 mutex_.Lock(); 160 mutex_owner_ = ThreadId::Current(); 161 DCHECK(IsLockedByCurrentThread()); 162} 163 164 165void ThreadManager::Unlock() { 166 mutex_owner_ = ThreadId::Invalid(); 167 mutex_.Unlock(); 168} 169 170 171static 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 182ThreadState::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 192ThreadState::~ThreadState() { 193 DeleteArray<char>(data_); 194} 195 196 197void ThreadState::AllocateSpace() { 198 data_ = NewArray<char>(ArchiveSpacePerThread()); 199} 200 201 202void ThreadState::Unlink() { 203 next_->previous_ = previous_; 204 previous_->next_ = next_; 205} 206 207 208void 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 219ThreadState* 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. 231ThreadState* ThreadManager::FirstThreadStateInUse() { 232 return in_use_anchor_->Next(); 233} 234 235 236ThreadState* 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.) 245ThreadManager::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 256ThreadManager::~ThreadManager() { 257 DeleteThreadStateList(free_anchor_); 258 DeleteThreadStateList(in_use_anchor_); 259} 260 261 262void 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 273void 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 290void 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 309void 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 322bool ThreadManager::IsArchived() { 323 Isolate::PerIsolateThreadData* data = 324 isolate_->FindPerThreadDataForThisThread(); 325 return data != NULL && data->thread_state() != NULL; 326} 327 328 329void 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 342void 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 353ThreadId ThreadManager::CurrentId() { 354 return ThreadId::Current(); 355} 356 357 358void 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