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 == 1500
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 stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg);
00370 }
00371 else {
00372 Check_Type(arg, T_FIXNUM);
00373 }
00374 }
00375
00376
00377 if( cfunc->calltype == CFUNC_CDECL
00378 #ifndef FUNC_STDCALL
00379 || cfunc->calltype == CFUNC_STDCALL
00380 #endif
00381 ){
00382 switch( cfunc->type ){
00383 case DLTYPE_VOID:
00384 #define CASE(n) case n: { \
00385 DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \
00386 f(DLSTACK_ARGS##n(stack)); \
00387 result = Qnil; \
00388 }
00389 CALL_CASE;
00390 #undef CASE
00391 break;
00392 case DLTYPE_VOIDP:
00393 #define CASE(n) case n: { \
00394 DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n,cfunc->ptr); \
00395 void * ret; \
00396 ret = f(DLSTACK_ARGS##n(stack)); \
00397 result = PTR2NUM(ret); \
00398 }
00399 CALL_CASE;
00400 #undef CASE
00401 break;
00402 case DLTYPE_CHAR:
00403 #define CASE(n) case n: { \
00404 DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n,cfunc->ptr); \
00405 char ret; \
00406 ret = f(DLSTACK_ARGS##n(stack)); \
00407 result = CHR2FIX(ret); \
00408 }
00409 CALL_CASE;
00410 #undef CASE
00411 break;
00412 case DLTYPE_SHORT:
00413 #define CASE(n) case n: { \
00414 DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n,cfunc->ptr); \
00415 short ret; \
00416 ret = f(DLSTACK_ARGS##n(stack)); \
00417 result = INT2NUM((int)ret); \
00418 }
00419 CALL_CASE;
00420 #undef CASE
00421 break;
00422 case DLTYPE_INT:
00423 #define CASE(n) case n: { \
00424 DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n,cfunc->ptr); \
00425 int ret; \
00426 ret = f(DLSTACK_ARGS##n(stack)); \
00427 result = INT2NUM(ret); \
00428 }
00429 CALL_CASE;
00430 #undef CASE
00431 break;
00432 case DLTYPE_LONG:
00433 #define CASE(n) case n: { \
00434 DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n,cfunc->ptr); \
00435 long ret; \
00436 ret = f(DLSTACK_ARGS##n(stack)); \
00437 result = LONG2NUM(ret); \
00438 }
00439 CALL_CASE;
00440 #undef CASE
00441 break;
00442 #if HAVE_LONG_LONG
00443 case DLTYPE_LONG_LONG:
00444 #define CASE(n) case n: { \
00445 DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO##n,cfunc->ptr); \
00446 LONG_LONG ret; \
00447 ret = f(DLSTACK_ARGS##n(stack)); \
00448 result = LL2NUM(ret); \
00449 }
00450 CALL_CASE;
00451 #undef CASE
00452 break;
00453 #endif
00454 case DLTYPE_FLOAT:
00455 #define CASE(n) case n: { \
00456 DECL_FUNC_CDECL(f,float,DLSTACK_PROTO##n,cfunc->ptr); \
00457 float ret; \
00458 ret = f(DLSTACK_ARGS##n(stack)); \
00459 result = rb_float_new(ret); \
00460 }
00461 CALL_CASE;
00462 #undef CASE
00463 break;
00464 case DLTYPE_DOUBLE:
00465 #define CASE(n) case n: { \
00466 DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n,cfunc->ptr); \
00467 double ret; \
00468 ret = f(DLSTACK_ARGS##n(stack)); \
00469 result = rb_float_new(ret); \
00470 }
00471 CALL_CASE;
00472 #undef CASE
00473 break;
00474 default:
00475 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
00476 }
00477 }
00478 #ifdef FUNC_STDCALL
00479 else if( cfunc->calltype == CFUNC_STDCALL ){
00480
00481 switch( cfunc->type ){
00482 case DLTYPE_VOID:
00483 #define CASE(n) case n: { \
00484 DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n##_,cfunc->ptr); \
00485 f(DLSTACK_ARGS##n(stack)); \
00486 result = Qnil; \
00487 }
00488 CALL_CASE;
00489 #undef CASE
00490 break;
00491 case DLTYPE_VOIDP:
00492 #define CASE(n) case n: { \
00493 DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n##_,cfunc->ptr); \
00494 void * ret; \
00495 ret = f(DLSTACK_ARGS##n(stack)); \
00496 result = PTR2NUM(ret); \
00497 }
00498 CALL_CASE;
00499 #undef CASE
00500 break;
00501 case DLTYPE_CHAR:
00502 #define CASE(n) case n: { \
00503 DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n##_,cfunc->ptr); \
00504 char ret; \
00505 ret = f(DLSTACK_ARGS##n(stack)); \
00506 result = CHR2FIX(ret); \
00507 }
00508 CALL_CASE;
00509 #undef CASE
00510 break;
00511 case DLTYPE_SHORT:
00512 #define CASE(n) case n: { \
00513 DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n##_,cfunc->ptr); \
00514 short ret; \
00515 ret = f(DLSTACK_ARGS##n(stack)); \
00516 result = INT2NUM((int)ret); \
00517 }
00518 CALL_CASE;
00519 #undef CASE
00520 break;
00521 case DLTYPE_INT:
00522 #define CASE(n) case n: { \
00523 DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n##_,cfunc->ptr); \
00524 int ret; \
00525 ret = f(DLSTACK_ARGS##n(stack)); \
00526 result = INT2NUM(ret); \
00527 }
00528 CALL_CASE;
00529 #undef CASE
00530 break;
00531 case DLTYPE_LONG:
00532 #define CASE(n) case n: { \
00533 DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n##_,cfunc->ptr); \
00534 long ret; \
00535 ret = f(DLSTACK_ARGS##n(stack)); \
00536 result = LONG2NUM(ret); \
00537 }
00538 CALL_CASE;
00539 #undef CASE
00540 break;
00541 #if HAVE_LONG_LONG
00542 case DLTYPE_LONG_LONG:
00543 #define CASE(n) case n: { \
00544 DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO##n##_,cfunc->ptr); \
00545 LONG_LONG ret; \
00546 ret = f(DLSTACK_ARGS##n(stack)); \
00547 result = LL2NUM(ret); \
00548 }
00549 CALL_CASE;
00550 #undef CASE
00551 break;
00552 #endif
00553 case DLTYPE_FLOAT:
00554 #define CASE(n) case n: { \
00555 DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO##n##_,cfunc->ptr); \
00556 float ret; \
00557 ret = f(DLSTACK_ARGS##n(stack)); \
00558 result = rb_float_new(ret); \
00559 }
00560 CALL_CASE;
00561 #undef CASE
00562 break;
00563 case DLTYPE_DOUBLE:
00564 #define CASE(n) case n: { \
00565 DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO##n##_,cfunc->ptr); \
00566 double ret; \
00567 ret = f(DLSTACK_ARGS##n(stack)); \
00568 result = rb_float_new(ret); \
00569 }
00570 CALL_CASE;
00571 #undef CASE
00572 break;
00573 default:
00574 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
00575 }
00576 }
00577 #endif
00578 else{
00579 const char *name = rb_id2name(cfunc->calltype);
00580 if( name ){
00581 rb_raise(rb_eDLError, "unsupported call type: %s",
00582 name);
00583 }
00584 else{
00585 rb_raise(rb_eDLError, "unsupported call type: %"PRIxVALUE,
00586 cfunc->calltype);
00587 }
00588 }
00589
00590 rb_dl_set_last_error(self, INT2NUM(errno));
00591 #if defined(_WIN32)
00592 rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
00593 #endif
00594
00595 return result;
00596 }
00597 #if defined(_MSC_VER) && defined(_M_AMD64) && _MSC_VER == 1500
00598 # pragma optimize("", on)
00599 #endif
00600
00601
00602
00603
00604
00605
00606
00607 static VALUE
00608 rb_dlcfunc_to_i(VALUE self)
00609 {
00610 struct cfunc_data *cfunc;
00611
00612 TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
00613 return PTR2NUM(cfunc->ptr);
00614 }
00615
00616 void
00617 Init_dlcfunc(void)
00618 {
00619 id_last_error = rb_intern("__DL2_LAST_ERROR__");
00620 #if defined(_WIN32)
00621 id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__");
00622 #endif
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 rb_cDLCFunc = rb_define_class_under(rb_mDL, "CFunc", rb_cObject);
00640 rb_define_alloc_func(rb_cDLCFunc, rb_dlcfunc_s_allocate);
00641
00642
00643
00644
00645
00646
00647 rb_define_module_function(rb_cDLCFunc, "last_error", rb_dl_get_last_error, 0);
00648 #if defined(_WIN32)
00649
00650
00651
00652
00653
00654
00655 rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0);
00656 #endif
00657 rb_define_method(rb_cDLCFunc, "initialize", rb_dlcfunc_initialize, -1);
00658 rb_define_method(rb_cDLCFunc, "call", rb_dlcfunc_call, 1);
00659 rb_define_method(rb_cDLCFunc, "[]", rb_dlcfunc_call, 1);
00660 rb_define_method(rb_cDLCFunc, "name", rb_dlcfunc_name, 0);
00661 rb_define_method(rb_cDLCFunc, "ctype", rb_dlcfunc_ctype, 0);
00662 rb_define_method(rb_cDLCFunc, "ctype=", rb_dlcfunc_set_ctype, 1);
00663 rb_define_method(rb_cDLCFunc, "calltype", rb_dlcfunc_calltype, 0);
00664 rb_define_method(rb_cDLCFunc, "calltype=", rb_dlcfunc_set_calltype, 1);
00665 rb_define_method(rb_cDLCFunc, "ptr", rb_dlcfunc_ptr, 0);
00666 rb_define_method(rb_cDLCFunc, "ptr=", rb_dlcfunc_set_ptr, 1);
00667 rb_define_method(rb_cDLCFunc, "inspect", rb_dlcfunc_inspect, 0);
00668 rb_define_method(rb_cDLCFunc, "to_s", rb_dlcfunc_inspect, 0);
00669 rb_define_method(rb_cDLCFunc, "to_i", rb_dlcfunc_to_i, 0);
00670 }
00671