Remove preemption thread and API
BUG=v8:3004 R=svenpanne@chromium.org, yangguo@chromium.org LOG=y Review URL: https://codereview.chromium.org/62283010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17967 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
2340aa4164
commit
662dd44875
@ -5271,12 +5271,6 @@ class V8_EXPORT Locker {
|
||||
|
||||
~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.
|
||||
|
50
src/d8.cc
50
src/d8.cc
@ -1379,43 +1379,6 @@ bool Shell::SetOptions(int argc, char* argv[]) {
|
||||
} 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.
|
||||
@ -1554,14 +1517,6 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
|
||||
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
|
||||
@ -1574,11 +1529,6 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
if (threads.length() > 0 && options.use_preemption) {
|
||||
Locker lock(isolate);
|
||||
Locker::StopPreemption(isolate);
|
||||
}
|
||||
#endif // V8_SHARED
|
||||
return 0;
|
||||
}
|
||||
|
4
src/d8.h
4
src/d8.h
@ -219,8 +219,6 @@ class ShellOptions {
|
||||
public:
|
||||
ShellOptions() :
|
||||
#ifndef V8_SHARED
|
||||
use_preemption(true),
|
||||
preemption_interval(10),
|
||||
num_parallel_files(0),
|
||||
parallel_files(NULL),
|
||||
#endif // V8_SHARED
|
||||
@ -245,8 +243,6 @@ class ShellOptions {
|
||||
}
|
||||
|
||||
#ifndef V8_SHARED
|
||||
bool use_preemption;
|
||||
int preemption_interval;
|
||||
int num_parallel_files;
|
||||
char** parallel_files;
|
||||
#endif // V8_SHARED
|
||||
|
@ -814,8 +814,6 @@ static Object* RuntimePreempt(Isolate* isolate) {
|
||||
// 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
|
||||
|
@ -611,10 +611,6 @@ DEFINE_int(hash_seed, 0,
|
||||
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")
|
||||
|
||||
|
@ -1549,7 +1549,6 @@ Isolate::Isolate()
|
||||
write_iterator_(NULL),
|
||||
global_handles_(NULL),
|
||||
eternal_handles_(NULL),
|
||||
context_switcher_(NULL),
|
||||
thread_manager_(NULL),
|
||||
fp_stubs_generated_(false),
|
||||
has_installed_extensions_(false),
|
||||
@ -1690,10 +1689,6 @@ void Isolate::Deinit() {
|
||||
|
||||
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();
|
||||
|
||||
@ -1805,8 +1800,6 @@ Isolate::~Isolate() {
|
||||
delete write_iterator_;
|
||||
write_iterator_ = NULL;
|
||||
|
||||
delete context_switcher_;
|
||||
context_switcher_ = NULL;
|
||||
delete thread_manager_;
|
||||
thread_manager_ = NULL;
|
||||
|
||||
@ -2038,11 +2031,6 @@ bool Isolate::Init(Deserializer* des) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -58,7 +58,6 @@ struct CodeStubInterfaceDescriptor;
|
||||
class CodeTracer;
|
||||
class CompilationCache;
|
||||
class ContextSlotCache;
|
||||
class ContextSwitcher;
|
||||
class Counters;
|
||||
class CpuFeatures;
|
||||
class CpuProfiler;
|
||||
@ -919,12 +918,6 @@ class Isolate {
|
||||
|
||||
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() {
|
||||
@ -1293,7 +1286,6 @@ class Isolate {
|
||||
ConsStringIteratorOp* write_iterator_;
|
||||
GlobalHandles* global_handles_;
|
||||
EternalHandles* eternal_handles_;
|
||||
ContextSwitcher* context_switcher_;
|
||||
ThreadManager* thread_manager_;
|
||||
RuntimeState runtime_state_;
|
||||
bool fp_stubs_generated_;
|
||||
|
@ -133,18 +133,6 @@ Unlocker::~Unlocker() {
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
|
||||
@ -419,63 +407,5 @@ void ThreadManager::TerminateExecution(ThreadId thread_id) {
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -139,34 +139,6 @@ class ThreadManager {
|
||||
};
|
||||
|
||||
|
||||
// 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_
|
||||
|
@ -14478,116 +14478,6 @@ THREADED_TEST(CrossContextNew) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -33,28 +33,6 @@
|
||||
#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,
|
||||
|
Loading…
Reference in New Issue
Block a user