7eac9f355e
This CL introduces dart_api_dl.h which exposes a subset of dart_api.h and dart_native_api.h for dynamic linking at runtime through the FFI. Dynamic linking is done through including dart_api_dl.cc in a shared library and passing NativeApi.initializeApiDLData to the init function. This CL also includes Native API versioning to deal with possible version skew between native api version against which native libraries are compiled and the version in the DartVM the code is run on. The subset of symbols in the CL includes handle related symbols, error related symbols, handle scope symbols, and native port sumbols. Design: http://go/dart-ffi-expose-dart-api Closes: https://github.com/dart-lang/sdk/issues/40607 Closes: https://github.com/dart-lang/sdk/issues/36858 Closes: https://github.com/dart-lang/sdk/issues/41319 Closes: https://github.com/flutter/flutter/issues/46887 Closes: https://github.com/flutter/flutter/issues/47061 Misc: Closes: https://github.com/dart-lang/sdk/issues/42260 Change-Id: I9e557808dbc99b341f23964cbddbb05f26d7a6c5 Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,dart-sdk-linux-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,front-end-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-mac-debug-x64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-nnbd-linux-debug-x64-try,analyzer-nnbd-linux-release-try,front-end-nnbd-linux-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/145592 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
113 lines
3.7 KiB
Dart
113 lines
3.7 KiB
Dart
// Copyright (c) 2020, 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.
|
|
//
|
|
// Sample showing how to do async callbacks by telling the Dart isolate to
|
|
// yields its execution thread to C so it can perform the callbacks on the
|
|
// main Dart thread.
|
|
//
|
|
// TODO(dartbug.com/37022): Update this when we get real async callbacks.
|
|
|
|
import 'dart:ffi';
|
|
import 'dart:isolate';
|
|
|
|
import 'package:expect/expect.dart';
|
|
|
|
import '../dylib_utils.dart';
|
|
|
|
int globalResult = 0;
|
|
int numCallbacks1 = 0;
|
|
int numCallbacks2 = 0;
|
|
|
|
main() async {
|
|
print("Dart = Dart mutator thread executing Dart.");
|
|
print("C Da = Dart mutator thread executing C.");
|
|
print("C T1 = Some C thread executing C.");
|
|
print("C T2 = Some C thread executing C.");
|
|
print("C = C T1 or C T2.");
|
|
print("Dart: Setup.");
|
|
Expect.isTrue(NativeApi.majorVersion == 1);
|
|
Expect.isTrue(NativeApi.minorVersion >= 0);
|
|
final initializeApi = dl.lookupFunction<IntPtr Function(Pointer<Void>),
|
|
int Function(Pointer<Void>)>("InitDartApiDL");
|
|
Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
|
|
|
|
final interactiveCppRequests = ReceivePort()..listen(requestExecuteCallback);
|
|
final int nativePort = interactiveCppRequests.sendPort.nativePort;
|
|
registerCallback1(nativePort, callback1FP);
|
|
registerCallback2(nativePort, callback2FP);
|
|
print("Dart: Tell C to start worker threads.");
|
|
startWorkSimulator();
|
|
|
|
// We need to yield control in order to be able to receive messages.
|
|
while (numCallbacks2 < 3) {
|
|
print("Dart: Yielding (able to receive messages on port).");
|
|
await asyncSleep(500);
|
|
}
|
|
print("Dart: Received expected number of callbacks.");
|
|
|
|
Expect.equals(2, numCallbacks1);
|
|
Expect.equals(3, numCallbacks2);
|
|
Expect.equals(14, globalResult);
|
|
|
|
print("Dart: Tell C to stop worker threads.");
|
|
stopWorkSimulator();
|
|
interactiveCppRequests.close();
|
|
print("Dart: Done.");
|
|
}
|
|
|
|
int callback1(int a) {
|
|
print("Dart: callback1($a).");
|
|
numCallbacks1++;
|
|
return a + 3;
|
|
}
|
|
|
|
void callback2(int a) {
|
|
print("Dart: callback2($a).");
|
|
globalResult += a;
|
|
numCallbacks2++;
|
|
}
|
|
|
|
void requestExecuteCallback(dynamic message) {
|
|
final int work_address = message;
|
|
final work = Pointer<Work>.fromAddress(work_address);
|
|
print("Dart: Calling into C to execute callback ($work).");
|
|
executeCallback(work);
|
|
print("Dart: Done with callback.");
|
|
}
|
|
|
|
final callback1FP = Pointer.fromFunction<IntPtr Function(IntPtr)>(callback1, 0);
|
|
|
|
final callback2FP = Pointer.fromFunction<Void Function(IntPtr)>(callback2);
|
|
|
|
final dl = dlopenPlatformSpecific("ffi_test_functions");
|
|
|
|
final registerCallback1 = dl.lookupFunction<
|
|
Void Function(Int64 sendPort,
|
|
Pointer<NativeFunction<IntPtr Function(IntPtr)>> functionPointer),
|
|
void Function(int sendPort,
|
|
Pointer<NativeFunction<IntPtr Function(IntPtr)>> functionPointer)>(
|
|
'RegisterMyCallbackBlocking');
|
|
|
|
final registerCallback2 = dl.lookupFunction<
|
|
Void Function(Int64 sendPort,
|
|
Pointer<NativeFunction<Void Function(IntPtr)>> functionPointer),
|
|
void Function(int sendPort,
|
|
Pointer<NativeFunction<Void Function(IntPtr)>> functionPointer)>(
|
|
'RegisterMyCallbackNonBlocking');
|
|
|
|
final startWorkSimulator =
|
|
dl.lookupFunction<Void Function(), void Function()>('StartWorkSimulator');
|
|
|
|
final stopWorkSimulator =
|
|
dl.lookupFunction<Void Function(), void Function()>('StopWorkSimulator');
|
|
|
|
final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
|
|
void Function(Pointer<Work>)>('ExecuteCallback');
|
|
|
|
class Work extends Struct {}
|
|
|
|
Future asyncSleep(int ms) {
|
|
return new Future.delayed(Duration(milliseconds: ms));
|
|
}
|