00001 // Copyright 2008 the V8 project authors. All rights reserved. 00002 // Redistribution and use in source and binary forms, with or without 00003 // modification, are permitted provided that the following conditions are 00004 // met: 00005 // 00006 // * Redistributions of source code must retain the above copyright 00007 // notice, this list of conditions and the following disclaimer. 00008 // * Redistributions in binary form must reproduce the above 00009 // copyright notice, this list of conditions and the following 00010 // disclaimer in the documentation and/or other materials provided 00011 // with the distribution. 00012 // * Neither the name of Google Inc. nor the names of its 00013 // contributors may be used to endorse or promote products derived 00014 // from this software without specific prior written permission. 00015 // 00016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00017 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00018 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00019 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00020 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00021 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00026 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 00028 #include "v8.h" 00029 00030 #include "api.h" 00031 #include "debug.h" 00032 #include "execution.h" 00033 #include "v8threads.h" 00034 00035 namespace v8 { 00036 00037 static internal::Thread::LocalStorageKey thread_state_key = 00038 internal::Thread::CreateThreadLocalKey(); 00039 00040 // Constructor for the Locker object. Once the Locker is constructed the 00041 // current thread will be guaranteed to have the big V8 lock. 00042 Locker::Locker() : has_lock_(false), top_level_(true) { 00043 // Get the big lock if necessary. 00044 if (!internal::ThreadManager::IsLockedByCurrentThread()) { 00045 internal::ThreadManager::Lock(); 00046 has_lock_ = true; 00047 // This may be a locker within an unlocker in which case we have to 00048 // get the saved state for this thread and restore it. 00049 if (internal::ThreadManager::RestoreThread()) { 00050 top_level_ = false; 00051 } 00052 } 00053 ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); 00054 } 00055 00056 00057 bool Locker::IsLocked() { 00058 return internal::ThreadManager::IsLockedByCurrentThread(); 00059 } 00060 00061 00062 Locker::~Locker() { 00063 ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); 00064 if (has_lock_) { 00065 if (!top_level_) { 00066 internal::ThreadManager::ArchiveThread(); 00067 } 00068 internal::ThreadManager::Unlock(); 00069 } 00070 } 00071 00072 00073 Unlocker::Unlocker() { 00074 ASSERT(internal::ThreadManager::IsLockedByCurrentThread()); 00075 internal::ThreadManager::ArchiveThread(); 00076 internal::ThreadManager::Unlock(); 00077 } 00078 00079 00080 Unlocker::~Unlocker() { 00081 ASSERT(!internal::ThreadManager::IsLockedByCurrentThread()); 00082 internal::ThreadManager::Lock(); 00083 internal::ThreadManager::RestoreThread(); 00084 } 00085 00086 00087 void Locker::StartPreemption(int every_n_ms) { 00088 v8::internal::ContextSwitcher::StartPreemption(every_n_ms); 00089 } 00090 00091 00092 void Locker::StopPreemption() { 00093 v8::internal::ContextSwitcher::StopPreemption(); 00094 } 00095 00096 00097 namespace internal { 00098 00099 00100 bool ThreadManager::RestoreThread() { 00101 // First check whether the current thread has been 'lazily archived', ie 00102 // not archived at all. If that is the case we put the state storage we 00103 // had prepared back in the free list, since we didn't need it after all. 00104 if (lazily_archived_thread_.IsSelf()) { 00105 lazily_archived_thread_.Initialize(ThreadHandle::INVALID); 00106 ASSERT(Thread::GetThreadLocal(thread_state_key) == 00107 lazily_archived_thread_state_); 00108 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST); 00109 lazily_archived_thread_state_ = NULL; 00110 Thread::SetThreadLocal(thread_state_key, NULL); 00111 return true; 00112 } 00113 // If there is another thread that was lazily archived then we have to really 00114 // archive it now. 00115 if (lazily_archived_thread_.IsValid()) { 00116 EagerlyArchiveThread(); 00117 } 00118 ThreadState* state = 00119 reinterpret_cast<ThreadState*>(Thread::GetThreadLocal(thread_state_key)); 00120 if (state == NULL) { 00121 return false; 00122 } 00123 char* from = state->data(); 00124 from = HandleScopeImplementer::RestoreThread(from); 00125 from = Top::RestoreThread(from); 00126 from = Debug::RestoreDebug(from); 00127 from = StackGuard::RestoreStackGuard(from); 00128 Thread::SetThreadLocal(thread_state_key, NULL); 00129 state->Unlink(); 00130 state->LinkInto(ThreadState::FREE_LIST); 00131 return true; 00132 } 00133 00134 00135 void ThreadManager::Lock() { 00136 mutex_->Lock(); 00137 mutex_owner_.Initialize(ThreadHandle::SELF); 00138 ASSERT(IsLockedByCurrentThread()); 00139 } 00140 00141 00142 void ThreadManager::Unlock() { 00143 mutex_owner_.Initialize(ThreadHandle::INVALID); 00144 mutex_->Unlock(); 00145 } 00146 00147 00148 static int ArchiveSpacePerThread() { 00149 return HandleScopeImplementer::ArchiveSpacePerThread() + 00150 Top::ArchiveSpacePerThread() + 00151 Debug::ArchiveSpacePerThread() + 00152 StackGuard::ArchiveSpacePerThread(); 00153 } 00154 00155 00156 ThreadState* ThreadState::free_anchor_ = new ThreadState(); 00157 ThreadState* ThreadState::in_use_anchor_ = new ThreadState(); 00158 00159 00160 ThreadState::ThreadState() : next_(this), previous_(this) { 00161 } 00162 00163 00164 void ThreadState::AllocateSpace() { 00165 data_ = NewArray<char>(ArchiveSpacePerThread()); 00166 } 00167 00168 00169 void ThreadState::Unlink() { 00170 next_->previous_ = previous_; 00171 previous_->next_ = next_; 00172 } 00173 00174 00175 void ThreadState::LinkInto(List list) { 00176 ThreadState* flying_anchor = 00177 list == FREE_LIST ? free_anchor_ : in_use_anchor_; 00178 next_ = flying_anchor->next_; 00179 previous_ = flying_anchor; 00180 flying_anchor->next_ = this; 00181 next_->previous_ = this; 00182 } 00183 00184 00185 ThreadState* ThreadState::GetFree() { 00186 ThreadState* gotten = free_anchor_->next_; 00187 if (gotten == free_anchor_) { 00188 ThreadState* new_thread_state = new ThreadState(); 00189 new_thread_state->AllocateSpace(); 00190 return new_thread_state; 00191 } 00192 return gotten; 00193 } 00194 00195 00196 // Gets the first in the list of archived threads. 00197 ThreadState* ThreadState::FirstInUse() { 00198 return in_use_anchor_->Next(); 00199 } 00200 00201 00202 ThreadState* ThreadState::Next() { 00203 if (next_ == in_use_anchor_) return NULL; 00204 return next_; 00205 } 00206 00207 00208 Mutex* ThreadManager::mutex_ = OS::CreateMutex(); 00209 ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID); 00210 ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID); 00211 ThreadState* ThreadManager::lazily_archived_thread_state_ = NULL; 00212 00213 00214 void ThreadManager::ArchiveThread() { 00215 ASSERT(!lazily_archived_thread_.IsValid()); 00216 ASSERT(Thread::GetThreadLocal(thread_state_key) == NULL); 00217 ThreadState* state = ThreadState::GetFree(); 00218 state->Unlink(); 00219 Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state)); 00220 lazily_archived_thread_.Initialize(ThreadHandle::SELF); 00221 lazily_archived_thread_state_ = state; 00222 } 00223 00224 00225 void ThreadManager::EagerlyArchiveThread() { 00226 ThreadState* state = lazily_archived_thread_state_; 00227 state->LinkInto(ThreadState::IN_USE_LIST); 00228 char* to = state->data(); 00229 to = HandleScopeImplementer::ArchiveThread(to); 00230 to = Top::ArchiveThread(to); 00231 to = Debug::ArchiveDebug(to); 00232 to = StackGuard::ArchiveStackGuard(to); 00233 lazily_archived_thread_.Initialize(ThreadHandle::INVALID); 00234 lazily_archived_thread_state_ = NULL; 00235 } 00236 00237 00238 void ThreadManager::Iterate(ObjectVisitor* v) { 00239 // Expecting no threads during serialization/deserialization 00240 for (ThreadState* state = ThreadState::FirstInUse(); 00241 state != NULL; 00242 state = state->Next()) { 00243 char* data = state->data(); 00244 data = HandleScopeImplementer::Iterate(v, data); 00245 data = Top::Iterate(v, data); 00246 } 00247 } 00248 00249 00250 void ThreadManager::MarkCompactPrologue() { 00251 for (ThreadState* state = ThreadState::FirstInUse(); 00252 state != NULL; 00253 state = state->Next()) { 00254 char* data = state->data(); 00255 data += HandleScopeImplementer::ArchiveSpacePerThread(); 00256 Top::MarkCompactPrologue(data); 00257 } 00258 } 00259 00260 00261 void ThreadManager::MarkCompactEpilogue() { 00262 for (ThreadState* state = ThreadState::FirstInUse(); 00263 state != NULL; 00264 state = state->Next()) { 00265 char* data = state->data(); 00266 data += HandleScopeImplementer::ArchiveSpacePerThread(); 00267 Top::MarkCompactEpilogue(data); 00268 } 00269 } 00270 00271 00272 ContextSwitcher::ContextSwitcher(int every_n_ms) 00273 : preemption_semaphore_(OS::CreateSemaphore(0)), 00274 keep_going_(true), 00275 sleep_ms_(every_n_ms) { 00276 } 00277 00278 00279 static v8::internal::ContextSwitcher* switcher; 00280 00281 00282 void ContextSwitcher::StartPreemption(int every_n_ms) { 00283 ASSERT(Locker::IsLocked()); 00284 if (switcher == NULL) { 00285 switcher = new ContextSwitcher(every_n_ms); 00286 switcher->Start(); 00287 } else { 00288 switcher->sleep_ms_ = every_n_ms; 00289 } 00290 } 00291 00292 00293 void ContextSwitcher::StopPreemption() { 00294 ASSERT(Locker::IsLocked()); 00295 if (switcher != NULL) { 00296 switcher->Stop(); 00297 delete(switcher); 00298 switcher = NULL; 00299 } 00300 } 00301 00302 00303 void ContextSwitcher::Run() { 00304 while (keep_going_) { 00305 OS::Sleep(sleep_ms_); 00306 StackGuard::Preempt(); 00307 WaitForPreemption(); 00308 } 00309 } 00310 00311 00312 void ContextSwitcher::Stop() { 00313 ASSERT(Locker::IsLocked()); 00314 keep_going_ = false; 00315 preemption_semaphore_->Signal(); 00316 Join(); 00317 } 00318 00319 00320 void ContextSwitcher::WaitForPreemption() { 00321 preemption_semaphore_->Wait(); 00322 } 00323 00324 00325 void ContextSwitcher::PreemptionReceived() { 00326 ASSERT(Locker::IsLocked()); 00327 switcher->preemption_semaphore_->Signal(); 00328 } 00329 00330 00331 } // namespace internal 00332 } // namespace v8