| Index: runtime/vm/thread_test.cc
|
| diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
|
| index 2dcf56805513f9745f792203630750b50a37fe09..99302caf787a7c6b2d557ae032f868ef5995d43a 100644
|
| --- a/runtime/vm/thread_test.cc
|
| +++ b/runtime/vm/thread_test.cc
|
| @@ -205,6 +205,179 @@ VM_TEST_CASE(ManyTasksWithZones) {
|
| }
|
|
|
|
|
| +#ifndef PRODUCT
|
| +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();
|
| + }
|
| + }
|
| + }
|
| +
|
| + 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 (intptr_t i = 0; i < kTaskCount; i++) {
|
| + 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 (intptr_t 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];
|
| + Zone* top_zone = thread->zone();
|
| +
|
| + Thread* current_thread = Thread::Current();
|
| + StackZone stack_zone(current_thread);
|
| + Zone* current_zone = current_thread->zone();
|
| +
|
| + // Check that all zones are present with correct sizes.
|
| + while (top_zone != NULL) {
|
| + char* zone_info_buf =
|
| + OS::SCreate(current_zone,
|
| + "\"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.
|
| + char* thread_info_buf = OS::SCreate(current_zone,
|
| + "\"type\":\"_Thread\","
|
| + "\"id\":\"threads\\/%" Pd64 "",
|
| + thread->os_thread()->trace_id());
|
| +
|
| + // Ensure the isolate for each thread is valid.
|
| +
|
| + char* isolate_info_buf =
|
| + OS::SCreate(current_zone,
|
| + "\"type\":\"Isolate\","
|
| + "\"fixedId\":true,"
|
| + "\"id\":\"isolates\\/%" Pd64 "",
|
| + static_cast<int64_t>(thread_isolate->main_port()));
|
| +
|
| + EXPECT_SUBSTRING(thread_info_buf, json);
|
| + EXPECT_SUBSTRING(isolate_info_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();
|
|
|