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 <iinozemtsev@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
a6f06e8c9f
commit
51ea42537a
@@ -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
|
||||
|
||||
+41
-14
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "engine/engine.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#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<Engine::IsolateData> 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<Engine::IsolateData> 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<Engine::IsolateData> isolate_data =
|
||||
DataForIsolate(Dart_CurrentIsolate());
|
||||
return Dart_Invoke(isolate_data->isolate_library,
|
||||
isolate_data->drain_microtasks_function_name, 0, nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<Engine::IsolateData> 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<Engine::IsolateData>())
|
||||
.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
|
||||
|
||||
+15
-7
@@ -6,7 +6,6 @@
|
||||
#define RUNTIME_ENGINE_ENGINE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#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<Dart_Isolate> isolates_;
|
||||
|
||||
// Stores per-isolate mutexes, used by Engine::LockIsolate/UnlockIsolate.
|
||||
std::unordered_map<Dart_Isolate, Mutex> mutexes_;
|
||||
// Stores per-isolate engine state.
|
||||
std::unordered_map<Dart_Isolate, std::shared_ptr<IsolateData>> isolate_data_;
|
||||
|
||||
// Default scheduler.
|
||||
DartEngine_MessageScheduler default_scheduler_;
|
||||
// Per-isolate message schedulers.
|
||||
std::unordered_map<Dart_Isolate, DartEngine_MessageScheduler> 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<IsolateData> DataForIsolate(Dart_Isolate isolate);
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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" ]
|
||||
}
|
||||
|
||||
@@ -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<int> returnRegularFuture(int delayMs) async {
|
||||
await Future.delayed(Duration(milliseconds: 5));
|
||||
return 256;
|
||||
}
|
||||
|
||||
Future<int> returnMicrotaskFuture(int delayMs) => Future.microtask(() async {
|
||||
await Future.delayed(Duration(milliseconds: delayMs));
|
||||
return 256;
|
||||
});
|
||||
|
||||
Stream<int> 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<int> produceIntStreamWithController(int count, int delayMs) {
|
||||
final delay = Duration(milliseconds: delayMs);
|
||||
|
||||
final sc = StreamController<int>();
|
||||
(() async {
|
||||
for (var i = 0; i < count; i++) {
|
||||
await Future.delayed(delay);
|
||||
sc.add(i);
|
||||
}
|
||||
sc.close();
|
||||
})();
|
||||
return sc.stream;
|
||||
}
|
||||
|
||||
Future<int> 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<int> awaitAndMultiply(Future<int> a, Future<int> b) async =>
|
||||
(await a) * (await b);
|
||||
|
||||
class AwaitAndMultiplyCall {
|
||||
final _a = Completer<int>();
|
||||
final _b = Completer<int>();
|
||||
|
||||
Future<int> getA() => _a.future;
|
||||
Future<int> 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<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
|
||||
callbackPtr,
|
||||
).asFunction<void Function(Pointer<Opaque>, int)>()(
|
||||
Pointer<Opaque>.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<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
|
||||
callbackPtr,
|
||||
).asFunction<void Function(Pointer<Opaque>, int)>()(
|
||||
Pointer<Opaque>.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<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
|
||||
callbackPtr,
|
||||
).asFunction<void Function(Pointer<Opaque>, int)>()(
|
||||
Pointer<Opaque>.fromAddress(contextPtr),
|
||||
await sumIntStream(count, delayMs, useAsyncStar),
|
||||
);
|
||||
+25
-13
@@ -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 <typename T>
|
||||
inline T WithIsolate(Dart_Isolate isolate, std::function<T()> 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<void()> body) {
|
||||
DartEngine_AcquireIsolate(isolate);
|
||||
Dart_EnterScope();
|
||||
body();
|
||||
Dart_ExitScope();
|
||||
DartEngine_ReleaseIsolate();
|
||||
return body();
|
||||
}
|
||||
|
||||
#endif /* SAMPLES_EMBEDDER_HELPERS_H_ */
|
||||
|
||||
@@ -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<String> args) {
|
||||
throw 'Unimplemented';
|
||||
}
|
||||
|
||||
@@ -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<String> args) {
|
||||
throw 'Unimplemented';
|
||||
}
|
||||
|
||||
@@ -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 <chrono>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#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<std::promise<int64_t>*>(context);
|
||||
promise->set_value(value);
|
||||
delete promise;
|
||||
}
|
||||
|
||||
// Helper to call Dart function `returnRegularFutureC`.
|
||||
std::future<int64_t> ReturnRegularFuture(Dart_Isolate isolate,
|
||||
int64_t delay_ms,
|
||||
bool use_microtask) {
|
||||
auto promise = new std::promise<int64_t>();
|
||||
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<intptr_t>(&FulfillIntPromise)), // callback
|
||||
Dart_NewInteger(reinterpret_cast<intptr_t>(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<int64_t> SumIntStream(Dart_Isolate isolate,
|
||||
int count,
|
||||
int64_t delay_ms,
|
||||
bool use_async_star) {
|
||||
auto promise = new std::promise<int64_t>();
|
||||
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<intptr_t>(&FulfillIntPromise)), // callback
|
||||
Dart_NewInteger(reinterpret_cast<intptr_t>(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<int64_t>&& 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<int64_t> 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<int64_t>();
|
||||
auto future = promise->get_future();
|
||||
|
||||
IsolateScope isolate_scope(isolate);
|
||||
DartScope dart_scope;
|
||||
|
||||
Dart_Handle args[] = {
|
||||
Dart_NewInteger(reinterpret_cast<intptr_t>(&FulfillIntPromise)),
|
||||
Dart_NewInteger(reinterpret_cast<intptr_t>(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();
|
||||
}
|
||||
@@ -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 <condition_variable>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
@@ -9,7 +13,7 @@
|
||||
|
||||
// Calls `startTimer` from timer.dart
|
||||
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
|
||||
WithIsolate(isolate, [&]() {
|
||||
WithIsolate<void>(isolate, [&]() {
|
||||
std::initializer_list<Dart_Handle> 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<void>(isolate, [&]() {
|
||||
CheckError(Dart_Invoke(Dart_RootLibrary(),
|
||||
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
|
||||
"calling stopTimer");
|
||||
|
||||
@@ -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 <future>
|
||||
@@ -9,7 +13,7 @@
|
||||
|
||||
// Calls `startTimer` from timer.dart
|
||||
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
|
||||
WithIsolate(isolate, [&]() {
|
||||
WithIsolate<void>(isolate, [&]() {
|
||||
std::initializer_list<Dart_Handle> 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<void>(isolate, [&]() {
|
||||
CheckError(Dart_Invoke(Dart_RootLibrary(),
|
||||
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
|
||||
"calling stopTimer");
|
||||
|
||||
@@ -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 <iostream>
|
||||
#include "helpers.h"
|
||||
#include "include/dart_api.h"
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user