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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/isolate.h"
6#include "include/dart_api.h"
7#include "platform/assert.h"
8#include "vm/globals.h"
9#include "vm/lockers.h"
10#include "vm/thread_barrier.h"
11#include "vm/thread_pool.h"
12#include "vm/unit_test.h"
13
14namespace dart {
15
16VM_UNIT_TEST_CASE(IsolateCurrent) {
17 Dart_Isolate isolate = TestCase::CreateTestIsolate();
18 EXPECT_EQ(isolate, Dart_CurrentIsolate());
19 Dart_ShutdownIsolate();
20 EXPECT_EQ(reinterpret_cast<Dart_Isolate>(NULL), Dart_CurrentIsolate());
21}
22
23// Test to ensure that an exception is thrown if no isolate creation
24// callback has been set by the embedder when an isolate is spawned.
25TEST_CASE(IsolateSpawn) {
26 const char* kScriptChars =
27 "import 'dart:isolate';\n"
28 // Ignores printed lines.
29 "var _nullPrintClosure = (String line) {};\n"
30 "void entry(message) {}\n"
31 "void testMain() {\n"
32 " Isolate.spawn(entry, null);\n"
33 // TODO(floitsch): the following code is only to bump the event loop
34 // so it executes asynchronous microtasks.
35 " var rp = RawReceivePort();\n"
36 " rp.sendPort.send(null);\n"
37 " rp.handler = (_) { rp.close(); };\n"
38 "}\n";
39
40 Dart_Handle test_lib = TestCase::LoadTestScript(kScriptChars, NULL);
41
42 // Setup the internal library's 'internalPrint' function.
43 // Necessary because asynchronous errors use "print" to print their
44 // stack trace.
45 Dart_Handle url = NewString("dart:_internal");
46 EXPECT_VALID(url);
47 Dart_Handle internal_lib = Dart_LookupLibrary(url);
48 EXPECT_VALID(internal_lib);
49 Dart_Handle print = Dart_GetField(test_lib, NewString("_nullPrintClosure"));
50 Dart_Handle result =
51 Dart_SetField(internal_lib, NewString("_printClosure"), print);
52
53 EXPECT_VALID(result);
54
55 // Setup the 'scheduleImmediate' closure.
56 url = NewString("dart:isolate");
57 EXPECT_VALID(url);
58 Dart_Handle isolate_lib = Dart_LookupLibrary(url);
59 EXPECT_VALID(isolate_lib);
60 Dart_Handle schedule_immediate_closure = Dart_Invoke(
61 isolate_lib, NewString("_getIsolateScheduleImmediateClosure"), 0, NULL);
62 Dart_Handle args[1];
63 args[0] = schedule_immediate_closure;
64 url = NewString("dart:async");
65 EXPECT_VALID(url);
66 Dart_Handle async_lib = Dart_LookupLibrary(url);
67 EXPECT_VALID(async_lib);
68 EXPECT_VALID(Dart_Invoke(async_lib, NewString("_setScheduleImmediateClosure"),
69 1, args));
70
71 result = Dart_Invoke(test_lib, NewString("testMain"), 0, NULL);
72 EXPECT_VALID(result);
73 // Run until all ports to isolate are closed.
74 result = Dart_RunLoop();
75 EXPECT_ERROR(result, "Unsupported operation: Isolate.spawn");
76 EXPECT(Dart_ErrorHasException(result));
77 Dart_Handle exception_result = Dart_ErrorGetException(result);
78 EXPECT_VALID(exception_result);
79}
80
81class InterruptChecker : public ThreadPool::Task {
82 public:
83 static const intptr_t kTaskCount;
84 static const intptr_t kIterations;
85
86 InterruptChecker(Thread* thread, ThreadBarrier* barrier)
87 : thread_(thread), barrier_(barrier) {}
88
89 virtual void Run() {
90 Thread::EnterIsolateAsHelper(thread_->isolate(), Thread::kUnknownTask);
91 // Tell main thread that we are ready.
92 barrier_->Sync();
93 for (intptr_t i = 0; i < kIterations; ++i) {
94 // Busy wait for interrupts.
95 uword limit = 0;
96 do {
97 limit = reinterpret_cast<RelaxedAtomic<uword>*>(
98 thread_->stack_limit_address())
99 ->load();
100 } while (
101 (limit == thread_->saved_stack_limit_) ||
102 (((limit & Thread::kInterruptsMask) & Thread::kVMInterrupt) == 0));
103 // Tell main thread that we observed the interrupt.
104 barrier_->Sync();
105 }
106 Thread::ExitIsolateAsHelper();
107 barrier_->Exit();
108 }
109
110 private:
111 Thread* thread_;
112 ThreadBarrier* barrier_;
113};
114
115const intptr_t InterruptChecker::kTaskCount = 5;
116const intptr_t InterruptChecker::kIterations = 10;
117
118// Test and document usage of Isolate::HasInterruptsScheduled.
119//
120// Go through a number of rounds of scheduling interrupts and waiting until all
121// unsynchronized busy-waiting tasks observe it (in the current implementation,
122// the exact latency depends on cache coherence). Synchronization is then used
123// to ensure that the response to the interrupt, i.e., starting a new round,
124// happens *after* the interrupt is observed. Without this synchronization, the
125// compiler and/or CPU could reorder operations to make the tasks observe the
126// round update *before* the interrupt is set.
127TEST_CASE(StackLimitInterrupts) {
128 Isolate* isolate = thread->isolate();
129 ThreadBarrier barrier(InterruptChecker::kTaskCount + 1,
130 isolate->heap()->barrier(),
131 isolate->heap()->barrier_done());
132 // Start all tasks. They will busy-wait until interrupted in the first round.
133 for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) {
134 Dart::thread_pool()->Run<InterruptChecker>(thread, &barrier);
135 }
136 // Wait for all tasks to get ready for the first round.
137 barrier.Sync();
138 for (intptr_t i = 0; i < InterruptChecker::kIterations; ++i) {
139 thread->ScheduleInterrupts(Thread::kVMInterrupt);
140 // Wait for all tasks to observe the interrupt.
141 barrier.Sync();
142 // Continue with next round.
143 uword interrupts = thread->GetAndClearInterrupts();
144 EXPECT((interrupts & Thread::kVMInterrupt) != 0);
145 }
146 barrier.Exit();
147}
148
149class IsolateTestHelper {
150 public:
151 static uword GetStackLimit(Thread* thread) { return thread->stack_limit_; }
152 static uword GetSavedStackLimit(Thread* thread) {
153 return thread->saved_stack_limit_;
154 }
155 static uword GetDeferredInterruptsMask(Thread* thread) {
156 return thread->deferred_interrupts_mask_;
157 }
158 static uword GetDeferredInterrupts(Thread* thread) {
159 return thread->deferred_interrupts_;
160 }
161};
162
163TEST_CASE(NoOOBMessageScope) {
164 // Finish any GC in progress so that no kVMInterrupt is added for GC reasons.
165 {
166 TransitionNativeToVM transition(thread);
167 GCTestHelper::CollectAllGarbage();
168 const Error& error = Error::Handle(thread->HandleInterrupts());
169 RELEASE_ASSERT(error.IsNull());
170 }
171
172 // EXPECT_EQ is picky about type agreement for its arguments.
173 const uword kZero = 0;
174 const uword kMessageInterrupt = Thread::kMessageInterrupt;
175 const uword kVMInterrupt = Thread::kVMInterrupt;
176 uword stack_limit;
177 uword interrupt_bits;
178
179 // Initially no interrupts are scheduled or deferred.
180 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
181 IsolateTestHelper::GetSavedStackLimit(thread));
182 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
183 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
184
185 {
186 // Defer message interrupts.
187 NoOOBMessageScope no_msg_scope(thread);
188 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
189 IsolateTestHelper::GetSavedStackLimit(thread));
190 EXPECT_EQ(kMessageInterrupt,
191 IsolateTestHelper::GetDeferredInterruptsMask(thread));
192 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
193
194 // Schedule a message, it is deferred.
195 thread->ScheduleInterrupts(Thread::kMessageInterrupt);
196 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
197 IsolateTestHelper::GetSavedStackLimit(thread));
198 EXPECT_EQ(kMessageInterrupt,
199 IsolateTestHelper::GetDeferredInterruptsMask(thread));
200 EXPECT_EQ(kMessageInterrupt,
201 IsolateTestHelper::GetDeferredInterrupts(thread));
202
203 // Schedule a vm interrupt, it is not deferred.
204 thread->ScheduleInterrupts(Thread::kVMInterrupt);
205 stack_limit = IsolateTestHelper::GetStackLimit(thread);
206 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread));
207 EXPECT((stack_limit & Thread::kVMInterrupt) != 0);
208 EXPECT_EQ(kMessageInterrupt,
209 IsolateTestHelper::GetDeferredInterruptsMask(thread));
210 EXPECT_EQ(kMessageInterrupt,
211 IsolateTestHelper::GetDeferredInterrupts(thread));
212
213 // Clear the vm interrupt. Message is still deferred.
214 interrupt_bits = thread->GetAndClearInterrupts();
215 EXPECT_EQ(kVMInterrupt, interrupt_bits);
216 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
217 IsolateTestHelper::GetSavedStackLimit(thread));
218 EXPECT_EQ(kMessageInterrupt,
219 IsolateTestHelper::GetDeferredInterruptsMask(thread));
220 EXPECT_EQ(kMessageInterrupt,
221 IsolateTestHelper::GetDeferredInterrupts(thread));
222 }
223
224 // Restore message interrupts. Message is now pending.
225 stack_limit = IsolateTestHelper::GetStackLimit(thread);
226 EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(thread));
227 EXPECT((stack_limit & Thread::kMessageInterrupt) != 0);
228 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
229 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
230
231 {
232 // Defer message interrupts, again. The pending interrupt is deferred.
233 NoOOBMessageScope no_msg_scope(thread);
234 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
235 IsolateTestHelper::GetSavedStackLimit(thread));
236 EXPECT_EQ(kMessageInterrupt,
237 IsolateTestHelper::GetDeferredInterruptsMask(thread));
238 EXPECT_EQ(kMessageInterrupt,
239 IsolateTestHelper::GetDeferredInterrupts(thread));
240 }
241
242 // Restore, then clear interrupts. The world is as it was.
243 interrupt_bits = thread->GetAndClearInterrupts();
244 EXPECT_EQ(kMessageInterrupt, interrupt_bits);
245 EXPECT_EQ(IsolateTestHelper::GetStackLimit(thread),
246 IsolateTestHelper::GetSavedStackLimit(thread));
247 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(thread));
248 EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(thread));
249}
250
251} // namespace dart
252