From 59e4e93ef7b6b7f1536e3c56374cc6b8d74b5d28 Mon Sep 17 00:00:00 2001 From: naruse Date: Thu, 25 Feb 2010 22:49:20 +0000 Subject: * ext/dl: revert dl with libffi because it can't run on mswin now. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26764 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/dl/callback/depend | 15 +++ ext/dl/callback/extconf.rb | 14 +++ ext/dl/callback/mkcallback.rb | 238 +++++++++++++++++++++++++++++++++++++++ ext/dl/cfunc.c | 39 +++---- ext/dl/closure.c | 230 -------------------------------------- ext/dl/cptr.c | 4 +- ext/dl/depend | 6 - ext/dl/dl.c | 17 ++- ext/dl/dl.h | 12 -- ext/dl/dl_conversions.c | 40 ------- ext/dl/dl_conversions.h | 10 -- ext/dl/extconf.rb | 22 ---- ext/dl/lib/dl/callback.rb | 51 ++++++--- ext/dl/lib/dl/closure.rb | 19 ---- ext/dl/lib/dl/func.rb | 64 +++++++---- ext/dl/lib/dl/import.rb | 9 +- ext/dl/lib/dl/value.rb | 11 +- ext/dl/method.c | 251 ------------------------------------------ 18 files changed, 390 insertions(+), 662 deletions(-) create mode 100644 ext/dl/callback/depend create mode 100644 ext/dl/callback/extconf.rb create mode 100644 ext/dl/callback/mkcallback.rb delete mode 100644 ext/dl/closure.c delete mode 100644 ext/dl/dl_conversions.c delete mode 100644 ext/dl/dl_conversions.h delete mode 100644 ext/dl/lib/dl/closure.rb delete mode 100644 ext/dl/method.c (limited to 'ext') diff --git a/ext/dl/callback/depend b/ext/dl/callback/depend new file mode 100644 index 0000000000..7a1dc1ee62 --- /dev/null +++ b/ext/dl/callback/depend @@ -0,0 +1,15 @@ +src: callback.c \ + callback-0.c callback-1.c callback-2.c \ + callback-3.c callback-4.c callback-5.c \ + callback-6.c callback-7.c callback-8.c + +$(OBJS): $(hdrdir)/ruby.h + +callback-0.c callback-1.c callback-2.c \ +callback-3.c callback-4.c callback-5.c \ +callback-6.c callback-7.c callback-8.c \ + : callback.c + +callback.c: $(srcdir)/mkcallback.rb $(srcdir)/../dl.h + @echo "generating callback.c" + @$(RUBY) $(srcdir)/mkcallback.rb -output=callback $(srcdir)/../dl.h diff --git a/ext/dl/callback/extconf.rb b/ext/dl/callback/extconf.rb new file mode 100644 index 0000000000..6c3387670d --- /dev/null +++ b/ext/dl/callback/extconf.rb @@ -0,0 +1,14 @@ +require 'mkmf' + +if compiled?("dl") + callbacks = (0..8).map{|i| "callback-#{i}"}.unshift("callback") + callback_srcs = callbacks.map{|basename| "#{basename}.c"} + callback_objs = callbacks.map{|basename| "#{basename}.o"} + + $distcleanfiles << '$(SRCS)' + $srcs = callback_srcs + $objs = callback_objs + $INCFLAGS << " -I$(srcdir)/.." + + create_makefile("dl/callback") +end diff --git a/ext/dl/callback/mkcallback.rb b/ext/dl/callback/mkcallback.rb new file mode 100644 index 0000000000..d2f9e3f2e1 --- /dev/null +++ b/ext/dl/callback/mkcallback.rb @@ -0,0 +1,238 @@ +#!ruby -s +$output ||= "callback" +$out = open("#{$output}.c", "w") + +$dl_h = ARGV[0] || "dl.h" + +# import DLSTACK_SIZE, DLSTACK_ARGS and so on +File.open($dl_h){|f| + pre = "" + f.each{|line| + line.chop! + if( line[-1] == ?\\ ) + line.chop! + line.concat(" ") + pre += line + next + end + if( pre.size > 0 ) + line = pre + line + pre = "" + end + case line + when /#define\s+DLSTACK_SIZE\s+\(?(\d+)\)?/ + DLSTACK_SIZE = $1.to_i + when /#define\s+DLSTACK_ARGS\s+(.+)/ + DLSTACK_ARGS = $1.to_i + when /#define\s+DLTYPE_([A-Z_]+)\s+\(?(\d+)\)?/ + eval("#{$1} = #{$2}") + when /#define\s+MAX_DLTYPE\s+\(?(\d+)\)?/ + MAX_DLTYPE = $1.to_i + when /#define\s+MAX_CALLBACK\s+\(?(\d+)\)?/ + MAX_CALLBACK = $1.to_i + end + } +} + +CDECL = "cdecl" +STDCALL = "stdcall" + +CALLTYPES = [CDECL, STDCALL] + +DLTYPE = { + VOID => { + :name => 'void', + :type => 'void', + :conv => nil, + }, + CHAR => { + :name => 'char', + :type => 'char', + :conv => 'NUM2CHR(%s)' + }, + SHORT => { + :name => 'short', + :type => 'short', + :conv => 'NUM2INT(%s)', + }, + INT => { + :name => 'int', + :type => 'int', + :conv => 'NUM2INT(%s)', + }, + LONG => { + :name => 'long', + :type => 'long', + :conv => 'NUM2LONG(%s)', + }, + LONG_LONG => { + :name => 'long_long', + :type => 'LONG_LONG', + :conv => 'NUM2LL(%s)', + }, + FLOAT => { + :name => 'float', + :type => 'float', + :conv => '(float)RFLOAT_VALUE(%s)', + }, + DOUBLE => { + :name => 'double', + :type => 'double', + :conv => 'RFLOAT_VALUE(%s)', + }, + VOIDP => { + :name => 'ptr', + :type => 'void *', + :conv => 'NUM2PTR(%s)', + }, +} + + +def func_name(ty, argc, n, calltype) + "rb_dl_callback_#{DLTYPE[ty][:name]}_#{argc}_#{n}_#{calltype}" +end + +$out << (< 0 ? ", args[#{argc}]" : ""}; +#{ + (0...argc).collect{|i| + " args[%d] = LONG2NUM(stack%d);" % [i,i] + }.join("\n") +} + cb = rb_ary_entry(rb_ary_entry(#{proc_entry}, #{ty}), #{(n * DLSTACK_SIZE) + argc}); + ret = rb_funcall2(cb, rb_dl_cb_call, #{argc}, #{argc > 0 ? 'args' : 'NULL'}); + return #{DLTYPE[ty][:conv] ? DLTYPE[ty][:conv] % "ret" : ""}; +} +#{calltype == STDCALL ? "#endif\n" : ""} + EOS +end + +def gen_push_proc_ary(ty, aryname) + sprintf(" rb_ary_push(#{aryname}, rb_ary_new3(%d,%s));", + MAX_CALLBACK * DLSTACK_SIZE, + (0...MAX_CALLBACK).collect{ + (0...DLSTACK_SIZE).collect{ "Qnil" }.join(",") + }.join(",")) +end + +def gen_push_addr_ary(ty, aryname, calltype) + sprintf(" rb_ary_push(#{aryname}, rb_ary_new3(%d,%s));", + MAX_CALLBACK * DLSTACK_SIZE, + (0...MAX_CALLBACK).collect{|i| + (0...DLSTACK_SIZE).collect{|argc| + "PTR2NUM(%s)" % func_name(ty,argc,i,calltype) + }.join(",") + }.join(",")) +end + +def gen_callback_file(ty) + filename = "#{$output}-#{ty}.c" + initname = "rb_dl_init_callbacks_#{ty}" + body = <<-EOS +#include "dl.h" + +extern VALUE rb_DLCdeclCallbackAddrs, rb_DLCdeclCallbackProcs; +#ifdef FUNC_STDCALL +extern VALUE rb_DLStdcallCallbackAddrs, rb_DLStdcallCallbackProcs; +#endif +extern ID rb_dl_cb_call; + EOS + yield body + body << <<-EOS +void +#{initname}() +{ +#{gen_push_proc_ary(ty, "rb_DLCdeclCallbackProcs")} +#{gen_push_addr_ary(ty, "rb_DLCdeclCallbackAddrs", CDECL)} +#ifdef FUNC_STDCALL +#{gen_push_proc_ary(ty, "rb_DLStdcallCallbackProcs")} +#{gen_push_addr_ary(ty, "rb_DLStdcallCallbackAddrs", STDCALL)} +#endif +} + EOS + [filename, initname, body] +end + +callbacks = [] +for ty in 0...MAX_DLTYPE + filename, initname, body = gen_callback_file(ty) {|f| + foreach_proc_entry do |calltype, proc_entry| + for argc in 0...DLSTACK_SIZE + for n in 0...MAX_CALLBACK + f << gencallback(ty, calltype, proc_entry, argc, n) + end + end + end + } + $out << "void #{initname}();\n" + callbacks << [filename, body] +end + +$out << (<name ) xfree(data->name); data->ptr = saddr; @@ -284,11 +284,11 @@ rb_dlcfunc_inspect(VALUE self) { VALUE val; char *str; - size_t str_size; + int str_size; struct cfunc_data *cfunc; - + TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); - + str_size = (cfunc->name ? strlen(cfunc->name) : 0) + 100; str = ruby_xmalloc(str_size); snprintf(str, str_size - 1, @@ -339,31 +339,22 @@ rb_dlcfunc_call(VALUE self, VALUE ary) memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE); Check_Type(ary, T_ARRAY); - + TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); if( cfunc->ptr == 0 ){ rb_raise(rb_eDLError, "can't call null-function"); return Qnil; } - - if( RARRAY_LEN(ary) >= DLSTACK_SIZE ){ - rb_raise(rb_eDLError, "too many arguments (stack overflow)"); - } + for( i = 0; i < RARRAY_LEN(ary); i++ ){ - unsigned long rb_big2ulong_pack(VALUE x); - VALUE arg = RARRAY_PTR(ary)[i]; - - rb_check_safe_obj(arg); - if (FIXNUM_P(arg)) { - stack[i] = FIX2LONG(arg); - } - else { - Check_Type(arg, T_BIGNUM); - stack[i] = rb_big2ulong_pack(arg); + if( i >= DLSTACK_SIZE ){ + rb_raise(rb_eDLError, "too many arguments (stack overflow)"); } + rb_check_safe_obj(RARRAY_PTR(ary)[i]); + stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]); } - + /* calltype == CFUNC_CDECL */ if( cfunc->calltype == CFUNC_CDECL #ifndef FUNC_STDCALL diff --git a/ext/dl/closure.c b/ext/dl/closure.c deleted file mode 100644 index a2e0b05bb4..0000000000 --- a/ext/dl/closure.c +++ /dev/null @@ -1,230 +0,0 @@ -/* -*- C -*- - * $Id$ - */ - -#include -#include "dl.h" -#include -#include - -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_LENINT(rbargs); - VALUE *params = xcalloc(argc, sizeof(VALUE *)); - VALUE ret; - int i, dl_type; - - for (i = 0; i < argc; i++) { - 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); - } - } - - ret = rb_funcall2(self, rb_intern("call"), argc, params); - - 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 = (float)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; - ffi_status result; - int i, argc; - - if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi)) - abi = INT2NUM(FFI_DEFAULT_ABI); - - argc = RARRAY_LENINT(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; - - 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; - void *code; - - TypedData_Get_Struct(self, dl_closure, &dlclosure_data_type, cl); - - 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 */ diff --git a/ext/dl/cptr.c b/ext/dl/cptr.c index 75848f8358..11ecf6f81d 100644 --- a/ext/dl/cptr.c +++ b/ext/dl/cptr.c @@ -104,7 +104,7 @@ rb_dlptr2cptr(VALUE val) else{ rb_raise(rb_eTypeError, "DL::PtrData was expected"); } - + return ptr; } @@ -186,7 +186,7 @@ static VALUE rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) { VALUE size, sym, obj; - long s; + int s; freefunc_t f; switch (rb_scan_args(argc, argv, "11", &size, &sym)) { diff --git a/ext/dl/depend b/ext/dl/depend index b6bb5a8b57..992c17c1b8 100644 --- a/ext/dl/depend +++ b/ext/dl/depend @@ -1,13 +1,7 @@ cfunc.o: cfunc.c dl.h $(hdrdir)/ruby.h -closure.o: closure.c dl.h dl_conversions.h $(hdrdir)/ruby.h - cptr.o: cptr.c dl.h $(hdrdir)/ruby.h $(hdrdir)/io.h handle.o: handle.c dl.h $(hdrdir)/ruby.h -method.o: method.c dl.h dl_conversions.h $(hdrdir)/ruby.h - dl.o: dl.c dl.h $(hdrdir)/ruby.h $(hdrdir)/io.h - -dl_conversions.o: dl_conversions.c dl_conversions.h diff --git a/ext/dl/dl.c b/ext/dl/dl.c index 8f8212015b..9635794883 100644 --- a/ext/dl/dl.c +++ b/ext/dl/dl.c @@ -77,6 +77,19 @@ rb_dl_value2ptr(VALUE self, VALUE val) return PTR2NUM((void*)val); } +static void +rb_dl_init_callbacks(VALUE dl) +{ + static const char cb[] = "dl/callback.so"; + + rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb); + rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb); +#ifdef FUNC_STDCALL + rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb); + rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb); +#endif +} + void Init_dl(void) { @@ -94,6 +107,8 @@ Init_dl(void) rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK)); rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE)); + rb_dl_init_callbacks(rb_mDL); + rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL)); rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY)); rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW)); @@ -147,6 +162,4 @@ Init_dl(void) Init_dlhandle(); Init_dlcfunc(); Init_dlptr(); - Init_dlfunction(); - Init_dlclosure(); } diff --git a/ext/dl/dl.h b/ext/dl/dl.h index 81c8ee3bd9..d06cad4e6b 100644 --- a/ext/dl/dl.h +++ b/ext/dl/dl.h @@ -3,12 +3,6 @@ #include -#ifdef USE_HEADER_HACKS -#include -#else -#include -#endif - #if !defined(FUNC_CDECL) # define FUNC_CDECL(x) x #endif @@ -136,7 +130,6 @@ extern VALUE rb_mDL; extern VALUE rb_cDLHandle; -extern VALUE rb_cDLCPtr; extern VALUE rb_cDLSymbol; extern VALUE rb_eDLError; extern VALUE rb_eDLTypeError; @@ -228,9 +221,4 @@ VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func); VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func); VALUE rb_dlptr_malloc(long size, freefunc_t func); -VALUE rb_dl_set_last_error(VALUE self, VALUE val); -#if defined(HAVE_WINDOWS_H) -VALUE rb_dl_set_win32_last_error(VALUE self, VALUE val); -#endif - #endif diff --git a/ext/dl/dl_conversions.c b/ext/dl/dl_conversions.c deleted file mode 100644 index 1331006507..0000000000 --- a/ext/dl/dl_conversions.c +++ /dev/null @@ -1,40 +0,0 @@ -#include - -ffi_type * -rb_dl_type_to_ffi_type(int dl_type) -{ - int signed_p = 1; - - if (dl_type < 0) { - dl_type = -1 * dl_type; - signed_p = 0; - } - -#define rb_ffi_type_of(t) (signed_p ? &ffi_type_s##t : &ffi_type_u##t) - - switch (dl_type) { - case DLTYPE_VOID: - return &ffi_type_void; - case DLTYPE_VOIDP: - return &ffi_type_pointer; - case DLTYPE_CHAR: - return rb_ffi_type_of(char); - case DLTYPE_SHORT: - return rb_ffi_type_of(short); - case DLTYPE_INT: - return rb_ffi_type_of(int); - case DLTYPE_LONG: - return rb_ffi_type_of(long); -#if HAVE_LONG_LONG - case DLTYPE_LONG_LONG: - return rb_ffi_type_of(int64); -#endif - case DLTYPE_FLOAT: - return &ffi_type_float; - case DLTYPE_DOUBLE: - return &ffi_type_double; - default: - rb_raise(rb_eRuntimeError, "unknown type %d", dl_type); - } - return &ffi_type_pointer; -} diff --git a/ext/dl/dl_conversions.h b/ext/dl/dl_conversions.h deleted file mode 100644 index 13c904733d..0000000000 --- a/ext/dl/dl_conversions.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef DL_CONVERSIONS -#define DL_CONVERSIONS - -#include - -#define DL2FFI_TYPE(a) rb_dl_type_to_ffi_type(a) - -ffi_type * rb_dl_type_to_ffi_type(int dl_type); - -#endif diff --git a/ext/dl/extconf.rb b/ext/dl/extconf.rb index e2b7af6410..8317ac35ad 100644 --- a/ext/dl/extconf.rb +++ b/ext/dl/extconf.rb @@ -8,30 +8,8 @@ $INSTALLFILES = [ ["dl.h", "$(HDRDIR)"], ] -if pkg_config("libffi") - # libffi closure api must be switched depending on the version - if system("pkg-config --atleast-version=3.0.9 libffi") - $defs.push(format('-DUSE_NEW_CLOSURE_API')) - end -else - dir_config('ffi', '/usr/include', '/usr/lib') -end - -unless have_header('ffi.h') - if have_header('ffi/ffi.h') - $defs.push(format('-DUSE_HEADER_HACKS')) - else - abort "ffi is missing" - end -end - -unless have_library('ffi') - abort "ffi is missing" -end - check = true if( have_header("dlfcn.h") ) - have_library("dl") check &&= have_func("dlopen") check &&= have_func("dlclose") diff --git a/ext/dl/lib/dl/callback.rb b/ext/dl/lib/dl/callback.rb index 53da888d9d..c8daaf6322 100644 --- a/ext/dl/lib/dl/callback.rb +++ b/ext/dl/lib/dl/callback.rb @@ -1,21 +1,26 @@ require 'dl' -require 'dl/closure' require 'thread' module DL SEM = Mutex.new - CdeclCallbackProcs = {} - CdeclCallbackAddrs = {} - - def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = DL::Function::DEFAULT, &cbp) + def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp) if( argc < 0 ) raise(ArgumentError, "arity should not be less than 0.") end - - closure = DL::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp) - proc_entry[closure.to_i] = closure - closure.to_i + addr = nil + SEM.synchronize{ + ary = proc_entry[ty] + (0...MAX_CALLBACK).each{|n| + idx = (n * DLSTACK_SIZE) + argc + if( ary[idx].nil? ) + ary[idx] = cbp + addr = addr_entry[ty][idx] + break + end + } + } + addr end def set_cdecl_callback(ty, argc, &cbp) @@ -23,14 +28,32 @@ module DL end def set_stdcall_callback(ty, argc, &cbp) - set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, DL::Function::STDCALL, &cbp) + set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp) end def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil) - addr = addr.to_i - return false unless proc_entry.key?(addr) - proc_entry.delete(addr) - true + index = nil + if( ctype ) + addr_entry[ctype].each_with_index{|xaddr, idx| + if( xaddr == addr ) + index = idx + end + } + else + addr_entry.each{|ty,entry| + entry.each_with_index{|xaddr, idx| + if( xaddr == addr ) + index = idx + end + } + } + end + if( index and proc_entry[ctype][index] ) + proc_entry[ctype][index] = nil + return true + else + return false + end end def remove_cdecl_callback(addr, ctype = nil) diff --git a/ext/dl/lib/dl/closure.rb b/ext/dl/lib/dl/closure.rb deleted file mode 100644 index eca941dfbc..0000000000 --- a/ext/dl/lib/dl/closure.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'dl' - -module DL - class Closure - attr_reader :ctype - attr_reader :args - - class BlockCaller < DL::Closure - def initialize ctype, args, abi = DL::Function::DEFAULT, &block - super(ctype, args, abi) - @block = block - end - - def call *args - @block.call(*args) - end - end - end -end diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb index c5a2dda355..7a8b62e325 100644 --- a/ext/dl/lib/dl/func.rb +++ b/ext/dl/lib/dl/func.rb @@ -1,26 +1,26 @@ require 'dl' -require 'dl/closure' require 'dl/callback' require 'dl/stack' require 'dl/value' require 'thread' module DL - class Function < DL::Method + class Function include DL include ValueUtil - def initialize cfunc, argtypes, abi = DEFAULT, &block - if block_given? - @cfunc = Class.new(DL::Closure) { - define_method(:call, block) - }.new(cfunc.ctype, argtypes) + def initialize(cfunc, argtypes, &proc) + @cfunc = cfunc + @stack = Stack.new(argtypes.collect{|ty| ty.abs}) + if( @cfunc.ctype < 0 ) + @cfunc.ctype = @cfunc.ctype.abs + @unsigned = true else - @cfunc = cfunc + @unsigned = false + end + if( proc ) + bind(&proc) end - - @args = argtypes - super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi) end def to_i() @@ -32,10 +32,11 @@ module DL end def call(*args, &block) - if block_given? - args.find { |a| DL::Function === a }.bind_at_call(&block) - end - super + funcs = [] + args = wrap_args(args, @stack.types, funcs, &block) + r = @cfunc.call(@stack.pack(args)) + funcs.each{|f| f.unbind_at_call()} + return wrap_result(r) end def wrap_result(r) @@ -51,16 +52,33 @@ module DL end def bind(&block) - @cfunc = Class.new(DL::Closure) { - def initialize ctype, args, block - super(ctype, args) - @block = block + if( !block ) + raise(RuntimeError, "block must be given.") + end + if( @cfunc.ptr == 0 ) + cb = Proc.new{|*args| + ary = @stack.unpack(args) + @stack.types.each_with_index{|ty, idx| + case ty + when TYPE_VOIDP + ary[idx] = CPtr.new(ary[idx]) + end + } + r = block.call(*ary) + wrap_arg(r, @cfunc.ctype, []) + } + case @cfunc.calltype + when :cdecl + @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb) + when :stdcall + @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb) + else + raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}") end - - def call *args - @block.call(*args) + if( @cfunc.ptr == 0 ) + raise(RuntimeException, "can't bind C function.") end - }.new(@cfunc.ctype, @args, block) + end end def unbind() diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb index 4c101d0f5c..199354c18e 100644 --- a/ext/dl/lib/dl/import.rb +++ b/ext/dl/lib/dl/import.rb @@ -1,5 +1,4 @@ require 'dl' -require 'dl/closure' require 'dl/func.rb' require 'dl/struct.rb' require 'dl/cparser.rb' @@ -212,11 +211,9 @@ module DL end def bind_function(name, ctype, argtype, call_type = nil, &block) - closure = Class.new(DL::Closure) { - define_method(:call, block) - }.new(ctype, argtype) - - Function.new(closure, argtype) + f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype) + f.bind(&block) + f end def create_temp_function(name, ctype, argtype, call_type = nil) diff --git a/ext/dl/lib/dl/value.rb b/ext/dl/lib/dl/value.rb index cc6da6a7fb..56dfcefa32 100644 --- a/ext/dl/lib/dl/value.rb +++ b/ext/dl/lib/dl/value.rb @@ -36,7 +36,16 @@ module DL end end - def wrap_arg(arg, ty, funcs = [], &block) + def wrap_args(args, tys, funcs, &block) + result = [] + tys ||= [] + args.each_with_index{|arg, idx| + result.push(wrap_arg(arg, tys[idx], funcs, &block)) + } + result + end + + def wrap_arg(arg, ty, funcs, &block) funcs ||= [] case arg when nil diff --git a/ext/dl/method.c b/ext/dl/method.c deleted file mode 100644 index 1bd0fa8c3e..0000000000 --- a/ext/dl/method.c +++ /dev/null @@ -1,251 +0,0 @@ -/* -*- C -*- - * $Id$ - */ - -#include -#include -#include "dl.h" -#include - -VALUE rb_cDLMethod; - -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(void *p) -{ - ffi_cif *ptr = p; - if (ptr->arg_types) xfree(ptr->arg_types); - xfree(ptr); -} - -static size_t -dlfunction_memsize(const void *p) -{ - /* const */ffi_cif *ptr = (ffi_cif *)p; - 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/method", - 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_initialize(int argc, VALUE argv[], VALUE self) -{ - ffi_cif * cif; - ffi_type **arg_types; - ffi_status result; - VALUE ptr, args, ret_type, abi; - int i; - - rb_scan_args(argc, argv, "31", &ptr, &args, &ret_type, &abi); - if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI); - - rb_iv_set(self, "@ptr", ptr); - rb_iv_set(self, "@args", args); - rb_iv_set(self, "@return_type", ret_type); - rb_iv_set(self, "@abi", abi); - - TypedData_Get_Struct(self, ffi_cif, &dlfunction_data_type, cif); - - arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *)); - - 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; - - result = ffi_prep_cif ( - cif, - NUM2INT(abi), - RARRAY_LENINT(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 = (float)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 ULONG2NUM(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; - VALUE cfunc, types; - int i; - - 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)); - - cfunc = rb_iv_get(self, "@ptr"); - types = rb_iv_get(self, "@args"); - - for (i = 0; i < argc; i++) { - VALUE dl_type = RARRAY_PTR(types)[i]; - VALUE src = argv[i]; - - if(NUM2INT(dl_type) == DLTYPE_VOIDP) { - if(NIL_P(src)) { - src = INT2NUM(0); - } else if(rb_cDLCPtr != CLASS_OF(src)) { - src = rb_funcall(rb_cDLCPtr, rb_intern("[]"), 1, src); - } - src = rb_Integer(src); - } - - 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_iv_get(self, "@return_type"), retval); -} - -void -Init_dlfunction(void) -{ - rb_cDLMethod = rb_define_class_under(rb_mDL, "Method", rb_cObject); - - rb_define_const(rb_cDLMethod, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI)); - -#ifdef FFI_STDCALL - rb_define_const(rb_cDLMethod, "STDCALL", INT2NUM(FFI_STDCALL)); -#endif - - rb_define_alloc_func(rb_cDLMethod, rb_dlfunc_allocate); - - rb_define_method(rb_cDLMethod, "call", rb_dlfunction_call, -1); - - rb_define_method(rb_cDLMethod, "initialize", rb_dlfunction_initialize, -1); -} -/* vim: set noet sw=4 sts=4 */ -- cgit v1.2.3