Re: Closure callbacks via dart:ffi?

271 views
Skip to first unread message

Daco Harkes 🔵

unread,
Apr 30, 2020, 4:42:21 AM4/30/20
to Steve Anton, Dart FFI
Hi Steve,

Nice to meet you! Yes, I'm the main dev on dart:ffi. Yeah, of course, I'm happy to answer any questions. :-)

A Map<int,Function> is indeed a good solution. It requires you to manage the lifetime of closures. Managing lifetime should be relatively easy if you know you'll call a closure exactly once, otherwise it's more tricky. (Note that any support that we add to dart:ffi for calling closures would also require explicit lifetime tracking, unless we add a C++&Dart combined GC like they did with V8&Browser DOM. So you can't really get around that.)

Unfortunately, bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) does not expose sending or receiving Closures (it does not use Dart_Handle but Dart_CObject* as message type, and that does not include closures).

Note: If you want to call back the closures asynchronously, you need to use Ports as the mechanism. Messages can be sent on any thread and get in the Dart event queue, while dart:ffi callbacks must be invoked on the Dart mutator thread. There are two ways to do this. #1 Dispatch in Dart based on a message from a port (sample), or #2 Send a message to Dart through native Ports and yield the main Dart thread to C to do the callbacks (sample).

Note 2: The Flutter embedder does not re-expose the dart_api symbols, so we use dynamic linking. Which can be seen in the samples as well.

Currently, I'm working on a feature that would simplify your use case: turning Object on the Dart-side of a FFI trampoline call into a Dart_Handle on the C side. This allows you to pass the closure to C through FFI directly without the Map<int,Function>. You can then use a Dart_PersistentHandle on the C side to manage the lifetime. And use sample#2 as described above to pass the closure back to Dart in a callback.

+Dart FFI for if other people have the same questions.

Kind regards,

On Wed, Apr 29, 2020 at 7:39 PM Steve Anton <steve...@google.com> wrote:
Hey Daco,

I've been playing around with dart:ffi the last few days with the goal of writing Dart <-> C++ bindings for a subset of WebRTC. I see you're the most active responder for dart:ffi issues on Github, so I hope you don't mind me shooting you a question individually :)

I see in this example you can generate C++ function pointers from static Dart functions and call them on the same thread as the Dart isolate. Curious if you have thought about design patterns for calling Dart closures from C++? For example, a relatively common use case would be to resolve a Future from C++, or add to a Stream.

The most straightforward solution I thought of so far is to have a global map in Dart which indexes from an integer to a closure, then pass that ID down to C++ and back up in the static function callback.

I suppose another idea is to use the Dart_Port to post a CObject. Not sure how that would interact with the event loop when called on the same thread as Dart.

Best,
Steve


--
Daco Harkes

Daco Harkes 🔵

unread,
May 1, 2020, 5:22:00 AM5/1/20
to Steve Anton, Dart FFI
Hi Steve,

I'm currently working on:
- Dart_Handles in ffi calls (CL in progress)
- Finalizers
- Passing structs by value

In general we track our issues on https://github.com/dart-lang/sdk/labels/library-ffi. That contains issues for the features we'd like to add. If you have any suggestions from your experience, please let us know.

Kind regards,

On Fri, May 1, 2020 at 3:23 AM Steve Anton <steve...@google.com> wrote:
Thanks Daco. I think for my use case Dart_PostCObject will be sufficient.

Exposing Dart_Handle to C sounds very interesting and should make it more ergonomic to use callbacks. Are there any other additions to ffi that are coming soon?


--
Daco Harkes
Reply all
Reply to author
Forward
0 new messages