Skip to content
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

Calling a native function through a function pointer #404

Closed
bfoz opened this issue Jan 17, 2015 · 7 comments
Closed

Calling a native function through a function pointer #404

bfoz opened this issue Jan 17, 2015 · 7 comments

Comments

@bfoz
Copy link
Contributor

bfoz commented Jan 17, 2015

I'm working with an existing library that has methods that return pointers to structures full of pointers to functions. Using the documentation (thanks!) I've figured out how to model the pointers in the structures, but to do anything useful with the structures I need to be able to call the pointed-to-functions. So far, I haven't found the magic incantation in the docs, and my Google-fu is failing me.

I'm getting structs of the form...

typedef struct
{
    int (*func1)(...);
    int (*func2)(...);
    ...
} function_table;

struct my_struct
{
    function_table* vt;
};

How do I call func1, func2, etc?

If calling function pointers isn't already implemented, I'd be willing to take a stab at it if someone would be kind enough to point me in the right direction.

@tduehr
Copy link
Member

tduehr commented Jan 20, 2015

Are you looking to call that yourself or for the C library to call it?

Regardless of the use case there the underlying class for both the callbacks and functions is a pointer class.

Take a look at Callbacks and the struct callback spec. All of those should respond to #call.

Here's the relevant spec:

    module CallbackMember3
      extend FFI::Library
      ffi_lib TestLibrary::PATH
      class TestStruct < FFI::Struct
        layout \
          :add, callback([ :int, :int ], :int),
          :sub, callback([ :int, :int ], :int)
      end
      attach_function :struct_call_add_cb, [TestStruct, :int, :int], :int
      attach_function :struct_call_sub_cb, [TestStruct, :int, :int], :int
    end

    s = CallbackMember3::TestStruct.new
    add = Proc.new { |a,b| a+b}
    s[:add] = add
    fn = s[:add]
    expect(fn.respond_to?(:call)).to be true
    expect(fn.call(1, 2)).to eq(3)

The documentation for most of ffi needs a pretty good review.

@bfoz
Copy link
Contributor Author

bfoz commented Jan 21, 2015

I need to call it from my code. The library appears to be using structures full of pointers to approximate virtual functions, but using only C. Calling various factory methods yields said structures, and I need to call the provided "virtual methods" from Ruby.

Using your example, I think I need something like...

attach_function :factory_method, [], TestStruct

subclass = CallbackMember3.factory_method()
fn = subclass[:add]
fn.call(3,4)   # => call whatever method the pointer points to

@tduehr
Copy link
Member

tduehr commented Jan 21, 2015

That looks about right. There should be no need to park the function in a variable: subclass[:add].call(3,4) should work unless you need a null guard of some sort.

@bfoz
Copy link
Contributor Author

bfoz commented Jan 25, 2015

That did the trick, thanks.

The only remaining hangup came from using nested structures, which meant that I needed to use #ptr to reference the nested one...

class FunctionTable < FFI::Struct
    layout :function1, callback(...) 
end

class MyStruct < FFI::Struct
    layout :vt, FunctionTable.ptr     # <= This is the part that I forgot
end

my_struct = factory_method()
my_struct[:vt][:function1].call(...)     # It works!

Thanks for your help.

Is there a good place to add this to the documentation? I might as well make sure that no one else gets hung up on this.

@tduehr
Copy link
Member

tduehr commented Jan 26, 2015

I'd add it to the wiki. Possibly, to the Struct module's yardoc.

@tduehr tduehr closed this as completed Jan 26, 2015
@bfoz
Copy link
Contributor Author

bfoz commented Jan 27, 2015

Done and done.

@tduehr
Copy link
Member

tduehr commented Jan 27, 2015

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants