Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/fiddle/closure.c

Go to the documentation of this file.

    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