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 ThreadId ThreadInterrupter::interrupter_thread_id_ = Thread::kInvalidThreadId; | 54 ThreadId ThreadInterrupter::interrupter_thread_id_ = |
| 55 OSThread::kInvalidThreadId; |
55 Monitor* ThreadInterrupter::monitor_ = NULL; | 56 Monitor* ThreadInterrupter::monitor_ = NULL; |
56 intptr_t ThreadInterrupter::interrupt_period_ = 1000; | 57 intptr_t ThreadInterrupter::interrupt_period_ = 1000; |
57 intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout; | 58 intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout; |
58 ThreadLocalKey ThreadInterrupter::thread_state_key_ = | 59 ThreadLocalKey ThreadInterrupter::thread_state_key_ = |
59 Thread::kUnsetThreadLocalKey; | 60 OSThread::kUnsetThreadLocalKey; |
60 | 61 |
61 | 62 |
62 void ThreadInterrupter::InitOnce() { | 63 void ThreadInterrupter::InitOnce() { |
63 ASSERT(!initialized_); | 64 ASSERT(!initialized_); |
64 ASSERT(thread_state_key_ == Thread::kUnsetThreadLocalKey); | 65 ASSERT(thread_state_key_ == OSThread::kUnsetThreadLocalKey); |
65 thread_state_key_ = Thread::CreateThreadLocal(); | 66 thread_state_key_ = OSThread::CreateThreadLocal(); |
66 ASSERT(thread_state_key_ != Thread::kUnsetThreadLocalKey); | 67 ASSERT(thread_state_key_ != OSThread::kUnsetThreadLocalKey); |
67 monitor_ = new Monitor(); | 68 monitor_ = new Monitor(); |
68 ASSERT(monitor_ != NULL); | 69 ASSERT(monitor_ != NULL); |
69 initialized_ = true; | 70 initialized_ = true; |
70 } | 71 } |
71 | 72 |
72 | 73 |
73 void ThreadInterrupter::Startup() { | 74 void ThreadInterrupter::Startup() { |
74 ASSERT(initialized_); | 75 ASSERT(initialized_); |
75 if (FLAG_trace_thread_interrupter) { | 76 if (FLAG_trace_thread_interrupter) { |
76 OS::Print("ThreadInterrupter starting up.\n"); | 77 OS::Print("ThreadInterrupter starting up.\n"); |
77 } | 78 } |
78 ASSERT(interrupter_thread_id_ == Thread::kInvalidThreadId); | 79 ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadId); |
79 { | 80 { |
80 MonitorLocker startup_ml(monitor_); | 81 MonitorLocker startup_ml(monitor_); |
81 Thread::Start(ThreadMain, 0); | 82 OSThread::Start(ThreadMain, 0); |
82 while (!thread_running_) { | 83 while (!thread_running_) { |
83 startup_ml.Wait(); | 84 startup_ml.Wait(); |
84 } | 85 } |
85 } | 86 } |
86 ASSERT(interrupter_thread_id_ != Thread::kInvalidThreadId); | 87 ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadId); |
87 if (FLAG_trace_thread_interrupter) { | 88 if (FLAG_trace_thread_interrupter) { |
88 OS::Print("ThreadInterrupter running.\n"); | 89 OS::Print("ThreadInterrupter running.\n"); |
89 } | 90 } |
90 } | 91 } |
91 | 92 |
92 | 93 |
93 void ThreadInterrupter::Shutdown() { | 94 void ThreadInterrupter::Shutdown() { |
94 { | 95 { |
95 MonitorLocker shutdown_ml(monitor_); | 96 MonitorLocker shutdown_ml(monitor_); |
96 if (shutdown_) { | 97 if (shutdown_) { |
97 // Already shutdown. | 98 // Already shutdown. |
98 return; | 99 return; |
99 } | 100 } |
100 shutdown_ = true; | 101 shutdown_ = true; |
101 // Notify. | 102 // Notify. |
102 monitor_->Notify(); | 103 monitor_->Notify(); |
103 ASSERT(initialized_); | 104 ASSERT(initialized_); |
104 if (FLAG_trace_thread_interrupter) { | 105 if (FLAG_trace_thread_interrupter) { |
105 OS::Print("ThreadInterrupter shutting down.\n"); | 106 OS::Print("ThreadInterrupter shutting down.\n"); |
106 } | 107 } |
107 } | 108 } |
108 #if defined(TARGET_OS_WINDOWS) | 109 #if defined(TARGET_OS_WINDOWS) |
109 // On Windows, a thread's exit-code can leak into the process's exit-code, | 110 // On Windows, a thread's exit-code can leak into the process's exit-code, |
110 // if exiting 'at same time' as the process ends. By joining with the thread | 111 // if exiting 'at same time' as the process ends. By joining with the thread |
111 // here, we avoid this race condition. | 112 // here, we avoid this race condition. |
112 ASSERT(interrupter_thread_id_ != Thread::kInvalidThreadId); | 113 ASSERT(interrupter_thread_id_ != OSThread::kInvalidThreadId); |
113 Thread::Join(interrupter_thread_id_); | 114 OSThread::Join(interrupter_thread_id_); |
114 interrupter_thread_id_ = Thread::kInvalidThreadId; | 115 interrupter_thread_id_ = OSThread::kInvalidThreadId; |
115 #else | 116 #else |
116 // On non-Windows platforms, just wait for the thread interrupter to signal | 117 // On non-Windows platforms, just wait for the thread interrupter to signal |
117 // that it has exited the loop. | 118 // that it has exited the loop. |
118 { | 119 { |
119 MonitorLocker shutdown_ml(monitor_); | 120 MonitorLocker shutdown_ml(monitor_); |
120 while (thread_running_) { | 121 while (thread_running_) { |
121 // Wait for thread to exit. | 122 // Wait for thread to exit. |
122 shutdown_ml.Wait(); | 123 shutdown_ml.Wait(); |
123 } | 124 } |
124 } | 125 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 _EnsureThreadStateCreated(); | 177 _EnsureThreadStateCreated(); |
177 // Clear callback and data. | 178 // Clear callback and data. |
178 UpdateStateObject(NULL, NULL); | 179 UpdateStateObject(NULL, NULL); |
179 } | 180 } |
180 | 181 |
181 | 182 |
182 InterruptableThreadState* ThreadInterrupter::_EnsureThreadStateCreated() { | 183 InterruptableThreadState* ThreadInterrupter::_EnsureThreadStateCreated() { |
183 InterruptableThreadState* state = CurrentThreadState(); | 184 InterruptableThreadState* state = CurrentThreadState(); |
184 if (state == NULL) { | 185 if (state == NULL) { |
185 // Create thread state object lazily. | 186 // Create thread state object lazily. |
186 ThreadId current_thread = Thread::GetCurrentThreadId(); | 187 ThreadId current_thread = OSThread::GetCurrentThreadId(); |
187 if (FLAG_trace_thread_interrupter) { | 188 if (FLAG_trace_thread_interrupter) { |
188 intptr_t tid = Thread::ThreadIdToIntPtr(current_thread); | 189 intptr_t tid = OSThread::ThreadIdToIntPtr(current_thread); |
189 OS::Print("ThreadInterrupter Tracking %p\n", | 190 OS::Print("ThreadInterrupter Tracking %p\n", |
190 reinterpret_cast<void*>(tid)); | 191 reinterpret_cast<void*>(tid)); |
191 } | 192 } |
192 // Note: We currently do not free a thread's InterruptableThreadState. | 193 // Note: We currently do not free a thread's InterruptableThreadState. |
193 state = new InterruptableThreadState(); | 194 state = new InterruptableThreadState(); |
194 ASSERT(state != NULL); | 195 ASSERT(state != NULL); |
195 state->callback = NULL; | 196 state->callback = NULL; |
196 state->data = NULL; | 197 state->data = NULL; |
197 state->id = current_thread; | 198 state->id = current_thread; |
198 SetCurrentThreadState(state); | 199 SetCurrentThreadState(state); |
199 } | 200 } |
200 return state; | 201 return state; |
201 } | 202 } |
202 | 203 |
203 | 204 |
204 void ThreadInterrupter::UpdateStateObject(ThreadInterruptCallback callback, | 205 void ThreadInterrupter::UpdateStateObject(ThreadInterruptCallback callback, |
205 void* data) { | 206 void* data) { |
206 InterruptableThreadState* state = CurrentThreadState(); | 207 InterruptableThreadState* state = CurrentThreadState(); |
207 ThreadId current_thread = Thread::GetCurrentThreadId(); | 208 ThreadId current_thread = OSThread::GetCurrentThreadId(); |
208 ASSERT(state != NULL); | 209 ASSERT(state != NULL); |
209 ASSERT(Thread::Compare(state->id, Thread::GetCurrentThreadId())); | 210 ASSERT(OSThread::Compare(state->id, OSThread::GetCurrentThreadId())); |
210 SetCurrentThreadState(NULL); | 211 SetCurrentThreadState(NULL); |
211 // It is now safe to modify the state object. If an interrupt occurs, | 212 // It is now safe to modify the state object. If an interrupt occurs, |
212 // the current thread state will be NULL. | 213 // the current thread state will be NULL. |
213 state->callback = callback; | 214 state->callback = callback; |
214 state->data = data; | 215 state->data = data; |
215 SetCurrentThreadState(state); | 216 SetCurrentThreadState(state); |
216 if (FLAG_trace_thread_interrupter) { | 217 if (FLAG_trace_thread_interrupter) { |
217 intptr_t tid = Thread::ThreadIdToIntPtr(current_thread); | 218 intptr_t tid = OSThread::ThreadIdToIntPtr(current_thread); |
218 if (callback == NULL) { | 219 if (callback == NULL) { |
219 OS::Print("ThreadInterrupter Cleared %p\n", reinterpret_cast<void*>(tid)); | 220 OS::Print("ThreadInterrupter Cleared %p\n", reinterpret_cast<void*>(tid)); |
220 } else { | 221 } else { |
221 OS::Print("ThreadInterrupter Updated %p\n", reinterpret_cast<void*>(tid)); | 222 OS::Print("ThreadInterrupter Updated %p\n", reinterpret_cast<void*>(tid)); |
222 } | 223 } |
223 } | 224 } |
224 } | 225 } |
225 | 226 |
226 | 227 |
227 InterruptableThreadState* ThreadInterrupter::GetCurrentThreadState() { | 228 InterruptableThreadState* ThreadInterrupter::GetCurrentThreadState() { |
228 return _EnsureThreadStateCreated(); | 229 return _EnsureThreadStateCreated(); |
229 } | 230 } |
230 | 231 |
231 | 232 |
232 InterruptableThreadState* ThreadInterrupter::CurrentThreadState() { | 233 InterruptableThreadState* ThreadInterrupter::CurrentThreadState() { |
233 InterruptableThreadState* state = reinterpret_cast<InterruptableThreadState*>( | 234 InterruptableThreadState* state = reinterpret_cast<InterruptableThreadState*>( |
234 Thread::GetThreadLocal(thread_state_key_)); | 235 OSThread::GetThreadLocal(thread_state_key_)); |
235 return state; | 236 return state; |
236 } | 237 } |
237 | 238 |
238 | 239 |
239 void ThreadInterrupter::SetCurrentThreadState(InterruptableThreadState* state) { | 240 void ThreadInterrupter::SetCurrentThreadState(InterruptableThreadState* state) { |
240 Thread::SetThreadLocal(thread_state_key_, reinterpret_cast<uword>(state)); | 241 OSThread::SetThreadLocal(thread_state_key_, |
| 242 reinterpret_cast<uword>(state)); |
241 } | 243 } |
242 | 244 |
243 | 245 |
244 void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data) { | 246 void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data) { |
245 // NoOp. | 247 // NoOp. |
246 } | 248 } |
247 | 249 |
248 | 250 |
249 class ThreadInterrupterVisitIsolates : public IsolateVisitor { | 251 class ThreadInterrupterVisitIsolates : public IsolateVisitor { |
250 public: | 252 public: |
(...skipping 21 matching lines...) Expand all Loading... |
272 | 274 |
273 void ThreadInterrupter::ThreadMain(uword parameters) { | 275 void ThreadInterrupter::ThreadMain(uword parameters) { |
274 ASSERT(initialized_); | 276 ASSERT(initialized_); |
275 InstallSignalHandler(); | 277 InstallSignalHandler(); |
276 if (FLAG_trace_thread_interrupter) { | 278 if (FLAG_trace_thread_interrupter) { |
277 OS::Print("ThreadInterrupter thread running.\n"); | 279 OS::Print("ThreadInterrupter thread running.\n"); |
278 } | 280 } |
279 { | 281 { |
280 // Signal to main thread we are ready. | 282 // Signal to main thread we are ready. |
281 MonitorLocker startup_ml(monitor_); | 283 MonitorLocker startup_ml(monitor_); |
282 interrupter_thread_id_ = Thread::GetCurrentThreadId(); | 284 interrupter_thread_id_ = OSThread::GetCurrentThreadId(); |
283 thread_running_ = true; | 285 thread_running_ = true; |
284 startup_ml.Notify(); | 286 startup_ml.Notify(); |
285 } | 287 } |
286 { | 288 { |
287 ThreadInterrupterVisitIsolates visitor; | 289 ThreadInterrupterVisitIsolates visitor; |
288 current_wait_time_ = interrupt_period_; | 290 current_wait_time_ = interrupt_period_; |
289 MonitorLocker wait_ml(monitor_); | 291 MonitorLocker wait_ml(monitor_); |
290 while (!shutdown_) { | 292 while (!shutdown_) { |
291 intptr_t r = wait_ml.WaitMicros(current_wait_time_); | 293 intptr_t r = wait_ml.WaitMicros(current_wait_time_); |
292 | 294 |
(...skipping 24 matching lines...) Expand all Loading... |
317 } | 319 } |
318 { | 320 { |
319 // Signal to main thread we are exiting. | 321 // Signal to main thread we are exiting. |
320 MonitorLocker shutdown_ml(monitor_); | 322 MonitorLocker shutdown_ml(monitor_); |
321 thread_running_ = false; | 323 thread_running_ = false; |
322 shutdown_ml.Notify(); | 324 shutdown_ml.Notify(); |
323 } | 325 } |
324 } | 326 } |
325 | 327 |
326 } // namespace dart | 328 } // namespace dart |
OLD | NEW |