123456789_123456789_123456789_123456789_123456789_

Class: Fiddle::Closure

Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: ext/fiddle/closure.c,
ext/fiddle/lib/fiddle/closure.rb

Overview

Description

An FFI closure wrapper, for handling callbacks.

Example

closure = Class.new(Fiddle::Closure) {
  def call
    10
  end
}.new(Fiddle::TYPE_INT, [])
   #=> #<#<Class:0x0000000150d308>:0x0000000150d240>
func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
   #=> #<Fiddle::Function:0x00000001516e58>
func.call
   #=> 10

Class Method Summary

Instance Attribute Summary

  • #args readonly

    arguments of the FFI closure.

  • #ctype readonly

    the C type of the return of the FFI closure.

Instance Method Summary

  • #to_i

    Returns the memory address for this closure.

Constructor Details

.new(ret, args, abi = Fiddle::DEFAULT)

Construct a new Closure object.

  • ret is the C type to be returned

  • #args is an Array of arguments, passed to the callback function

  • abi is the abi of the closure

If there is an error in preparing the ffi_cif or ffi_prep_closure, then a RuntimeError will be raised.

[ GitHub ]

  
# File 'ext/fiddle/closure.c', line 218

static VALUE
initialize(int rbargc, VALUE argv[], VALUE self)
{
    VALUE ret;
    VALUE args;
    VALUE abi;
    fiddle_closure * cl;
    ffi_cif * cif;
    ffi_closure *pcl;
    ffi_status result;
    int i, argc;

    if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
	abi = INT2NUM(FFI_DEFAULT_ABI);

    Check_Type(args, T_ARRAY);

    argc = RARRAY_LENINT(args);

    TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);

    cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));

    for (i = 0; i < argc; i++) {
        int type = NUM2INT(RARRAY_AREF(args, i));
        cl->argv[i] = INT2FFI_TYPE(type);
    }
    cl->argv[argc] = NULL;

    rb_iv_set(self, "@ctype", ret);
    rb_iv_set(self, "@args", args);

    cif = &cl->cif;
    pcl = cl->pcl;

    result = ffi_prep_cif(cif, NUM2INT(abi), argc,
                INT2FFI_TYPE(NUM2INT(ret)),
		cl->argv);

    if (FFI_OK != result)
	rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);

#if USE_FFI_CLOSURE_ALLOC
    result = ffi_prep_closure_loc(pcl, cif, callback,
		(void *)self, cl->code);
#else
    result = ffi_prep_closure(pcl, cif, callback, (void *)self);
    cl->code = (void *)pcl;
    i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
    if (i) {
	rb_sys_fail("mprotect");
    }
#endif

    if (FFI_OK != result)
	rb_raise(rb_eRuntimeError, "error prepping closure %d", result);

    return self;
}

Instance Attribute Details

#args (readonly)

arguments of the FFI closure

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/closure.rb', line 9

attr_reader :args

#ctype (readonly)

the C type of the return of the FFI closure

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/closure.rb', line 6

attr_reader :ctype

Instance Method Details

#to_i

Returns the memory address for this closure

[ GitHub ]

  
# File 'ext/fiddle/closure.c', line 278

static VALUE
to_i(VALUE self)
{
    fiddle_closure * cl;
    void *code;

    TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);

    code = cl->code;

    return PTR2NUM(code);
}