| Index: runtime/vm/thread_interrupter.cc
|
| diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
|
| index 58c94bec797cc04dadc697d31c33db8dd7d31f8e..616d29b5e7cae897580a8ee8315ccdcc0acbec37 100644
|
| --- a/runtime/vm/thread_interrupter.cc
|
| +++ b/runtime/vm/thread_interrupter.cc
|
| @@ -51,6 +51,7 @@ DEFINE_FLAG(bool, trace_thread_interrupter, false,
|
| bool ThreadInterrupter::initialized_ = false;
|
| bool ThreadInterrupter::shutdown_ = false;
|
| bool ThreadInterrupter::thread_running_ = false;
|
| +bool ThreadInterrupter::woken_up_ = false;
|
| ThreadJoinId ThreadInterrupter::interrupter_thread_id_ =
|
| OSThread::kInvalidThreadJoinId;
|
| Monitor* ThreadInterrupter::monitor_ = NULL;
|
| @@ -124,9 +125,14 @@ void ThreadInterrupter::SetInterruptPeriod(intptr_t period) {
|
|
|
|
|
| void ThreadInterrupter::WakeUp() {
|
| + if (!initialized_) {
|
| + // Early call.
|
| + return;
|
| + }
|
| ASSERT(initialized_);
|
| {
|
| MonitorLocker ml(monitor_);
|
| + woken_up_ = true;
|
| if (!InDeepSleep()) {
|
| // No need to notify, regularly waking up.
|
| return;
|
| @@ -137,35 +143,6 @@ void ThreadInterrupter::WakeUp() {
|
| }
|
|
|
|
|
| -void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data) {
|
| - // NoOp.
|
| -}
|
| -
|
| -
|
| -class ThreadInterrupterVisitIsolates : public IsolateVisitor {
|
| - public:
|
| - ThreadInterrupterVisitIsolates() {
|
| - profiled_thread_count_ = 0;
|
| - }
|
| -
|
| - void VisitIsolate(Isolate* isolate) {
|
| - ASSERT(isolate != NULL);
|
| - profiled_thread_count_ += isolate->ProfileInterrupt();
|
| - }
|
| -
|
| - intptr_t profiled_thread_count() const {
|
| - return profiled_thread_count_;
|
| - }
|
| -
|
| - void set_profiled_thread_count(intptr_t profiled_thread_count) {
|
| - profiled_thread_count_ = profiled_thread_count;
|
| - }
|
| -
|
| - private:
|
| - intptr_t profiled_thread_count_;
|
| -};
|
| -
|
| -
|
| void ThreadInterrupter::ThreadMain(uword parameters) {
|
| ASSERT(initialized_);
|
| InstallSignalHandler();
|
| @@ -180,35 +157,55 @@ void ThreadInterrupter::ThreadMain(uword parameters) {
|
| startup_ml.Notify();
|
| }
|
| {
|
| - ThreadInterrupterVisitIsolates visitor;
|
| + intptr_t interrupted_thread_count = 0;
|
| current_wait_time_ = interrupt_period_;
|
| MonitorLocker wait_ml(monitor_);
|
| while (!shutdown_) {
|
| intptr_t r = wait_ml.WaitMicros(current_wait_time_);
|
|
|
| - if ((r == Monitor::kNotified) && shutdown_) {
|
| + if (shutdown_) {
|
| break;
|
| }
|
|
|
| if ((r == Monitor::kNotified) && InDeepSleep()) {
|
| // Woken up from deep sleep.
|
| - ASSERT(visitor.profiled_thread_count() == 0);
|
| + ASSERT(interrupted_thread_count == 0);
|
| // Return to regular interrupts.
|
| current_wait_time_ = interrupt_period_;
|
| }
|
|
|
| - // Reset count before visiting isolates.
|
| - visitor.set_profiled_thread_count(0);
|
| - Isolate::VisitIsolates(&visitor);
|
| + // Reset count before interrupting any threads.
|
| + interrupted_thread_count = 0;
|
| +
|
| + // Temporarily drop the monitor while we interrupt threads.
|
| + monitor_->Exit();
|
| +
|
| + {
|
| + ThreadIterator it;
|
| + while (it.HasNext()) {
|
| + Thread* thread = it.Next();
|
| + if (thread->ThreadInterruptsEnabled()) {
|
| + interrupted_thread_count++;
|
| + InterruptThread(thread);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Take the monitor lock again.
|
| + monitor_->Enter();
|
|
|
| - if (visitor.profiled_thread_count() == 0) {
|
| - // No isolates were profiled. In order to reduce unnecessary CPU
|
| - // load, we will wait until we are notified before attempting to
|
| - // interrupt again.
|
| + // Now that we have the lock, check if we were signaled to wake up while
|
| + // interrupting threads.
|
| + if (!woken_up_ && (interrupted_thread_count == 0)) {
|
| + // No threads were interrupted and we were not signaled to interrupt
|
| + // new threads. In order to reduce unnecessary CPU load, we will wait
|
| + // until we are notified before attempting to interrupt again.
|
| current_wait_time_ = Monitor::kNoTimeout;
|
| continue;
|
| }
|
|
|
| + woken_up_ = false;
|
| +
|
| ASSERT(current_wait_time_ != Monitor::kNoTimeout);
|
| }
|
| }
|
|
|