|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 #include <fiddle.h> 00002 00003 VALUE cFiddleClosure; 00004 00005 typedef struct { 00006 void * code; 00007 ffi_closure *pcl; 00008 ffi_cif * cif; 00009 int argc; 00010 ffi_type **argv; 00011 } fiddle_closure; 00012 00013 #if defined(MACOSX) || defined(__linux) || defined(__OpenBSD__) 00014 #define DONT_USE_FFI_CLOSURE_ALLOC 00015 #endif 00016 00017 static void 00018 dealloc(void * ptr) 00019 { 00020 fiddle_closure * cls = (fiddle_closure *)ptr; 00021 #ifndef DONT_USE_FFI_CLOSURE_ALLOC 00022 ffi_closure_free(cls->pcl); 00023 #else 00024 munmap(cls->pcl, sizeof(cls->pcl)); 00025 #endif 00026 xfree(cls->cif); 00027 if (cls->argv) xfree(cls->argv); 00028 xfree(cls); 00029 } 00030 00031 static size_t 00032 closure_memsize(const void * ptr) 00033 { 00034 fiddle_closure * cls = (fiddle_closure *)ptr; 00035 size_t size = 0; 00036 00037 if (ptr) { 00038 size += sizeof(*cls); 00039 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API 00040 size += ffi_raw_size(cls->cif); 00041 #endif 00042 size += sizeof(*cls->argv); 00043 size += sizeof(ffi_closure); 00044 } 00045 return size; 00046 } 00047 00048 const rb_data_type_t closure_data_type = { 00049 "fiddle/closure", 00050 0, dealloc, closure_memsize, 00051 }; 00052 00053 void 00054 callback(ffi_cif *cif, void *resp, void **args, void *ctx) 00055 { 00056 VALUE self = (VALUE)ctx; 00057 VALUE rbargs = rb_iv_get(self, "@args"); 00058 VALUE ctype = rb_iv_get(self, "@ctype"); 00059 int argc = RARRAY_LENINT(rbargs); 00060 VALUE *params = xcalloc(argc, sizeof(VALUE *)); 00061 VALUE ret; 00062 VALUE cPointer; 00063 int i, type; 00064 00065 cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); 00066 00067 for (i = 0; i < argc; i++) { 00068 type = NUM2INT(RARRAY_PTR(rbargs)[i]); 00069 switch (type) { 00070 case TYPE_VOID: 00071 argc = 0; 00072 break; 00073 case TYPE_INT: 00074 params[i] = INT2NUM(*(int *)args[i]); 00075 break; 00076 case TYPE_VOIDP: 00077 params[i] = rb_funcall(cPointer, rb_intern("[]"), 1, 00078 PTR2NUM(*(void **)args[i])); 00079 break; 00080 case TYPE_LONG: 00081 params[i] = LONG2NUM(*(long *)args[i]); 00082 break; 00083 case TYPE_CHAR: 00084 params[i] = INT2NUM(*(char *)args[i]); 00085 break; 00086 case TYPE_DOUBLE: 00087 params[i] = rb_float_new(*(double *)args[i]); 00088 break; 00089 case TYPE_FLOAT: 00090 params[i] = rb_float_new(*(float *)args[i]); 00091 break; 00092 #if HAVE_LONG_LONG 00093 case TYPE_LONG_LONG: 00094 params[i] = rb_ull2inum(*(unsigned LONG_LONG *)args[i]); 00095 break; 00096 #endif 00097 default: 00098 rb_raise(rb_eRuntimeError, "closure args: %d", type); 00099 } 00100 } 00101 00102 ret = rb_funcall2(self, rb_intern("call"), argc, params); 00103 00104 type = NUM2INT(ctype); 00105 switch (type) { 00106 case TYPE_VOID: 00107 break; 00108 case TYPE_LONG: 00109 *(long *)resp = NUM2LONG(ret); 00110 break; 00111 case TYPE_CHAR: 00112 *(char *)resp = NUM2INT(ret); 00113 break; 00114 case TYPE_VOIDP: 00115 *(void **)resp = NUM2PTR(ret); 00116 break; 00117 case TYPE_INT: 00118 *(int *)resp = NUM2INT(ret); 00119 break; 00120 case TYPE_DOUBLE: 00121 *(double *)resp = NUM2DBL(ret); 00122 break; 00123 case TYPE_FLOAT: 00124 *(float *)resp = (float)NUM2DBL(ret); 00125 break; 00126 #if HAVE_LONG_LONG 00127 case TYPE_LONG_LONG: 00128 *(unsigned LONG_LONG *)resp = rb_big2ull(ret); 00129 break; 00130 #endif 00131 default: 00132 rb_raise(rb_eRuntimeError, "closure retval: %d", type); 00133 } 00134 xfree(params); 00135 } 00136 00137 static VALUE 00138 allocate(VALUE klass) 00139 { 00140 fiddle_closure * closure; 00141 00142 VALUE i = TypedData_Make_Struct(klass, fiddle_closure, 00143 &closure_data_type, closure); 00144 00145 #ifndef DONT_USE_FFI_CLOSURE_ALLOC 00146 closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code); 00147 #else 00148 closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, 00149 MAP_ANON | MAP_PRIVATE, -1, 0); 00150 #endif 00151 closure->cif = xmalloc(sizeof(ffi_cif)); 00152 00153 return i; 00154 } 00155 00156 static VALUE 00157 initialize(int rbargc, VALUE argv[], VALUE self) 00158 { 00159 VALUE ret; 00160 VALUE args; 00161 VALUE abi; 00162 fiddle_closure * cl; 00163 ffi_cif * cif; 00164 ffi_closure *pcl; 00165 ffi_status result; 00166 int i, argc; 00167 00168 if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi)) 00169 abi = INT2NUM(FFI_DEFAULT_ABI); 00170 00171 Check_Type(args, T_ARRAY); 00172 00173 argc = RARRAY_LENINT(args); 00174 00175 TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl); 00176 00177 cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *)); 00178 00179 for (i = 0; i < argc; i++) { 00180 int type = NUM2INT(RARRAY_PTR(args)[i]); 00181 cl->argv[i] = INT2FFI_TYPE(type); 00182 } 00183 cl->argv[argc] = NULL; 00184 00185 rb_iv_set(self, "@ctype", ret); 00186 rb_iv_set(self, "@args", args); 00187 00188 cif = cl->cif; 00189 pcl = cl->pcl; 00190 00191 result = ffi_prep_cif(cif, NUM2INT(abi), argc, 00192 INT2FFI_TYPE(NUM2INT(ret)), 00193 cl->argv); 00194 00195 if (FFI_OK != result) 00196 rb_raise(rb_eRuntimeError, "error prepping CIF %d", result); 00197 00198 #ifndef DONT_USE_FFI_CLOSURE_ALLOC 00199 result = ffi_prep_closure_loc(pcl, cif, callback, 00200 (void *)self, cl->code); 00201 #else 00202 result = ffi_prep_closure(pcl, cif, callback, (void *)self); 00203 cl->code = (void *)pcl; 00204 mprotect(pcl, sizeof(pcl), PROT_READ | PROT_EXEC); 00205 #endif 00206 00207 if (FFI_OK != result) 00208 rb_raise(rb_eRuntimeError, "error prepping closure %d", result); 00209 00210 return self; 00211 } 00212 00213 static VALUE 00214 to_i(VALUE self) 00215 { 00216 fiddle_closure * cl; 00217 void *code; 00218 00219 TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl); 00220 00221 code = cl->code; 00222 00223 return PTR2NUM(code); 00224 } 00225 00226 void 00227 Init_fiddle_closure() 00228 { 00229 cFiddleClosure = rb_define_class_under(mFiddle, "Closure", rb_cObject); 00230 00231 rb_define_alloc_func(cFiddleClosure, allocate); 00232 00233 rb_define_method(cFiddleClosure, "initialize", initialize, -1); 00234 rb_define_method(cFiddleClosure, "to_i", to_i, 0); 00235 } 00236 /* vim: set noet sw=4 sts=4 */ 00237
1.7.3