Skip to content

Commit

Permalink
fix: Fix spawning isolates
Browse files Browse the repository at this point in the history
Setup the IO library, which needs to be setup to have Isolate.spawn work as it initializes the `VMService.script` callback (through `_Platform._nativeScript`).

Call `SetupCoreLibraries` from `OnIsolateInitialize` so that async functions in Isolates work

Add an example / test for isolate spawning.
  • Loading branch information
fuzzybinary committed Sep 29, 2024
1 parent 19d33df commit 6f28908
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 12 deletions.
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.21)

add_subdirectory(isolate_spawn)
add_subdirectory(simple_example)
add_subdirectory(simple_example_ffi)
add_subdirectory(realtime_example)
28 changes: 28 additions & 0 deletions examples/isolate_spawn/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.21)

project(isolate_spawn)

add_executable(isolate_spawn main.cpp)

target_include_directories(isolate_spawn PRIVATE
"${DART_DLL_DIR}"
"${DART_DIR}/runtime/include"
)

if(WIN32)
add_custom_command(TARGET isolate_spawn POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:isolate_spawn> $<TARGET_FILE_DIR:isolate_spawn>
COMMAND_EXPAND_LISTS
)
endif()

add_custom_command(TARGET isolate_spawn POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/hello_world.dart $<TARGET_FILE_DIR:isolate_spawn>
COMMAND_EXPAND_LISTS
)

target_link_libraries(isolate_spawn PUBLIC dart_dll)

if (MSVC)
set_property(TARGET isolate_spawn PROPERTY VS_DEBUGGER_WORKING_DIRECTORY $<TARGET_FILE_DIR:isolate_spawn>)
endif()
17 changes: 17 additions & 0 deletions examples/isolate_spawn/hello_world.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'dart:isolate';

@pragma('vm:external-name', 'SimplePrint')
external void simplePrint(String s);

Future<String> _isolateWorker() async {
simplePrint("Isolate work 1...");
await Future.delayed(Duration(seconds: 10));
simplePrint("Isolate work 2...");
return "done";
}

void main() async {
simplePrint("Hello From Dart!\n");
final isolateValue = await Isolate.run(_isolateWorker);
simplePrint("Isolate complete, returned $isolateValue");
}
81 changes: 81 additions & 0 deletions examples/isolate_spawn/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <string.h>
#include <iostream>

#include "dart_dll.h"

#include <dart_api.h>

Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) {
Dart_PropagateError(handle);
}
return handle;
}

void SimplePrint(Dart_NativeArguments arguments) {
Dart_Handle string = HandleError(Dart_GetNativeArgument(arguments, 0));
if (Dart_IsString(string)) {
const char* cstring;
Dart_StringToCString(string, &cstring);
std::cout << "Hello from C++. Dart says:\n";
std::cout << cstring << std::endl;
}
}

Dart_NativeFunction ResolveNativeFunction(Dart_Handle name,
int /* argc */,
bool* /* auto_setup_scope */) {
if (!Dart_IsString(name)) {
return nullptr;
}

Dart_NativeFunction result = nullptr;

const char* cname;
HandleError(Dart_StringToCString(name, &cname));

if (strcmp("SimplePrint", cname) == 0) {
result = SimplePrint;
}

return result;
}

int main() {
// Initialize Dart
DartDllConfig config;
config.service_port = 6222;

if (!DartDll_Initialize(config)) {
return -1;
}

// Load your main isolate file, also providing the path to a package config if one exists.
// The build makes sure these are coppied to the output directory for running the example
Dart_Isolate isolate = DartDll_LoadScript("hello_world.dart", nullptr);
if (isolate == nullptr) {
return -1;
}

// With the library loaded, you can now use the dart_api.h functions
// This includes setting the native function resolver:
Dart_EnterIsolate(isolate);
Dart_EnterScope();

Dart_Handle library = Dart_RootLibrary();
Dart_SetNativeResolver(library, ResolveNativeFunction, nullptr);

// And run "main"
Dart_Handle result = DartDll_RunMain(library);
if (Dart_IsError(result)) {
std::cerr << "Failed to invoke main: " << Dart_GetError(result);
}

Dart_ExitScope();
Dart_ShutdownIsolate();

// Don't forget to shutdown
DartDll_Shutdown();

return 0;
}
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ elseif(APPLE)
endif()

if(LIB_DART_DEBUG)
target_link_libraries(dart_dll debug ${LIB_DART_DEBUG})
target_link_libraries(dart_dll debug ${LIB_DART_DEBUG})
else()
target_link_libraries(dart_dll debug ${LIB_DART_RELEASE})
endif()
Expand Down
39 changes: 34 additions & 5 deletions src/dart_dll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
#include <bin/dartutils.h>
#include <bin/dfe.h>
#include <bin/gzip.h>
#include <bin/loader.h>
#include <bin/isolate_data.h>
#include <platform/utils.h>

using namespace dart::bin;
using namespace dart;

static DartDllConfig _dart_dll_config;

Expand Down Expand Up @@ -74,13 +77,39 @@ bool OnIsolateInitialize(void** child_callback_data, char** error) {
*child_callback_data = isolate_data;

Dart_EnterScope();

const auto script_uri = isolate_group_data->script_url;
// TODO
/*const bool isolate_run_app_snapshot =
isolate_group_data->RunFromAppSnapshot();*/
Dart_Handle result = SetupCoreLibraries(isolate, isolate_data,
/*group_start=*/false,
/*resolved_packages_config=*/nullptr);
if (Dart_IsError(result)) goto failed;

result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
if (Dart_IsError(result)) goto failed;

if (isolate_group_data->kernel_buffer() != nullptr) {
// Various core-library parts will send requests to the Loader to resolve
// relative URIs and perform other related tasks. We need Loader to be
// initialized for this to work because loading from Kernel binary
// bypasses normal source code loading paths that initialize it.
const char* resolved_script_uri = nullptr;
result = Dart_StringToCString(result, &resolved_script_uri);
if (Dart_IsError(result)) goto failed;
result = Loader::InitForSnapshot(resolved_script_uri, isolate_data);
if (Dart_IsError(result)) goto failed;
}

Dart_ExitScope();

return true;

// Make the isolate runnable so that it is ready to handle messages.
failed:
*error = Utils::StrDup(Dart_GetError(result));
Dart_ExitScope();
Dart_ExitIsolate();
*error = Dart_IsolateMakeRunnable(isolate);
Dart_EnterIsolate(isolate);
return *error == nullptr;
return false;
}

static void OnIsolateShutdown(void*, void*) {
Expand Down
25 changes: 19 additions & 6 deletions src/isolate_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
#include <include/dart_api.h>
#include <include/dart_embedder_api.h>

#include <bin/builtin.h>
#include <bin/dartutils.h>
#include <bin/dfe.h>
#include <bin/isolate_data.h>
#include <bin/loader.h>
#include <bin/snapshot_utils.h>
#include <bin/vmservice_impl.h>
#include <platform/utils.h>

using namespace dart::bin;
Expand Down Expand Up @@ -39,8 +41,11 @@ class DllIsolateGroupData : public IsolateGroupData {

Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
IsolateData* isolate_data,
bool is_isolate_group_start,
bool is_isolate_group_start,
const char** resolved_packages_config) {
auto isolate_group_data = isolate_data->isolate_group_data();
const auto packages_file = isolate_data->packages_file();
const auto script_uri = isolate_group_data->script_url;
Dart_Handle result;

// Prepare builtin and other core libraries for use to resolve URIs.
Expand All @@ -49,8 +54,7 @@ Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
result = DartUtils::PrepareForScriptLoading(false, true);
if (Dart_IsError(result)) return result;

// Setup packages config if specified.
const char* packages_file = isolate_data->packages_file();
// Setup packages config if specified.
result = DartUtils::SetupPackageConfig(packages_file);
if (Dart_IsError(result)) return result;

Expand All @@ -65,6 +69,15 @@ Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
}
}

// Setup the native resolver as the snapshot does not carry it.
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kIOLibrary);
Builtin::SetNativeResolver(Builtin::kCLILibrary);
VmService::SetNativeResolver();

result = DartUtils::SetupIOLibrary(nullptr, script_uri, true);
if (Dart_IsError(result)) return result;

return result;
}

Expand Down Expand Up @@ -169,7 +182,7 @@ Dart_Isolate CreateIsolate(bool is_main_isolate,
const uint8_t* isolate_snapshot_data = kDartCoreIsolateSnapshotData;
const uint8_t* isolate_snapshot_instructions =
kDartCoreIsolateSnapshotInstructions;

if (!is_main_isolate) {
app_snapshot = Snapshot::TryReadAppSnapshot(script_uri);
if (app_snapshot != nullptr && app_snapshot->IsJITorAOT()) {
Expand All @@ -192,8 +205,8 @@ Dart_Isolate CreateIsolate(bool is_main_isolate,

if (kernel_buffer == nullptr && !isolate_run_app_snapshot) {
dfe.ReadScript(script_uri, app_snapshot, &kernel_buffer,
&kernel_buffer_size, /*decode_uri=*/true,
&kernel_buffer_ptr);
&kernel_buffer_size, /*decode_uri=*/true,
&kernel_buffer_ptr);
}

flags->null_safety = true;
Expand Down
8 changes: 8 additions & 0 deletions src/isolate_setup.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once

#include <include/dart_api.h>
#include <bin/isolate_data.h>

using namespace dart::bin;

Dart_Isolate CreateKernelIsolate(const char* script_uri,
const char* main,
Expand All @@ -27,6 +30,11 @@ Dart_Isolate CreateIsolate(bool is_main_isolate,
void* isolate_data,
char** error);

Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
IsolateData* isolate_data,
bool is_isolate_group_start,
const char** resolved_packages_config);

void* GetUserIsolateData(void* isolate_group_data);

void DeleteIsolateData(void* raw_isolate_group_data, void* raw_isolate_data);
Expand Down

0 comments on commit 6f28908

Please sign in to comment.