| 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 |