Index: runtime/vm/thread_test.cc |
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc |
index 2dcf56805513f9745f792203630750b50a37fe09..0f07f53543a815165faa73fb960fe29665cad673 100644 |
--- a/runtime/vm/thread_test.cc |
+++ b/runtime/vm/thread_test.cc |
@@ -205,6 +205,173 @@ VM_TEST_CASE(ManyTasksWithZones) { |
} |
+#if defined(DEBUG) |
zra
2016/12/08 18:54:13
ditto
bkonyi
2016/12/08 20:58:32
Done.
|
+class SimpleTaskWithZoneAllocation : public ThreadPool::Task { |
+ public: |
+ SimpleTaskWithZoneAllocation(intptr_t id, |
+ Isolate* isolate, |
+ Thread** thread_ptr, |
+ Monitor* sync, |
+ Monitor* monitor, |
+ intptr_t* done_count, |
+ bool* wait) |
+ : id_(id), |
+ isolate_(isolate), |
+ thread_ptr_(thread_ptr), |
+ sync_(sync), |
+ monitor_(monitor), |
+ done_count_(done_count), |
+ wait_(wait) {} |
+ |
+ virtual void Run() { |
+ Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask); |
+ { |
+ Thread* thread = Thread::Current(); |
+ *thread_ptr_ = thread; |
+ CreateStackZones(id_); |
+ } |
+ Thread::ExitIsolateAsHelper(); |
+ // Notify the main thread that this thread has exited. |
+ { |
+ MonitorLocker ml(monitor_); |
+ *done_count_ += 1; |
+ ml.Notify(); |
+ } |
+ } |
+ |
+ private: |
+ void CreateStackZones(intptr_t num) { |
+ Thread* thread = Thread::Current(); |
+ *thread_ptr_ = thread; |
+ |
+ StackZone stack_zone(thread); |
+ HANDLESCOPE(thread); |
+ Zone* zone = thread->zone(); |
+ EXPECT_EQ(zone, stack_zone.GetZone()); |
+ |
+ // Create a zone (which is also a stack resource) and exercise it a bit. |
+ ZoneGrowableArray<bool>* a0 = new (zone) ZoneGrowableArray<bool>(zone, 1); |
+ GrowableArray<bool> a1(zone, 1); |
+ for (intptr_t i = 0; i < 1000 * num + id_; ++i) { |
+ a0->Add(true); |
+ a1.Add(true); |
+ } |
+ |
+ num -= 1; |
+ if (num != 0) { |
+ CreateStackZones(num); |
+ return; |
+ } |
+ { |
+ // Let the main thread know we're done with memory ops on this thread. |
+ MonitorLocker ml(monitor_); |
+ *done_count_ += 1; |
+ ml.Notify(); |
+ } |
+ // Wait for the go-ahead from the main thread to exit. |
+ { |
+ MonitorLocker sync_ml(sync_); |
+ while (*wait_) { |
+ sync_ml.Wait(); |
+ } |
+ } |
+ } |
zra
2016/12/08 18:54:13
missing newline.
bkonyi
2016/12/08 20:58:32
Done.
|
+ intptr_t id_; |
+ Isolate* isolate_; |
+ Thread** thread_ptr_; |
+ Monitor* sync_; |
+ Monitor* monitor_; |
+ intptr_t* done_count_; |
+ bool* wait_; |
+}; |
+ |
+ |
+TEST_CASE(ManySimpleTasksWithZones) { |
+ const int kTaskCount = 10; |
+ Monitor monitor; |
+ Monitor sync; |
+ Thread* threads[kTaskCount + 1]; |
+ Isolate* isolate = Thread::Current()->isolate(); |
+ intptr_t done_count = 0; |
+ bool wait = true; |
+ threads[kTaskCount] = Thread::Current(); |
+ |
+ EXPECT(isolate->heap()->GrowthControlState()); |
+ isolate->heap()->DisableGrowthControl(); |
+ for (int i = 0; i < kTaskCount; i++) { |
zra
2016/12/08 18:54:13
intptr_t i
bkonyi
2016/12/08 20:58:32
Done.
|
+ Dart::thread_pool()->Run(new SimpleTaskWithZoneAllocation( |
+ (i + 1), isolate, &threads[i], &sync, &monitor, &done_count, &wait)); |
+ } |
+ // Wait until all spawned tasks finish their memory operations. |
+ { |
+ MonitorLocker ml(&monitor); |
+ while (done_count < kTaskCount) { |
+ ml.Wait(); |
+ } |
+ // Reset the done counter for use later. |
+ done_count = 0; |
+ } |
+ |
+ JSONStream stream; |
+ Service::PrintJSONForVM(&stream, false); |
+ const char* json = stream.ToCString(); |
+ |
+ // Confirm all expected entries are in the JSON output. |
+ for (int i = 0; i < kTaskCount + 1; i++) { |
zra
2016/12/08 18:54:13
intptr_t i
bkonyi
2016/12/08 20:58:32
Done.
|
+ Thread* thread = threads[i]; |
+ Isolate* thread_isolate = thread->isolate(); |
+ // Buffer can handle any possible input length given types. |
+ char thread_address_buf[96]; |
+ char isolate_address_buf[64]; |
+ Zone* top_zone = thread->zone(); |
+ |
+ // Check that all zones are present with correct sizes. |
+ while (top_zone != NULL) { |
+ char zone_info_buf[96]; |
+ OS::SNPrint(zone_info_buf, sizeof(zone_info_buf), |
+ "\"type\":\"_Zone\"," |
+ "\"capacity\":%ld," |
+ "\"used\":%ld", |
+ top_zone->SizeInBytes(), top_zone->UsedSizeInBytes()); |
+ |
+ EXPECT_SUBSTRING(zone_info_buf, json); |
+ top_zone = top_zone->previous(); |
+ } |
+ |
+ // Check the thread exists and is the correct size. |
+ OS::SNPrint(thread_address_buf, sizeof(thread_address_buf), |
+ "\"type\":\"_Thread\"," |
+ "\"id\":\"threads\\/%" Pd64 "", |
+ thread->os_thread()->trace_id()); |
+ |
+ // Ensure the isolate for each thread is valid. |
+ OS::SNPrint(isolate_address_buf, sizeof(isolate_address_buf), |
+ "\"type\":\"Isolate\"," |
+ "\"fixedId\":true," |
+ "\"id\":\"isolates\\/%" Pd64 "", |
+ static_cast<int64_t>(thread_isolate->main_port())); |
+ |
+ EXPECT_SUBSTRING(thread_address_buf, json); |
+ EXPECT_SUBSTRING(isolate_address_buf, json); |
+ } |
+ |
+ // Unblock the tasks so they can finish. |
+ { |
+ MonitorLocker sync_ml(&sync); |
+ wait = false; |
+ sync_ml.NotifyAll(); |
+ } |
+ // Now wait for them all to exit before destroying the isolate. |
+ { |
+ MonitorLocker ml(&monitor); |
+ while (done_count < kTaskCount) { |
+ ml.Wait(); |
+ } |
+ } |
+} |
+#endif |
+ |
+ |
TEST_CASE(ThreadRegistry) { |
Isolate* orig = Thread::Current()->isolate(); |
Zone* orig_zone = Thread::Current()->zone(); |