00001
00002
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
00140
00141
00142
00143
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
00170
00171
00172
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
00185
00186
00187
00188
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
00201
00202
00203
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
00217
00218
00219
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
00232
00233
00234
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
00248
00249
00250
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
00263
00264
00265
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
00280
00281
00282
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
00324
00325
00326
00327
00328
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
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
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
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
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
00593
00594
00595
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