From 51ea42537af71379fc0d6919143326e45205ef4d Mon Sep 17 00:00:00 2001 From: Ivan Inozemtsev Date: Wed, 12 Feb 2025 11:10:25 -0800 Subject: [PATCH] Add support for flushing microtasks in dart_engine.h Also add a sample for calling Dart functions which return/accept futures. Change-Id: I932d0577709f4e068ccd3212797751ecb347c4f9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/408281 Commit-Queue: Ivan Inozemtsev Reviewed-by: Martin Kustermann --- runtime/engine/dart_engine_impl.cc | 4 + runtime/engine/engine.cc | 55 +++-- runtime/engine/engine.h | 22 +- runtime/engine/include/dart_engine.h | 11 + .../tools/entitlements/run_futures_aot.plist | 10 + .../entitlements/run_futures_kernel.plist | 10 + samples/embedder/BUILD.gn | 11 + samples/embedder/futures.dart | 129 ++++++++++++ samples/embedder/helpers.h | 38 ++-- samples/embedder/program1.dart | 4 + samples/embedder/program2.dart | 4 + samples/embedder/run_futures.cc | 188 ++++++++++++++++++ samples/embedder/run_timer.cc | 8 +- samples/embedder/run_timer_async.cc | 8 +- samples/embedder/run_two_programs.cc | 4 + samples/embedder/timer.dart | 4 + tests/standalone/embedder_samples_test.dart | 6 + 17 files changed, 478 insertions(+), 38 deletions(-) create mode 100644 runtime/tools/entitlements/run_futures_aot.plist create mode 100644 runtime/tools/entitlements/run_futures_kernel.plist create mode 100644 samples/embedder/futures.dart create mode 100644 samples/embedder/run_futures.cc diff --git a/runtime/engine/dart_engine_impl.cc b/runtime/engine/dart_engine_impl.cc index aa2e0e2ffc5..9b131c47864 100644 --- a/runtime/engine/dart_engine_impl.cc +++ b/runtime/engine/dart_engine_impl.cc @@ -72,5 +72,9 @@ DART_EXPORT void DartEngine_HandleMessage(Dart_Isolate isolate) { Engine::instance()->HandleMessage(isolate); } +DART_EXPORT Dart_Handle DartEngine_DrainMicrotasksQueue() { + return Engine::instance()->DrainMicrotasksQueue(); +} + } // namespace engine } // namespace dart diff --git a/runtime/engine/engine.cc b/runtime/engine/engine.cc index c2a082e46a0..16a68e5df66 100644 --- a/runtime/engine/engine.cc +++ b/runtime/engine/engine.cc @@ -4,7 +4,6 @@ #include "engine/engine.h" #include -#include #include "bin/dartutils.h" #include "include/dart_api.h" #include "include/dart_embedder_api.h" @@ -16,6 +15,8 @@ namespace dart { namespace engine { +constexpr char kRunPendingImmediateCallback[] = "_runPendingImmediateCallback"; + using platform::MutexLocker; Engine* Engine::instance() { @@ -195,8 +196,8 @@ Dart_Isolate Engine::StartIsolate(DartEngine_SnapshotData snapshot, Dart_Handle core_libs_result = bin::DartUtils::PrepareForScriptLoading(false, false); if (Dart_IsError(core_libs_result)) { - Dart_ShutdownIsolate(); *error = Utils::StrDup(Dart_GetError(core_libs_result)); + Dart_ShutdownIsolate(); return nullptr; } @@ -210,12 +211,27 @@ Dart_Isolate Engine::StartIsolate(DartEngine_SnapshotData snapshot, snapshot.kernel_buffer, snapshot.kernel_buffer_size); if (Dart_IsError(library)) { - Dart_ShutdownIsolate(); *error = Utils::StrDup(Dart_GetError(library)); + Dart_ShutdownIsolate(); return nullptr; } } + Dart_Handle isolate_library = Dart_LookupLibrary( + Dart_NewStringFromCString(bin::DartUtils::kIsolateLibURL)); + if (Dart_IsError(isolate_library)) { + *error = Utils::StrDup(Dart_GetError(isolate_library)); + Dart_ShutdownIsolate(); + return nullptr; + } + + std::shared_ptr isolate_data = DataForIsolate(isolate); + isolate_data->isolate_library = Dart_NewPersistentHandle(isolate_library); + isolate_data->drain_microtasks_function_name = Dart_NewPersistentHandle( + Dart_NewStringFromCString(kRunPendingImmediateCallback)); + isolate_data->scheduler.context = nullptr; + isolate_data->scheduler.schedule_callback = nullptr; + Dart_ExitScope(); Dart_ExitIsolate(); is_running_ = true; @@ -232,9 +248,12 @@ void Engine::Shutdown() { is_running_ = false; for (auto isolate : isolates_) { + std::shared_ptr isolate_data = DataForIsolate(isolate); LockIsolate(isolate); Dart_EnterIsolate(isolate); Dart_SetMessageNotifyCallback(nullptr); + Dart_DeletePersistentHandle(isolate_data->isolate_library); + Dart_DeletePersistentHandle(isolate_data->drain_microtasks_function_name); Dart_ShutdownIsolate(); UnlockIsolate(isolate); } @@ -277,17 +296,30 @@ void Engine::HandleMessage(Dart_Isolate isolate) { UnlockIsolate(isolate); } -Mutex& Engine::MutexForIsolate(Dart_Isolate isolate) { +Dart_Handle Engine::DrainMicrotasksQueue() { + std::shared_ptr isolate_data = + DataForIsolate(Dart_CurrentIsolate()); + return Dart_Invoke(isolate_data->isolate_library, + isolate_data->drain_microtasks_function_name, 0, nullptr); +} + +std::shared_ptr Engine::DataForIsolate( + Dart_Isolate isolate) { MutexLocker ml(&engine_state_); - return mutexes_[isolate]; + auto it = isolate_data_.find(isolate); + if (it == isolate_data_.end()) { + it = isolate_data_.emplace(isolate, std::make_shared()) + .first; + } + return it->second; } void Engine::LockIsolate(Dart_Isolate isolate) { - MutexForIsolate(isolate).Lock(); + DataForIsolate(isolate)->mutex.Lock(); } void Engine::UnlockIsolate(Dart_Isolate isolate) { - MutexForIsolate(isolate).Unlock(); + DataForIsolate(isolate)->mutex.Unlock(); } void Engine::NotifyMessage(Dart_Isolate isolate) { @@ -313,11 +345,7 @@ void Engine::NotifyMessage(Dart_Isolate isolate) { return; } - DartEngine_MessageScheduler scheduler; - { - MutexLocker ml(&engine_state_); - scheduler = schedulers_[isolate]; - } + DartEngine_MessageScheduler scheduler = DataForIsolate(isolate)->scheduler; if (scheduler.schedule_callback == nullptr) { scheduler = default_scheduler_; @@ -341,8 +369,7 @@ void Engine::SetDefaultMessageScheduler(DartEngine_MessageScheduler scheduler) { void Engine::SetMessageScheduler(DartEngine_MessageScheduler scheduler, Dart_Isolate isolate) { - MutexLocker ml(&engine_state_); - schedulers_[isolate] = scheduler; + DataForIsolate(isolate)->scheduler = scheduler; } } // namespace engine diff --git a/runtime/engine/engine.h b/runtime/engine/engine.h index 61d57ca7b6a..389ffa46866 100644 --- a/runtime/engine/engine.h +++ b/runtime/engine/engine.h @@ -6,7 +6,6 @@ #define RUNTIME_ENGINE_ENGINE_H_ #include -#include #include #include #include "include/dart_engine.h" @@ -54,6 +53,9 @@ class Engine { // Calls Dart_HandleMessage, managing an isolate lock and Dart scope. void HandleMessage(Dart_Isolate isolate); + // Drains the microtasks queue, requires an active isolate. + Dart_Handle DrainMicrotasksQueue(); + // Sets a callback to be called when Dart_HandleMessage returns an error. void SetHandleMessageErrorCallback( DartEngine_HandleMessageErrorCallback callback); @@ -85,6 +87,14 @@ class Engine { static void HandleMessageCallback(Dart_Isolate isolate); private: + // Engine's internal data for isolate. + struct IsolateData { + DartEngine_MessageScheduler scheduler; + Mutex mutex; + Dart_PersistentHandle isolate_library; + Dart_PersistentHandle drain_microtasks_function_name; + }; + // Set to false once shutdown starts. bool is_running_ = false; @@ -114,19 +124,17 @@ class Engine { // All isolates, started via Engine::StartIsolate. std::vector isolates_; - // Stores per-isolate mutexes, used by Engine::LockIsolate/UnlockIsolate. - std::unordered_map mutexes_; + // Stores per-isolate engine state. + std::unordered_map> isolate_data_; // Default scheduler. DartEngine_MessageScheduler default_scheduler_; - // Per-isolate message schedulers. - std::unordered_map schedulers_; // Callback to notify about Dart_HandleMessage errors. DartEngine_HandleMessageErrorCallback handle_message_error_callback_; - // Helper function to get an element from mutexes_. - Mutex& MutexForIsolate(Dart_Isolate isolate); + // Helper function to get an element from isolate_data_. + std::shared_ptr DataForIsolate(Dart_Isolate isolate); }; } // namespace engine diff --git a/runtime/engine/include/dart_engine.h b/runtime/engine/include/dart_engine.h index adf669f48d7..9d9e711dbfc 100644 --- a/runtime/engine/include/dart_engine.h +++ b/runtime/engine/include/dart_engine.h @@ -109,6 +109,17 @@ typedef void (*DartEngine_HandleMessageErrorCallback)( DART_EXPORT void DartEngine_SetHandleMessageErrorCallback( DartEngine_HandleMessageErrorCallback handle_message_error_callback); +/** + * Drains the microtasks queue. Requires to be an active isolate. + * + * Normally the microtasks queue is drained after handling each + * isolate message, but when the engine calls into Dart, it might be + * required to manually drain the microtasks queue. + * + * \return Dart_Handle invocation result. + */ +DART_EXPORT Dart_Handle DartEngine_DrainMicrotasksQueue(); + /** * Handles a single message for an isolate. */ diff --git a/runtime/tools/entitlements/run_futures_aot.plist b/runtime/tools/entitlements/run_futures_aot.plist new file mode 100644 index 00000000000..eeda4be95dc --- /dev/null +++ b/runtime/tools/entitlements/run_futures_aot.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.disable-library-validation + + + \ No newline at end of file diff --git a/runtime/tools/entitlements/run_futures_kernel.plist b/runtime/tools/entitlements/run_futures_kernel.plist new file mode 100644 index 00000000000..eeda4be95dc --- /dev/null +++ b/runtime/tools/entitlements/run_futures_kernel.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.disable-library-validation + + + \ No newline at end of file diff --git a/samples/embedder/BUILD.gn b/samples/embedder/BUILD.gn index cf132301b2c..27482072534 100644 --- a/samples/embedder/BUILD.gn +++ b/samples/embedder/BUILD.gn @@ -15,6 +15,7 @@ group("all") { group("aot") { deps = [ + ":run_futures_aot", ":run_main_aot", ":run_timer_aot", ":run_timer_async_aot", @@ -24,6 +25,7 @@ group("aot") { group("kernel") { deps = [ + ":run_futures_kernel", ":run_main_kernel", ":run_timer_async_kernel", ":run_timer_kernel", @@ -150,3 +152,12 @@ sample("run_timer_async") { snapshots("timer") { main_dart = "timer.dart" } + +snapshots("futures") { + main_dart = "futures.dart" +} + +sample("run_futures") { + sources = [ "run_futures.cc" ] + snapshots = [ ":futures" ] +} diff --git a/samples/embedder/futures.dart b/samples/embedder/futures.dart new file mode 100644 index 00000000000..2feaf2a04cf --- /dev/null +++ b/samples/embedder/futures.dart @@ -0,0 +1,129 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:ffi'; + +void main() async { + print( + 'returnRegularFuture returns: ' + '${await returnRegularFuture(5)}', + ); + print( + 'sumIntStream(useAsyncStar = false) returns: ' + '${await sumIntStream(5, 1, false)}', + ); + print( + 'sumIntStream(useAsyncStar = true) returns: ' + '${await sumIntStream(5, 1, true)}', + ); +} + +Future returnRegularFuture(int delayMs) async { + await Future.delayed(Duration(milliseconds: 5)); + return 256; +} + +Future returnMicrotaskFuture(int delayMs) => Future.microtask(() async { + await Future.delayed(Duration(milliseconds: delayMs)); + return 256; +}); + +Stream produceIntStreamWithAsyncStar(int count, int delayMs) async* { + final delay = Duration(milliseconds: delayMs); + + for (var i = 0; i < count; i++) { + await Future.delayed(delay); + yield i; + } +} + +Stream produceIntStreamWithController(int count, int delayMs) { + final delay = Duration(milliseconds: delayMs); + + final sc = StreamController(); + (() async { + for (var i = 0; i < count; i++) { + await Future.delayed(delay); + sc.add(i); + } + sc.close(); + })(); + return sc.stream; +} + +Future sumIntStream(int count, int delayMs, bool useAsyncStar) async { + final stream = + useAsyncStar + ? produceIntStreamWithAsyncStar(count, delayMs) + : produceIntStreamWithController(count, delayMs); + var sum = 0; + await for (var value in stream) { + sum += value; + } + return sum; +} + +Future awaitAndMultiply(Future a, Future b) async => + (await a) * (await b); + +class AwaitAndMultiplyCall { + final _a = Completer(); + final _b = Completer(); + + Future getA() => _a.future; + Future getB() => _b.future; + + @pragma('vm:entry-point', 'call') + void setA(int value) => _a.complete(value); + @pragma('vm:entry-point', 'call') + void setB(int value) => _b.complete(value); +} + +@pragma('vm:entry-point', 'call') +AwaitAndMultiplyCall awaitAndMultiplyC(int callbackPtr, int contextPtr) { + final call = AwaitAndMultiplyCall(); + () async { + Pointer, Int64)>>.fromAddress( + callbackPtr, + ).asFunction, int)>()( + Pointer.fromAddress(contextPtr), + await awaitAndMultiply(call.getA(), call.getB()), + ); + }(); + return call; +} + +@pragma('vm:entry-point', 'call') +// C-friendly wrapper over [returnRegularFuture]. +void returnRegularFutureC( + int delayMs, + bool useMicrotask, + int callbackPtr, + int contextPtr, +) async => + Pointer, Int64)>>.fromAddress( + callbackPtr, + ).asFunction, int)>()( + Pointer.fromAddress(contextPtr), + await (useMicrotask + ? returnMicrotaskFuture(delayMs) + : returnRegularFuture(delayMs)), + ); + +@pragma('vm:entry-point', 'call') +// C-friendly wrapper over [sumIntStream]. +void sumIntStreamC( + int count, + int delayMs, + bool useAsyncStar, + int callbackPtr, + int contextPtr, +) async => + Pointer, Int64)>>.fromAddress( + callbackPtr, + ).asFunction, int)>()( + Pointer.fromAddress(contextPtr), + await sumIntStream(count, delayMs, useAsyncStar), + ); diff --git a/samples/embedder/helpers.h b/samples/embedder/helpers.h index 1784aa342f7..fbcce055d5f 100644 --- a/samples/embedder/helpers.h +++ b/samples/embedder/helpers.h @@ -73,22 +73,34 @@ inline int64_t IntFromHandle(Dart_Handle handle) { return result; } +class DartScope { + public: + DartScope() { Dart_EnterScope(); } + virtual ~DartScope() { Dart_ExitScope(); } + + private: + DartScope(const DartScope&) = delete; + void operator=(const DartScope&) = delete; +}; + +class IsolateScope { + public: + explicit IsolateScope(Dart_Isolate isolate) { + DartEngine_AcquireIsolate(isolate); + } + virtual ~IsolateScope() { DartEngine_ReleaseIsolate(); } + + private: + IsolateScope(const IsolateScope&) = delete; + void operator=(const IsolateScope&) = delete; +}; + template inline T WithIsolate(Dart_Isolate isolate, std::function body) { - DartEngine_AcquireIsolate(isolate); - Dart_EnterScope(); - T result = body(); - Dart_ExitScope(); - DartEngine_ReleaseIsolate(); - return result; -} + IsolateScope isolate_scope(isolate); + DartScope dart_scope; -inline void WithIsolate(Dart_Isolate isolate, std::function body) { - DartEngine_AcquireIsolate(isolate); - Dart_EnterScope(); - body(); - Dart_ExitScope(); - DartEngine_ReleaseIsolate(); + return body(); } #endif /* SAMPLES_EMBEDDER_HELPERS_H_ */ diff --git a/samples/embedder/program1.dart b/samples/embedder/program1.dart index 25b7d96125f..cac54cc2e7d 100644 --- a/samples/embedder/program1.dart +++ b/samples/embedder/program1.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + void main(List args) { throw 'Unimplemented'; } diff --git a/samples/embedder/program2.dart b/samples/embedder/program2.dart index 051ae6e13d8..2885cb15478 100644 --- a/samples/embedder/program2.dart +++ b/samples/embedder/program2.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + void main(List args) { throw 'Unimplemented'; } diff --git a/samples/embedder/run_futures.cc b/samples/embedder/run_futures.cc new file mode 100644 index 00000000000..b8a1163943c --- /dev/null +++ b/samples/embedder/run_futures.cc @@ -0,0 +1,188 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include +#include +#include +#include +#include "helpers.h" +#include "include/dart_api.h" +#include "include/dart_engine.h" + +void ScheduleDartMessage(Dart_Isolate isolate, void* context) { + std::ignore = std::async(DartEngine_HandleMessage, isolate); +} + +void FulfillIntPromise(void* context, int64_t value) { + auto promise = reinterpret_cast*>(context); + promise->set_value(value); + delete promise; +} + +// Helper to call Dart function `returnRegularFutureC`. +std::future ReturnRegularFuture(Dart_Isolate isolate, + int64_t delay_ms, + bool use_microtask) { + auto promise = new std::promise(); + auto result = promise->get_future(); + + IsolateScope isolate_scope(isolate); + DartScope dart_scope; + + // args + Dart_Handle args[] = { + Dart_NewInteger(delay_ms), Dart_NewBoolean(use_microtask), + Dart_NewInteger( + reinterpret_cast(&FulfillIntPromise)), // callback + Dart_NewInteger(reinterpret_cast(promise)) // context + }; + + // call + CheckError(Dart_Invoke(Dart_RootLibrary(), + Dart_NewStringFromCString("returnRegularFutureC"), 4, + args)); + CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue"); + + return result; +} + +// Helper to call Dart function `sumIntStreamC`. +std::future SumIntStream(Dart_Isolate isolate, + int count, + int64_t delay_ms, + bool use_async_star) { + auto promise = new std::promise(); + auto result = promise->get_future(); + + IsolateScope isolate_scope(isolate); + DartScope dart_scope; + + // args + Dart_Handle args[] = { + Dart_NewInteger(count), Dart_NewInteger(delay_ms), + Dart_NewBoolean(use_async_star), + Dart_NewInteger( + reinterpret_cast(&FulfillIntPromise)), // callback + Dart_NewInteger(reinterpret_cast(promise)) // context + }; + + // call + CheckError(Dart_Invoke(Dart_RootLibrary(), + Dart_NewStringFromCString("sumIntStreamC"), 5, args)); + CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue"); + + return result; +} + +class AwaitAndMultiplyCall { + public: + AwaitAndMultiplyCall(Dart_Isolate isolate, + Dart_PersistentHandle handle, + std::future&& result) + : result(std::move(result)), isolate_(isolate), handle_(handle) {} + + void CompleteA(int64_t value) { + IsolateScope isolate_scope(isolate_); + DartScope dart_scope; + + Dart_Handle args[] = {Dart_NewInteger(value)}; + CheckError( + Dart_Invoke(handle_, Dart_NewStringFromCString("setA"), 1, args)); + CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue"); + } + + void CompleteB(int64_t value) { + IsolateScope isolate_scope(isolate_); + DartScope dart_scope; + + Dart_Handle args[] = {Dart_NewInteger(value)}; + CheckError( + Dart_Invoke(handle_, Dart_NewStringFromCString("setB"), 1, args)); + CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue"); + } + + std::future result; + + void Release() { + IsolateScope isolate_scope(isolate_); + DartScope dart_scope; + + Dart_DeletePersistentHandle(handle_); + } + + private: + Dart_Isolate isolate_; + Dart_PersistentHandle handle_; +}; + +AwaitAndMultiplyCall AwaitAndMultiply(Dart_Isolate isolate) { + auto promise = new std::promise(); + auto future = promise->get_future(); + + IsolateScope isolate_scope(isolate); + DartScope dart_scope; + + Dart_Handle args[] = { + Dart_NewInteger(reinterpret_cast(&FulfillIntPromise)), + Dart_NewInteger(reinterpret_cast(promise)), + }; + Dart_PersistentHandle call_handle = Dart_NewPersistentHandle(CheckError( + Dart_Invoke(Dart_RootLibrary(), + Dart_NewStringFromCString("awaitAndMultiplyC"), 2, args))); + CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue"); + + return AwaitAndMultiplyCall(isolate, call_handle, std::move(future)); +} + +int main(int argc, char** argv) { + if (argc == 1) { + std::cerr << "Must specify snapshot path" << std::endl; + std::exit(1); + } + char* error = nullptr; + + // + // Set up message handling and start isolate. + // + DartEngine_MessageScheduler scheduler{ScheduleDartMessage, nullptr}; + DartEngine_SetDefaultMessageScheduler(scheduler); + + DartEngine_SnapshotData snapshot_data = AutoSnapshotFromFile(argv[1], &error); + CheckError(error, "reading snapshot"); + Dart_Isolate isolate = DartEngine_CreateIsolate(snapshot_data, &error); + CheckError(error, "creating isolate"); + + // + // Call Dart functions. + // + + auto result1 = ReturnRegularFuture(isolate, 5, false).get(); + std::cout << "returnRegularFutureC(useMicrotask = false) returns: " << result1 + << std::endl; + + auto result2 = ReturnRegularFuture(isolate, 5, true).get(); + std::cout << "returnRegularFutureC(useMicrotask = true) returns: " << result2 + << std::endl; + + auto result3 = SumIntStream(isolate, 5, 5, false).get(); + std::cout << "sumIntStream(useAsyncStar = false) returns: " << result3 + << std::endl; + + auto result4 = SumIntStream(isolate, 5, 5, true).get(); + std::cout << "sumIntStream(useAsyncStar = true) returns: " << result4 + << std::endl; + + auto call = AwaitAndMultiply(isolate); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + call.CompleteB(5); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + call.CompleteA(20); + auto result5 = call.result.get(); + std::cout << "awaitAndMultiply(5, 20) = " << result5 << std::endl; + call.Release(); + // + // Shutdown + // + DartEngine_Shutdown(); +} diff --git a/samples/embedder/run_timer.cc b/samples/embedder/run_timer.cc index 5ddd1308f5c..a4a8195e8f8 100644 --- a/samples/embedder/run_timer.cc +++ b/samples/embedder/run_timer.cc @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + #include #include #include @@ -9,7 +13,7 @@ // Calls `startTimer` from timer.dart void StartTimer(Dart_Isolate isolate, uint32_t millis) { - WithIsolate(isolate, [&]() { + WithIsolate(isolate, [&]() { std::initializer_list args{Dart_NewInteger(millis)}; CheckError( Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"), @@ -20,7 +24,7 @@ void StartTimer(Dart_Isolate isolate, uint32_t millis) { // Calls `stopTimer` from timer.dart void StopTimer(Dart_Isolate isolate) { - WithIsolate(isolate, [&]() { + WithIsolate(isolate, [&]() { CheckError(Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("stopTimer"), 0, nullptr), "calling stopTimer"); diff --git a/samples/embedder/run_timer_async.cc b/samples/embedder/run_timer_async.cc index 13e610c02e6..92166f5fd67 100644 --- a/samples/embedder/run_timer_async.cc +++ b/samples/embedder/run_timer_async.cc @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + // Same as run_timer.cc, but uses std::async instead of a dedicated event loop // thread. Used as a demonstration of a custom message scheduler. #include @@ -9,7 +13,7 @@ // Calls `startTimer` from timer.dart void StartTimer(Dart_Isolate isolate, uint32_t millis) { - WithIsolate(isolate, [&]() { + WithIsolate(isolate, [&]() { std::initializer_list args{Dart_NewInteger(millis)}; CheckError( Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"), @@ -20,7 +24,7 @@ void StartTimer(Dart_Isolate isolate, uint32_t millis) { // Calls `stopTimer` from timer.dart void StopTimer(Dart_Isolate isolate) { - WithIsolate(isolate, [&]() { + WithIsolate(isolate, [&]() { CheckError(Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("stopTimer"), 0, nullptr), "calling stopTimer"); diff --git a/samples/embedder/run_two_programs.cc b/samples/embedder/run_two_programs.cc index a6707b86fa7..9b5222344b9 100644 --- a/samples/embedder/run_two_programs.cc +++ b/samples/embedder/run_two_programs.cc @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + #include #include "helpers.h" #include "include/dart_api.h" diff --git a/samples/embedder/timer.dart b/samples/embedder/timer.dart index 635668127d0..6a306e8de5d 100644 --- a/samples/embedder/timer.dart +++ b/samples/embedder/timer.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'dart:async'; void main() { diff --git a/tests/standalone/embedder_samples_test.dart b/tests/standalone/embedder_samples_test.dart index cce802c113c..eeff1382d4a 100644 --- a/tests/standalone/embedder_samples_test.dart +++ b/tests/standalone/embedder_samples_test.dart @@ -44,6 +44,9 @@ void main() { checkSample('$out/run_timer_async_kernel', [ '$out/gen/timer_kernel.dart.snapshot', ]); + checkSample('$out/run_futures_kernel', [ + '$out/gen/futures_kernel.dart.snapshot', + ]); // AOT Samples aren't built on some platforms. checkSample('$out/run_main_aot', [ @@ -59,4 +62,7 @@ void main() { checkSample('$out/run_timer_async_aot', [ '$out/timer_aot.snapshot', ], skipIfNotBuilt: true); + checkSample('$out/run_futures_aot', [ + '$out/futures_aot.snapshot', + ], skipIfNotBuilt: true); }