summaryrefslogtreecommitdiff
path: root/ext/dl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dl')
-rw-r--r--ext/dl/callback/depend15
-rw-r--r--ext/dl/callback/extconf.rb14
-rw-r--r--ext/dl/callback/mkcallback.rb238
-rw-r--r--ext/dl/cfunc.c39
-rw-r--r--ext/dl/closure.c230
-rw-r--r--ext/dl/cptr.c4
-rw-r--r--ext/dl/depend6
-rw-r--r--ext/dl/dl.c17
-rw-r--r--ext/dl/dl.h12
-rw-r--r--ext/dl/dl_conversions.c40
-rw-r--r--ext/dl/dl_conversions.h10
-rw-r--r--ext/dl/extconf.rb22
-rw-r--r--ext/dl/lib/dl/callback.rb51
-rw-r--r--ext/dl/lib/dl/closure.rb19
-rw-r--r--ext/dl/lib/dl/func.rb64
-rw-r--r--ext/dl/lib/dl/import.rb9
-rw-r--r--ext/dl/lib/dl/value.rb11
-rw-r--r--ext/dl/method.c251
18 files changed, 390 insertions, 662 deletions
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 << (<<EOS)
+#include "ruby.h"
+
+VALUE rb_DLCdeclCallbackAddrs, rb_DLCdeclCallbackProcs;
+#ifdef FUNC_STDCALL
+VALUE rb_DLStdcallCallbackAddrs, rb_DLStdcallCallbackProcs;
+#endif
+/*static void *cdecl_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
+#ifdef FUNC_STDCALL
+/*static void *stdcall_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
+#endif
+ID rb_dl_cb_call;
+EOS
+
+def foreach_proc_entry
+ for calltype in CALLTYPES
+ case calltype
+ when CDECL
+ proc_entry = "rb_DLCdeclCallbackProcs"
+ when STDCALL
+ proc_entry = "rb_DLStdcallCallbackProcs"
+ else
+ raise "unknown calltype: #{calltype}"
+ end
+ yield calltype, proc_entry
+ end
+end
+
+def gencallback(ty, calltype, proc_entry, argc, n)
+ <<-EOS
+#{calltype == STDCALL ? "\n#ifdef FUNC_STDCALL" : ""}
+static #{DLTYPE[ty][:type]}
+FUNC_#{calltype.upcase}(#{func_name(ty,argc,n,calltype)})(#{(0...argc).collect{|i| "DLSTACK_TYPE stack" + i.to_s}.join(", ")})
+{
+ VALUE ret, cb#{argc > 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 << (<<EOS)
+void
+Init_callback(void)
+{
+ VALUE tmp;
+ VALUE rb_mDL = rb_path2class("DL");
+
+ rb_dl_cb_call = rb_intern("call");
+
+ tmp = rb_DLCdeclCallbackProcs = rb_ary_new();
+ rb_define_const(rb_mDL, "CdeclCallbackProcs", tmp);
+
+ tmp = rb_DLCdeclCallbackAddrs = rb_ary_new();
+ rb_define_const(rb_mDL, "CdeclCallbackAddrs", tmp);
+
+#ifdef FUNC_STDCALL
+ tmp = rb_DLStdcallCallbackProcs = rb_ary_new();
+ rb_define_const(rb_mDL, "StdcallCallbackProcs", tmp);
+
+ tmp = rb_DLStdcallCallbackAddrs = rb_ary_new();
+ rb_define_const(rb_mDL, "StdcallCallbackAddrs", tmp);
+#endif
+
+#{
+ (0...MAX_DLTYPE).collect{|ty|
+ " rb_dl_init_callbacks_#{ty}();"
+ }.join("\n")
+}
+}
+EOS
+$out.close
+
+for filename, body in callbacks
+ open(filename, "wb") {|f| f.puts body}
+end
diff --git a/ext/dl/cfunc.c b/ext/dl/cfunc.c
index 21afcc5677..729dbe9ac6 100644
--- a/ext/dl/cfunc.c
+++ b/ext/dl/cfunc.c
@@ -16,7 +16,7 @@ rb_dl_get_last_error(VALUE self)
return rb_thread_local_aref(rb_thread_current(), id_last_error);
}
-VALUE
+static VALUE
rb_dl_set_last_error(VALUE self, VALUE val)
{
rb_thread_local_aset(rb_thread_current(), id_last_error, val);
@@ -33,7 +33,7 @@ rb_dl_get_win32_last_error(VALUE self)
return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
}
-VALUE
+static VALUE
rb_dl_set_win32_last_error(VALUE self, VALUE val)
{
rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val);
@@ -147,12 +147,12 @@ rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
struct cfunc_data *data;
void *saddr;
const char *sname;
-
+
rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
-
+
saddr = (void*)(NUM2PTR(rb_Integer(addr)));
sname = NIL_P(name) ? NULL : StringValuePtr(name);
-
+
TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data);
if( data->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 <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_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 <ruby.h>
-#ifdef USE_HEADER_HACKS
-#include <ffi/ffi.h>
-#else
-#include <ffi.h>
-#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 <dl_conversions.h>
-
-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 <dl.h>
-
-#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 <ruby.h>
-#include <errno.h>
-#include "dl.h"
-#include <dl_conversions.h>
-
-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 */