v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
v8threads.cc
Go to the documentation of this file.
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.
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();
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.
82  }
83  }
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 
98  return active_;
99 }
100 
101 
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 
119  : isolate_(reinterpret_cast<i::Isolate*>(isolate)) {
120  if (isolate_ == NULL) {
121  isolate_ = i::Isolate::GetDefaultIsolateForLocking();
122  }
124  if (isolate_->IsDefaultIsolate()) {
125  isolate_->Exit();
126  }
127  isolate_->thread_manager()->ArchiveThread();
128  isolate_->thread_manager()->Unlock();
129 }
130 
131 
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) {
144 }
145 
146 
149 }
150 
151 
152 namespace internal {
153 
154 
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();
208  return true;
209 }
210 
211 
213  mutex_->Lock();
214  mutex_owner_ = ThreadId::Current();
216 }
217 
218 
220  mutex_owner_ = ThreadId::Invalid();
221  mutex_->Unlock();
222 }
223 
224 
225 static int ArchiveSpacePerThread() {
228 #ifdef ENABLE_DEBUGGER_SUPPORT
229  Debug::ArchiveSpacePerThread() +
230 #endif
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 
253  next_->previous_ = previous_;
254  previous_->next_ = next_;
255 }
256 
257 
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 
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.
282  return in_use_anchor_->Next();
283 }
284 
285 
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 
315  ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
316  ASSERT(!IsArchived());
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() {
333  ThreadState* state = lazily_archived_thread_state_;
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 
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 
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 
384  for (ThreadState* state = FirstThreadStateInUse();
385  state != NULL;
386  state = state->Next()) {
387  char* data = state->data();
389  isolate_->IterateThread(v, data);
390  }
391 }
392 
393 
395  return ThreadId::Current();
396 }
397 
398 
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.
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.
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
char * ArchiveState(char *to)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping true
HandleScopeImplementer * handle_scope_implementer()
Definition: isolate.h:849
char * ArchiveThread(char *to)
Definition: api.cc:6351
void LinkInto(List list)
Definition: v8threads.cc:258
char * RestoreThread(char *from)
Definition: api.cc:6369
static int ArchiveSpacePerThread()
Definition: regexp-stack.h:86
Bootstrapper * bootstrapper()
Definition: isolate.h:803
PerIsolateThreadData * FindPerThreadDataForThisThread()
Definition: isolate.cc:352
RegExpStack * regexp_stack()
Definition: isolate.h:922
virtual int Unlock()=0
#define ASSERT(condition)
Definition: checks.h:270
char * RestoreState(char *from)
ThreadManager * thread_manager()
Definition: isolate.h:867
Locker(Isolate *isolate=NULL)
Definition: v8threads.cc:47
bool IsDefaultIsolate() const
Definition: isolate.h:467
void IterateArchivedThreads(ThreadVisitor *v)
Definition: v8threads.cc:383
StackGuard * stack_guard()
Definition: isolate.h:819
void set_id(ThreadId id)
Definition: v8threads.h:46
void TerminateExecution(ThreadId thread_id)
Definition: v8threads.cc:399
void FreeThreadResources()
Definition: isolate.h:651
char * RestoreStackGuard(char *from)
Definition: execution.cc:514
void ClearThread(const ExecutionAccess &lock)
Definition: execution.cc:561
char * ArchiveStack(char *to)
Definition: regexp-stack.cc:57
static void PreemptionReceived()
Definition: v8threads.cc:464
char * ArchiveStackGuard(char *to)
Definition: execution.cc:497
static ThreadId Current()
Definition: isolate.h:153
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
static void EnterDefaultIsolate()
Definition: isolate.cc:399
void Iterate(ObjectVisitor *v)
Definition: isolate.cc:475
char * RestoreStack(char *from)
Definition: regexp-stack.cc:67
static bool IsActive()
Definition: v8threads.cc:97
void Iterate(ObjectVisitor *v)
Definition: v8threads.cc:370
static void Sleep(const int milliseconds)
void set_thread_state(ThreadState *value)
Definition: isolate.h:386
ThreadState * GetFreeThreadState()
Definition: v8threads.cc:269
static int ArchiveSpacePerThread()
Definition: execution.h:180
void IterateThread(ThreadVisitor *v)
Definition: isolate.cc:429
ThreadState * thread_state() const
Definition: isolate.h:385
Unlocker(Isolate *isolate=NULL)
Definition: v8threads.cc:118
void Iterate(v8::internal::ObjectVisitor *v)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
static int ArchiveSpacePerThread()
Definition: isolate.h:650
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping true
Definition: flags.cc:157
static void StartPreemption(int every_n_ms)
Definition: v8threads.cc:142
ContextSwitcher * context_switcher()
Definition: isolate.h:869
char * ArchiveThread(char *to)
Definition: isolate.cc:1346
static ThreadId Invalid()
Definition: isolate.h:156
static void StartPreemption(int every_n_ms)
Definition: v8threads.cc:420
char * RestoreThread(char *from)
Definition: isolate.cc:1360
void set_context_switcher(ContextSwitcher *switcher)
Definition: isolate.h:871
virtual int Lock()=0
static void StopPreemption()
Definition: v8threads.cc:147
void set_terminate_on_restore(bool terminate_on_restore)
Definition: v8threads.h:51
ThreadState * FirstThreadStateInUse()
Definition: v8threads.cc:281
static int ArchiveSpacePerThread()
static bool IsLocked(Isolate *isolate=NULL)
Definition: v8threads.cc:88
static bool Initialize()
Definition: api.cc:4204
void InitThread(const ExecutionAccess &lock)
Definition: execution.cc:567
ThreadState * Next()
Definition: v8threads.cc:286