OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 "include/dart_api.h" | 5 #include "include/dart_api.h" |
6 #include "platform/assert.h" | 6 #include "platform/assert.h" |
7 #include "vm/globals.h" | 7 #include "vm/globals.h" |
8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
10 #include "vm/thread_barrier.h" | 10 #include "vm/thread_barrier.h" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 Dart_Handle exception_result = Dart_ErrorGetException(result); | 82 Dart_Handle exception_result = Dart_ErrorGetException(result); |
83 EXPECT_VALID(exception_result); | 83 EXPECT_VALID(exception_result); |
84 } | 84 } |
85 | 85 |
86 | 86 |
87 class InterruptChecker : public ThreadPool::Task { | 87 class InterruptChecker : public ThreadPool::Task { |
88 public: | 88 public: |
89 static const intptr_t kTaskCount; | 89 static const intptr_t kTaskCount; |
90 static const intptr_t kIterations; | 90 static const intptr_t kIterations; |
91 | 91 |
92 InterruptChecker(Isolate* isolate, | 92 InterruptChecker(Thread* thread, ThreadBarrier* barrier) |
93 ThreadBarrier* barrier) | 93 : thread_(thread), |
94 : isolate_(isolate), | |
95 barrier_(barrier) { | 94 barrier_(barrier) { |
96 } | 95 } |
97 | 96 |
98 virtual void Run() { | 97 virtual void Run() { |
99 Thread::EnterIsolateAsHelper(isolate_); | 98 Thread::EnterIsolateAsHelper(thread_->isolate()); |
100 // Tell main thread that we are ready. | 99 // Tell main thread that we are ready. |
101 barrier_->Sync(); | 100 barrier_->Sync(); |
102 for (intptr_t i = 0; i < kIterations; ++i) { | 101 for (intptr_t i = 0; i < kIterations; ++i) { |
103 // Busy wait for interrupts. | 102 // Busy wait for interrupts. |
104 while (!isolate_->HasInterruptsScheduled(Isolate::kVMInterrupt)) { | 103 uword limit = 0; |
105 // Do nothing. | 104 do { |
106 } | 105 limit = AtomicOperations::LoadRelaxed( |
| 106 reinterpret_cast<uword*>(thread_->stack_limit_address())); |
| 107 } while ((limit == thread_->saved_stack_limit_) || |
| 108 (((limit & Thread::kInterruptsMask) & |
| 109 Thread::kVMInterrupt) == 0)); |
107 // Tell main thread that we observed the interrupt. | 110 // Tell main thread that we observed the interrupt. |
108 barrier_->Sync(); | 111 barrier_->Sync(); |
109 } | 112 } |
110 Thread::ExitIsolateAsHelper(); | 113 Thread::ExitIsolateAsHelper(); |
111 barrier_->Exit(); | 114 barrier_->Exit(); |
112 } | 115 } |
113 | 116 |
114 private: | 117 private: |
115 Isolate* isolate_; | 118 Thread* thread_; |
116 ThreadBarrier* barrier_; | 119 ThreadBarrier* barrier_; |
117 }; | 120 }; |
118 | 121 |
119 | 122 |
120 const intptr_t InterruptChecker::kTaskCount = 5; | 123 const intptr_t InterruptChecker::kTaskCount = 5; |
121 const intptr_t InterruptChecker::kIterations = 10; | 124 const intptr_t InterruptChecker::kIterations = 10; |
122 | 125 |
123 // Test and document usage of Isolate::HasInterruptsScheduled. | 126 // Test and document usage of Isolate::HasInterruptsScheduled. |
124 // | 127 // |
125 // Go through a number of rounds of scheduling interrupts and waiting until all | 128 // Go through a number of rounds of scheduling interrupts and waiting until all |
126 // unsynchronized busy-waiting tasks observe it (in the current implementation, | 129 // unsynchronized busy-waiting tasks observe it (in the current implementation, |
127 // the exact latency depends on cache coherence). Synchronization is then used | 130 // the exact latency depends on cache coherence). Synchronization is then used |
128 // to ensure that the response to the interrupt, i.e., starting a new round, | 131 // to ensure that the response to the interrupt, i.e., starting a new round, |
129 // happens *after* the interrupt is observed. Without this synchronization, the | 132 // happens *after* the interrupt is observed. Without this synchronization, the |
130 // compiler and/or CPU could reorder operations to make the tasks observe the | 133 // compiler and/or CPU could reorder operations to make the tasks observe the |
131 // round update *before* the interrupt is set. | 134 // round update *before* the interrupt is set. |
132 TEST_CASE(StackLimitInterrupts) { | 135 TEST_CASE(StackLimitInterrupts) { |
133 Isolate* isolate = Thread::Current()->isolate(); | 136 Isolate* isolate = thread->isolate(); |
134 ThreadBarrier barrier(InterruptChecker::kTaskCount + 1, | 137 ThreadBarrier barrier(InterruptChecker::kTaskCount + 1, |
135 isolate->heap()->barrier(), | 138 isolate->heap()->barrier(), |
136 isolate->heap()->barrier_done()); | 139 isolate->heap()->barrier_done()); |
137 // Start all tasks. They will busy-wait until interrupted in the first round. | 140 // Start all tasks. They will busy-wait until interrupted in the first round. |
138 for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) { | 141 for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) { |
139 Dart::thread_pool()->Run(new InterruptChecker(isolate, &barrier)); | 142 Dart::thread_pool()->Run(new InterruptChecker(thread, &barrier)); |
140 } | 143 } |
141 // Wait for all tasks to get ready for the first round. | 144 // Wait for all tasks to get ready for the first round. |
142 barrier.Sync(); | 145 barrier.Sync(); |
143 for (intptr_t i = 0; i < InterruptChecker::kIterations; ++i) { | 146 for (intptr_t i = 0; i < InterruptChecker::kIterations; ++i) { |
144 isolate->ScheduleInterrupts(Isolate::kVMInterrupt); | 147 thread->ScheduleInterrupts(Thread::kVMInterrupt); |
145 // Wait for all tasks to observe the interrupt. | 148 // Wait for all tasks to observe the interrupt. |
146 barrier.Sync(); | 149 barrier.Sync(); |
147 // Continue with next round. | 150 // Continue with next round. |
148 uword interrupts = isolate->GetAndClearInterrupts(); | 151 uword interrupts = thread->GetAndClearInterrupts(); |
149 EXPECT((interrupts & Isolate::kVMInterrupt) != 0); | 152 EXPECT((interrupts & Thread::kVMInterrupt) != 0); |
150 } | 153 } |
151 barrier.Exit(); | 154 barrier.Exit(); |
152 } | 155 } |
153 | 156 |
154 | 157 |
155 class IsolateTestHelper { | 158 class IsolateTestHelper { |
156 public: | 159 public: |
157 static uword GetStackLimit(Isolate* isolate) { | 160 static uword GetStackLimit(Thread* thread) { |
158 return isolate->stack_limit_; | 161 return thread->stack_limit_; |
159 } | 162 } |
160 static uword GetSavedStackLimit(Isolate* isolate) { | 163 static uword GetSavedStackLimit(Thread* thread) { |
161 return isolate->saved_stack_limit_; | 164 return thread->saved_stack_limit_; |
162 } | 165 } |
163 static uword GetDeferredInterruptsMask(Isolate* isolate) { | 166 static uword GetDeferredInterruptsMask(Thread* thread) { |
164 return isolate->deferred_interrupts_mask_; | 167 return thread->deferred_interrupts_mask_; |
165 } | 168 } |
166 static uword GetDeferredInterrupts(Isolate* isolate) { | 169 static uword GetDeferredInterrupts(Thread* thread) { |
167 return isolate->deferred_interrupts_; | 170 return thread->deferred_interrupts_; |
168 } | 171 } |
169 }; | 172 }; |
170 | 173 |
171 | 174 |
172 TEST_CASE(NoOOBMessageScope) { | 175 TEST_CASE(NoOOBMessageScope) { |
173 // EXPECT_EQ is picky about type agreement for its arguments. | 176 // EXPECT_EQ is picky about type agreement for its arguments. |
174 const uword kZero = 0; | 177 const uword kZero = 0; |
175 const uword kMessageInterrupt = Isolate::kMessageInterrupt; | 178 const uword kMessageInterrupt = Thread::kMessageInterrupt; |
176 const uword kVMInterrupt = Isolate::kVMInterrupt; | 179 const uword kVMInterrupt = Thread::kVMInterrupt; |
177 uword stack_limit; | 180 uword stack_limit; |
178 uword interrupt_bits; | 181 uword interrupt_bits; |
179 | 182 |
180 // Initially no interrupts are scheduled or deferred. | 183 // Initially no interrupts are scheduled or deferred. |
181 Isolate* isolate = Thread::Current()->isolate(); | 184 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
182 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 185 IsolateTestHelper::GetSavedStackLimit(thread)); |
183 IsolateTestHelper::GetSavedStackLimit(isolate)); | 186 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
184 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 187 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread)); |
185 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate)); | |
186 | 188 |
187 { | 189 { |
188 // Defer message interrupts. | 190 // Defer message interrupts. |
189 NoOOBMessageScope no_msg_scope(Thread::Current()); | 191 NoOOBMessageScope no_msg_scope(thread); |
190 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 192 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
191 IsolateTestHelper::GetSavedStackLimit(isolate)); | 193 IsolateTestHelper::GetSavedStackLimit(thread)); |
192 EXPECT_EQ(kMessageInterrupt, | 194 EXPECT_EQ(kMessageInterrupt, |
193 IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 195 IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
194 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate)); | 196 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread)); |
195 | 197 |
196 // Schedule a message, it is deferred. | 198 // Schedule a message, it is deferred. |
197 isolate->ScheduleInterrupts(Isolate::kMessageInterrupt); | 199 thread->ScheduleInterrupts(Thread::kMessageInterrupt); |
198 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 200 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
199 IsolateTestHelper::GetSavedStackLimit(isolate)); | 201 IsolateTestHelper::GetSavedStackLimit(thread)); |
200 EXPECT_EQ(kMessageInterrupt, | 202 EXPECT_EQ(kMessageInterrupt, |
201 IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 203 IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
202 EXPECT_EQ(kMessageInterrupt, | 204 EXPECT_EQ(kMessageInterrupt, |
203 IsolateTestHelper::GetDeferredInterrupts(isolate)); | 205 IsolateTestHelper::GetDeferredInterrupts(thread)); |
204 | 206 |
205 // Schedule a vm interrupt, it is not deferred. | 207 // Schedule a vm interrupt, it is not deferred. |
206 isolate->ScheduleInterrupts(Isolate::kVMInterrupt); | 208 thread->ScheduleInterrupts(Thread::kVMInterrupt); |
207 stack_limit = IsolateTestHelper::GetStackLimit(isolate); | 209 stack_limit = IsolateTestHelper::GetStackLimit(thread); |
208 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(isolate)); | 210 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread)); |
209 EXPECT((stack_limit & Isolate::kVMInterrupt) != 0); | 211 EXPECT((stack_limit & Thread::kVMInterrupt) != 0); |
210 EXPECT_EQ(kMessageInterrupt, | 212 EXPECT_EQ(kMessageInterrupt, |
211 IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 213 IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
212 EXPECT_EQ(kMessageInterrupt, | 214 EXPECT_EQ(kMessageInterrupt, |
213 IsolateTestHelper::GetDeferredInterrupts(isolate)); | 215 IsolateTestHelper::GetDeferredInterrupts(thread)); |
214 | 216 |
215 // Clear the vm interrupt. Message is still deferred. | 217 // Clear the vm interrupt. Message is still deferred. |
216 interrupt_bits = isolate->GetAndClearInterrupts(); | 218 interrupt_bits = thread->GetAndClearInterrupts(); |
217 EXPECT_EQ(kVMInterrupt, interrupt_bits); | 219 EXPECT_EQ(kVMInterrupt, interrupt_bits); |
218 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 220 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
219 IsolateTestHelper::GetSavedStackLimit(isolate)); | 221 IsolateTestHelper::GetSavedStackLimit(thread)); |
220 EXPECT_EQ(kMessageInterrupt, | 222 EXPECT_EQ(kMessageInterrupt, |
221 IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 223 IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
222 EXPECT_EQ(kMessageInterrupt, | 224 EXPECT_EQ(kMessageInterrupt, |
223 IsolateTestHelper::GetDeferredInterrupts(isolate)); | 225 IsolateTestHelper::GetDeferredInterrupts(thread)); |
224 } | 226 } |
225 | 227 |
226 // Restore message interrupts. Message is now pending. | 228 // Restore message interrupts. Message is now pending. |
227 stack_limit = IsolateTestHelper::GetStackLimit(isolate); | 229 stack_limit = IsolateTestHelper::GetStackLimit(thread); |
228 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(isolate)); | 230 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread)); |
229 EXPECT((stack_limit & Isolate::kMessageInterrupt) != 0); | 231 EXPECT((stack_limit & Thread::kMessageInterrupt) != 0); |
230 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 232 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
231 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate)); | 233 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread)); |
232 | 234 |
233 { | 235 { |
234 // Defer message interrupts, again. The pending interrupt is deferred. | 236 // Defer message interrupts, again. The pending interrupt is deferred. |
235 NoOOBMessageScope no_msg_scope(Thread::Current()); | 237 NoOOBMessageScope no_msg_scope(thread); |
236 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 238 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
237 IsolateTestHelper::GetSavedStackLimit(isolate)); | 239 IsolateTestHelper::GetSavedStackLimit(thread)); |
238 EXPECT_EQ(kMessageInterrupt, | 240 EXPECT_EQ(kMessageInterrupt, |
239 IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 241 IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
240 EXPECT_EQ(kMessageInterrupt, | 242 EXPECT_EQ(kMessageInterrupt, |
241 IsolateTestHelper::GetDeferredInterrupts(isolate)); | 243 IsolateTestHelper::GetDeferredInterrupts(thread)); |
242 } | 244 } |
243 | 245 |
244 // Restore, then clear interrupts. The world is as it was. | 246 // Restore, then clear interrupts. The world is as it was. |
245 interrupt_bits = isolate->GetAndClearInterrupts(); | 247 interrupt_bits = thread->GetAndClearInterrupts(); |
246 EXPECT_EQ(kMessageInterrupt, interrupt_bits); | 248 EXPECT_EQ(kMessageInterrupt, interrupt_bits); |
247 EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate), | 249 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread), |
248 IsolateTestHelper::GetSavedStackLimit(isolate)); | 250 IsolateTestHelper::GetSavedStackLimit(thread)); |
249 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate)); | 251 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread)); |
250 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate)); | 252 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread)); |
251 } | 253 } |
252 | 254 |
253 } // namespace dart | 255 } // namespace dart |
OLD | NEW |