0.0
No release in over 3 years
Ruby gem for getting direct access to function pointers
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

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:

  1. Add direct-bind as a development dependency

  2. Use the built-in rake task to vendor the direct-bind sources into your own extension by adding to your Rakefile:

    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]
  3. 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!
    }
  4. 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
  5. git add the new direct-bind.h and direct-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.