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