Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a Perl 6 object through a Nativecall callback?

I'm working with the NativeCall interface.

The library is going to call my callback function a bunch of times.

That works fine. I can just declare my callback with the right signature, pass it in as &callback and the library calls the sub just fine.

It also has the capability to set a payload void *pointer to anything I want, and it will include that in the call to my callback function.

Can I hide a Perl Str, for example, in the payload and successfully round trip it?

sub set_userdata(Pointer) returns int32 is native { ... }

sub set_callback(&callback(Pointer $userdata --> int32)) returns int32 is native { ... }

sub callback(Pointer $userdata) returns int32 {
    my Str $mystring = ???
    ...
}

my Str $my-userdata-string;

set_userdata(???);
set_callback(&callback);

It seems like it could work with some incantation of binding, "is rw", nativecast() and/or .deref.

like image 575
Curt Tilmes Avatar asked Apr 12 '17 13:04

Curt Tilmes


2 Answers

You can only use a native representation in such a case (such as CStruct, CArray, and CPointer), or alternatively a Blob. You are also responsible for ensuring that you keep a reference to the thing you pass as userdata alive from Perl 6's perspective also, so the GC doesn't reclaim the memory that was passed to the C function.

Memory management is the reason you can't pass any old Perl 6 object off to a C function: there's no way for the GC to know whether the object is still reachable through some C data structure it can't introspect. In a VM like MoarVM objects are moved around in memory over time as part of the garbage collection process also, meaning that the C code could end up with an out-dated pointer.

An alternative strategy is not not pass a pointer at all, but instead pass an integer and use that to index into an array of objects. (That's how the libuv binding inside of MoarVM tracks down the VM-level callbacks, fwiw.)

like image 128
Jonathan Worthington Avatar answered Sep 30 '22 20:09

Jonathan Worthington


I got around this by just ignoring the userdata and making a new closure referencing the Perl object directly for every callback function. Since there is a new closure created every time I set the callback, I think this will leak memory over time.

like image 43
Curt Tilmes Avatar answered Sep 30 '22 21:09

Curt Tilmes