mirror of
https://github.com/ruby/ruby.git
synced 2025-09-19 10:33:58 +02:00
Wed Feb 3 10:12:09 2010 Aaron Patterson <tenderlove@ruby-lang.org>
* ext/dl/function.c: DL::Function now uses libffi * ext/dl/cfunc.c (rb_dl_set_last_error): set to non static so errors can be exposed. * ext/dl/closure.c: DL::Closure will now be used in place of ext/dl/callback/*. * ext/dl/dl.c: legacy callbacks removed in favor of libffi * ext/dl/dl_converions.(c,h): used for converting ruby types to FFI types. * ext/dl/callback/*: replaced by libffi callbacks. * ext/dl/lib/dl/callback.rb: Converting internal callbacks to use DL::Closure * ext/dl/lib/dl/closure.rb: Ruby parts of the new DL::Closure object * ext/dl/lib/dl/import.rb: More conversion to use DL::Closure object * ext/dl/lib/dl/value.rb (ruby2ffi): adding private method for DL::CPtr to ffi value conversion. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26545 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b378bda47c
commit
b386fe21ec
21 changed files with 802 additions and 378 deletions
233
ext/dl/function.c
Normal file
233
ext/dl/function.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/* -*- C -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <errno.h>
|
||||
#include "dl.h"
|
||||
#include <dl_conversions.h>
|
||||
|
||||
VALUE rb_cDLFunction;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char uchar; // ffi_type_uchar
|
||||
signed char schar; // ffi_type_schar
|
||||
unsigned short ushort; // ffi_type_sshort
|
||||
signed short sshort; // ffi_type_ushort
|
||||
unsigned int uint; // ffi_type_uint
|
||||
signed int sint; // ffi_type_sint
|
||||
unsigned long ulong; // ffi_type_ulong
|
||||
signed long slong; // ffi_type_slong
|
||||
float ffloat; // ffi_type_float
|
||||
double ddouble; // ffi_type_double
|
||||
#if HAVE_LONG_LONG
|
||||
unsigned LONG_LONG long_long; // ffi_type_uint64
|
||||
#endif
|
||||
void * pointer; // ffi_type_pointer
|
||||
} dl_generic;
|
||||
|
||||
static void
|
||||
dlfunction_free(ffi_cif *ptr)
|
||||
{
|
||||
if(ptr->arg_types) xfree(ptr->arg_types);
|
||||
xfree(ptr);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dlfunction_memsize(ffi_cif *ptr)
|
||||
{
|
||||
size_t size = 0;
|
||||
if(ptr) {
|
||||
size += sizeof(*ptr);
|
||||
size += ffi_raw_size(ptr);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
const rb_data_type_t dlfunction_data_type = {
|
||||
"dl/function",
|
||||
0, dlfunction_free, dlfunction_memsize,
|
||||
};
|
||||
|
||||
static VALUE
|
||||
rb_dlfunc_allocate(VALUE klass)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
|
||||
return TypedData_Make_Struct(klass, ffi_cif, &dlfunction_data_type, cif);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlfunction_native_init(VALUE self, VALUE args, VALUE ret_type, VALUE abi)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
ffi_type **arg_types;
|
||||
|
||||
TypedData_Get_Struct(self, ffi_cif, &dlfunction_data_type, cif);
|
||||
|
||||
arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *));
|
||||
|
||||
int i;
|
||||
for(i = 0; i < RARRAY_LEN(args); i++) {
|
||||
int type = NUM2INT(RARRAY_PTR(args)[i]);
|
||||
arg_types[i] = DL2FFI_TYPE(type);
|
||||
}
|
||||
arg_types[RARRAY_LEN(args)] = NULL;
|
||||
|
||||
ffi_status result = ffi_prep_cif(
|
||||
cif,
|
||||
NUM2INT(abi),
|
||||
RARRAY_LEN(args),
|
||||
DL2FFI_TYPE(NUM2INT(ret_type)),
|
||||
arg_types);
|
||||
|
||||
if(result)
|
||||
rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
dl2generic(int dl_type, VALUE src, dl_generic * dst)
|
||||
{
|
||||
int signed_p = 1;
|
||||
|
||||
if(dl_type < 0) {
|
||||
dl_type = -1 * dl_type;
|
||||
signed_p = 0;
|
||||
}
|
||||
|
||||
switch(dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
break;
|
||||
case DLTYPE_VOIDP:
|
||||
dst->pointer = NUM2PTR(rb_Integer(src));
|
||||
break;
|
||||
case DLTYPE_CHAR:
|
||||
case DLTYPE_SHORT:
|
||||
case DLTYPE_INT:
|
||||
dst->sint = NUM2INT(src);
|
||||
break;
|
||||
case DLTYPE_LONG:
|
||||
if(signed_p)
|
||||
dst->slong = NUM2LONG(src);
|
||||
else
|
||||
dst->ulong = NUM2LONG(src);
|
||||
break;
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
dst->long_long = rb_big2ull(src);
|
||||
break;
|
||||
#endif
|
||||
case DLTYPE_FLOAT:
|
||||
dst->ffloat = NUM2DBL(src);
|
||||
break;
|
||||
case DLTYPE_DOUBLE:
|
||||
dst->ddouble = NUM2DBL(src);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "unknown type %d", dl_type);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
unwrap_ffi(VALUE rettype, dl_generic retval)
|
||||
{
|
||||
int signed_p = 1;
|
||||
int dl_type = NUM2INT(rettype);
|
||||
|
||||
if(dl_type < 0) {
|
||||
dl_type = -1 * dl_type;
|
||||
signed_p = 0;
|
||||
}
|
||||
|
||||
switch(dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
return Qnil;
|
||||
case DLTYPE_VOIDP:
|
||||
return rb_dlptr_new((void *)retval.pointer, 0, NULL);
|
||||
case DLTYPE_CHAR:
|
||||
case DLTYPE_SHORT:
|
||||
case DLTYPE_INT:
|
||||
return INT2NUM(retval.sint);
|
||||
case DLTYPE_LONG:
|
||||
if(signed_p) return LONG2NUM(retval.slong);
|
||||
return LONG2NUM(retval.ulong);
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
return rb_ll2inum(retval.long_long);
|
||||
break;
|
||||
#endif
|
||||
case DLTYPE_FLOAT:
|
||||
return rb_float_new(retval.ffloat);
|
||||
case DLTYPE_DOUBLE:
|
||||
return rb_float_new(retval.ddouble);
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "unknown type %d", dl_type);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlfunction_call(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
dl_generic retval;
|
||||
dl_generic *generic_args;
|
||||
void **values;
|
||||
void * fun_ptr;
|
||||
|
||||
TypedData_Get_Struct(self, ffi_cif, &dlfunction_data_type, cif);
|
||||
|
||||
values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
|
||||
generic_args = xcalloc((size_t)argc, (size_t)sizeof(dl_generic));
|
||||
|
||||
VALUE cfunc = rb_iv_get(self, "@cfunc");
|
||||
VALUE types = rb_iv_get(self, "@args");
|
||||
|
||||
int i;
|
||||
for(i = 0; i < argc; i++) {
|
||||
VALUE dl_type = RARRAY_PTR(types)[i];
|
||||
VALUE src = rb_funcall(self,
|
||||
rb_intern("ruby2ffi"),
|
||||
2,
|
||||
argv[i],
|
||||
dl_type
|
||||
);
|
||||
|
||||
dl2generic(NUM2INT(dl_type), src, &generic_args[i]);
|
||||
values[i] = (void *)&generic_args[i];
|
||||
}
|
||||
values[argc] = NULL;
|
||||
|
||||
ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
|
||||
|
||||
rb_dl_set_last_error(self, INT2NUM(errno));
|
||||
#if defined(HAVE_WINDOWS_H)
|
||||
rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
|
||||
#endif
|
||||
|
||||
xfree(values);
|
||||
xfree(generic_args);
|
||||
|
||||
return unwrap_ffi(rb_funcall(cfunc, rb_intern("ctype"), 0), retval);
|
||||
}
|
||||
|
||||
void
|
||||
Init_dlfunction(void)
|
||||
{
|
||||
rb_cDLFunction = rb_define_class_under(rb_mDL, "Function", rb_cObject);
|
||||
|
||||
rb_define_const(rb_cDLFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
|
||||
|
||||
#ifdef FFI_STDCALL
|
||||
rb_define_const(rb_cDLFunction, "STDCALL", INT2NUM(FFI_STDCALL));
|
||||
#endif
|
||||
|
||||
rb_define_alloc_func(rb_cDLFunction, rb_dlfunc_allocate);
|
||||
|
||||
rb_define_private_method(rb_cDLFunction, "native_call", rb_dlfunction_call, -1);
|
||||
|
||||
rb_define_private_method(rb_cDLFunction, "native_init", rb_dlfunction_native_init, 3);
|
||||
}
|
||||
/* vim: set noet sw=4 sts=4 */
|
Loading…
Add table
Add a link
Reference in a new issue