Index: runtime/vm/thread_test.cc |
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc |
index 5cb270b6b4fa73a1c9d89bbfe8e85ec698831175..0eccd6496a92fe6e481df963321fb1ce033a6582 100644 |
--- a/runtime/vm/thread_test.cc |
+++ b/runtime/vm/thread_test.cc |
@@ -7,6 +7,8 @@ |
#include "vm/lockers.h" |
#include "vm/unit_test.h" |
#include "vm/profiler.h" |
+#include "vm/thread_pool.h" |
+#include "vm/thread_registry.h" |
namespace dart { |
@@ -82,4 +84,142 @@ UNIT_TEST_CASE(Monitor) { |
delete monitor; |
} |
+ |
+class ObjectCounter : public ObjectPointerVisitor { |
+ public: |
+ explicit ObjectCounter(Isolate* isolate, const Object* obj) |
+ : ObjectPointerVisitor(isolate), obj_(obj), count_(0) { } |
+ |
+ virtual void VisitPointers(RawObject** first, RawObject** last) { |
+ for (RawObject** current = first; current <= last; ++current) { |
+ if (*current == obj_->raw()) { |
+ ++count_; |
+ } |
+ } |
+ } |
+ |
+ intptr_t count() const { return count_; } |
+ |
+ private: |
+ const Object* obj_; |
+ intptr_t count_; |
+}; |
+ |
+ |
+class TaskWithZoneAllocation : public ThreadPool::Task { |
+ public: |
+ TaskWithZoneAllocation(Isolate* isolate, |
+ const String& foo, |
+ Monitor* monitor, |
+ bool* done, |
+ intptr_t id) |
+ : isolate_(isolate), foo_(foo), monitor_(monitor), done_(done), id_(id) {} |
+ virtual void Run() { |
+ Thread::EnterIsolateAsHelper(isolate_); |
+ { |
+ // Create a zone (which is also a stack resource) and exercise it a bit. |
+ StackZone stack_zone(Thread::Current()); |
+ Zone* zone = Thread::Current()->zone(); |
+ EXPECT_EQ(zone, stack_zone.GetZone()); |
+ ZoneGrowableArray<bool>* a0 = new(zone) ZoneGrowableArray<bool>(zone, 1); |
+ GrowableArray<bool> a1(zone, 1); |
+ for (intptr_t i = 0; i < 100000; ++i) { |
+ a0->Add(true); |
+ a1.Add(true); |
+ } |
+ // Check that we can create handles (but not yet allocate heap objects). |
+ String& str = String::Handle(zone, foo_.raw()); |
+ EXPECT(str.Equals("foo")); |
+ const intptr_t unique_smi = id_ + 928327281; |
+ Smi& smi = Smi::Handle(zone, Smi::New(unique_smi)); |
+ EXPECT(smi.Value() == unique_smi); |
+ ObjectCounter counter(isolate_, &smi); |
+ // Ensure that our particular zone is visited. |
+ // TODO(koda): Remove "->thread_registry()" after updating stack walker. |
+ isolate_->thread_registry()->VisitObjectPointers(&counter); |
+ EXPECT_EQ(1, counter.count()); |
+ } |
+ Thread::ExitIsolateAsHelper(); |
+ { |
+ MonitorLocker ml(monitor_); |
+ *done_ = true; |
+ ml.Notify(); |
+ } |
+ } |
+ |
+ private: |
+ Isolate* isolate_; |
+ const String& foo_; |
+ Monitor* monitor_; |
+ bool* done_; |
+ intptr_t id_; |
+}; |
+ |
+ |
+TEST_CASE(ManyTasksWithZones) { |
+ const int kTaskCount = 100; |
+ Monitor sync[kTaskCount]; |
+ bool done[kTaskCount]; |
+ Isolate* isolate = Thread::Current()->isolate(); |
+ String& foo = String::Handle(String::New("foo")); |
+ |
+ for (int i = 0; i < kTaskCount; i++) { |
+ done[i] = false; |
+ Dart::thread_pool()->Run( |
+ new TaskWithZoneAllocation(isolate, foo, &sync[i], &done[i], i)); |
+ } |
+ for (int i = 0; i < kTaskCount; i++) { |
+ // Check that main mutator thread can still freely use its own zone. |
+ String& bar = String::Handle(String::New("bar")); |
+ if (i % 10 == 0) { |
+ // Mutator thread is free to independently move in/out/between isolates. |
+ Thread::ExitIsolate(); |
+ } |
+ MonitorLocker ml(&sync[i]); |
+ while (!done[i]) { |
+ ml.Wait(); |
+ } |
+ EXPECT(done[i]); |
+ if (i % 10 == 0) { |
+ Thread::EnterIsolate(isolate); |
+ } |
+ EXPECT(bar.Equals("bar")); |
+ } |
+} |
+ |
+ |
+TEST_CASE(ThreadRegistry) { |
+ Isolate* orig = Thread::Current()->isolate(); |
+ Zone* orig_zone = Thread::Current()->zone(); |
+ char* orig_str = orig_zone->PrintToString("foo"); |
+ Thread::ExitIsolate(); |
+ Isolate::Flags vm_flags; |
+ Dart_IsolateFlags api_flags; |
+ vm_flags.CopyTo(&api_flags); |
+ Isolate* isos[2]; |
+ // Create and enter a new isolate. |
+ isos[0] = Isolate::Init(NULL, api_flags); |
+ Zone* zone0 = Thread::Current()->zone(); |
+ EXPECT(zone0 != orig_zone); |
+ isos[0]->Shutdown(); |
+ Thread::ExitIsolate(); |
+ // Create and enter yet another isolate. |
+ isos[1] = Isolate::Init(NULL, api_flags); |
+ { |
+ // Create a stack resource this time, and exercise it. |
+ StackZone stack_zone(Thread::Current()); |
+ Zone* zone1 = Thread::Current()->zone(); |
+ EXPECT(zone1 != zone0); |
+ EXPECT(zone1 != orig_zone); |
+ } |
+ isos[1]->Shutdown(); |
+ Thread::ExitIsolate(); |
+ Thread::EnterIsolate(orig); |
+ // Original zone should be preserved. |
+ EXPECT_EQ(orig_zone, Thread::Current()->zone()); |
+ EXPECT_STREQ("foo", orig_str); |
+ delete isos[0]; |
+ delete isos[1]; |
+} |
+ |
} // namespace dart |