Ruby  1.9.3p448(2013-06-27revision41675)
closure.c
Go to the documentation of this file.
1 #include <fiddle.h>
2 
4 
5 typedef struct {
6  void * code;
7  ffi_closure *pcl;
8  ffi_cif cif;
9  int argc;
10  ffi_type **argv;
12 
13 #if defined(MACOSX) || defined(__linux) || defined(__OpenBSD__)
14 #define DONT_USE_FFI_CLOSURE_ALLOC
15 #endif
16 
17 static void
18 dealloc(void * ptr)
19 {
20  fiddle_closure * cls = (fiddle_closure *)ptr;
21 #ifndef DONT_USE_FFI_CLOSURE_ALLOC
22  ffi_closure_free(cls->pcl);
23 #else
24  munmap(cls->pcl, sizeof(cls->pcl));
25 #endif
26  if (cls->argv) xfree(cls->argv);
27  xfree(cls);
28 }
29 
30 static size_t
31 closure_memsize(const void * ptr)
32 {
33  fiddle_closure * cls = (fiddle_closure *)ptr;
34  size_t size = 0;
35 
36  if (ptr) {
37  size += sizeof(*cls);
38 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
39  size += ffi_raw_size(&cls->cif);
40 #endif
41  size += sizeof(*cls->argv);
42  size += sizeof(ffi_closure);
43  }
44  return size;
45 }
46 
48  "fiddle/closure",
49  {0, dealloc, closure_memsize,},
50 };
51 
52 void
53 callback(ffi_cif *cif, void *resp, void **args, void *ctx)
54 {
55  VALUE self = (VALUE)ctx;
56  VALUE rbargs = rb_iv_get(self, "@args");
57  VALUE ctype = rb_iv_get(self, "@ctype");
58  int argc = RARRAY_LENINT(rbargs);
59  VALUE params = rb_ary_tmp_new(argc);
60  VALUE ret;
61  VALUE cPointer;
62  int i, type;
63 
64  cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
65 
66  for (i = 0; i < argc; i++) {
67  type = NUM2INT(RARRAY_PTR(rbargs)[i]);
68  switch (type) {
69  case TYPE_VOID:
70  argc = 0;
71  break;
72  case TYPE_INT:
73  rb_ary_push(params, INT2NUM(*(int *)args[i]));
74  break;
75  case -TYPE_INT:
76  rb_ary_push(params, UINT2NUM(*(unsigned int *)args[i]));
77  break;
78  case TYPE_VOIDP:
79  rb_ary_push(params,
80  rb_funcall(cPointer, rb_intern("[]"), 1,
81  PTR2NUM(*(void **)args[i])));
82  break;
83  case TYPE_LONG:
84  rb_ary_push(params, LONG2NUM(*(long *)args[i]));
85  break;
86  case -TYPE_LONG:
87  rb_ary_push(params, ULONG2NUM(*(unsigned long *)args[i]));
88  break;
89  case TYPE_CHAR:
90  rb_ary_push(params, INT2NUM(*(signed char *)args[i]));
91  break;
92  case -TYPE_CHAR:
93  rb_ary_push(params, UINT2NUM(*(unsigned char *)args[i]));
94  break;
95  case TYPE_SHORT:
96  rb_ary_push(params, INT2NUM(*(signed short *)args[i]));
97  break;
98  case -TYPE_SHORT:
99  rb_ary_push(params, UINT2NUM(*(unsigned short *)args[i]));
100  break;
101  case TYPE_DOUBLE:
102  rb_ary_push(params, rb_float_new(*(double *)args[i]));
103  break;
104  case TYPE_FLOAT:
105  rb_ary_push(params, rb_float_new(*(float *)args[i]));
106  break;
107 #if HAVE_LONG_LONG
108  case TYPE_LONG_LONG:
109  rb_ary_push(params, LL2NUM(*(LONG_LONG *)args[i]));
110  break;
111  case -TYPE_LONG_LONG:
112  rb_ary_push(params, ULL2NUM(*(unsigned LONG_LONG *)args[i]));
113  break;
114 #endif
115  default:
116  rb_raise(rb_eRuntimeError, "closure args: %d", type);
117  }
118  }
119 
120  ret = rb_funcall2(self, rb_intern("call"), argc, RARRAY_PTR(params));
121  RB_GC_GUARD(params);
122 
123  type = NUM2INT(ctype);
124  switch (type) {
125  case TYPE_VOID:
126  break;
127  case TYPE_LONG:
128  *(long *)resp = NUM2LONG(ret);
129  break;
130  case -TYPE_LONG:
131  *(unsigned long *)resp = NUM2ULONG(ret);
132  break;
133  case TYPE_CHAR:
134  case TYPE_SHORT:
135  case TYPE_INT:
136  *(ffi_sarg *)resp = NUM2INT(ret);
137  break;
138  case -TYPE_CHAR:
139  case -TYPE_SHORT:
140  case -TYPE_INT:
141  *(ffi_arg *)resp = NUM2UINT(ret);
142  break;
143  case TYPE_VOIDP:
144  *(void **)resp = NUM2PTR(ret);
145  break;
146  case TYPE_DOUBLE:
147  *(double *)resp = NUM2DBL(ret);
148  break;
149  case TYPE_FLOAT:
150  *(float *)resp = (float)NUM2DBL(ret);
151  break;
152 #if HAVE_LONG_LONG
153  case TYPE_LONG_LONG:
154  *(LONG_LONG *)resp = NUM2LL(ret);
155  break;
156  case -TYPE_LONG_LONG:
157  *(unsigned LONG_LONG *)resp = NUM2ULL(ret);
158  break;
159 #endif
160  default:
161  rb_raise(rb_eRuntimeError, "closure retval: %d", type);
162  }
163 }
164 
165 static VALUE
167 {
168  fiddle_closure * closure;
169 
171  &closure_data_type, closure);
172 
173 #ifndef DONT_USE_FFI_CLOSURE_ALLOC
174  closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
175 #else
176  closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
177  MAP_ANON | MAP_PRIVATE, -1, 0);
178 #endif
179 
180  return i;
181 }
182 
183 static VALUE
184 initialize(int rbargc, VALUE argv[], VALUE self)
185 {
186  VALUE ret;
187  VALUE args;
188  VALUE abi;
189  fiddle_closure * cl;
190  ffi_cif * cif;
191  ffi_closure *pcl;
192  ffi_status result;
193  int i, argc;
194 
195  if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
196  abi = INT2NUM(FFI_DEFAULT_ABI);
197 
198  Check_Type(args, T_ARRAY);
199 
200  argc = RARRAY_LENINT(args);
201 
202  TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
203 
204  cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));
205 
206  for (i = 0; i < argc; i++) {
207  int type = NUM2INT(RARRAY_PTR(args)[i]);
208  cl->argv[i] = INT2FFI_TYPE(type);
209  }
210  cl->argv[argc] = NULL;
211 
212  rb_iv_set(self, "@ctype", ret);
213  rb_iv_set(self, "@args", args);
214 
215  cif = &cl->cif;
216  pcl = cl->pcl;
217 
218  result = ffi_prep_cif(cif, NUM2INT(abi), argc,
219  INT2FFI_TYPE(NUM2INT(ret)),
220  cl->argv);
221 
222  if (FFI_OK != result)
223  rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
224 
225 #ifndef DONT_USE_FFI_CLOSURE_ALLOC
226  result = ffi_prep_closure_loc(pcl, cif, callback,
227  (void *)self, cl->code);
228 #else
229  result = ffi_prep_closure(pcl, cif, callback, (void *)self);
230  cl->code = (void *)pcl;
231  mprotect(pcl, sizeof(pcl), PROT_READ | PROT_EXEC);
232 #endif
233 
234  if (FFI_OK != result)
235  rb_raise(rb_eRuntimeError, "error prepping closure %d", result);
236 
237  return self;
238 }
239 
240 static VALUE
241 to_i(VALUE self)
242 {
243  fiddle_closure * cl;
244  void *code;
245 
246  TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
247 
248  code = cl->code;
249 
250  return PTR2NUM(code);
251 }
252 
253 void
255 {
256 #if 0
257  mFiddle = rb_define_module("Fiddle"); /* let rdoc know about mFiddle */
258 #endif
259 
260  /*
261  * Document-class: Fiddle::Closure
262  *
263  * == Description
264  *
265  * An FFI closure wrapper, for handling callbacks.
266  *
267  * == Example
268  *
269  * closure = Class.new(Fiddle::Closure) {
270  * def call
271  * 10
272  * end
273  * }.new(Fiddle::TYPE_INT, [])
274  * => #<#<Class:0x0000000150d308>:0x0000000150d240>
275  * func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
276  * => #<Fiddle::Function:0x00000001516e58>
277  * func.call
278  * => 10
279  */
281 
283 
284  /*
285  * Document-method: new
286  *
287  * call-seq: new(ret, args, abi = Fiddle::DEFAULT)
288  *
289  * Construct a new Closure object.
290  *
291  * * +ret+ is the C type to be returned
292  * * +args+ are passed the callback
293  * * +abi+ is the abi of the closure
294  *
295  * If there is an error in preparing the ffi_cif or ffi_prep_closure,
296  * then a RuntimeError will be raised.
297  */
298  rb_define_method(cFiddleClosure, "initialize", initialize, -1);
299 
300  /*
301  * Document-method: to_i
302  *
303  * Returns the memory address for this closure
304  */
305  rb_define_method(cFiddleClosure, "to_i", to_i, 0);
306 }
307 /* vim: set noet sw=4 sts=4 */
static long NUM2LONG(VALUE x)
Definition: ruby.h:510
static VALUE UINT2NUM(unsigned int v)
Definition: ruby.h:992
#define TYPE_VOIDP
Definition: fiddle.h:89
VALUE mFiddle
Definition: fiddle.c:3
int i
Definition: win32ole.c:776
#define NUM2INT(x)
Definition: ruby.h:536
#define NUM2UINT(x)
Definition: ruby.h:537
#define LONG2NUM(i)
Definition: cparse.c:72
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:840
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:740
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:380
static VALUE INT2NUM(int v)
Definition: ruby.h:981
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:638
#define NUM2PTR(x)
Definition: dl.h:178
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:514
#define Check_Type(v, t)
Definition: ruby.h:459
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1574
#define TYPE_CHAR
Definition: fiddle.h:90
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define T_ARRAY
Definition: ruby.h:420
#define TYPE_SHORT
Definition: fiddle.h:91
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:53
#define NUM2DBL(x)
Definition: ruby.h:574
int args
Definition: win32ole.c:777
#define TYPE_INT
Definition: fiddle.h:92
#define TYPE_DOUBLE
Definition: fiddle.h:98
#define TYPE_LONG
Definition: fiddle.h:93
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1246
VALUE rb_eRuntimeError
Definition: error.c:466
static VALUE to_i(VALUE self)
Definition: closure.c:241
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2220
const rb_data_type_t closure_data_type
Definition: closure.c:47
#define PTR2NUM(x)
Definition: dl.h:177
int argc
Definition: ruby.c:120
ffi_closure * pcl
Definition: closure.c:7
#define INT2FFI_TYPE(_type)
Definition: conversions.h:32
ffi_type ** argv
Definition: closure.c:10
static void dealloc(void *ptr)
Definition: closure.c:18
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1635
VALUE rb_funcall2(VALUE, ID, int, const VALUE *)
Calls a method.
Definition: vm_eval.c:669
#define RB_GC_GUARD(object)
Definition: generator.h:50
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2228
static VALUE initialize(int rbargc, VALUE argv[], VALUE self)
Definition: closure.c:184
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1415
#define NULL
int type
Definition: tcltklib.c:107
unsigned long VALUE
Definition: ruby.h:88
static VALUE result
Definition: nkf.c:40
#define RARRAY_PTR(ARRAY)
Definition: generator.h:36
ffi_cif cif
Definition: closure.c:8
#define RARRAY_LENINT(ary)
Definition: ruby.h:718
void xfree(void *)
#define TYPE_FLOAT
Definition: fiddle.h:97
VALUE rb_float_new(double)
Definition: numeric.c:582
static VALUE allocate(VALUE klass)
Definition: closure.c:166
VALUE cFiddleClosure
Definition: closure.c:3
int size
Definition: encoding.c:51
#define TYPE_VOID
Definition: fiddle.h:88
static VALUE ULONG2NUM(unsigned long v)
Definition: ruby.h:1015
#define NUM2ULONG(x)
Definition: ruby.h:515
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:829
void Init_fiddle_closure()
Definition: closure.c:254
void * code
Definition: closure.c:6
VALUE rb_define_module(const char *name)
Definition: class.c:586
#define rb_intern(str)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1209
static size_t closure_memsize(const void *ptr)
Definition: closure.c:31
char ** argv
Definition: ruby.c:121
#define xcalloc
Definition: defines.h:66