Flutter Engine
The Flutter Engine
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)
Definition: Transform_inl.h:98
#define EXPECT(type, expectedAlignment, expectedSize)
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:436
static Dart_Isolate CreateTestIsolate(const char *name=nullptr, void *isolate_group_data=nullptr, void *isolate_data=nullptr)
Definition: unit_test.cc:140
bool Run(Args &&... args)
Definition: thread_pool.h:45
@ kVMInterrupt
Definition: thread.h:488
@ kInterruptsMask
Definition: thread.h:491
@ kUnknownTask
Definition: thread.h:346
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
Definition: thread.cc:499
uword stack_limit_address() const
Definition: thread.h:399
IsolateGroup * isolate_group() const
Definition: thread.h:541
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
Definition: thread.cc:481
#define ILLEGAL_PORT
Definition: dart_api.h:1535
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
Definition: dart_vm.cc:33
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)
Definition: isolate_test.cc:28
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)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value)
TEST_CASE(DirectoryCurrent)
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)
VM_UNIT_TEST_CASE(DirectoryCurrentNoScope)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
def print(*args, **kwargs)
Definition: run_tests.py:49
#define EXPECT_ERROR(handle, substring)
Definition: unit_test.h:663
#define EXPECT_VALID(handle)
Definition: unit_test.h:643