• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/dl/cfunc.c

Go to the documentation of this file.
00001 /* -*- C -*-
00002  * $Id: cfunc.c 28156 2010-06-04 01:46:36Z nobu $
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(HAVE_WINDOWS_H)
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 /*
00320  * call-seq:
00321  *    dlcfunc.call(ary)   => some_value
00322  *    dlcfunc[ary]        => some_value
00323  *
00324  * Calls the function pointer passing in +ary+ as values to the underlying
00325  * C function.  The return value depends on the ctype.
00326  */
00327 static VALUE
00328 rb_dlcfunc_call(VALUE self, VALUE ary)
00329 {
00330     struct cfunc_data *cfunc;
00331     int i;
00332     DLSTACK_TYPE stack[DLSTACK_SIZE];
00333     VALUE result = Qnil;
00334 
00335     rb_secure_update(self);
00336 
00337     memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
00338     Check_Type(ary, T_ARRAY);
00339 
00340     TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
00341 
00342     if( cfunc->ptr == 0 ){
00343         rb_raise(rb_eDLError, "can't call null-function");
00344         return Qnil;
00345     }
00346 
00347     for( i = 0; i < RARRAY_LEN(ary); i++ ){
00348         VALUE arg;
00349         if( i >= DLSTACK_SIZE ){
00350             rb_raise(rb_eDLError, "too many arguments (stack overflow)");
00351         }
00352         arg = rb_to_int(RARRAY_PTR(ary)[i]);
00353         rb_check_safe_obj(arg);
00354         if (FIXNUM_P(arg)) {
00355             stack[i] = (DLSTACK_TYPE)FIX2LONG(arg);
00356         }
00357         else if (RB_TYPE_P(arg, T_BIGNUM)) {
00358             stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg);
00359         }
00360         else {
00361             Check_Type(arg, T_FIXNUM);
00362         }
00363     }
00364 
00365     /* calltype == CFUNC_CDECL */
00366     if( cfunc->calltype == CFUNC_CDECL
00367 #ifndef FUNC_STDCALL
00368         || cfunc->calltype == CFUNC_STDCALL
00369 #endif
00370         ){
00371         switch( cfunc->type ){
00372         case DLTYPE_VOID:
00373 #define CASE(n) case n: { \
00374             DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \
00375             f(DLSTACK_ARGS##n(stack)); \
00376             result = Qnil; \
00377 }
00378             CALL_CASE;
00379 #undef CASE
00380             break;
00381         case DLTYPE_VOIDP:
00382 #define CASE(n) case n: { \
00383             DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n,cfunc->ptr); \
00384             void * ret; \
00385             ret = f(DLSTACK_ARGS##n(stack)); \
00386             result = PTR2NUM(ret); \
00387 }
00388             CALL_CASE;
00389 #undef CASE
00390             break;
00391         case DLTYPE_CHAR:
00392 #define CASE(n) case n: { \
00393             DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n,cfunc->ptr); \
00394             char ret; \
00395             ret = f(DLSTACK_ARGS##n(stack)); \
00396             result = CHR2FIX(ret); \
00397 }
00398             CALL_CASE;
00399 #undef CASE
00400             break;
00401         case DLTYPE_SHORT:
00402 #define CASE(n) case n: { \
00403             DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n,cfunc->ptr); \
00404             short ret; \
00405             ret = f(DLSTACK_ARGS##n(stack)); \
00406             result = INT2NUM((int)ret); \
00407 }
00408             CALL_CASE;
00409 #undef CASE
00410             break;
00411         case DLTYPE_INT:
00412 #define CASE(n) case n: { \
00413             DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n,cfunc->ptr); \
00414             int ret; \
00415             ret = f(DLSTACK_ARGS##n(stack)); \
00416             result = INT2NUM(ret); \
00417 }
00418             CALL_CASE;
00419 #undef CASE
00420             break;
00421         case DLTYPE_LONG:
00422 #define CASE(n) case n: { \
00423             DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n,cfunc->ptr); \
00424             long ret; \
00425             ret = f(DLSTACK_ARGS##n(stack)); \
00426             result = LONG2NUM(ret); \
00427 }
00428             CALL_CASE;
00429 #undef CASE
00430             break;
00431 #if HAVE_LONG_LONG  /* used in ruby.h */
00432         case DLTYPE_LONG_LONG:
00433 #define CASE(n) case n: { \
00434             DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO##n,cfunc->ptr); \
00435             LONG_LONG ret; \
00436             ret = f(DLSTACK_ARGS##n(stack)); \
00437             result = LL2NUM(ret); \
00438 }
00439             CALL_CASE;
00440 #undef CASE
00441             break;
00442 #endif
00443         case DLTYPE_FLOAT:
00444 #define CASE(n) case n: { \
00445             DECL_FUNC_CDECL(f,float,DLSTACK_PROTO##n,cfunc->ptr); \
00446             float ret; \
00447             ret = f(DLSTACK_ARGS##n(stack)); \
00448             result = rb_float_new(ret); \
00449 }
00450             CALL_CASE;
00451 #undef CASE
00452             break;
00453         case DLTYPE_DOUBLE:
00454 #define CASE(n) case n: { \
00455             DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n,cfunc->ptr); \
00456             double ret; \
00457             ret = f(DLSTACK_ARGS##n(stack)); \
00458             result = rb_float_new(ret); \
00459 }
00460             CALL_CASE;
00461 #undef CASE
00462             break;
00463         default:
00464             rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
00465         }
00466     }
00467 #ifdef FUNC_STDCALL
00468     else if( cfunc->calltype == CFUNC_STDCALL ){
00469         /* calltype == CFUNC_STDCALL */
00470         switch( cfunc->type ){
00471         case DLTYPE_VOID:
00472 #define CASE(n) case n: { \
00473             DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n##_,cfunc->ptr); \
00474             f(DLSTACK_ARGS##n(stack)); \
00475             result = Qnil; \
00476 }
00477             CALL_CASE;
00478 #undef CASE
00479             break;
00480         case DLTYPE_VOIDP:
00481 #define CASE(n) case n: { \
00482             DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n##_,cfunc->ptr); \
00483             void * ret; \
00484             ret = f(DLSTACK_ARGS##n(stack)); \
00485             result = PTR2NUM(ret); \
00486 }
00487             CALL_CASE;
00488 #undef CASE
00489             break;
00490         case DLTYPE_CHAR:
00491 #define CASE(n) case n: { \
00492             DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n##_,cfunc->ptr); \
00493             char ret; \
00494             ret = f(DLSTACK_ARGS##n(stack)); \
00495             result = CHR2FIX(ret); \
00496 }
00497             CALL_CASE;
00498 #undef CASE
00499             break;
00500         case DLTYPE_SHORT:
00501 #define CASE(n) case n: { \
00502             DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n##_,cfunc->ptr); \
00503             short ret; \
00504             ret = f(DLSTACK_ARGS##n(stack)); \
00505             result = INT2NUM((int)ret); \
00506 }
00507             CALL_CASE;
00508 #undef CASE
00509             break;
00510         case DLTYPE_INT:
00511 #define CASE(n) case n: { \
00512             DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n##_,cfunc->ptr); \
00513             int ret; \
00514             ret = f(DLSTACK_ARGS##n(stack)); \
00515             result = INT2NUM(ret); \
00516 }
00517             CALL_CASE;
00518 #undef CASE
00519             break;
00520         case DLTYPE_LONG:
00521 #define CASE(n) case n: { \
00522             DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n##_,cfunc->ptr); \
00523             long ret; \
00524             ret = f(DLSTACK_ARGS##n(stack)); \
00525             result = LONG2NUM(ret); \
00526 }
00527             CALL_CASE;
00528 #undef CASE
00529             break;
00530 #if HAVE_LONG_LONG  /* used in ruby.h */
00531         case DLTYPE_LONG_LONG:
00532 #define CASE(n) case n: { \
00533             DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO##n##_,cfunc->ptr); \
00534             LONG_LONG ret; \
00535             ret = f(DLSTACK_ARGS##n(stack)); \
00536             result = LL2NUM(ret); \
00537 }
00538             CALL_CASE;
00539 #undef CASE
00540             break;
00541 #endif
00542         case DLTYPE_FLOAT:
00543 #define CASE(n) case n: { \
00544             DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO##n##_,cfunc->ptr); \
00545             float ret; \
00546             ret = f(DLSTACK_ARGS##n(stack)); \
00547             result = rb_float_new(ret); \
00548 }
00549             CALL_CASE;
00550 #undef CASE
00551             break;
00552         case DLTYPE_DOUBLE:
00553 #define CASE(n) case n: { \
00554             DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO##n##_,cfunc->ptr); \
00555             double ret; \
00556             ret = f(DLSTACK_ARGS##n(stack)); \
00557             result = rb_float_new(ret); \
00558 }
00559             CALL_CASE;
00560 #undef CASE
00561             break;
00562         default:
00563             rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
00564         }
00565     }
00566 #endif
00567     else{
00568         rb_raise(rb_eDLError,
00569 #ifndef LONG_LONG_VALUE
00570                  "unsupported call type: %lx",
00571 #else
00572                  "unsupported call type: %llx",
00573 #endif
00574                  cfunc->calltype);
00575     }
00576 
00577     rb_dl_set_last_error(self, INT2NUM(errno));
00578 #if defined(HAVE_WINDOWS_H)
00579     rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
00580 #endif
00581 
00582     return result;
00583 }
00584 
00585 /*
00586  * call-seq:
00587  *    dlfunc.to_i   => integer
00588  *
00589  * Returns the memory location of this function pointer as an integer.
00590  */
00591 static VALUE
00592 rb_dlcfunc_to_i(VALUE self)
00593 {
00594   struct cfunc_data *cfunc;
00595 
00596   TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
00597   return PTR2NUM(cfunc->ptr);
00598 }
00599 
00600 void
00601 Init_dlcfunc(void)
00602 {
00603     id_last_error = rb_intern("__DL2_LAST_ERROR__");
00604 #if defined(HAVE_WINDOWS_H)
00605     id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__");
00606 #endif
00607     rb_cDLCFunc = rb_define_class_under(rb_mDL, "CFunc", rb_cObject);
00608     rb_define_alloc_func(rb_cDLCFunc, rb_dlcfunc_s_allocate);
00609     rb_define_module_function(rb_cDLCFunc, "last_error", rb_dl_get_last_error, 0);
00610 #if defined(HAVE_WINDOWS_H)
00611     rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0);
00612 #endif
00613     rb_define_method(rb_cDLCFunc, "initialize", rb_dlcfunc_initialize, -1);
00614     rb_define_method(rb_cDLCFunc, "call", rb_dlcfunc_call, 1);
00615     rb_define_method(rb_cDLCFunc, "[]",   rb_dlcfunc_call, 1);
00616     rb_define_method(rb_cDLCFunc, "name", rb_dlcfunc_name, 0);
00617     rb_define_method(rb_cDLCFunc, "ctype", rb_dlcfunc_ctype, 0);
00618     rb_define_method(rb_cDLCFunc, "ctype=", rb_dlcfunc_set_ctype, 1);
00619     rb_define_method(rb_cDLCFunc, "calltype", rb_dlcfunc_calltype, 0);
00620     rb_define_method(rb_cDLCFunc, "calltype=", rb_dlcfunc_set_calltype, 1);
00621     rb_define_method(rb_cDLCFunc, "ptr",  rb_dlcfunc_ptr, 0);
00622     rb_define_method(rb_cDLCFunc, "ptr=", rb_dlcfunc_set_ptr, 1);
00623     rb_define_method(rb_cDLCFunc, "inspect", rb_dlcfunc_inspect, 0);
00624     rb_define_method(rb_cDLCFunc, "to_s", rb_dlcfunc_inspect, 0);
00625     rb_define_method(rb_cDLCFunc, "to_i", rb_dlcfunc_to_i, 0);
00626 }
00627 

Generated on Wed Sep 8 2010 09:55:00 for Ruby by  doxygen 1.7.1