direct-bind
A ruby gem for getting direct access to cfunc method function pointers.
In one sentence: it retrieves function pointers that got passed in to rb_define_method
.
E.g. consider this call:
VALUE my_method(VALUE self) { /* ... */ }
void define_function(VALUE klass) {
rb_define_method(klass, "my_method", my_method, 0);
}
direct-bind
allows you to retrieve the my_method
pointer again:
void call_function_directly(VALUE klass, VALUE instance) {
direct_bind_cfunc_result result = direct_bind_get_cfunc_with_arity(klass, rb_intern("my_method"), 0, true);
// At this point result.func == my_method, and you can call it without dispatching through the VM
result.func(instance);
}
Why? Its main use-case is on very low-level Ruby tools.
Often Ruby VM APIs are not exposed as public functions but we would like to call them without dispatching through the VM. direct-bind
enables such use-cases.
One example is finding out if a given thread is alive:
VALUE (*is_thread_alive)(VALUE thread);
is_thread_alive = direct_bind_get_cfunc_with_arity(rb_cThread, rb_intern("alive?"), 0, true).func;
is_thread_alive(rb_thread_current());
Quickest start
Looking for a realistic example? direct-bind
was integrated into gvl-tracing
in this commit which provides a full example and use-case on how to use it.
direct-bind
is intended to be vendored by other gems, not used directly. Here’s what you need to do to integrate direct-bind
into your project:
-
Add
direct-bind
as a development dependency -
Use the built-in rake task to vendor the
direct-bind
sources into your own extension by adding to yourRakefile
:require "direct_bind/rake" DirectBind::Rake::InstallTask.new("your_extension_name") # This should be the same as you set up in `Rake::ExtensionTask.new` # Extecute the install task by e.g. adding it before your compile step task default: [:"direct-bind:install", :compile]
-
Use
direct-bind
in your native extension:#include "direct-bind.h" // Example: Directly bind access to Thread#alive? static VALUE (*is_thread_alive)(VALUE thread); void Init_your_extension(void) { VALUE your_extension_module = rb_define_module("YourExtension"); direct_bind_initialize(your_extension_module, true); is_thread_alive = direct_bind_get_cfunc_with_arity(rb_cThread, rb_intern("alive?"), 0, true).func; // Function is ready to be called! }
-
Use the RSpec helper in your tests to make sure the vendoring is working correctly:
require "direct_bind/rspec_helper" # Add this test-case it "uses the correct direct-bind gem version" do DirectBind::RSpecHelper.expect_direct_bind_version_to_be_up_to_date_in(YourExtension) # Same module/class as used in `direct_bind_initialize` end
-
git add
the newdirect-bind.h
anddirect-bind.c
files that showed up in your extension folder
Installation
Install the gem and add to the application’s Gemfile
or gems.rb
file by executing:
$ bundle add direct-bind
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install direct-bind
Usage
Use require "direct-bind"
to load the gem.
Requirements
direct-bind
has been tested on Ruby 2.5+. It can probably run on older Rubies too, but I have no use-case for it. PRs to extend support for older Rubies (and what’s your use-case) are welcome :)
Installation and deployment
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org. To run specs, run bundle exec rake spec
.
To run all actions (build the extension, check linting, and run specs), run bundle exec rake
.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/ivoanjo/direct-bind. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
Code of Conduct
Everyone interacting in the direct-bind project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.