-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ffi/isolate] Support passing/receiving Pointers to/from Isolates. #50457
Comments
I think the main reason we decided to disable this is to catch situations when users accidentally send a pointer to another isolate without realising that they need to do something special around lifetime. (e.g. if you send a pointer to some reference counted resource to another isolate you might need to increment reference count and install a finaliser on the receiving end, etc.). /cc @dcharkes |
Correct, this is why we decided that. I did actually make a prototype for supporting sending We could consider adding support for sending @modulovalue what is your native-memory/native-resource management strategy? |
I plan to manage reference counters on my own. i.e. An Isolate exiting would remove all its references at once, or an isolate could report atomic changes through for example the native finalizer provided by Dart_NewExternalUTF16String. (_Passing around Pointers to native memory intended to be used by external strings was my primary motivation for this issue. The second use case was to share thin wrappers over pointers to Wasmer objects between isolates. Some context around that can be found here dart-archive/wasm#97. _) |
@mkustermann in #50715 (comment) edit: sgtm |
Is this issue considered wontfix? I'd like to pass pointers to an isolate without the ceremony of covertly serializing pointer addresses. |
It's assumed that if the pointer hangs on to native memory which needs freeing / releasing / ... that an enclosing class refers to it and has a finalizer attached. Sending such objects with finalizers is disallowed. But we'll allow sending Someone just has to make a CL for it. @dcharkes ? |
This is actually my explicit usecase. My classes implement NativeFinalizers, and I'm keeping references to them from the main isolate. Is this disallowed because of the memory cloning aspect of isolates? I.e., when the isolate is done the copied objects get GC'd and then the finalizer is triggered, rendering the object held outside the isolate invalid? |
Yes, allowing a clone of a finalizable object would make things problematic: Should the finalizer run when all clones are dead, should it run multiple times / for every clone, does cloning a finalizable need to perform some action (e.g. increasing a refcount), ... |
Is there some generally accepted solution for making asynchronous FFI functions? I have potentially long running methods in my underlying libraries and don't want to block the UI on them. I figured isolates was an easy way to do that, but I guess not, due to the finalizer restrictions. |
Yes, the most simple way is to spawn an isolate and run a (possibly blocking) ffi call there. Is it possible for you to pass finalizable state via C memory (not dart objects) to the other isolate or make the isolate create this state on it's own? |
If you do more than 16 isolates, make sure to use what @mkustermann added recently to address: |
I figured it would come to this. It's not ideal, but it's probably the only real solution. Thanks for the help. |
What are the implications of this? Will the type signatures of |
No, the static types will all stay.
|
If For cases like that, the generated classes should probably have |
I also encountered this problem. I find a simple solution, but I can't say whether it may have other problems. void blockingFunc() async {
final argPtr = malloc<Char>();
final argPtrInt = argPtr.address;
await Isolate.run(() => _bindings.blocking_func(Pointer.fromAddress(argPtrInt));
malloc.free(argPtr);
} Can't pass |
I made an example of |
As mentioned above in #50457 (comment) we consider Users should be mindful that using FFI is stepping outside the safe sandbox. As a result one should be careful with how pointers are handled. If they represent a resource that needs freeing, a class implementing |
Consider the following example:
Running it throws the following error:
It looks like moving Pointers through isolates isn't supported.
One workaround is to read and pass the integer address itself, and to create a pointer manually from that address in the target isolate. However, this is highly inconvenient, as one has to architect his models around integer addresses and not Pointers if he wants to be able to send the models itself across isolates.
I intend to share native memory across isolates and it would be great for these use cases if this restriction could be lifted. cc: @mraleph
The text was updated successfully, but these errors were encountered: