~Locker();
- V8_DEPRECATED("This will be remvoed.",
- static void StartPreemption(Isolate *isolate, int every_n_ms));
-
- V8_DEPRECATED("This will be removed",
- static void StopPreemption(Isolate* isolate));
-
/**
* Returns whether or not the locker for a given isolate, is locked by the
* current thread.
} else if (strcmp(argv[i], "--send-idle-notification") == 0) {
options.send_idle_notification = true;
argv[i] = NULL;
- } else if (strcmp(argv[i], "--preemption") == 0) {
-#ifdef V8_SHARED
- printf("D8 with shared library does not support multi-threading\n");
- return false;
-#else
- options.use_preemption = true;
- argv[i] = NULL;
-#endif // V8_SHARED
- } else if (strcmp(argv[i], "--nopreemption") == 0) {
-#ifdef V8_SHARED
- printf("D8 with shared library does not support multi-threading\n");
- return false;
-#else
- options.use_preemption = false;
- argv[i] = NULL;
-#endif // V8_SHARED
- } else if (strcmp(argv[i], "--preemption-interval") == 0) {
-#ifdef V8_SHARED
- printf("D8 with shared library does not support multi-threading\n");
- return false;
-#else
- if (++i < argc) {
- argv[i-1] = NULL;
- char* end = NULL;
- options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
- if (options.preemption_interval <= 0
- || *end != '\0'
- || errno == ERANGE) {
- printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
- return false;
- }
- argv[i] = NULL;
- } else {
- printf("Missing value for --preemption-interval\n");
- return false;
- }
-#endif // V8_SHARED
} else if (strcmp(argv[i], "-f") == 0) {
// Ignore any -f flags for compatibility with other stand-alone
// JavaScript engines.
V8::IdleNotification(kLongIdlePauseInMs);
}
}
-
-#ifndef V8_SHARED
- // Start preemption if threads have been created and preemption is enabled.
- if (threads.length() > 0
- && options.use_preemption) {
- Locker::StartPreemption(isolate, options.preemption_interval);
- }
-#endif // V8_SHARED
}
#ifndef V8_SHARED
thread->Join();
delete thread;
}
-
- if (threads.length() > 0 && options.use_preemption) {
- Locker lock(isolate);
- Locker::StopPreemption(isolate);
- }
#endif // V8_SHARED
return 0;
}
public:
ShellOptions() :
#ifndef V8_SHARED
- use_preemption(true),
- preemption_interval(10),
num_parallel_files(0),
parallel_files(NULL),
#endif // V8_SHARED
}
#ifndef V8_SHARED
- bool use_preemption;
- int preemption_interval;
int num_parallel_files;
char** parallel_files;
#endif // V8_SHARED
// Clear the preempt request flag.
isolate->stack_guard()->Continue(PREEMPT);
- ContextSwitcher::PreemptionReceived();
-
#ifdef ENABLE_DEBUGGER_SUPPORT
if (isolate->debug()->InDebugger()) {
// If currently in the debugger don't do any actual preemption but record
DEFINE_bool(profile_deserialization, false,
"Print the time it takes to deserialize the snapshot.")
-// v8.cc
-DEFINE_bool(preemption, false,
- "activate a 100ms timer that switches between V8 threads")
-
// Regexp
DEFINE_bool(regexp_optimization, true, "generate optimized regexp code")
write_iterator_(NULL),
global_handles_(NULL),
eternal_handles_(NULL),
- context_switcher_(NULL),
thread_manager_(NULL),
fp_stubs_generated_(false),
has_installed_extensions_(false),
delete deoptimizer_data_;
deoptimizer_data_ = NULL;
- if (FLAG_preemption) {
- v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
- v8::Locker::StopPreemption(reinterpret_cast<v8::Isolate*>(this));
- }
builtins_.TearDown();
bootstrapper_->TearDown();
delete write_iterator_;
write_iterator_ = NULL;
- delete context_switcher_;
- context_switcher_ = NULL;
delete thread_manager_;
thread_manager_ = NULL;
}
}
- if (FLAG_preemption) {
- v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
- v8::Locker::StartPreemption(reinterpret_cast<v8::Isolate*>(this), 100);
- }
-
#ifdef ENABLE_DEBUGGER_SUPPORT
debug_->SetUp(create_heap_objects);
#endif
class CodeTracer;
class CompilationCache;
class ContextSlotCache;
-class ContextSwitcher;
class Counters;
class CpuFeatures;
class CpuProfiler;
ThreadManager* thread_manager() { return thread_manager_; }
- ContextSwitcher* context_switcher() { return context_switcher_; }
-
- void set_context_switcher(ContextSwitcher* switcher) {
- context_switcher_ = switcher;
- }
-
StringTracker* string_tracker() { return string_tracker_; }
unibrow::Mapping<unibrow::Ecma262UnCanonicalize>* jsregexp_uncanonicalize() {
ConsStringIteratorOp* write_iterator_;
GlobalHandles* global_handles_;
EternalHandles* eternal_handles_;
- ContextSwitcher* context_switcher_;
ThreadManager* thread_manager_;
RuntimeState runtime_state_;
bool fp_stubs_generated_;
}
-void Locker::StartPreemption(v8::Isolate* isolate, int every_n_ms) {
- v8::internal::ContextSwitcher::StartPreemption(
- reinterpret_cast<i::Isolate*>(isolate), every_n_ms);
-}
-
-
-void Locker::StopPreemption(v8::Isolate* isolate) {
- v8::internal::ContextSwitcher::StopPreemption(
- reinterpret_cast<i::Isolate*>(isolate));
-}
-
-
namespace internal {
}
-ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms)
- : Thread("v8:CtxtSwitcher"),
- keep_going_(true),
- sleep_ms_(every_n_ms),
- isolate_(isolate) {
-}
-
-
-// Set the scheduling interval of V8 threads. This function starts the
-// ContextSwitcher thread if needed.
-void ContextSwitcher::StartPreemption(Isolate* isolate, int every_n_ms) {
- ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
- if (isolate->context_switcher() == NULL) {
- // If the ContextSwitcher thread is not running at the moment start it now.
- isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms));
- isolate->context_switcher()->Start();
- } else {
- // ContextSwitcher thread is already running, so we just change the
- // scheduling interval.
- isolate->context_switcher()->sleep_ms_ = every_n_ms;
- }
-}
-
-
-// Disable preemption of V8 threads. If multiple threads want to use V8 they
-// must cooperatively schedule amongst them from this point on.
-void ContextSwitcher::StopPreemption(Isolate* isolate) {
- ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
- if (isolate->context_switcher() != NULL) {
- // The ContextSwitcher thread is running. We need to stop it and release
- // its resources.
- isolate->context_switcher()->keep_going_ = false;
- // Wait for the ContextSwitcher thread to exit.
- isolate->context_switcher()->Join();
- // Thread has exited, now we can delete it.
- delete(isolate->context_switcher());
- isolate->set_context_switcher(NULL);
- }
-}
-
-
-// Main loop of the ContextSwitcher thread: Preempt the currently running V8
-// thread at regular intervals.
-void ContextSwitcher::Run() {
- while (keep_going_) {
- OS::Sleep(sleep_ms_);
- isolate()->stack_guard()->Preempt();
- }
-}
-
-
-// Acknowledge the preemption by the receiving thread.
-void ContextSwitcher::PreemptionReceived() {
- // There is currently no accounting being done for this. But could be in the
- // future, which is why we leave this in.
-}
-
-
} // namespace internal
} // namespace v8
};
-// The ContextSwitcher thread is used to schedule regular preemptions to
-// multiple running V8 threads. Generally it is necessary to call
-// StartPreemption if there is more than one thread running. If not, a single
-// JavaScript can take full control of V8 and not allow other threads to run.
-class ContextSwitcher: public Thread {
- public:
- // Set the preemption interval for the ContextSwitcher thread.
- static void StartPreemption(Isolate* isolate, int every_n_ms);
-
- // Stop sending preemption requests to threads.
- static void StopPreemption(Isolate* isolate);
-
- // Preempted thread needs to call back to the ContextSwitcher to acknowledge
- // the handling of a preemption request.
- static void PreemptionReceived();
-
- private:
- ContextSwitcher(Isolate* isolate, int every_n_ms);
-
- Isolate* isolate() const { return isolate_; }
-
- void Run();
-
- bool keep_going_;
- int sleep_ms_;
- Isolate* isolate_;
-};
-
} } // namespace v8::internal
#endif // V8_V8THREADS_H_
}
-class ApplyInterruptTest {
- public:
- ApplyInterruptTest() : block_(0) {}
- ~ApplyInterruptTest() {}
- void RunTest() {
- gc_count_ = 0;
- gc_during_apply_ = 0;
- apply_success_ = false;
- gc_success_ = false;
- GCThread gc_thread(this);
- gc_thread.Start();
- v8::Isolate* isolate = CcTest::isolate();
- v8::Locker::StartPreemption(isolate, 1);
-
- LongRunningApply();
- {
- v8::Unlocker unlock(isolate);
- gc_thread.Join();
- }
- v8::Locker::StopPreemption(isolate);
- CHECK(apply_success_);
- CHECK(gc_success_);
- }
-
- private:
- // Number of garbage collections required.
- static const int kRequiredGCs = 2;
-
- class GCThread : public i::Thread {
- public:
- explicit GCThread(ApplyInterruptTest* test)
- : Thread("GCThread"), test_(test) {}
- virtual void Run() {
- test_->CollectGarbage();
- }
- private:
- ApplyInterruptTest* test_;
- };
-
- void CollectGarbage() {
- block_.Wait();
- while (gc_during_apply_ < kRequiredGCs) {
- {
- v8::Locker lock(CcTest::isolate());
- v8::Isolate::Scope isolate_scope(CcTest::isolate());
- CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
- gc_count_++;
- }
- i::OS::Sleep(1);
- }
- gc_success_ = true;
- }
-
- void LongRunningApply() {
- block_.Signal();
- int rounds = 0;
- while (gc_during_apply_ < kRequiredGCs) {
- int gc_before = gc_count_;
- {
- const char* c_source =
- "function do_very_little(bar) {"
- " this.foo = bar;"
- "}"
- "for (var i = 0; i < 100000; i++) {"
- " do_very_little.apply(this, ['bar']);"
- "}";
- Local<String> source = String::New(c_source);
- Local<Script> script = Script::Compile(source);
- Local<Value> result = script->Run();
- // Check that no exception was thrown.
- CHECK(!result.IsEmpty());
- }
- int gc_after = gc_count_;
- gc_during_apply_ += gc_after - gc_before;
- rounds++;
- }
- apply_success_ = true;
- }
-
- i::Semaphore block_;
- int gc_count_;
- int gc_during_apply_;
- bool apply_success_;
- bool gc_success_;
-};
-
-
-// Test that nothing bad happens if we get a preemption just when we were
-// about to do an apply().
-TEST(ApplyInterruption) {
- v8::Locker lock(CcTest::isolate());
- v8::V8::Initialize();
- v8::HandleScope scope(CcTest::isolate());
- Local<Context> local_env;
- {
- LocalContext env;
- local_env = env.local();
- }
-
- // Local context should still be live.
- CHECK(!local_env.IsEmpty());
- local_env->Enter();
-
- // Should complete without problems.
- ApplyInterruptTest().RunTest();
-
- local_env->Exit();
-}
-
-
// Verify that we can clone an object
TEST(ObjectClone) {
LocalContext env;
#include "cctest.h"
-TEST(Preemption) {
- v8::Isolate* isolate = CcTest::isolate();
- v8::Locker locker(isolate);
- v8::V8::Initialize();
- v8::HandleScope scope(isolate);
- v8::Handle<v8::Context> context = v8::Context::New(isolate);
- v8::Context::Scope context_scope(context);
-
- v8::Locker::StartPreemption(isolate, 100);
-
- v8::Handle<v8::Script> script = v8::Script::Compile(
- v8::String::New("var count = 0; var obj = new Object(); count++;\n"));
-
- script->Run();
-
- v8::Locker::StopPreemption(isolate);
- v8::internal::OS::Sleep(500); // Make sure the timer fires.
-
- script->Run();
-}
-
-
enum Turn {
FILL_CACHE,
CLEAN_CACHE,