| // 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 == 2); | |
| Expect.isTrue(NativeApi.minorVersion >= 2); | |
| 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', | |
| ); | |
| final class Work extends Opaque {} | |
| Future asyncSleep(int ms) { | |
| return new Future.delayed(Duration(milliseconds: ms)); | |
| } |