Ruby  2.0.0p648(2015-12-16revision53162)
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  i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
232  if (i) {
233  rb_sys_fail("mprotect");
234  }
235 #endif
236 
237  if (FFI_OK != result)
238  rb_raise(rb_eRuntimeError, "error prepping closure %d", result);
239 
240  return self;
241 }
242 
243 static VALUE
244 to_i(VALUE self)
245 {
246  fiddle_closure * cl;
247  void *code;
248 
249  TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
250 
251  code = cl->code;
252 
253  return PTR2NUM(code);
254 }
255 
256 void
258 {
259 #if 0
260  mFiddle = rb_define_module("Fiddle"); /* let rdoc know about mFiddle */
261 #endif
262 
263  /*
264  * Document-class: Fiddle::Closure
265  *
266  * == Description
267  *
268  * An FFI closure wrapper, for handling callbacks.
269  *
270  * == Example
271  *
272  * closure = Class.new(Fiddle::Closure) {
273  * def call
274  * 10
275  * end
276  * }.new(Fiddle::TYPE_INT, [])
277  * #=> #<#<Class:0x0000000150d308>:0x0000000150d240>
278  * func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
279  * #=> #<Fiddle::Function:0x00000001516e58>
280  * func.call
281  * #=> 10
282  */
284 
286 
287  /*
288  * Document-method: new
289  *
290  * call-seq: new(ret, args, abi = Fiddle::DEFAULT)
291  *
292  * Construct a new Closure object.
293  *
294  * * +ret+ is the C type to be returned
295  * * +args+ is an Array of arguments, passed to the callback function
296  * * +abi+ is the abi of the closure
297  *
298  * If there is an error in preparing the ffi_cif or ffi_prep_closure,
299  * then a RuntimeError will be raised.
300  */
301  rb_define_method(cFiddleClosure, "initialize", initialize, -1);
302 
303  /*
304  * Document-method: to_i
305  *
306  * Returns the memory address for this closure
307  */
308  rb_define_method(cFiddleClosure, "to_i", to_i, 0);
309 }
310 /* vim: set noet sw=4 sts=4 */
#define TYPE_VOIDP
Definition: fiddle.h:113
VALUE mFiddle
Definition: fiddle.c:3
#define INT2NUM(x)
Definition: ruby.h:1178
int i
Definition: win32ole.c:784
#define NUM2INT(x)
Definition: ruby.h:622
#define NUM2UINT(x)
Definition: ruby.h:623
static VALUE rb_float_new(double d)
Definition: ruby.h:790
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1030
#define ULONG2NUM(x)
Definition: ruby.h:1209
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:465
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:773
#define NUM2PTR(x)
Definition: dl.h:169
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:534
#define Check_Type(v, t)
Definition: ruby.h:539
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1788
#define TYPE_CHAR
Definition: fiddle.h:114
#define RB_GC_GUARD(v)
Definition: ruby.h:530
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define T_ARRAY
Definition: ruby.h:492
#define TYPE_SHORT
Definition: fiddle.h:115
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:53
#define NUM2DBL(x)
Definition: ruby.h:675
int args
Definition: win32ole.c:785
#define TYPE_INT
Definition: fiddle.h:116
#define TYPE_DOUBLE
Definition: fiddle.h:122
#define TYPE_LONG
Definition: fiddle.h:117
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
VALUE rb_eRuntimeError
Definition: error.c:515
static VALUE to_i(VALUE self)
Definition: closure.c:244
#define UINT2NUM(x)
Definition: ruby.h:1188
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2586
const rb_data_type_t closure_data_type
Definition: closure.c:47
#define PTR2NUM(x)
Definition: dl.h:168
int argc
Definition: ruby.c:130
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:1876
VALUE rb_funcall2(VALUE, ID, int, const VALUE *)
Calls a method.
Definition: vm_eval.c:804
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2594
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:1570
int type
Definition: tcltklib.c:111
unsigned long VALUE
Definition: ruby.h:104
static VALUE result
Definition: nkf.c:40
ffi_cif cif
Definition: closure.c:8
#define RARRAY_LENINT(ary)
Definition: ruby.h:908
void rb_sys_fail(const char *mesg)
Definition: error.c:1907
void xfree(void *)
#define LONG2NUM(x)
Definition: ruby.h:1199
#define TYPE_FLOAT
Definition: fiddle.h:121
static VALUE allocate(VALUE klass)
Definition: closure.c:166
VALUE cFiddleClosure
Definition: closure.c:3
int size
Definition: encoding.c:52
#define TYPE_VOID
Definition: fiddle.h:112
#define NUM2ULONG(x)
Definition: ruby.h:601
#define RARRAY_PTR(a)
Definition: ruby.h:904
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1019
void Init_fiddle_closure()
Definition: closure.c:257
void * code
Definition: closure.c:6
VALUE rb_define_module(const char *name)
Definition: class.c:606
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
static size_t closure_memsize(const void *ptr)
Definition: closure.c:31
#define NUM2LONG(x)
Definition: ruby.h:592
char ** argv
Definition: ruby.c:131
#define xcalloc
Definition: defines.h:66