OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/thread_interrupter.h" | 5 #include "vm/thread_interrupter.h" |
6 | 6 |
7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
8 #include "vm/lockers.h" | 8 #include "vm/lockers.h" |
9 #include "vm/os.h" | 9 #include "vm/os.h" |
10 #include "vm/simulator.h" | 10 #include "vm/simulator.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 // thread local storage pointer is set again. This has an important side | 44 // thread local storage pointer is set again. This has an important side |
45 // effect: if the thread is interrupted by a signal handler during a ThreadState | 45 // effect: if the thread is interrupted by a signal handler during a ThreadState |
46 // update the signal handler will immediately return. | 46 // update the signal handler will immediately return. |
47 | 47 |
48 DEFINE_FLAG(bool, trace_thread_interrupter, false, | 48 DEFINE_FLAG(bool, trace_thread_interrupter, false, |
49 "Trace thread interrupter"); | 49 "Trace thread interrupter"); |
50 | 50 |
51 bool ThreadInterrupter::initialized_ = false; | 51 bool ThreadInterrupter::initialized_ = false; |
52 bool ThreadInterrupter::shutdown_ = false; | 52 bool ThreadInterrupter::shutdown_ = false; |
53 bool ThreadInterrupter::thread_running_ = false; | 53 bool ThreadInterrupter::thread_running_ = false; |
| 54 bool ThreadInterrupter::woken_up_ = false; |
54 ThreadJoinId ThreadInterrupter::interrupter_thread_id_ = | 55 ThreadJoinId ThreadInterrupter::interrupter_thread_id_ = |
55 OSThread::kInvalidThreadJoinId; | 56 OSThread::kInvalidThreadJoinId; |
56 Monitor* ThreadInterrupter::monitor_ = NULL; | 57 Monitor* ThreadInterrupter::monitor_ = NULL; |
57 intptr_t ThreadInterrupter::interrupt_period_ = 1000; | 58 intptr_t ThreadInterrupter::interrupt_period_ = 1000; |
58 intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout; | 59 intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout; |
59 | 60 |
60 | 61 |
61 void ThreadInterrupter::InitOnce() { | 62 void ThreadInterrupter::InitOnce() { |
62 ASSERT(!initialized_); | 63 ASSERT(!initialized_); |
63 monitor_ = new Monitor(); | 64 monitor_ = new Monitor(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 if (shutdown_) { | 119 if (shutdown_) { |
119 return; | 120 return; |
120 } | 121 } |
121 ASSERT(initialized_); | 122 ASSERT(initialized_); |
122 ASSERT(period > 0); | 123 ASSERT(period > 0); |
123 interrupt_period_ = period; | 124 interrupt_period_ = period; |
124 } | 125 } |
125 | 126 |
126 | 127 |
127 void ThreadInterrupter::WakeUp() { | 128 void ThreadInterrupter::WakeUp() { |
| 129 if (!initialized_) { |
| 130 // Early call. |
| 131 return; |
| 132 } |
128 ASSERT(initialized_); | 133 ASSERT(initialized_); |
129 { | 134 { |
130 MonitorLocker ml(monitor_); | 135 MonitorLocker ml(monitor_); |
| 136 woken_up_ = true; |
131 if (!InDeepSleep()) { | 137 if (!InDeepSleep()) { |
132 // No need to notify, regularly waking up. | 138 // No need to notify, regularly waking up. |
133 return; | 139 return; |
134 } | 140 } |
135 // Notify the interrupter to wake it from its deep sleep. | 141 // Notify the interrupter to wake it from its deep sleep. |
136 ml.Notify(); | 142 ml.Notify(); |
137 } | 143 } |
138 } | 144 } |
139 | 145 |
140 | 146 |
141 void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data) { | |
142 // NoOp. | |
143 } | |
144 | |
145 | |
146 class ThreadInterrupterVisitIsolates : public IsolateVisitor { | |
147 public: | |
148 ThreadInterrupterVisitIsolates() { | |
149 profiled_thread_count_ = 0; | |
150 } | |
151 | |
152 void VisitIsolate(Isolate* isolate) { | |
153 ASSERT(isolate != NULL); | |
154 profiled_thread_count_ += isolate->ProfileInterrupt(); | |
155 } | |
156 | |
157 intptr_t profiled_thread_count() const { | |
158 return profiled_thread_count_; | |
159 } | |
160 | |
161 void set_profiled_thread_count(intptr_t profiled_thread_count) { | |
162 profiled_thread_count_ = profiled_thread_count; | |
163 } | |
164 | |
165 private: | |
166 intptr_t profiled_thread_count_; | |
167 }; | |
168 | |
169 | |
170 void ThreadInterrupter::ThreadMain(uword parameters) { | 147 void ThreadInterrupter::ThreadMain(uword parameters) { |
171 ASSERT(initialized_); | 148 ASSERT(initialized_); |
172 InstallSignalHandler(); | 149 InstallSignalHandler(); |
173 if (FLAG_trace_thread_interrupter) { | 150 if (FLAG_trace_thread_interrupter) { |
174 OS::Print("ThreadInterrupter thread running.\n"); | 151 OS::Print("ThreadInterrupter thread running.\n"); |
175 } | 152 } |
176 { | 153 { |
177 // Signal to main thread we are ready. | 154 // Signal to main thread we are ready. |
178 MonitorLocker startup_ml(monitor_); | 155 MonitorLocker startup_ml(monitor_); |
179 interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId(); | 156 interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId(); |
180 thread_running_ = true; | 157 thread_running_ = true; |
181 startup_ml.Notify(); | 158 startup_ml.Notify(); |
182 } | 159 } |
183 { | 160 { |
184 ThreadInterrupterVisitIsolates visitor; | 161 intptr_t interrupted_thread_count = 0; |
185 current_wait_time_ = interrupt_period_; | 162 current_wait_time_ = interrupt_period_; |
186 MonitorLocker wait_ml(monitor_); | 163 MonitorLocker wait_ml(monitor_); |
187 while (!shutdown_) { | 164 while (!shutdown_) { |
188 intptr_t r = wait_ml.WaitMicros(current_wait_time_); | 165 intptr_t r = wait_ml.WaitMicros(current_wait_time_); |
189 | 166 |
190 if ((r == Monitor::kNotified) && shutdown_) { | 167 if (shutdown_) { |
191 break; | 168 break; |
192 } | 169 } |
193 | 170 |
194 if ((r == Monitor::kNotified) && InDeepSleep()) { | 171 if ((r == Monitor::kNotified) && InDeepSleep()) { |
195 // Woken up from deep sleep. | 172 // Woken up from deep sleep. |
196 ASSERT(visitor.profiled_thread_count() == 0); | 173 ASSERT(interrupted_thread_count == 0); |
197 // Return to regular interrupts. | 174 // Return to regular interrupts. |
198 current_wait_time_ = interrupt_period_; | 175 current_wait_time_ = interrupt_period_; |
199 } | 176 } |
200 | 177 |
201 // Reset count before visiting isolates. | 178 // Reset count before interrupting any threads. |
202 visitor.set_profiled_thread_count(0); | 179 interrupted_thread_count = 0; |
203 Isolate::VisitIsolates(&visitor); | |
204 | 180 |
205 if (visitor.profiled_thread_count() == 0) { | 181 // Temporarily drop the monitor while we interrupt threads. |
206 // No isolates were profiled. In order to reduce unnecessary CPU | 182 monitor_->Exit(); |
207 // load, we will wait until we are notified before attempting to | 183 |
208 // interrupt again. | 184 { |
| 185 ThreadIterator it; |
| 186 while (it.HasNext()) { |
| 187 Thread* thread = it.Next(); |
| 188 if (thread->ThreadInterruptsEnabled()) { |
| 189 interrupted_thread_count++; |
| 190 InterruptThread(thread); |
| 191 } |
| 192 } |
| 193 } |
| 194 |
| 195 // Take the monitor lock again. |
| 196 monitor_->Enter(); |
| 197 |
| 198 // Now that we have the lock, check if we were signaled to wake up while |
| 199 // interrupting threads. |
| 200 if (!woken_up_ && (interrupted_thread_count == 0)) { |
| 201 // No threads were interrupted and we were not signaled to interrupt |
| 202 // new threads. In order to reduce unnecessary CPU load, we will wait |
| 203 // until we are notified before attempting to interrupt again. |
209 current_wait_time_ = Monitor::kNoTimeout; | 204 current_wait_time_ = Monitor::kNoTimeout; |
210 continue; | 205 continue; |
211 } | 206 } |
212 | 207 |
| 208 woken_up_ = false; |
| 209 |
213 ASSERT(current_wait_time_ != Monitor::kNoTimeout); | 210 ASSERT(current_wait_time_ != Monitor::kNoTimeout); |
214 } | 211 } |
215 } | 212 } |
216 RemoveSignalHandler(); | 213 RemoveSignalHandler(); |
217 if (FLAG_trace_thread_interrupter) { | 214 if (FLAG_trace_thread_interrupter) { |
218 OS::Print("ThreadInterrupter thread exiting.\n"); | 215 OS::Print("ThreadInterrupter thread exiting.\n"); |
219 } | 216 } |
220 { | 217 { |
221 // Signal to main thread we are exiting. | 218 // Signal to main thread we are exiting. |
222 MonitorLocker shutdown_ml(monitor_); | 219 MonitorLocker shutdown_ml(monitor_); |
223 thread_running_ = false; | 220 thread_running_ = false; |
224 shutdown_ml.Notify(); | 221 shutdown_ml.Notify(); |
225 } | 222 } |
226 } | 223 } |
227 | 224 |
228 } // namespace dart | 225 } // namespace dart |
OLD | NEW |