Index: runtime/vm/thread_test.cc |
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc |
index 2dcf56805513f9745f792203630750b50a37fe09..96744bde31d9e274d839c7a1b7fb8c79dedba5e1 100644 |
--- a/runtime/vm/thread_test.cc |
+++ b/runtime/vm/thread_test.cc |
@@ -205,6 +205,158 @@ VM_TEST_CASE(ManyTasksWithZones) { |
} |
+#ifndef RELEASE |
+class SimpleTaskWithZoneAllocation : public ThreadPool::Task { |
+ public: |
+ SimpleTaskWithZoneAllocation(Isolate* isolate, |
+ Thread** thread_ptr, |
+ Monitor* sync, |
+ Monitor* monitor, |
+ bool* done, |
+ bool* wait) |
+ : isolate_(isolate), |
+ thread_ptr_(thread_ptr), |
+ sync_(sync), |
+ monitor_(monitor), |
+ done_(done), |
+ wait_(wait) {} |
+ |
+ virtual void Run() { |
+ Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask); |
+ { |
+ Thread* thread = Thread::Current(); |
+ *thread_ptr_ = thread; |
+ |
+ // Create a zone (which is also a stack resource) and exercise it a bit. |
+ StackZone stack_zone(thread); |
+ HANDLESCOPE(thread); |
+ Zone* zone = thread->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); |
+ } |
+ // Let the main thread know we're done with memory ops on this thread. |
+ { |
+ MonitorLocker ml(monitor_); |
+ *done_ = true; |
+ ml.Notify(); |
+ } |
+ // Wait for the go-ahead from the main thread to exit. |
+ { |
+ MonitorLocker sync_ml(sync_); |
+ while (*wait_) { |
+ sync_ml.Wait(); |
+ } |
+ } |
+ } |
+ Thread::ExitIsolateAsHelper(); |
+ // Notify the main thread that this thread has exited. |
+ { |
+ MonitorLocker ml(monitor_); |
+ *done_ = true; |
+ ml.Notify(); |
+ } |
+ } |
+ |
+ private: |
+ Isolate* isolate_; |
+ Thread** thread_ptr_; |
+ Monitor* sync_; |
+ Monitor* monitor_; |
+ Monitor* done_monitor_; |
+ bool* done_; |
+ bool* wait_; |
+}; |
+ |
+ |
+VM_TEST_CASE(ManySimpleTasksWithZones) { |
+ const int kTaskCount = 10; |
+ Monitor monitor[kTaskCount]; |
+ Monitor sync; |
+ Thread* threads[kTaskCount + 1]; |
+ Isolate* isolate = Thread::Current()->isolate(); |
+ bool done[kTaskCount]; |
+ bool wait = true; |
+ threads[kTaskCount] = Thread::Current(); |
+ |
+ EXPECT(isolate->heap()->GrowthControlState()); |
+ isolate->heap()->DisableGrowthControl(); |
+ for (int i = 0; i < kTaskCount; i++) { |
+ done[i] = false; |
+ Dart::thread_pool()->Run(new SimpleTaskWithZoneAllocation( |
+ isolate, &threads[i], &sync, &monitor[i], &done[i], &wait)); |
+ } |
+ // Wait until all spawned tasks finish their memory operations. |
+ for (int i = 0; i < kTaskCount; i++) { |
+ MonitorLocker ml(&monitor[i]); |
+ while (!done[i]) { |
+ ml.Wait(); |
+ } |
+ // Reset flag to be reused later. |
+ done[i] = false; |
+ } |
siva
2016/12/07 22:12:53
Why does this have to use so many monitors one for
|
+ |
+ JSONStream stream; |
+ Isolate::PrintAllIsolatesMemoryInfoToJSONLocked(&stream); |
+ const char* json = stream.ToCString(); |
+ |
+ // Confirm all expected entries are in the JSON output. |
+ for (int i = 0; i < kTaskCount + 1; i++) { |
+ 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]; |
+ intptr_t thread_zone_size_total = 0; |
+ Zone* top_zone = thread->zone(); |
+ |
+ // Check that all zones are present with correct sizes. |
+ while (top_zone != NULL) { |
+ char zone_info_buf[64]; |
+ snprintf(zone_info_buf, sizeof(zone_info_buf), |
+ "\"address\":\"0x%" Px "\",\"size\":%ld", |
+ reinterpret_cast<uword>(top_zone), top_zone->SizeInBytes()); |
+ |
+ EXPECT_SUBSTRING(zone_info_buf, json); |
+ thread_zone_size_total += top_zone->SizeInBytes(); |
+ top_zone = top_zone->previous(); |
+ } |
+ |
+ // Check the thread exists and is the correct size. |
+ snprintf(thread_address_buf, sizeof(thread_address_buf), |
+ "\"thread_address\":\"0x%" Px |
+ "\",\"thread_zone_size_total\":\"%ld\"", |
+ reinterpret_cast<uword>(thread), thread_zone_size_total); |
+ |
+ // Ensure the isolate for each thread is valid. |
+ snprintf(isolate_address_buf, sizeof(isolate_address_buf), |
+ "\"isolate_address\":\"0x%" Px "\"", |
+ reinterpret_cast<uword>(thread_isolate)); |
+ |
+ 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. |
+ for (int i = 0; i < kTaskCount; i++) { |
+ MonitorLocker ml(&monitor[i]); |
+ while (!done[i]) { |
+ ml.Wait(); |
+ } |
+ } |
siva
2016/12/07 22:12:53
Ditto comment about waiting for tasks to exit, cou
|
+} |
+#endif |
+ |
+ |
TEST_CASE(ThreadRegistry) { |
Isolate* orig = Thread::Current()->isolate(); |
Zone* orig_zone = Thread::Current()->zone(); |