Files
sdk/samples/ffi/async/sample_async_callback.dart
T
Daco Harkes 7eac9f355e [vm/ffi] Expose a subset of dart_(native_)api.h for dynamic linking.
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>
2020-06-18 07:30:43 +00:00

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));
}