Skip to content

julia functions as C callbacks #1096

@vtjnash

Description

@vtjnash

--- update ---
the original issue is pretty much covered by cfunction. the remaining issues are:

  • support closures
  • adding conversion wrapper in case of inexact matches

---- original text ---
To enable certain function calls to C code, it would be helpful to have a function callback API in Julia (this is partly inspired by the libuv interface, which ended up handling most of these issues by creating a tight coupling between julila function and types and libuv callbacks and types)

The two issues that I currently see would need to be handled are:

  1. Since pointers are leaving control of Julia, the garbage collector needs to know not to clean-up anything that may be used in the future (and notified when it can)
  2. Since C doesn't natively have type information, it requires some sort of reverse ccall interface

To handle 1, I think it may be safest to create a garbage collector allocation pool. Objects can be pushed to and popped from it from within Julia (using ref counting?). Then possibly add a default behavior that parameters to a ccall containing a Callback object are automatically saved until all callbacks are manually deleted. (since additional and previous calls to C functions may also hold onto object pointers, it may be useful to have this as a separately available function)

To handle 2, it will be necessary to indicate type information to the ccall. One possibility is to make a type that contains the information type Callback{ params <: Tuple } end and is passed to the ccall in the third argument tuple. A generic function name would then be passed in the parameters list. A second possibility is to make Callback a simple type that contains all of that information type Callback; params <: Tuple; f :: Function; end. A third (similar) possibility is to do the exact function lookup in Julia and require something like the value returned by getmethods and printed by whicht. In any case, I envision that ccall would JIT an intermediary function that converts from raw bits types to Julia types. This prompts the last possibility (and possibly my favorite) of having make_callback return a raw pointer to a newly JIT'd intermediary C function:

callback_fcn = make_callback(fcn::Function, arg_types::Tuple)
arg2 = "test"
cpreserve(arg2); cpreserve(fcn) # if args are not automatically preserved
ccall(:cfcn, Void, (Ptr, String), callback_fcn, arg2)
...
crelease(arg2) # if args are not automatically preserved
crelease(fcn) # if args are automatically preserved, arg2 won't be freed till after this point

A final question is whether pointer_to_array is the best way to grab a c array? Or is there some way to indicate this in the argument type?

Thoughts and alternatives? Am I missing any challenging callback argument types?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions