| Index: runtime/vm/isolate_test.cc
|
| diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
|
| index f5f0506aeaa63bf4cc3356b4c4d89f994cdab854..75ae5a4d95113ecc7ad84b8daa86f29705718a85 100644
|
| --- a/runtime/vm/isolate_test.cc
|
| +++ b/runtime/vm/isolate_test.cc
|
| @@ -6,6 +6,8 @@
|
| #include "platform/assert.h"
|
| #include "vm/globals.h"
|
| #include "vm/isolate.h"
|
| +#include "vm/lockers.h"
|
| +#include "vm/thread_pool.h"
|
| #include "vm/unit_test.h"
|
|
|
| namespace dart {
|
| @@ -80,4 +82,120 @@ TEST_CASE(IsolateSpawn) {
|
| EXPECT_VALID(exception_result);
|
| }
|
|
|
| +
|
| +class InterruptChecker : public ThreadPool::Task {
|
| + public:
|
| + static const intptr_t kTaskCount;
|
| + static const intptr_t kIterations;
|
| +
|
| + InterruptChecker(Isolate* isolate,
|
| + Monitor* monitor,
|
| + bool* awake,
|
| + Monitor* round_monitor,
|
| + const intptr_t* round)
|
| + : isolate_(isolate),
|
| + monitor_(monitor),
|
| + awake_(awake),
|
| + round_monitor_(round_monitor),
|
| + round_(round) {
|
| + }
|
| +
|
| + virtual void Run() {
|
| + Thread::EnterIsolateAsHelper(isolate_);
|
| + for (intptr_t i = 0; i < kIterations; ++i) {
|
| + // Busy wait for interrupts.
|
| + while (!isolate_->HasInterruptsScheduled(Isolate::kVMInterrupt)) {
|
| + // Do nothing.
|
| + }
|
| + // Tell main thread that we observed the interrupt.
|
| + {
|
| + MonitorLocker ml(monitor_);
|
| + ASSERT(!*awake_);
|
| + *awake_ = true;
|
| + ml.Notify();
|
| + }
|
| + // Wait for main thread to let us resume.
|
| + {
|
| + MonitorLocker ml(round_monitor_);
|
| + EXPECT(*round_ == i || *round_ == (i + 1));
|
| + while (*round_ == i) {
|
| + ml.Wait();
|
| + }
|
| + EXPECT(*round_ == i + 1);
|
| + }
|
| + }
|
| + Thread::ExitIsolateAsHelper();
|
| + // Use awake to signal exit.
|
| + {
|
| + MonitorLocker ml(monitor_);
|
| + *awake_ = true;
|
| + ml.Notify();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + Isolate* isolate_;
|
| + Monitor* monitor_;
|
| + bool* awake_;
|
| + Monitor* round_monitor_;
|
| + const intptr_t* round_;
|
| +};
|
| +
|
| +
|
| +const intptr_t InterruptChecker::kTaskCount = 50;
|
| +const intptr_t InterruptChecker::kIterations = 1000;
|
| +
|
| +
|
| +// Waits for all tasks to set their flag, then clears them all.
|
| +static void WaitForAllTasks(bool* flags, Monitor* monitor) {
|
| + MonitorLocker ml(monitor);
|
| + while (true) {
|
| + intptr_t count = 0;
|
| + for (intptr_t task = 0; task < InterruptChecker::kTaskCount; ++task) {
|
| + if (flags[task]) {
|
| + ++count;
|
| + }
|
| + }
|
| + if (count == InterruptChecker::kTaskCount) {
|
| + memset(flags, 0, sizeof(*flags) * count);
|
| + break;
|
| + } else {
|
| + ml.Wait();
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Test and document usage of Isolate::HasInterruptsScheduled.
|
| +//
|
| +// Go through a number of rounds of scheduling interrupts and waiting until all
|
| +// unsynchronized busy-waiting tasks observe it (in the current implementation,
|
| +// the exact latency depends on cache coherence). Synchronization is then used
|
| +// to enforce the required memory ordering, to ensure correct progression of
|
| +// the rounds.
|
| +TEST_CASE(StackLimitInterrupts) {
|
| + Monitor monitor;
|
| + bool awake[InterruptChecker::kTaskCount];
|
| + memset(awake, 0, sizeof(awake));
|
| + Monitor round_monitor;
|
| + intptr_t round = 0;
|
| + Isolate* isolate = Thread::Current()->isolate();
|
| + for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) {
|
| + Dart::thread_pool()->Run(new InterruptChecker(
|
| + isolate, &monitor, &awake[task], &round_monitor, &round));
|
| + }
|
| + for (intptr_t i = 0; i < InterruptChecker::kIterations; ++i) {
|
| + isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
|
| + WaitForAllTasks(awake, &monitor);
|
| + uword interrupts = isolate->GetAndClearInterrupts();
|
| + EXPECT((interrupts & Isolate::kVMInterrupt) != 0);
|
| + {
|
| + MonitorLocker ml(&round_monitor);
|
| + ++round;
|
| + ml.NotifyAll();
|
| + }
|
| + }
|
| + // Wait for tasks to exit cleanly.
|
| + WaitForAllTasks(awake, &monitor);
|
| +}
|
| +
|
| } // namespace dart
|
|
|