Chromium Code Reviews| Index: runtime/vm/thread_test.cc |
| diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc |
| index f781783d8e43dd403a088228bc4248e126446c3d..1d81b9b052755ac55e822d66c61bbaf042a3e25e 100644 |
| --- a/runtime/vm/thread_test.cc |
| +++ b/runtime/vm/thread_test.cc |
| @@ -224,4 +224,202 @@ TEST_CASE(ThreadRegistry) { |
| delete isos[1]; |
| } |
| + |
| +// A helper thread that alternatingly cooperates and organizes |
| +// safepoint rendezvous. At rendezvous, it explicitly visits the |
| +// stacks looking for a specific marker (Smi) to verify that the expected |
| +// number threads are actually visited. The task is "done" when it has |
| +// successfully made all other tasks and the main thread rendezvous (may |
| +// not happen in the first rendezvous, since tasks are still starting up). |
| +class SafepointTestTask : public ThreadPool::Task { |
| + public: |
| + static const intptr_t kTaskCount = 5; |
| + |
| + SafepointTestTask(Isolate* isolate, |
| + Mutex* mutex, |
| + intptr_t* expected_count, |
| + intptr_t* done, |
| + intptr_t* exited) |
| + : isolate_(isolate), |
| + mutex_(mutex), |
| + expected_count_(expected_count), |
| + done_(done), |
| + exited_(exited) {} |
| + |
| + virtual void Run() { |
| + Thread::EnterIsolateAsHelper(isolate_); |
| + for (int i = 0; ; ++i) { |
| + Thread* thread = Thread::Current(); |
| + StackZone stack_zone(thread); |
| + Zone* zone = thread->zone(); |
| + HANDLESCOPE(thread); |
| + const intptr_t kUniqueSmi = 928327281; |
| + Smi& smi = Smi::Handle(zone, Smi::New(kUniqueSmi)); |
| + { |
| + MutexLocker ml(mutex_); |
| + ++*expected_count_; |
| + } |
| + if ((i % 100) != 0) { |
| + // Usually, we just cooperate. |
| + isolate_->thread_registry()->CheckSafepoint(); |
| + } else { |
| + // But occasionally, organize a rendezvous. |
| + isolate_->thread_registry()->SafepointAllThreads(); |
| + ObjectCounter counter(isolate_, &smi); |
| + isolate_->thread_registry()->VisitObjectPointers(&counter); |
| + { |
| + MutexLocker ml(mutex_); |
| + EXPECT_EQ(*expected_count_, counter.count()); |
| + } |
| + UserTag& tag = UserTag::Handle(zone, isolate_->current_tag()); |
| + if (tag.raw() != isolate_->default_tag()) { |
| + String& label = String::Handle(zone, tag.label()); |
| + EXPECT(label.Equals("foo")); |
| + MutexLocker ml(mutex_); |
| + if (*expected_count_ == kTaskCount) { |
| + ++*done_; |
| + } |
| + } |
| + isolate_->thread_registry()->ResumeAllThreads(); |
| + } |
| + // Clear handle and adjust expectation. Check whether we're done. |
| + smi = Smi::New(0); |
| + { |
| + MutexLocker ml(mutex_); |
| + --*expected_count_; |
| + if (*done_ == kTaskCount) { |
| + break; |
| + } |
| + } |
| + } |
| + Thread::ExitIsolateAsHelper(); |
| + { |
| + MutexLocker ml(mutex_); |
| + ++*exited_; |
| + } |
| + } |
| + |
| + private: |
| + Isolate* isolate_; |
| + Mutex* mutex_; |
| + intptr_t* expected_count_; // # copies of kUniqueSmi we expect to visit. |
| + intptr_t* done_; // # tasks that successfully safepointed once. |
| + intptr_t* exited_; // # tasks that are no longer running. |
| +}; |
| + |
| + |
| +// Test rendezvous of: |
| +// - helpers in VM code, |
| +// - main thread in pure Dart, |
| +// organized by |
| +// - helpers. |
| +TEST_CASE(SafepointTestDart) { |
| + Isolate* isolate = Thread::Current()->isolate(); |
| + Mutex mutex; |
| + intptr_t expected_count = 0; |
| + intptr_t done = 0; |
| + intptr_t exited = 0; |
| + const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. |
|
Ivan Posva
2015/07/31 20:28:09
Comment does not parse.
koda
2015/07/31 22:40:44
Linker was unhappy with the inlined static constan
|
| + for (int i = 0; i < num_tasks; i++) { |
| + Dart::thread_pool()->Run(new SafepointTestTask( |
| + isolate, &mutex, &expected_count, &done, &exited)); |
| + } |
| + // Run Dart code on the main thread long enough to allow all helpers |
| + // to get their verification done and exit. Use a specific UserTag |
| + // to enable the helpers to verify that the main thread is |
| + // successfully interrupted in the pure Dart loop. |
| + char buffer[1024]; |
| + OS::SNPrint(buffer, sizeof(buffer), |
| + "import 'dart:profiler';\n" |
| + "int dummy = 0;\n" |
| + "main() {\n" |
| + " new UserTag('foo').makeCurrent();\n" |
| + " for (dummy = 0; dummy < 1234567890; ++dummy) {\n" |
|
Ivan Posva
2015/07/31 20:28:09
How long does this test execute on simulated archi
koda
2015/07/31 22:40:44
Now using smaller loop count if USING_SIMULATOR.
|
| + " dummy += (dummy & 1);\n" |
| + " }\n" |
| + "}\n"); |
| + Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL); |
| + EXPECT_VALID(lib); |
| + Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| + EXPECT_VALID(result); |
| + // Ensure we looped long enough to allow all helpers to succeed and exit. |
| + { |
| + MutexLocker ml(&mutex); |
| + EXPECT_EQ(num_tasks, done); |
| + EXPECT_EQ(num_tasks, exited); |
| + } |
| +} |
| + |
| + |
| +// Test rendezvous of: |
| +// - helpers in VM code, and |
| +// - main thread in VM code, |
| +// organized by |
| +// - helpers. |
| +TEST_CASE(SafepointTestVM) { |
| + Thread* thread = Thread::Current(); |
| + Isolate* isolate = thread->isolate(); |
| + Mutex mutex; |
| + intptr_t expected_count = 0; |
| + intptr_t done = 0; |
| + intptr_t exited = 0; |
| + const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. |
| + for (int i = 0; i < num_tasks; i++) { |
| + Dart::thread_pool()->Run(new SafepointTestTask( |
| + isolate, &mutex, &expected_count, &done, &exited)); |
| + } |
| + String& label = String::Handle(String::New("foo")); |
| + UserTag& tag = UserTag::Handle(UserTag::New(label)); |
| + isolate->set_current_tag(tag); |
| + while (true) { |
| + isolate->thread_registry()->CheckSafepoint(); |
| + MutexLocker ml(&mutex); |
| + if (exited == num_tasks) { |
| + break; |
| + } |
| + } |
| +} |
| + |
| + |
| +// Test rendezvous of: |
| +// - helpers in VM code, and |
| +// - main thread in VM code, |
| +// organized by |
| +// - main thread, and |
| +// - helpers. |
| +TEST_CASE(SafepointTestVM2) { |
| + Thread* thread = Thread::Current(); |
| + Isolate* isolate = thread->isolate(); |
| + Mutex mutex; |
| + intptr_t expected_count = 0; |
| + intptr_t done = 0; |
| + intptr_t exited = 0; |
| + const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. |
| + for (int i = 0; i < num_tasks; i++) { |
| + Dart::thread_pool()->Run(new SafepointTestTask( |
| + isolate, &mutex, &expected_count, &done, &exited)); |
| + } |
| + bool all_helpers = false; |
| + do { |
| + isolate->thread_registry()->SafepointAllThreads(); |
| + { |
| + MutexLocker ml(&mutex); |
| + if (expected_count == num_tasks) { |
| + all_helpers = true; |
| + } |
| + } |
| + isolate->thread_registry()->ResumeAllThreads(); |
| + } while (!all_helpers); |
| + String& label = String::Handle(String::New("foo")); |
| + UserTag& tag = UserTag::Handle(UserTag::New(label)); |
| + isolate->set_current_tag(tag); |
| + while (true) { |
| + isolate->thread_registry()->CheckSafepoint(); |
| + MutexLocker ml(&mutex); |
| + if (exited == num_tasks) { |
| + break; |
| + } |
| + } |
| +} |
| + |
| } // namespace dart |