Chromium Code Reviews| 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(); |