Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 74 additions & 24 deletions runtime/dart_isolate_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,27 @@ class AutoIsolateShutdown {
AutoIsolateShutdown() = default;

AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
fml::RefPtr<fml::TaskRunner> runner)
: isolate_(std::move(isolate)), runner_(std::move(runner)) {}
fml::RefPtr<fml::TaskRunner> runner,
bool confirm_shutdown)
: isolate_(std::move(isolate)),
runner_(std::move(runner)),
confirm_shutdown_(confirm_shutdown) {}

~AutoIsolateShutdown() {
if (!IsValid()) {
return;
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(runner_, [isolate = isolate_, &latch]() {
FML_LOG(INFO) << "Shutting down isolate.";
if (!isolate->Shutdown()) {
FML_LOG(ERROR) << "Could not shutdown isolate.";
FML_CHECK(false);
}
latch.Signal();
});
fml::TaskRunner::RunNowOrPostTask(
runner_,
[isolate = isolate_, &latch, confirm_shutdown = confirm_shutdown_]() {
FML_LOG(INFO) << "Shutting down isolate.";
if (!isolate->Shutdown() && confirm_shutdown) {
FML_LOG(ERROR) << "Could not shutdown isolate.";
FML_CHECK(false);
}
latch.Signal();
});
latch.Wait();
}

Expand Down Expand Up @@ -149,6 +154,7 @@ class AutoIsolateShutdown {
private:
std::shared_ptr<DartIsolate> isolate_;
fml::RefPtr<fml::TaskRunner> runner_;
bool confirm_shutdown_;

FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown);
};
Expand All @@ -158,7 +164,8 @@ static void RunDartCodeInIsolate(DartVMRef& vm_ref,
const Settings& settings,
fml::RefPtr<fml::TaskRunner> task_runner,
std::string entrypoint,
const std::vector<std::string>& args) {
const std::vector<std::string>& args,
bool confirm_shutdown) {
FML_CHECK(task_runner->RunsTasksOnCurrentThread());

if (!vm_ref) {
Expand Down Expand Up @@ -193,8 +200,8 @@ static void RunDartCodeInIsolate(DartVMRef& vm_ref,
settings.isolate_shutdown_callback // isolate shutdown callback
);

auto root_isolate =
std::make_unique<AutoIsolateShutdown>(weak_isolate.lock(), task_runner);
auto root_isolate = std::make_unique<AutoIsolateShutdown>(
weak_isolate.lock(), task_runner, confirm_shutdown);

if (!root_isolate->IsValid()) {
FML_LOG(ERROR) << "Could not create isolate.";
Expand Down Expand Up @@ -267,13 +274,14 @@ static std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
const Settings& settings,
fml::RefPtr<fml::TaskRunner> task_runner,
std::string entrypoint,
const std::vector<std::string>& args) {
const std::vector<std::string>& args,
bool confirm_shutdown) {
std::unique_ptr<AutoIsolateShutdown> result;
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runner, fml::MakeCopyable([&]() mutable {
RunDartCodeInIsolate(vm_ref, result, settings, task_runner, entrypoint,
args);
args, confirm_shutdown);
latch.Signal();
}));
latch.Wait();
Expand All @@ -285,7 +293,7 @@ TEST_F(DartIsolateTest, IsolateCanLoadAndRunDartCode) {
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
"main", {});
"main", {}, true);
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
}
Expand All @@ -295,7 +303,7 @@ TEST_F(DartIsolateTest, IsolateCannotLoadAndRunUnknownDartEntrypoint) {
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
"thisShouldNotExist", {});
"thisShouldNotExist", {}, true);
ASSERT_FALSE(isolate);
}

Expand All @@ -304,7 +312,7 @@ TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
"main", {});
"main", {}, true);

ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
Expand All @@ -328,7 +336,7 @@ TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"canRegisterNativeCallback", {});
"canRegisterNativeCallback", {}, true);
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
latch.Wait();
Expand All @@ -351,7 +359,7 @@ TEST_F(DartIsolateTest, CanSaveCompilationTrace) {
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"testCanSaveCompilationTrace", {});
"testCanSaveCompilationTrace", {}, true);
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);

Expand All @@ -377,8 +385,9 @@ TEST_F(DartIsolateTest, CanLaunchSecondaryIsolates) {
child_shutdown_latch.Signal();
};
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"testCanLaunchSecondaryIsolate", {});
auto isolate =
RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"testCanLaunchSecondaryIsolate", {}, true);
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
child_shutdown_latch.Wait(); // wait for child isolate to shutdown first
Expand All @@ -397,13 +406,54 @@ TEST_F(DartIsolateTest, CanRecieveArguments) {

const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"testCanRecieveArguments", {"arg1"});
auto isolate =
RunDartCodeInIsolate(vm_ref, settings, CreateNewThread(),
"testCanRecieveArguments", {"arg1"}, true);
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);

latch.Wait();
}

TEST_F(DartIsolateTest, RootIsolateShutdownStopsChildIsolates) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
fml::CountDownLatch latch(12);
fml::CountDownLatch shutdown_latch(5);
AddNativeCallback("NotifyNative",
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
latch.CountDown();
})));
AddNativeCallback(
"PassMessage", CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
auto message = tonic::DartConverter<std::string>::FromDart(
Dart_GetNativeArgument(args, 0));
ASSERT_EQ("In child Isolate.", message);
latch.CountDown();
})));

size_t destruction_callback_count = 0;
auto settings = CreateSettingsForFixture();
settings.isolate_shutdown_callback = [&shutdown_latch,
&destruction_callback_count]() {
destruction_callback_count++;
shutdown_latch.CountDown();
};
auto vm_ref = DartVMRef::Create(settings);
auto vm_data = vm_ref.GetVMData();

std::unique_ptr<AutoIsolateShutdown> isolate;
fml::RefPtr<fml::TaskRunner> task_runner = CreateNewThread();
fml::TaskRunner::RunNowOrPostTask(
task_runner, fml::MakeCopyable([&]() mutable {
RunDartCodeInIsolate(vm_ref, isolate, settings, task_runner,
"testSecondaryIsolateShutdown", {}, false);
}));
latch.Wait(); // wait for last NotifyNative called by main isolate
ASSERT_TRUE(isolate->get()->Shutdown() || true);
shutdown_latch.Wait();
// root isolate will be auto-shutdown
ASSERT_EQ(destruction_callback_count, 5u);
}

} // namespace testing
} // namespace flutter
15 changes: 15 additions & 0 deletions runtime/fixtures/runtime_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,18 @@ void testCanLaunchSecondaryIsolate() {
void testCanRecieveArguments(List<String> args) {
notifyResult(args != null && args.length == 1 && args[0] == 'arg1');
}

@pragma('vm:entry-point')
void testSecondaryIsolateShutdown() {
final onExit = RawReceivePort((_) { notifyNative(); });
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 1', onExit: onExit.sendPort);
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 2', onExit: onExit.sendPort);
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 3', onExit: onExit.sendPort);
Isolate.spawn(shutdownIsolateMain, 'You are isolate number 4', onExit: onExit.sendPort);
}

void shutdownIsolateMain(String message) {
print('Secondary isolate got message: ' + message);
passMessage('In child Isolate.');
notifyNative();
}