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