1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/dl: change the callback mechanism.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2532 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ttate 2002-06-09 17:47:34 +00:00
parent d5ceb6ef82
commit 2d5b7f7365
8 changed files with 214 additions and 240 deletions

View file

@ -1,3 +1,7 @@
Sun Jun 9 17:40:41 2002 Takaaki Tateishi <ttate@kt.jaist.ac.jp>
* ext/dl: change the callback mechanism.
Thu Jun 6 19:50:39 2002 KONISHI Hiromasa <H_Konishi@ruby-lang.org>
* sample/biorhythm.rb (getPosiiton,etc)

View file

@ -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;
VALUE type, proc;
int rettype, entry, i;
char fname[127];
ftype = 0;
type = StringValuePtr(*str);
len = RSTRING(*str)->len;
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);
rettype = 0x06;
break;
case 'P':
rettype = 0x07;
break;
default:
rb_raise(rb_eDLError, "unsupported type `%c'", type[i]);
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:
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);
};
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);
rb_raise(rb_eDLTypeError, "unsupported type `%s'", STR2CSTR(rettype));
}
else{
return Qnil;
};
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;
}
}
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;
freefunc_t f = rb_dlsym2csym(sym);
int i, j;
key = rb_dl_callback_type(&types);
entry = rb_hash_aref(DLFuncTable, key);
if( entry == Qnil ){
return Qnil;
};
return rb_hash_aref(entry, num);
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);

View file

@ -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

View file

@ -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}

View file

@ -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 mkfunc(rettype, fnum, argc)
args = (0..(argc-1)).collect{|i| "long arg#{i}"}.join(", ")
def func_arg(x,i)
ctype = DLTYPE[x][:ctype]
"#{ctype} arg#{i}"
end
subst_code = (0..(argc-1)).collect{|i|
" buff[#{i.to_s}] = arg#{i.to_s};"
}.join("\n")
def func_args(types)
t = []
types[1..-1].each_with_index{|x,i| t.push(func_arg(x,i))}
t.join(", ")
end
ret_code =
if( DLTYPE[rettype][:c2rb] )
" return #{DLTYPE[rettype][:rb2c][\"retval\"]};"
else
" /* no return value */"
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
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")
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
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
}

View file

@ -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
}

View file

@ -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

View file

@ -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)