Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
isolate_test.cc
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "include/dart_api.h"
6
7#include "platform/assert.h"
8
9#include "vm/globals.h"
10#include "vm/isolate.h"
11#include "vm/lockers.h"
12#include "vm/port.h"
13#include "vm/thread_barrier.h"
14#include "vm/thread_pool.h"
15#include "vm/unit_test.h"
16
17namespace dart {
18
19VM_UNIT_TEST_CASE(IsolateCurrent) {
21 EXPECT_EQ(isolate, Dart_CurrentIsolate());
23 EXPECT_EQ(static_cast<Dart_Isolate>(nullptr), Dart_CurrentIsolate());
24}
25
26// Test to ensure that an exception is thrown if no isolate creation
27// callback has been set by the embedder when an isolate is spawned.
28void IsolateSpawn(const char* platform_script_value) {
29 char* scriptChars = OS::SCreate(
30 nullptr,
31 "import 'dart:isolate';\n"
32 // Ignores printed lines.
33 "var _nullPrintClosure = (String line) {};\n"
34 "var _platformScript = () => Uri.parse(\"%s\");\n"
35 "void entry(message) {}\n"
36 "void testMain() {\n"
37 " Isolate.spawn(entry, null);\n"
38 // TODO(floitsch): the following code is only to bump the event loop
39 // so it executes asynchronous microtasks.
40 " var rp = RawReceivePort();\n"
41 " rp.sendPort.send(null);\n"
42 " rp.handler = (_) { rp.close(); };\n"
43 "}\n",
44 platform_script_value);
45
46 Dart_Handle test_lib = TestCase::LoadTestScript(scriptChars, nullptr);
47
48 free(scriptChars);
49
50 // Setup the internal library's 'internalPrint' function.
51 // Necessary because asynchronous errors use "print" to print their
52 // stack trace.
53 Dart_Handle url = NewString("dart:_internal");
54 EXPECT_VALID(url);
55 Dart_Handle internal_lib = Dart_LookupLibrary(url);
56 EXPECT_VALID(internal_lib);
57 Dart_Handle print = Dart_GetField(test_lib, NewString("_nullPrintClosure"));
60 Dart_SetField(internal_lib, NewString("_printClosure"), print);
62
63 Dart_Handle platform_script =
64 Dart_GetField(test_lib, NewString("_platformScript"));
65 EXPECT_VALID(platform_script);
66 Dart_Handle vmlibraryhooks_class =
67 Dart_GetClass(internal_lib, NewString("VMLibraryHooks"));
68 EXPECT_VALID(vmlibraryhooks_class);
69 result = Dart_SetField(vmlibraryhooks_class, NewString("platformScript"),
70 platform_script);
72
73 // Setup the 'scheduleImmediate' closure.
74 url = NewString("dart:isolate");
75 EXPECT_VALID(url);
76 Dart_Handle isolate_lib = Dart_LookupLibrary(url);
77 EXPECT_VALID(isolate_lib);
78 Dart_Handle schedule_immediate_closure =
79 Dart_Invoke(isolate_lib, NewString("_getIsolateScheduleImmediateClosure"),
80 0, nullptr);
82 args[0] = schedule_immediate_closure;
83 url = NewString("dart:async");
84 EXPECT_VALID(url);
85 Dart_Handle async_lib = Dart_LookupLibrary(url);
86 EXPECT_VALID(async_lib);
87 EXPECT_VALID(Dart_Invoke(async_lib, NewString("_setScheduleImmediateClosure"),
88 1, args));
89
90 result = Dart_Invoke(test_lib, NewString("testMain"), 0, nullptr);
92 // Run until all ports to isolate are closed.
95 result,
96 "Lightweight isolate spawn is not supported by this Dart embedder");
98 Dart_Handle exception_result = Dart_ErrorGetException(result);
99 EXPECT_VALID(exception_result);
100}
101
102TEST_CASE(IsolateSpawn_FileUri) {
103 IsolateSpawn("file:/a.dart");
104}
105
106TEST_CASE(IsolateSpawn_PackageUri) {
107 IsolateSpawn("package:/a.dart");
108}
109
111 public:
112 static constexpr intptr_t kTaskCount = 5;
113 static constexpr intptr_t kIterations = 10;
114
116 : thread_(thread), barrier_(barrier) {}
117
118 virtual void Run() {
119 const bool kBypassSafepoint = false;
121 Thread::kUnknownTask, kBypassSafepoint);
122 // Tell main thread that we are ready.
123 barrier_->Sync();
124 for (intptr_t i = 0; i < kIterations; ++i) {
125 // Busy wait for interrupts.
126 uword limit = 0;
127 do {
128 limit = reinterpret_cast<RelaxedAtomic<uword>*>(
129 thread_->stack_limit_address())
130 ->load();
131 } while (
132 (limit == thread_->saved_stack_limit_) ||
133 (((limit & Thread::kInterruptsMask) & Thread::kVMInterrupt) == 0));
134 // Tell main thread that we observed the interrupt.
135 barrier_->Sync();
136 }
137 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
138 barrier_->Sync();
139 barrier_->Release();
140 }
141
142 private:
143 Thread* thread_;
144 ThreadBarrier* barrier_;
145};
146
147// Test and document usage of Isolate::HasInterruptsScheduled.
148//
149// Go through a number of rounds of scheduling interrupts and waiting until all
150// unsynchronized busy-waiting tasks observe it (in the current implementation,
151// the exact latency depends on cache coherence). Synchronization is then used
152// to ensure that the response to the interrupt, i.e., starting a new round,
153// happens *after* the interrupt is observed. Without this synchronization, the
154// compiler and/or CPU could reorder operations to make the tasks observe the
155// round update *before* the interrupt is set.
156TEST_CASE(StackLimitInterrupts) {
159 // Start all tasks. They will busy-wait until interrupted in the first round.
160 for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) {
161 Dart::thread_pool()->Run<InterruptChecker>(thread, barrier);
162 }
163 // Wait for all tasks to get ready for the first round.
164 barrier->Sync();
165 for (intptr_t i = 0; i < InterruptChecker::kIterations; ++i) {
166 thread->ScheduleInterrupts(Thread::kVMInterrupt);
167 // Wait for all tasks to observe the interrupt.
168 barrier->Sync();
169 // Continue with next round.
170 uword interrupts = thread->GetAndClearInterrupts();
171 EXPECT((interrupts & Thread::kVMInterrupt) != 0);
172 }
173 barrier->Sync();
174 barrier->Release();
175}
176
178 auto isolate = thread->isolate();
179 auto& port = ReceivePort::Handle();
180
181 EXPECT(!isolate->HasLivePorts());
182
183 {
184 // Make port.
185 port = isolate->CreateReceivePort(String::null_string());
186 EXPECT(port.is_open());
187 EXPECT(port.keep_isolate_alive());
188 EXPECT(port.Id() != ILLEGAL_PORT);
189 EXPECT(PortMap::PortExists(port.Id()));
190 EXPECT(isolate->HasLivePorts());
191
192 // Make port not keep isolate alive.
193 isolate->SetReceivePortKeepAliveState(port, false);
194 EXPECT(port.is_open());
195 EXPECT(!port.keep_isolate_alive());
196 EXPECT(!isolate->HasLivePorts());
197
198 // Mark it alive again.
199 isolate->SetReceivePortKeepAliveState(port, true);
200 EXPECT(port.is_open());
201 EXPECT(port.keep_isolate_alive());
202 EXPECT(isolate->HasLivePorts());
203
204 // Close the port.
205 isolate->CloseReceivePort(port);
206 EXPECT(!port.is_open());
207 EXPECT(!port.keep_isolate_alive());
208 EXPECT(!isolate->HasLivePorts());
209
210 // Closing again should be a NOP.
211 isolate->CloseReceivePort(port);
212 EXPECT(!port.is_open());
213 EXPECT(!port.keep_isolate_alive());
214 EXPECT(!isolate->HasLivePorts());
215 }
216
217 {
218 // Make port.
219 port = isolate->CreateReceivePort(String::null_string());
220 EXPECT_NE(0, port.Id());
221 EXPECT(PortMap::PortExists(port.Id()));
222 EXPECT(isolate->HasLivePorts());
223
224 // Make port not keep isolate alive.
225 isolate->SetReceivePortKeepAliveState(port, false);
226 EXPECT(port.is_open());
227 EXPECT(!port.keep_isolate_alive());
228 EXPECT(!isolate->HasLivePorts());
229
230 // Close the port while it's not keep alive port.
231 isolate->CloseReceivePort(port);
232 EXPECT(!port.is_open());
233 EXPECT(!port.keep_isolate_alive());
234 EXPECT(!isolate->HasLivePorts());
235 }
236
237 EXPECT(!isolate->HasLivePorts());
238}
239
240ISOLATE_UNIT_TEST_CASE(Isolate_MayExit_True) {
241 TransitionVMToNative transition(thread);
242
243 EXPECT_EQ(false, thread->is_unwind_in_progress());
244
246
247 Dart_Handle lib =
249 EXPECT(!Dart_IsError(lib));
250
252 lib, Dart_NewStringFromCString("Isolate"), 0, nullptr);
253 EXPECT(!Dart_IsError(isolate_type));
254
256 Dart_Invoke(isolate_type, Dart_NewStringFromCString("exit"), 0, nullptr);
258
260
261 EXPECT_EQ(true, thread->is_unwind_in_progress());
262}
263
264ISOLATE_UNIT_TEST_CASE(Isolate_MayExit_False) {
265 TransitionVMToNative transition(thread);
266
267 EXPECT_EQ(false, thread->is_unwind_in_progress());
268
270
271 Dart_Handle lib =
273 EXPECT(!Dart_IsError(lib));
274
276 lib, Dart_NewStringFromCString("Isolate"), 0, nullptr);
277 EXPECT(!Dart_IsError(isolate_type));
278
279 Dart_Handle setter_result = Dart_SetField(
280 isolate_type, Dart_NewStringFromCString("_mayExit"), Dart_False());
281 EXPECT(!Dart_IsError(setter_result));
282
284 Dart_Invoke(isolate_type, Dart_NewStringFromCString("exit"), 0, nullptr);
286
288
289 EXPECT_EQ(false, thread->is_unwind_in_progress());
290}
291
292} // namespace dart
SI T load(const P *ptr)
#define EXPECT(type, expectedAlignment, expectedSize)
void print(void *str)
Definition bridge.cpp:126
static ThreadPool * thread_pool()
Definition dart.h:73
static constexpr intptr_t kIterations
static constexpr intptr_t kTaskCount
InterruptChecker(Thread *thread, ThreadBarrier *barrier)
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static Object & Handle()
Definition object.h:407
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition unit_test.cc:422
static Dart_Isolate CreateTestIsolate(const char *name=nullptr, void *isolate_group_data=nullptr, void *isolate_data=nullptr)
Definition unit_test.cc:139
bool Run(Args &&... args)
Definition thread_pool.h:45
@ kInterruptsMask
Definition thread.h:490
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
Definition thread.cc:494
uword stack_limit_address() const
Definition thread.h:398
IsolateGroup * isolate_group() const
Definition thread.h:540
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
Definition thread.cc:476
#define ILLEGAL_PORT
Definition dart_api.h:1530
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition dart_api.h:88
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
DART_EXPORT void Dart_EnterScope()
DART_EXPORT Dart_Handle Dart_False()
DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, Dart_Handle class_name)
void IsolateSpawn(const char *platform_script_value)
DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_GetNonNullableType(Dart_Handle library, Dart_Handle class_name, intptr_t number_of_type_arguments, Dart_Handle *type_arguments)
DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
uintptr_t uword
Definition globals.h:501
DART_EXPORT Dart_Isolate Dart_CurrentIsolate()
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value)
Dart_Handle NewString(const char *str)
DART_EXPORT Dart_Handle Dart_RunLoop()
DART_EXPORT void Dart_ExitScope()
DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url)
DART_EXPORT void Dart_ShutdownIsolate()
DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char *str)
DART_EXPORT bool Dart_IsFatalError(Dart_Handle object)
#define VM_UNIT_TEST_CASE(name)
Definition unit_test.h:33
#define EXPECT_ERROR(handle, substring)
Definition unit_test.h:670
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64
#define TEST_CASE(name)
Definition unit_test.h:85
#define EXPECT_VALID(handle)
Definition unit_test.h:650