summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/dl/dl.c248
-rw-r--r--ext/dl/doc/dl.txt8
-rw-r--r--ext/dl/extconf.rb48
-rw-r--r--ext/dl/mkcallback.rb109
-rw-r--r--ext/dl/mkcbtable.rb34
-rw-r--r--ext/dl/sample/libc.rb2
-rw-r--r--ext/dl/test/test.rb7
7 files changed, 213 insertions, 243 deletions
diff --git a/ext/dl/dl.c b/ext/dl/dl.c
index 99df0ba193..e704a6d4a0 100644
--- a/ext/dl/dl.c
+++ b/ext/dl/dl.c
@@ -11,9 +11,95 @@ VALUE rb_eDLError;
VALUE rb_eDLTypeError;
static VALUE DLFuncTable;
-static void *rb_dl_func_table[MAX_CALLBACK_TYPE][MAX_CALLBACK];
+static void *rb_dl_callback_table[CALLBACK_TYPES][MAX_CALLBACK];
static ID id_call;
+static int
+rb_dl_scan_callback_args(long stack[], const char *proto,
+ int *argc, VALUE (*argv)[])
+{
+ int i;
+ long *sp;
+ VALUE val;
+
+ sp = stack;
+ for( i=1; proto[i]; i++ ){
+ switch( proto[i] ){
+ case 'C':
+ {
+ char v;
+ memcpy(&v, sp, sizeof(long));
+ sp++;
+ val = INT2NUM(v);
+ }
+ break;
+ case 'H':
+ {
+ short v;
+ memcpy(&v, sp, sizeof(long));
+ sp++;
+ val = INT2NUM(v);
+ }
+ break;
+ case 'I':
+ {
+ int v;
+ memcpy(&v, sp, sizeof(long));
+ sp++;
+ val = INT2NUM(v);
+ }
+ break;
+ case 'L':
+ {
+ long v;
+ memcpy(&v, sp, sizeof(long));
+ sp++;
+ val = INT2NUM(v);
+ }
+ break;
+ case 'F':
+ {
+ float v;
+ memcpy(&v, sp, sizeof(float));
+ sp += sizeof(float)/sizeof(long);
+ val = rb_float_new(v);
+ }
+ break;
+ case 'D':
+ {
+ double v;
+ memcpy(&v, sp, sizeof(double));
+ sp += sizeof(double)/sizeof(long);
+ val = rb_float_new(v);
+ }
+ break;
+ case 'P':
+ {
+ void *v;
+ memcpy(&v, sp, sizeof(void*));
+ sp++;
+ val = rb_dlptr_new(v, 0, 0);
+ }
+ break;
+ case 'S':
+ {
+ char *v;
+ memcpy(&v, sp, sizeof(void*));
+ sp++;
+ val = rb_tainted_str_new2(v);
+ }
+ break;
+ default:
+ rb_raise(rb_eDLTypeError, "unsupported type `%c'", proto[i]);
+ break;
+ }
+ (*argv)[i-1] = val;
+ }
+ *argc = (i - 1);
+
+ return (*argc);
+}
+
#include "callback.func"
static void
@@ -476,121 +562,88 @@ rb_dl_sizeof(VALUE self, VALUE str)
}
static VALUE
-rb_dl_callback_type(VALUE *str)
+rb_dl_callback(int argc, VALUE argv[], VALUE self)
{
- char *type;
- int len;
- int i;
- long ftype;
-
- ftype = 0;
- type = StringValuePtr(*str);
- len = RSTRING(*str)->len;
+ VALUE type, proc;
+ int rettype, entry, i;
+ char fname[127];
- if( len - 1 > MAX_CBARG ){
- rb_raise(rb_eDLError, "maximum number of the argument is %d.", MAX_CBARG);
- };
-
- for( i = len - 1; i > 0; i-- ){
- switch( type[i] ){
- case 'P':
- CBPUSH_P(ftype);
- break;
- case 'I':
- CBPUSH_I(ftype);
- break;
- case 'L':
- CBPUSH_L(ftype);
- break;
- case 'F':
- CBPUSH_F(ftype);
- break;
- case 'D':
- CBPUSH_D(ftype);
- default:
- rb_raise(rb_eDLError, "unsupported type `%c'", type[i]);
- break;
- };
+ proc = Qnil;
+ switch( rb_scan_args(argc, argv, "11", &type, &proc) ){
+ case 1:
+ if( rb_block_given_p() ){
+ proc = rb_f_lambda();
+ }
+ else{
+ proc = Qnil;
+ }
+ default:
+ break;
}
- switch( type[0] ){
+ Check_Type(type, T_STRING);
+ switch( STR2CSTR(type)[0] ){
case '0':
- CBPUSH_0(ftype);
+ rettype = 0x00;
break;
- case 'P':
- CBPUSH_P(ftype);
+ case 'C':
+ rettype = 0x01;
+ break;
+ case 'H':
+ rettype = 0x02;
break;
case 'I':
- CBPUSH_I(ftype);
+ rettype = 0x03;
break;
case 'L':
- CBPUSH_L(ftype);
+ rettype = 0x04;
break;
case 'F':
- CBPUSH_F(ftype);
+ rettype = 0x05;
break;
case 'D':
- CBPUSH_D(ftype);
- break;
- default:
- rb_raise(rb_eDLError, "unsupported type `%c'", type[i]);
+ rettype = 0x06;
break;
- };
-
- return INT2NUM(ftype);
-}
-
-VALUE
-rb_dl_set_callback(int argc, VALUE argv[], VALUE self)
-{
- VALUE types, num, proc;
- VALUE key;
- VALUE entry;
- void *func;
-
- char func_name[1024];
- extern dln_sym();
-
- switch( rb_scan_args(argc, argv, "21", &types, &num, &proc) ){
- case 2:
- proc = rb_f_lambda();
- break;
- case 3:
+ case 'P':
+ rettype = 0x07;
break;
default:
- rb_bug("rb_dl_set_callback");
- };
-
- key = rb_dl_callback_type(&types);
- entry = rb_hash_aref(DLFuncTable, key);
- if( entry == Qnil ){
- entry = rb_hash_new();
- rb_hash_aset(DLFuncTable, key, entry);
- };
+ rb_raise(rb_eDLTypeError, "unsupported type `%s'", STR2CSTR(rettype));
+ }
- func = rb_dl_func_table[NUM2INT(key)][NUM2INT(num)];
- if( func ){
- rb_hash_aset(entry, num, proc);
- snprintf(func_name, 1023, "rb_dl_func%d_%d", NUM2INT(key), NUM2INT(num));
- return rb_dlsym_new(func, func_name, RSTRING(types)->ptr);
+ entry = -1;
+ for( i=0; i < MAX_CALLBACK; i++ ){
+ if( rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(rettype), INT2NUM(i))) == Qnil ){
+ entry = i;
+ break;
+ }
}
- else{
- return Qnil;
- };
+ if( entry < 0 ){
+ rb_raise(rb_eDLError, "too many callbacks are defined.");
+ }
+
+ rb_hash_aset(DLFuncTable,
+ rb_assoc_new(INT2NUM(rettype),INT2NUM(entry)),
+ rb_assoc_new(type,proc));
+ sprintf(fname, "rb_dl_callback_func_%d_%d", rettype, entry);
+ return rb_dlsym_new(rb_dl_callback_table[rettype][entry], fname, STR2CSTR(type));
}
-VALUE
-rb_dl_get_callback(VALUE self, VALUE types, VALUE num)
+static VALUE
+rb_dl_remove_callback(VALUE mod, VALUE sym)
{
- VALUE key;
- VALUE entry;
-
- key = rb_dl_callback_type(&types);
- entry = rb_hash_aref(DLFuncTable, key);
- if( entry == Qnil ){
- return Qnil;
- };
- return rb_hash_aref(entry, num);
+ freefunc_t f = rb_dlsym2csym(sym);
+ int i, j;
+
+ for( i=0; i < CALLBACK_TYPES; i++ ){
+ for( j=0; j < MAX_CALLBACK; j++ ){
+ if( rb_dl_callback_table[i][j] == f ){
+ rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(i),INT2NUM(j)),Qnil);
+ break;
+ }
+ }
+ }
+ return Qnil;
}
void
@@ -627,13 +680,12 @@ Init_dl()
rb_define_const(rb_mDL, "MINOR_VERSION", INT2NUM(DL_MINOR_VERSION));
rb_define_const(rb_mDL, "PATCH_VERSION", INT2NUM(DL_PATCH_VERSION));
rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG));
- rb_define_const(rb_mDL, "MAX_CBARG", INT2NUM(MAX_CBARG));
- rb_define_const(rb_mDL, "MAX_CBENT", INT2NUM(MAX_CBENT));
rb_define_const(rb_mDL, "DLSTACK", rb_tainted_str_new2(DLSTACK_METHOD));
rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
- rb_define_module_function(rb_mDL, "set_callback", rb_dl_set_callback, -1);
- rb_define_module_function(rb_mDL, "get_callback", rb_dl_get_callback, 2);
+ rb_define_module_function(rb_mDL, "callback", rb_dl_callback, -1);
+ rb_define_module_function(rb_mDL, "define_callback", rb_dl_callback, -1);
+ rb_define_module_function(rb_mDL, "remove_callback", rb_dl_remove_callback, 1);
rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
rb_define_module_function(rb_mDL, "strdup", rb_dl_strdup, 1);
rb_define_module_function(rb_mDL, "sizeof", rb_dl_sizeof, 1);
diff --git a/ext/dl/doc/dl.txt b/ext/dl/doc/dl.txt
index c3d06a6efb..114baafcb7 100644
--- a/ext/dl/doc/dl.txt
+++ b/ext/dl/doc/dl.txt
@@ -52,9 +52,9 @@ struct and union which are defined in "dl/struct.rb" as follows:
"long tv_uses",
]
end
- val = LIBC::Timeval.alloc # allocate the memory.
+ val = LIBC::Timeval.malloc # allocate the memory.
-The above example uses LIBC::Timeval.alloc, since we use LIBC::Timeval.new(ptr)
+The above example uses LIBC::Timeval.malloc, since we use LIBC::Timeval.new(ptr)
to wrap the given PtrData object which is, for example, created by DL::malloc().
DL::malloc() is a function to allocate a memory by using the C library function
malloc().
@@ -244,10 +244,10 @@ the type of each argument.
p : a mutable object (void *)
0 : void function (this must be a first character of the prototype)
-the cbtype consists of type specifiers 0, I, L, D and P.
+the cbtype consists of type specifiers 0, C, I, H, L, F, D, S and P.
for example:
- DL.set_callback('IPP',0){|ptr1,ptr2|
+ DL.callback('IPP'){|ptr1,ptr2|
str1 = ptr1.ptr.to_s
str2 = ptr2.ptr.to_s
return str1 <=> str2
diff --git a/ext/dl/extconf.rb b/ext/dl/extconf.rb
index 9f3875071e..7b7c48f1a2 100644
--- a/ext/dl/extconf.rb
+++ b/ext/dl/extconf.rb
@@ -11,10 +11,8 @@ if( ARGV.include?("--help") )
--with-type-char strictly use type 'char'
--with-type-short strictly use type 'short'
--with-type-float strictly use type 'float'
- --with-args=<max_arg>,<max_cbarg>,<max_cbent>
- <max_arg>: maximum number of arguments of the function
- <max_cbarg>: maximum number of arguments of the callback
- <max_cbent>: maximum number of callback entries
+ --with-args=<max_arg>
+ --with-callback=<max_callback>
--enable-asm use the embedded assembler for passing arguments.
(this option is available for i386 machine now.)
--enable-dlstack use a stack emulation for constructing function call.
@@ -58,8 +56,6 @@ $with_type_int &= DLTYPE[INT][:sym]
$with_type_float &= DLTYPE[FLOAT][:sym]
$with_type_voidp &= DLTYPE[VOIDP][:sym]
-$with_cbtype_voidp = DLTYPE[VOIDP][:cb]
-
$with_type_char = enable_config("type-char", $with_type_char)
$with_type_short = enable_config("type-short", $with_type_short)
$with_type_float = enable_config("type-float", $with_type_float)
@@ -68,7 +64,7 @@ $with_asm = enable_config("asm", $with_asm)
$with_dlstack = enable_config("dlstack", $with_dlstack)
args = with_config("args")
-max_arg = max_cbarg = max_cbent = nil
+max_arg = nil
if( $with_asm || $with_dlstack )
$with_type_char = true
$with_type_short = true
@@ -76,31 +72,20 @@ if( $with_asm || $with_dlstack )
max_arg = 0
end
if( args )
- max_arg,max_cbarg,max_cbent = args.split(",").collect{|c| c.to_i}
- if( !(max_arg && max_cbarg && max_cbent) )
- print("--with-args=<max_arg>,<max_cbarg>,<max_cbent>\n")
+ max_arg = args.to_i
+ if( !max_arg )
+ print("--with-args=<max_arg>\n")
exit(1)
end
end
max_arg ||= 6
-max_cbarg ||= 3
-max_cbent ||= 3
-
-max_callback_type = types2num(DLTYPE.keys.sort[-1,1] * (max_cbarg + 1)) + 1
-max_callback = max_cbent
-#m = [1].pack("i")
-#c,cs = m.unpack("c")
-#bigendian = (c == 0)
-#print("bigendian ... #{bigendian ? 'true' : 'false'}\n")
+max_callback = with_config("callback","10").to_i
+callback_types = DLTYPE.keys.length
$dlconfig_h = <<EOF
-#define MAX_ARG #{max_arg}
-#define MAX_CBARG #{max_cbarg}
-#define MAX_CBENT #{max_cbent}
-#define MAX_CALLBACK_TYPE #{max_callback_type}
-#define MAX_CALLBACK #{max_callback}
+#define MAX_ARG #{max_arg}
EOF
def dlc_define(const)
@@ -109,6 +94,8 @@ def dlc_define(const)
"#endif\n"
end
+$dlconfig_h << "#define MAX_CALLBACK #{max_callback}\n"
+$dlconfig_h << "#define CALLBACK_TYPES #{callback_types}\n"
if( $with_dlstack )
$dlconfig_h << "#define USE_DLSTACK\n"
else
@@ -137,15 +124,6 @@ end
if( $with_type_voidp )
$dlconfig_h << "#define WITH_TYPE_VOIDP\n"
end
-if( $with_cbtype_voidp )
- $dlconfig_h << "#define WITH_CBTYPE_VOIDP\n"
-end
-#if( bigendian )
-# $dlconfig_h << "#define BIGENDIAN"
-#else
-# $dlconfig_h << "#define LITTLEENDIAN"
-#end
-
if( have_header("dlfcn.h") )
dlc_define("HAVE_DLFCN_H")
@@ -182,8 +160,8 @@ EOF
File.update("dlconfig.rb", <<EOF)
MAX_ARG = #{max_arg}
-MAX_CBARG = #{max_cbarg}
-MAX_CBENT = #{max_cbent}
+MAX_CALLBACK = #{max_callback}
+CALLBACK_TYPES = #{callback_types}
DLTYPE[CHAR][:sym] = #{$with_type_char}
DLTYPE[SHORT][:sym] = #{$with_type_short}
DLTYPE[INT][:sym] = #{$with_type_int}
diff --git a/ext/dl/mkcallback.rb b/ext/dl/mkcallback.rb
index 32c7b451d7..217fef4fba 100644
--- a/ext/dl/mkcallback.rb
+++ b/ext/dl/mkcallback.rb
@@ -5,79 +5,46 @@ $:.unshift File.dirname(__FILE__)
require 'type'
require 'dlconfig'
-$int_eq_long = try_run(<<EOF)
-int main() {
- return sizeof(int) == sizeof(long) ? 0 : 1;
-}
-EOF
-
-def func_arg(x,i)
- ctype = DLTYPE[x][:ctype]
- "#{ctype} arg#{i}"
-end
-
-def func_args(types)
- t = []
- types[1..-1].each_with_index{|x,i| t.push(func_arg(x,i))}
- t.join(", ")
-end
-
-def funcall_args(types)
- num = types.length - 1
- if( num > 0 )
- t = []
- types[1..-1].each_with_index{|x,i| t.push(DLTYPE[x][:c2rb].call("arg#{i}"))}
- return num.to_s + ", " + t.join(", ")
- else
- return num.to_s
- end
-end
-
-def output_func(types, n = 0)
- func_name = "rb_dl_func#{types2num(types)}_#{n}"
- code =
- "#{func_name}(#{func_args(types)}) /* #{types2ctypes(types).inspect} */\n" +
- "{\n" +
- " VALUE val, obj;\n" +
- "#ifdef DEBUG\n" +
- " printf(\"#{func_name}()\\n\");\n" +
- "#endif\n" +
- " obj = rb_hash_aref(DLFuncTable, INT2NUM(#{types2num(types)}));\n" +
- " obj = rb_hash_aref(obj,INT2NUM(#{n}));\n" +
- " val = rb_funcall(obj, id_call,\n" +
- " #{funcall_args(types)});\n"
-
- rtype = DLTYPE[types[0]][:ctype]
- rcode = DLTYPE[types[0]][:rb2c]
- if( rcode )
- code += " return #{rcode.call('val')};\n"
- end
-
- code =
- rtype + "\n" +
- code +
- "}\n\n"
- if( n < MAX_CBENT - 1)
- return code + output_func(types, n+1)
- else
- return code
- end
-end
-
-
-def rec_output(types = [VOID])
- print output_func(types)
- if( types.length <= MAX_CBARG )
- DLTYPE.keys.sort.each{|t|
- if( t != VOID && DLTYPE[t][:cb] )
- rec_output(types + [t])
- end
- }
- end
+def mkfunc(rettype, fnum, argc)
+ args = (0..(argc-1)).collect{|i| "long arg#{i}"}.join(", ")
+
+ subst_code = (0..(argc-1)).collect{|i|
+ " buff[#{i.to_s}] = arg#{i.to_s};"
+ }.join("\n")
+
+ ret_code =
+ if( DLTYPE[rettype][:c2rb] )
+ " return #{DLTYPE[rettype][:rb2c][\"retval\"]};"
+ else
+ " /* no return value */"
+ end
+
+ code = [
+ "static #{DLTYPE[rettype][:ctype]}",
+ "rb_dl_callback_func_#{rettype.to_s}_#{fnum.to_s}(#{args})",
+ "{",
+ " VALUE retval, proto, proc, obj;",
+ " VALUE argv[#{argc.to_s}];",
+ " int argc;",
+ " long buff[#{argc.to_s}];",
+ "",
+ subst_code,
+ "",
+ " obj = rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(#{rettype.to_s}),INT2NUM(#{fnum.to_s})));",
+ " proto = rb_ary_entry(obj, 0);",
+ " proc = rb_ary_entry(obj, 1);",
+ " rb_dl_scan_callback_args(buff, STR2CSTR(proto), &argc, &argv);",
+ " retval = rb_funcall2(proc, id_call, argc, argv);",
+ "",
+ ret_code,
+ "}",
+ ].join("\n")
+
+ return code
end
DLTYPE.keys.sort.each{|t|
- if( DLTYPE[t][:cb] )
- rec_output([t])
+ for n in 0..(MAX_CALLBACK - 1)
+ print(mkfunc(t, n, 15), "\n\n")
end
}
diff --git a/ext/dl/mkcbtable.rb b/ext/dl/mkcbtable.rb
index f25f012e4c..165c4bdc88 100644
--- a/ext/dl/mkcbtable.rb
+++ b/ext/dl/mkcbtable.rb
@@ -5,38 +5,14 @@ $:.unshift File.dirname(__FILE__)
require 'type'
require 'dlconfig'
-$int_eq_long = try_run(<<EOF)
-int main() {
- return sizeof(int) == sizeof(long) ? 0 : 1;
-}
-EOF
-
-def output_func(types, n = 0)
+def mktable(rettype, fnum, argc)
code =
- "/* #{types2ctypes(types).inspect} */\n" +
- "rb_dl_func_table[#{types2num(types)}][#{n}] " +
- "= rb_dl_func#{types2num(types)}_#{n};\n"
- if( n < MAX_CBENT - 1)
- return code + output_func(types, n+1)
- else
- return code
- end
-end
-
-
-def rec_output(types = [VOID])
- print output_func(types)
- if( types.length <= MAX_CBARG )
- DLTYPE.keys.sort.each{|t|
- if( t != VOID && DLTYPE[t][:cb] )
- rec_output(types + [t])
- end
- }
- end
+ "rb_dl_callback_table[#{rettype}][#{fnum}] = &rb_dl_callback_func_#{rettype.to_s}_#{fnum};"
+ return code
end
DLTYPE.keys.sort.each{|t|
- if( DLTYPE[t][:cb] )
- rec_output([t])
+ for n in 0..(MAX_CALLBACK - 1)
+ print(mktable(t, n, 15), "\n")
end
}
diff --git a/ext/dl/sample/libc.rb b/ext/dl/sample/libc.rb
index 7d1de2601d..9975828be3 100644
--- a/ext/dl/sample/libc.rb
+++ b/ext/dl/sample/libc.rb
@@ -38,7 +38,7 @@ module LIBC
end
-$cb1 = DL.set_callback('IPP', 0){|ptr1, ptr2|
+$cb1 = DL.callback('IPP'){|ptr1, ptr2|
str1 = ptr1.ptr.to_s
str2 = ptr2.ptr.to_s
str1 <=> str2
diff --git a/ext/dl/test/test.rb b/ext/dl/test/test.rb
index 316201a0b3..3e124783fa 100644
--- a/ext/dl/test/test.rb
+++ b/ext/dl/test/test.rb
@@ -38,8 +38,6 @@ print("MINOR_VERSION = #{DL::MINOR_VERSION}\n")
print("\n")
print("DLSTACK = #{DL::DLSTACK}\n")
print("MAX_ARG = #{DL::MAX_ARG}\n")
-print("MAX_CBARG = #{DL::MAX_CBARG}\n")
-print("MAX_CBENT = #{DL::MAX_CBENT}\n")
print("\n")
print("DL::FREE = #{DL::FREE.inspect}\n")
print("\n")
@@ -205,8 +203,7 @@ debug r,rs
assert("callback1", :must, r == 1)
-callback2 = DL.set_callback("LLP", 0){|arg1,arg2|
- ptr = arg2 # DL::PtrData.new(arg2)
+callback2 = DL.callback("LLP"){|num,ptr|
msg = ptr.to_s
if( msg == "callback message" )
2
@@ -218,7 +215,7 @@ debug callback2
r,rs = h["test_call_func1", "IP"][callback2]
debug r,rs
assert("callback2", :must, r == 2)
-
+DL.remove_callback(callback2)
ptr = DL.malloc(DL.sizeof('CL'))
ptr.struct!("CL", :c, :l)