|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* -*- C -*- 00002 * $Id: cfunc.c 30559 2011-01-16 06:30:33Z yugui $ 00003 */ 00004 00005 #include <ruby.h> 00006 #include <errno.h> 00007 #include "dl.h" 00008 00009 VALUE rb_big2ulong_pack(VALUE x); 00010 00011 VALUE rb_cDLCFunc; 00012 00013 static ID id_last_error; 00014 00015 static VALUE 00016 rb_dl_get_last_error(VALUE self) 00017 { 00018 return rb_thread_local_aref(rb_thread_current(), id_last_error); 00019 } 00020 00021 static VALUE 00022 rb_dl_set_last_error(VALUE self, VALUE val) 00023 { 00024 rb_thread_local_aset(rb_thread_current(), id_last_error, val); 00025 return Qnil; 00026 } 00027 00028 #if defined(_WIN32) 00029 #include <windows.h> 00030 static ID id_win32_last_error; 00031 00032 static VALUE 00033 rb_dl_get_win32_last_error(VALUE self) 00034 { 00035 return rb_thread_local_aref(rb_thread_current(), id_win32_last_error); 00036 } 00037 00038 static VALUE 00039 rb_dl_set_win32_last_error(VALUE self, VALUE val) 00040 { 00041 rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val); 00042 return Qnil; 00043 } 00044 #endif 00045 00046 00047 static void 00048 dlcfunc_free(void *ptr) 00049 { 00050 struct cfunc_data *data = ptr; 00051 if( data->name ){ 00052 xfree(data->name); 00053 } 00054 xfree(data); 00055 } 00056 00057 static size_t 00058 dlcfunc_memsize(const void *ptr) 00059 { 00060 const struct cfunc_data *data = ptr; 00061 size_t size = 0; 00062 if( data ){ 00063 size += sizeof(*data); 00064 if( data->name ){ 00065 size += strlen(data->name) + 1; 00066 } 00067 } 00068 return size; 00069 } 00070 00071 const rb_data_type_t dlcfunc_data_type = { 00072 "dl/cfunc", 00073 0, dlcfunc_free, dlcfunc_memsize, 00074 }; 00075 00076 VALUE 00077 rb_dlcfunc_new(void (*func)(), int type, const char *name, ID calltype) 00078 { 00079 VALUE val; 00080 struct cfunc_data *data; 00081 00082 rb_secure(4); 00083 if( func ){ 00084 val = TypedData_Make_Struct(rb_cDLCFunc, struct cfunc_data, &dlcfunc_data_type, data); 00085 data->ptr = (void *)(VALUE)func; 00086 data->name = name ? strdup(name) : NULL; 00087 data->type = type; 00088 data->calltype = calltype; 00089 } 00090 else{ 00091 val = Qnil; 00092 } 00093 00094 return val; 00095 } 00096 00097 void * 00098 rb_dlcfunc2ptr(VALUE val) 00099 { 00100 struct cfunc_data *data; 00101 void * func; 00102 00103 if( rb_typeddata_is_kind_of(val, &dlcfunc_data_type) ){ 00104 data = DATA_PTR(val); 00105 func = data->ptr; 00106 } 00107 else if( val == Qnil ){ 00108 func = NULL; 00109 } 00110 else{ 00111 rb_raise(rb_eTypeError, "DL::CFunc was expected"); 00112 } 00113 00114 return func; 00115 } 00116 00117 static VALUE 00118 rb_dlcfunc_s_allocate(VALUE klass) 00119 { 00120 VALUE obj; 00121 struct cfunc_data *data; 00122 00123 obj = TypedData_Make_Struct(klass, struct cfunc_data, &dlcfunc_data_type, data); 00124 data->ptr = 0; 00125 data->name = 0; 00126 data->type = 0; 00127 data->calltype = CFUNC_CDECL; 00128 00129 return obj; 00130 } 00131 00132 int 00133 rb_dlcfunc_kind_p(VALUE func) 00134 { 00135 return rb_typeddata_is_kind_of(func, &dlcfunc_data_type); 00136 } 00137 00138 /* 00139 * call-seq: 00140 * DL::CFunc.new(address, type=DL::TYPE_VOID, name=nil, calltype=:cdecl) 00141 * 00142 * Create a new function that points to +address+ with an optional return type 00143 * of +type+, a name of +name+ and a calltype of +calltype+. 00144 */ 00145 static VALUE 00146 rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self) 00147 { 00148 VALUE addr, name, type, calltype; 00149 struct cfunc_data *data; 00150 void *saddr; 00151 const char *sname; 00152 00153 rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype); 00154 00155 saddr = (void*)(NUM2PTR(rb_Integer(addr))); 00156 sname = NIL_P(name) ? NULL : StringValuePtr(name); 00157 00158 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data); 00159 if( data->name ) xfree(data->name); 00160 data->ptr = saddr; 00161 data->name = sname ? strdup(sname) : 0; 00162 data->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type); 00163 data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype); 00164 00165 return Qnil; 00166 } 00167 00168 /* 00169 * call-seq: 00170 * name => str 00171 * 00172 * Get the name of this function 00173 */ 00174 static VALUE 00175 rb_dlcfunc_name(VALUE self) 00176 { 00177 struct cfunc_data *cfunc; 00178 00179 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00180 return cfunc->name ? rb_tainted_str_new2(cfunc->name) : Qnil; 00181 } 00182 00183 /* 00184 * call-seq: 00185 * cfunc.ctype => num 00186 * 00187 * Get the C function return value type. See DL for a list of constants 00188 * corresponding to this method's return value. 00189 */ 00190 static VALUE 00191 rb_dlcfunc_ctype(VALUE self) 00192 { 00193 struct cfunc_data *cfunc; 00194 00195 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00196 return INT2NUM(cfunc->type); 00197 } 00198 00199 /* 00200 * call-seq: 00201 * cfunc.ctype = type 00202 * 00203 * Set the C function return value type to +type+. 00204 */ 00205 static VALUE 00206 rb_dlcfunc_set_ctype(VALUE self, VALUE ctype) 00207 { 00208 struct cfunc_data *cfunc; 00209 00210 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00211 cfunc->type = NUM2INT(ctype); 00212 return ctype; 00213 } 00214 00215 /* 00216 * call-seq: 00217 * cfunc.calltype => symbol 00218 * 00219 * Get the call type of this function. 00220 */ 00221 static VALUE 00222 rb_dlcfunc_calltype(VALUE self) 00223 { 00224 struct cfunc_data *cfunc; 00225 00226 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00227 return ID2SYM(cfunc->calltype); 00228 } 00229 00230 /* 00231 * call-seq: 00232 * cfunc.calltype = symbol 00233 * 00234 * Set the call type for this function. 00235 */ 00236 static VALUE 00237 rb_dlcfunc_set_calltype(VALUE self, VALUE sym) 00238 { 00239 struct cfunc_data *cfunc; 00240 00241 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00242 cfunc->calltype = SYM2ID(sym); 00243 return sym; 00244 } 00245 00246 /* 00247 * call-seq: 00248 * cfunc.ptr 00249 * 00250 * Get the underlying function pointer as a DL::CPtr object. 00251 */ 00252 static VALUE 00253 rb_dlcfunc_ptr(VALUE self) 00254 { 00255 struct cfunc_data *cfunc; 00256 00257 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00258 return PTR2NUM(cfunc->ptr); 00259 } 00260 00261 /* 00262 * call-seq: 00263 * cfunc.ptr = pointer 00264 * 00265 * Set the underlying function pointer to a DL::CPtr named +pointer+. 00266 */ 00267 static VALUE 00268 rb_dlcfunc_set_ptr(VALUE self, VALUE addr) 00269 { 00270 struct cfunc_data *cfunc; 00271 00272 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00273 cfunc->ptr = NUM2PTR(addr); 00274 00275 return Qnil; 00276 } 00277 00278 /* 00279 * call-seq: inspect 00280 * 00281 * Returns a string formatted with an easily readable representation of the 00282 * internal state of the DL::CFunc 00283 */ 00284 static VALUE 00285 rb_dlcfunc_inspect(VALUE self) 00286 { 00287 VALUE val; 00288 struct cfunc_data *cfunc; 00289 00290 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00291 00292 val = rb_sprintf("#<DL::CFunc:%p ptr=%p type=%d name='%s'>", 00293 cfunc, 00294 cfunc->ptr, 00295 cfunc->type, 00296 cfunc->name ? cfunc->name : ""); 00297 OBJ_TAINT(val); 00298 return val; 00299 } 00300 00301 00302 # define DECL_FUNC_CDECL(f,ret,args,val) \ 00303 ret (FUNC_CDECL(*f))(args) = (ret (FUNC_CDECL(*))(args))(VALUE)(val) 00304 #ifdef FUNC_STDCALL 00305 # define DECL_FUNC_STDCALL(f,ret,args,val) \ 00306 ret (FUNC_STDCALL(*f))(args) = (ret (FUNC_STDCALL(*))(args))(VALUE)(val) 00307 #endif 00308 00309 #define CALL_CASE switch( RARRAY_LEN(ary) ){ \ 00310 CASE(0); break; \ 00311 CASE(1); break; CASE(2); break; CASE(3); break; CASE(4); break; CASE(5); break; \ 00312 CASE(6); break; CASE(7); break; CASE(8); break; CASE(9); break; CASE(10);break; \ 00313 CASE(11);break; CASE(12);break; CASE(13);break; CASE(14);break; CASE(15);break; \ 00314 CASE(16);break; CASE(17);break; CASE(18);break; CASE(19);break; CASE(20);break; \ 00315 default: rb_raise(rb_eArgError, "too many arguments"); \ 00316 } 00317 00318 00319 #if defined(_MSC_VER) && defined(_M_AMD64) && _MSC_VER == 1500 00320 # pragma optimize("", off) 00321 #endif 00322 /* 00323 * call-seq: 00324 * dlcfunc.call(ary) => some_value 00325 * dlcfunc[ary] => some_value 00326 * 00327 * Calls the function pointer passing in +ary+ as values to the underlying 00328 * C function. The return value depends on the ctype. 00329 */ 00330 static VALUE 00331 rb_dlcfunc_call(VALUE self, VALUE ary) 00332 { 00333 struct cfunc_data *cfunc; 00334 int i; 00335 DLSTACK_TYPE stack[DLSTACK_SIZE]; 00336 VALUE result = Qnil; 00337 00338 rb_secure_update(self); 00339 00340 memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE); 00341 Check_Type(ary, T_ARRAY); 00342 00343 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00344 00345 if( cfunc->ptr == 0 ){ 00346 rb_raise(rb_eDLError, "can't call null-function"); 00347 return Qnil; 00348 } 00349 00350 for( i = 0; i < RARRAY_LEN(ary); i++ ){ 00351 VALUE arg; 00352 if( i >= DLSTACK_SIZE ){ 00353 rb_raise(rb_eDLError, "too many arguments (stack overflow)"); 00354 } 00355 arg = rb_to_int(RARRAY_PTR(ary)[i]); 00356 rb_check_safe_obj(arg); 00357 if (FIXNUM_P(arg)) { 00358 stack[i] = (DLSTACK_TYPE)FIX2LONG(arg); 00359 } 00360 else if (RB_TYPE_P(arg, T_BIGNUM)) { 00361 stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg); 00362 } 00363 else { 00364 Check_Type(arg, T_FIXNUM); 00365 } 00366 } 00367 00368 /* calltype == CFUNC_CDECL */ 00369 if( cfunc->calltype == CFUNC_CDECL 00370 #ifndef FUNC_STDCALL 00371 || cfunc->calltype == CFUNC_STDCALL 00372 #endif 00373 ){ 00374 switch( cfunc->type ){ 00375 case DLTYPE_VOID: 00376 #define CASE(n) case n: { \ 00377 DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \ 00378 f(DLSTACK_ARGS##n(stack)); \ 00379 result = Qnil; \ 00380 } 00381 CALL_CASE; 00382 #undef CASE 00383 break; 00384 case DLTYPE_VOIDP: 00385 #define CASE(n) case n: { \ 00386 DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n,cfunc->ptr); \ 00387 void * ret; \ 00388 ret = f(DLSTACK_ARGS##n(stack)); \ 00389 result = PTR2NUM(ret); \ 00390 } 00391 CALL_CASE; 00392 #undef CASE 00393 break; 00394 case DLTYPE_CHAR: 00395 #define CASE(n) case n: { \ 00396 DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n,cfunc->ptr); \ 00397 char ret; \ 00398 ret = f(DLSTACK_ARGS##n(stack)); \ 00399 result = CHR2FIX(ret); \ 00400 } 00401 CALL_CASE; 00402 #undef CASE 00403 break; 00404 case DLTYPE_SHORT: 00405 #define CASE(n) case n: { \ 00406 DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n,cfunc->ptr); \ 00407 short ret; \ 00408 ret = f(DLSTACK_ARGS##n(stack)); \ 00409 result = INT2NUM((int)ret); \ 00410 } 00411 CALL_CASE; 00412 #undef CASE 00413 break; 00414 case DLTYPE_INT: 00415 #define CASE(n) case n: { \ 00416 DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n,cfunc->ptr); \ 00417 int ret; \ 00418 ret = f(DLSTACK_ARGS##n(stack)); \ 00419 result = INT2NUM(ret); \ 00420 } 00421 CALL_CASE; 00422 #undef CASE 00423 break; 00424 case DLTYPE_LONG: 00425 #define CASE(n) case n: { \ 00426 DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n,cfunc->ptr); \ 00427 long ret; \ 00428 ret = f(DLSTACK_ARGS##n(stack)); \ 00429 result = LONG2NUM(ret); \ 00430 } 00431 CALL_CASE; 00432 #undef CASE 00433 break; 00434 #if HAVE_LONG_LONG /* used in ruby.h */ 00435 case DLTYPE_LONG_LONG: 00436 #define CASE(n) case n: { \ 00437 DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO##n,cfunc->ptr); \ 00438 LONG_LONG ret; \ 00439 ret = f(DLSTACK_ARGS##n(stack)); \ 00440 result = LL2NUM(ret); \ 00441 } 00442 CALL_CASE; 00443 #undef CASE 00444 break; 00445 #endif 00446 case DLTYPE_FLOAT: 00447 #define CASE(n) case n: { \ 00448 DECL_FUNC_CDECL(f,float,DLSTACK_PROTO##n,cfunc->ptr); \ 00449 float ret; \ 00450 ret = f(DLSTACK_ARGS##n(stack)); \ 00451 result = rb_float_new(ret); \ 00452 } 00453 CALL_CASE; 00454 #undef CASE 00455 break; 00456 case DLTYPE_DOUBLE: 00457 #define CASE(n) case n: { \ 00458 DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n,cfunc->ptr); \ 00459 double ret; \ 00460 ret = f(DLSTACK_ARGS##n(stack)); \ 00461 result = rb_float_new(ret); \ 00462 } 00463 CALL_CASE; 00464 #undef CASE 00465 break; 00466 default: 00467 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type); 00468 } 00469 } 00470 #ifdef FUNC_STDCALL 00471 else if( cfunc->calltype == CFUNC_STDCALL ){ 00472 /* calltype == CFUNC_STDCALL */ 00473 switch( cfunc->type ){ 00474 case DLTYPE_VOID: 00475 #define CASE(n) case n: { \ 00476 DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00477 f(DLSTACK_ARGS##n(stack)); \ 00478 result = Qnil; \ 00479 } 00480 CALL_CASE; 00481 #undef CASE 00482 break; 00483 case DLTYPE_VOIDP: 00484 #define CASE(n) case n: { \ 00485 DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00486 void * ret; \ 00487 ret = f(DLSTACK_ARGS##n(stack)); \ 00488 result = PTR2NUM(ret); \ 00489 } 00490 CALL_CASE; 00491 #undef CASE 00492 break; 00493 case DLTYPE_CHAR: 00494 #define CASE(n) case n: { \ 00495 DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00496 char ret; \ 00497 ret = f(DLSTACK_ARGS##n(stack)); \ 00498 result = CHR2FIX(ret); \ 00499 } 00500 CALL_CASE; 00501 #undef CASE 00502 break; 00503 case DLTYPE_SHORT: 00504 #define CASE(n) case n: { \ 00505 DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00506 short ret; \ 00507 ret = f(DLSTACK_ARGS##n(stack)); \ 00508 result = INT2NUM((int)ret); \ 00509 } 00510 CALL_CASE; 00511 #undef CASE 00512 break; 00513 case DLTYPE_INT: 00514 #define CASE(n) case n: { \ 00515 DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00516 int ret; \ 00517 ret = f(DLSTACK_ARGS##n(stack)); \ 00518 result = INT2NUM(ret); \ 00519 } 00520 CALL_CASE; 00521 #undef CASE 00522 break; 00523 case DLTYPE_LONG: 00524 #define CASE(n) case n: { \ 00525 DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00526 long ret; \ 00527 ret = f(DLSTACK_ARGS##n(stack)); \ 00528 result = LONG2NUM(ret); \ 00529 } 00530 CALL_CASE; 00531 #undef CASE 00532 break; 00533 #if HAVE_LONG_LONG /* used in ruby.h */ 00534 case DLTYPE_LONG_LONG: 00535 #define CASE(n) case n: { \ 00536 DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00537 LONG_LONG ret; \ 00538 ret = f(DLSTACK_ARGS##n(stack)); \ 00539 result = LL2NUM(ret); \ 00540 } 00541 CALL_CASE; 00542 #undef CASE 00543 break; 00544 #endif 00545 case DLTYPE_FLOAT: 00546 #define CASE(n) case n: { \ 00547 DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00548 float ret; \ 00549 ret = f(DLSTACK_ARGS##n(stack)); \ 00550 result = rb_float_new(ret); \ 00551 } 00552 CALL_CASE; 00553 #undef CASE 00554 break; 00555 case DLTYPE_DOUBLE: 00556 #define CASE(n) case n: { \ 00557 DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO##n##_,cfunc->ptr); \ 00558 double ret; \ 00559 ret = f(DLSTACK_ARGS##n(stack)); \ 00560 result = rb_float_new(ret); \ 00561 } 00562 CALL_CASE; 00563 #undef CASE 00564 break; 00565 default: 00566 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type); 00567 } 00568 } 00569 #endif 00570 else{ 00571 rb_raise(rb_eDLError, 00572 #ifndef LONG_LONG_VALUE 00573 "unsupported call type: %lx", 00574 #else 00575 "unsupported call type: %llx", 00576 #endif 00577 cfunc->calltype); 00578 } 00579 00580 rb_dl_set_last_error(self, INT2NUM(errno)); 00581 #if defined(_WIN32) 00582 rb_dl_set_win32_last_error(self, INT2NUM(GetLastError())); 00583 #endif 00584 00585 return result; 00586 } 00587 #if defined(_MSC_VER) && defined(_M_AMD64) && _MSC_VER == 1500 00588 # pragma optimize("", on) 00589 #endif 00590 00591 /* 00592 * call-seq: 00593 * dlfunc.to_i => integer 00594 * 00595 * Returns the memory location of this function pointer as an integer. 00596 */ 00597 static VALUE 00598 rb_dlcfunc_to_i(VALUE self) 00599 { 00600 struct cfunc_data *cfunc; 00601 00602 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc); 00603 return PTR2NUM(cfunc->ptr); 00604 } 00605 00606 void 00607 Init_dlcfunc(void) 00608 { 00609 id_last_error = rb_intern("__DL2_LAST_ERROR__"); 00610 #if defined(_WIN32) 00611 id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__"); 00612 #endif 00613 rb_cDLCFunc = rb_define_class_under(rb_mDL, "CFunc", rb_cObject); 00614 rb_define_alloc_func(rb_cDLCFunc, rb_dlcfunc_s_allocate); 00615 rb_define_module_function(rb_cDLCFunc, "last_error", rb_dl_get_last_error, 0); 00616 #if defined(_WIN32) 00617 rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0); 00618 #endif 00619 rb_define_method(rb_cDLCFunc, "initialize", rb_dlcfunc_initialize, -1); 00620 rb_define_method(rb_cDLCFunc, "call", rb_dlcfunc_call, 1); 00621 rb_define_method(rb_cDLCFunc, "[]", rb_dlcfunc_call, 1); 00622 rb_define_method(rb_cDLCFunc, "name", rb_dlcfunc_name, 0); 00623 rb_define_method(rb_cDLCFunc, "ctype", rb_dlcfunc_ctype, 0); 00624 rb_define_method(rb_cDLCFunc, "ctype=", rb_dlcfunc_set_ctype, 1); 00625 rb_define_method(rb_cDLCFunc, "calltype", rb_dlcfunc_calltype, 0); 00626 rb_define_method(rb_cDLCFunc, "calltype=", rb_dlcfunc_set_calltype, 1); 00627 rb_define_method(rb_cDLCFunc, "ptr", rb_dlcfunc_ptr, 0); 00628 rb_define_method(rb_cDLCFunc, "ptr=", rb_dlcfunc_set_ptr, 1); 00629 rb_define_method(rb_cDLCFunc, "inspect", rb_dlcfunc_inspect, 0); 00630 rb_define_method(rb_cDLCFunc, "to_s", rb_dlcfunc_inspect, 0); 00631 rb_define_method(rb_cDLCFunc, "to_i", rb_dlcfunc_to_i, 0); 00632 } 00633
1.7.3