diff options
author | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-02-03 01:23:48 +0000 |
---|---|---|
committer | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-02-03 01:23:48 +0000 |
commit | b386fe21eca01e03a5ca447792354632e549c94e (patch) | |
tree | 30b480ee3ab580e28053d1ec3f31a5fd5285aa9c /ext/dl/closure.c | |
parent | b378bda47c3960acd983890efd01ac08794f6fd3 (diff) |
Wed Feb 3 10:12:09 2010 Aaron Patterson <[email protected]>
* 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
Diffstat (limited to 'ext/dl/closure.c')
-rw-r--r-- | ext/dl/closure.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/ext/dl/closure.c b/ext/dl/closure.c new file mode 100644 index 0000000000..a32b27ebc2 --- /dev/null +++ b/ext/dl/closure.c @@ -0,0 +1,228 @@ +/* -*- C -*- + * $Id$ + */ + +#include <ruby.h> +#include "dl.h" +#include <sys/mman.h> +#include <dl_conversions.h> + +VALUE rb_cDLClosure; + +typedef struct { + void * code; + ffi_closure *pcl; + ffi_cif * cif; + int argc; + ffi_type **argv; +} dl_closure; + +static void +dlclosure_free(void * ptr) +{ + dl_closure * cls = (dl_closure *)ptr; +#ifdef USE_NEW_CLOSURE_API + ffi_closure_free(cls->pcl); +#else + munmap(cls->pcl, sizeof(cls->pcl)); +#endif + xfree(cls->cif); + if(cls->argv) xfree(cls->argv); + xfree(cls); +} + +static size_t +dlclosure_memsize(const void * ptr) +{ + dl_closure * cls = (dl_closure *)ptr; + + size_t size = 0; + if(ptr) { + size += sizeof(*cls); + size += ffi_raw_size(cls->cif); + size += sizeof(*cls->argv); + size += sizeof(ffi_closure); + } + return size; +} + +const rb_data_type_t dlclosure_data_type = { + "dl/closure", + 0, dlclosure_free, dlclosure_memsize, +}; + +void +dlc_callback(ffi_cif *cif, void *resp, void **args, void *ctx) +{ + VALUE self = (VALUE)ctx; + VALUE rbargs = rb_iv_get(self, "@args"); + VALUE ctype = rb_iv_get(self, "@ctype"); + int argc = RARRAY_LEN(rbargs); + VALUE *params = xcalloc(argc, sizeof(VALUE *)); + + int i; + for(i = 0; i < argc; i++) { + int dl_type = NUM2INT(RARRAY_PTR(rbargs)[i]); + switch(dl_type) { + case DLTYPE_VOID: + argc = 0; + break; + case DLTYPE_INT: + params[i] = INT2NUM(*(int *)args[i]); + break; + case DLTYPE_VOIDP: + params[i] = rb_dlptr_new(*(void **)args[i], 0, NULL); + break; + case DLTYPE_LONG: + params[i] = LONG2NUM(*(long *)args[i]); + break; + case DLTYPE_CHAR: + params[i] = INT2NUM(*(char *)args[i]); + break; + case DLTYPE_DOUBLE: + params[i] = rb_float_new(*(double *)args[i]); + break; + case DLTYPE_FLOAT: + params[i] = rb_float_new(*(float *)args[i]); + break; +#if HAVE_LONG_LONG + case DLTYPE_LONG_LONG: + params[i] = rb_ull2inum(*(unsigned LONG_LONG *)args[i]); + break; +#endif + default: + rb_raise(rb_eRuntimeError, "closure args: %d", dl_type); + } + } + + VALUE ret = rb_funcall2(self, rb_intern("call"), argc, params); + + int dl_type = NUM2INT(ctype); + switch(dl_type) { + case DLTYPE_VOID: + break; + case DLTYPE_LONG: + *(long *)resp = NUM2LONG(ret); + break; + case DLTYPE_CHAR: + *(char *)resp = NUM2INT(ret); + break; + case DLTYPE_VOIDP: + *(void **)resp = NUM2PTR(ret); + break; + case DLTYPE_INT: + *(int *)resp = NUM2INT(ret); + break; + case DLTYPE_DOUBLE: + *(double *)resp = NUM2DBL(ret); + break; + case DLTYPE_FLOAT: + *(float *)resp = NUM2DBL(ret); + break; +#if HAVE_LONG_LONG + case DLTYPE_LONG_LONG: + *(unsigned LONG_LONG *)resp = rb_big2ull(ret); + break; +#endif + default: + rb_raise(rb_eRuntimeError, "closure retval: %d", dl_type); + } + xfree(params); +} + +static VALUE +rb_dlclosure_allocate(VALUE klass) +{ + dl_closure * closure; + + VALUE i = TypedData_Make_Struct(klass, dl_closure, + &dlclosure_data_type, closure); + +#ifdef USE_NEW_CLOSURE_API + closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code); +#else + closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + closure->cif = xmalloc(sizeof(ffi_cif)); + + return i; +} + +static VALUE +rb_dlclosure_init(int rbargc, VALUE argv[], VALUE self) +{ + VALUE ret; + VALUE args; + VALUE abi; + + dl_closure * cl; + ffi_cif * cif; + ffi_closure *pcl; + + if(2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi)) + abi = INT2NUM(FFI_DEFAULT_ABI); + + int i; + int argc = RARRAY_LEN(args); + + TypedData_Get_Struct(self, dl_closure, &dlclosure_data_type, cl); + + cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *)); + + for(i = 0; i < argc; i++) { + int dltype = NUM2INT(RARRAY_PTR(args)[i]); + cl->argv[i] = DL2FFI_TYPE(dltype); + } + cl->argv[argc] = NULL; + + rb_iv_set(self, "@ctype", ret); + rb_iv_set(self, "@args", args); + + cif = cl->cif; + pcl = cl->pcl; + + ffi_status result = ffi_prep_cif(cif, NUM2INT(abi), argc, + DL2FFI_TYPE(NUM2INT(ret)), + cl->argv); + + if(FFI_OK != result) + rb_raise(rb_eRuntimeError, "error prepping CIF %d", result); + +#ifdef USE_NEW_CLOSURE_API + result = ffi_prep_closure_loc(pcl, cif, dlc_callback, + (void *)self, cl->code); +#else + result = ffi_prep_closure(pcl, cif, dlc_callback, (void *)self); + cl->code = (void *)pcl; + mprotect(pcl, sizeof(pcl), PROT_READ | PROT_EXEC); +#endif + + if(FFI_OK != result) + rb_raise(rb_eRuntimeError, "error prepping closure %d", result); + + return self; +} + +static VALUE +rb_dlclosure_to_i(VALUE self) +{ + dl_closure * cl; + + TypedData_Get_Struct(self, dl_closure, &dlclosure_data_type, cl); + + void * code = cl->code; + + return PTR2NUM(code); +} + +void +Init_dlclosure(void) +{ + rb_cDLClosure = rb_define_class_under(rb_mDL, "Closure", rb_cObject); + rb_define_alloc_func(rb_cDLClosure, rb_dlclosure_allocate); + + rb_define_method(rb_cDLClosure, "initialize", rb_dlclosure_init, -1); + rb_define_method(rb_cDLClosure, "to_i", rb_dlclosure_to_i, 0); +} +/* vim: set noet sw=4 sts=4 */ |