// 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), int Function(Pointer) >("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.fromAddress(work_address); print("Dart: Calling into C to execute callback ($work)."); executeCallback(work); print("Dart: Done with callback."); } final callback1FP = Pointer.fromFunction(callback1, 0); final callback2FP = Pointer.fromFunction(callback2); final dl = dlopenPlatformSpecific("ffi_test_functions"); final registerCallback1 = dl .lookupFunction< Void Function( Int64 sendPort, Pointer> functionPointer, ), void Function( int sendPort, Pointer> functionPointer, ) >('RegisterMyCallbackBlocking'); final registerCallback2 = dl .lookupFunction< Void Function( Int64 sendPort, Pointer> functionPointer, ), void Function( int sendPort, Pointer> functionPointer, ) >('RegisterMyCallbackNonBlocking'); final startWorkSimulator = dl.lookupFunction( 'StartWorkSimulator', ); final stopWorkSimulator = dl.lookupFunction( 'StopWorkSimulator', ); final executeCallback = dl .lookupFunction), void Function(Pointer)>( 'ExecuteCallback', ); final class Work extends Opaque {} Future asyncSleep(int ms) { return new Future.delayed(Duration(milliseconds: ms)); }