Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e96c740

Browse files
authored
Test child isolates are terminated when root is shutdown (#13048)
1 parent 86e3ebb commit e96c740

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

runtime/dart_isolate_unittests.cc

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,27 @@ class AutoIsolateShutdown {
9999
AutoIsolateShutdown() = default;
100100

101101
AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
102-
fml::RefPtr<fml::TaskRunner> runner)
103-
: isolate_(std::move(isolate)), runner_(std::move(runner)) {}
102+
fml::RefPtr<fml::TaskRunner> runner,
103+
bool confirm_shutdown)
104+
: isolate_(std::move(isolate)),
105+
runner_(std::move(runner)),
106+
confirm_shutdown_(confirm_shutdown) {}
104107

105108
~AutoIsolateShutdown() {
106109
if (!IsValid()) {
107110
return;
108111
}
109112
fml::AutoResetWaitableEvent latch;
110-
fml::TaskRunner::RunNowOrPostTask(runner_, [isolate = isolate_, &latch]() {
111-
FML_LOG(INFO) << "Shutting down isolate.";
112-
if (!isolate->Shutdown()) {
113-
FML_LOG(ERROR) << "Could not shutdown isolate.";
114-
FML_CHECK(false);
115-
}
116-
latch.Signal();
117-
});
113+
fml::TaskRunner::RunNowOrPostTask(
114+
runner_,
115+
[isolate = isolate_, &latch, confirm_shutdown = confirm_shutdown_]() {
116+
FML_LOG(INFO) << "Shutting down isolate.";
117+
if (!isolate->Shutdown() && confirm_shutdown) {
118+
FML_LOG(ERROR) << "Could not shutdown isolate.";
119+
FML_CHECK(false);
120+
}
121+
latch.Signal();
122+
});
118123
latch.Wait();
119124
}
120125

@@ -149,6 +154,7 @@ class AutoIsolateShutdown {
149154
private:
150155
std::shared_ptr<DartIsolate> isolate_;
151156
fml::RefPtr<fml::TaskRunner> runner_;
157+
bool confirm_shutdown_;
152158

153159
FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown);
154160
};
@@ -158,7 +164,8 @@ static void RunDartCodeInIsolate(DartVMRef& vm_ref,
158164
const Settings& settings,
159165
fml::RefPtr<fml::TaskRunner> task_runner,
160166
std::string entrypoint,
161-
const std::vector<std::string>& args) {
167+
const std::vector<std::string>& args,
168+
bool confirm_shutdown) {
162169
FML_CHECK(task_runner->RunsTasksOnCurrentThread());
163170

164171
if (!vm_ref) {
@@ -193,8 +200,8 @@ static void RunDartCodeInIsolate(DartVMRef& vm_ref,
193200
settings.isolate_shutdown_callback // isolate shutdown callback
194201
);
195202

196-
auto root_isolate =
197-
std::make_unique<AutoIsolateShutdown>(weak_isolate.lock(), task_runner);
203+
auto root_isolate = std::make_unique<AutoIsolateShutdown>(
204+
weak_isolate.lock(), task_runner, confirm_shutdown);
198205

199206
if (!root_isolate->IsValid()) {
200207
FML_LOG(ERROR) << "Could not create isolate.";
@@ -267,13 +274,14 @@ static std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
267274
const Settings& settings,
268275
fml::RefPtr<fml::TaskRunner> task_runner,
269276
std::string entrypoint,
270-
const std::vector<std::string>& args) {
277+
const std::vector<std::string>& args,
278+
bool confirm_shutdown) {
271279
std::unique_ptr<AutoIsolateShutdown> result;
272280
fml::AutoResetWaitableEvent latch;
273281
fml::TaskRunner::RunNowOrPostTask(
274282
task_runner, fml::MakeCopyable([&]() mutable {
275283
RunDartCodeInIsolate(vm_ref, result, settings, task_runner, entrypoint,
276-
args);
284+
args, confirm_shutdown);
277285
latch.Signal();
278286
}));
279287
latch.Wait();
@@ -285,7 +293,7 @@ TEST_F(DartIsolateTest, IsolateCanLoadAndRunDartCode) {
285293
const auto settings = CreateSettingsForFixture();
286294
auto vm_ref = DartVMRef::Create(settings);
287295
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
288-
"main", {});
296+
"main", {}, true);
289297
ASSERT_TRUE(isolate);
290298
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
291299
}
@@ -295,7 +303,7 @@ TEST_F(DartIsolateTest, IsolateCannotLoadAndRunUnknownDartEntrypoint) {
295303
const auto settings = CreateSettingsForFixture();
296304
auto vm_ref = DartVMRef::Create(settings);
297305
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
298-
"thisShouldNotExist", {});
306+
"thisShouldNotExist", {}, true);
299307
ASSERT_FALSE(isolate);
300308
}
301309

@@ -304,7 +312,7 @@ TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {
304312
const auto settings = CreateSettingsForFixture();
305313
auto vm_ref = DartVMRef::Create(settings);
306314
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
307-
"main", {});
315+
"main", {}, true);
308316

309317
ASSERT_TRUE(isolate);
310318
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
@@ -328,7 +336,7 @@ TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
328336
const auto settings = CreateSettingsForFixture();
329337
auto vm_ref = DartVMRef::Create(settings);
330338
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
331-
"canRegisterNativeCallback", {});
339+
"canRegisterNativeCallback", {}, true);
332340
ASSERT_TRUE(isolate);
333341
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
334342
latch.Wait();
@@ -351,7 +359,7 @@ TEST_F(DartIsolateTest, CanSaveCompilationTrace) {
351359
const auto settings = CreateSettingsForFixture();
352360
auto vm_ref = DartVMRef::Create(settings);
353361
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
354-
"testCanSaveCompilationTrace", {});
362+
"testCanSaveCompilationTrace", {}, true);
355363
ASSERT_TRUE(isolate);
356364
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
357365

@@ -377,8 +385,9 @@ TEST_F(DartIsolateTest, CanLaunchSecondaryIsolates) {
377385
child_shutdown_latch.Signal();
378386
};
379387
auto vm_ref = DartVMRef::Create(settings);
380-
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
381-
"testCanLaunchSecondaryIsolate", {});
388+
auto isolate =
389+
RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
390+
"testCanLaunchSecondaryIsolate", {}, true);
382391
ASSERT_TRUE(isolate);
383392
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
384393
child_shutdown_latch.Wait(); // wait for child isolate to shutdown first
@@ -397,13 +406,54 @@ TEST_F(DartIsolateTest, CanRecieveArguments) {
397406

398407
const auto settings = CreateSettingsForFixture();
399408
auto vm_ref = DartVMRef::Create(settings);
400-
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
401-
"testCanRecieveArguments", {"arg1"});
409+
auto isolate =
410+
RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
411+
"testCanRecieveArguments", {"arg1"}, true);
402412
ASSERT_TRUE(isolate);
403413
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
404414

405415
latch.Wait();
406416
}
407417

418+
TEST_F(DartIsolateTest, RootIsolateShutdownStopsChildIsolates) {
419+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
420+
fml::CountDownLatch latch(12);
421+
fml::CountDownLatch shutdown_latch(5);
422+
AddNativeCallback("NotifyNative",
423+
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
424+
latch.CountDown();
425+
})));
426+
AddNativeCallback(
427+
"PassMessage", CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
428+
auto message = tonic::DartConverter<std::string>::FromDart(
429+
Dart_GetNativeArgument(args, 0));
430+
ASSERT_EQ("In child Isolate.", message);
431+
latch.CountDown();
432+
})));
433+
434+
size_t destruction_callback_count = 0;
435+
auto settings = CreateSettingsForFixture();
436+
settings.isolate_shutdown_callback = [&shutdown_latch,
437+
&destruction_callback_count]() {
438+
destruction_callback_count++;
439+
shutdown_latch.CountDown();
440+
};
441+
auto vm_ref = DartVMRef::Create(settings);
442+
auto vm_data = vm_ref.GetVMData();
443+
444+
std::unique_ptr<AutoIsolateShutdown> isolate;
445+
fml::RefPtr<fml::TaskRunner> task_runner = CreateNewThread();
446+
fml::TaskRunner::RunNowOrPostTask(
447+
task_runner, fml::MakeCopyable([&]() mutable {
448+
RunDartCodeInIsolate(vm_ref, isolate, settings, task_runner,
449+
"testSecondaryIsolateShutdown", {}, false);
450+
}));
451+
latch.Wait(); // wait for last NotifyNative called by main isolate
452+
ASSERT_TRUE(isolate->get()->Shutdown() || true);
453+
shutdown_latch.Wait();
454+
// root isolate will be auto-shutdown
455+
ASSERT_EQ(destruction_callback_count, 5u);
456+
}
457+
408458
} // namespace testing
409459
} // namespace flutter

runtime/fixtures/runtime_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,18 @@ void testCanLaunchSecondaryIsolate() {
6060
void testCanRecieveArguments(List<String> args) {
6161
notifyResult(args != null && args.length == 1 && args[0] == 'arg1');
6262
}
63+
64+
@pragma('vm:entry-point')
65+
void testSecondaryIsolateShutdown() {
66+
final onExit = RawReceivePort((_) { notifyNative(); });
67+
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 1', onExit: onExit.sendPort);
68+
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 2', onExit: onExit.sendPort);
69+
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 3', onExit: onExit.sendPort);
70+
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 4', onExit: onExit.sendPort);
71+
}
72+
73+
void shutdownIsolateMain(String message) {
74+
print('Secondary isolate got message: ' + message);
75+
passMessage('In child Isolate.');
76+
notifyNative();
77+
}

0 commit comments

Comments
 (0)