From 2d5b7f736518fb343469cd2bee721120309d8dca Mon Sep 17 00:00:00 2001 From: ttate Date: Sun, 9 Jun 2002 17:47:34 +0000 Subject: * ext/dl: change the callback mechanism. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2532 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/dl/dl.c | 248 ++++++++++++++++++++++++++++++-------------------- ext/dl/doc/dl.txt | 8 +- ext/dl/extconf.rb | 48 +++------- ext/dl/mkcallback.rb | 109 ++++++++-------------- ext/dl/mkcbtable.rb | 34 +------ ext/dl/sample/libc.rb | 2 +- ext/dl/test/test.rb | 7 +- 7 files changed, 213 insertions(+), 243 deletions(-) (limited to 'ext/dl') 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=,, - : maximum number of arguments of the function - : maximum number of arguments of the callback - : maximum number of callback entries + --with-args= + --with-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=,,\n") + max_arg = args.to_i + if( !max_arg ) + print("--with-args=\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 = < 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(< 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) -- cgit v1.2.3