Ruby  2.1.10p492(2016-04-01revision54464)
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(USE_FFI_CLOSURE_ALLOC)
14 #elif defined(__OpenBSD__) || defined(__APPLE__) || defined(__linux__)
15 # define USE_FFI_CLOSURE_ALLOC 0
16 #elif defined(RUBY_LIBFFI_MODVERSION) && RUBY_LIBFFI_MODVERSION < 3000005 && \
17  (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64))
18 # define USE_FFI_CLOSURE_ALLOC 0
19 #else
20 # define USE_FFI_CLOSURE_ALLOC 1
21 #endif
22 
23 static void
24 dealloc(void * ptr)
25 {
26  fiddle_closure * cls = (fiddle_closure *)ptr;
27 #if USE_FFI_CLOSURE_ALLOC
28  ffi_closure_free(cls->pcl);
29 #else
30  munmap(cls->pcl, sizeof(*cls->pcl));
31 #endif
32  if (cls->argv) xfree(cls->argv);
33  xfree(cls);
34 }
35 
36 static size_t
37 closure_memsize(const void * ptr)
38 {
39  fiddle_closure * cls = (fiddle_closure *)ptr;
40  size_t size = 0;
41 
42  if (ptr) {
43  size += sizeof(*cls);
44 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
45  size += ffi_raw_size(&cls->cif);
46 #endif
47  size += sizeof(*cls->argv);
48  size += sizeof(ffi_closure);
49  }
50  return size;
51 }
52 
54  "fiddle/closure",
55  {0, dealloc, closure_memsize,},
56 };
57 
58 void
59 callback(ffi_cif *cif, void *resp, void **args, void *ctx)
60 {
61  VALUE self = (VALUE)ctx;
62  VALUE rbargs = rb_iv_get(self, "@args");
63  VALUE ctype = rb_iv_get(self, "@ctype");
64  int argc = RARRAY_LENINT(rbargs);
65  VALUE params = rb_ary_tmp_new(argc);
66  VALUE ret;
67  VALUE cPointer;
68  int i, type;
69 
70  cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
71 
72  for (i = 0; i < argc; i++) {
73  type = NUM2INT(RARRAY_PTR(rbargs)[i]);
74  switch (type) {
75  case TYPE_VOID:
76  argc = 0;
77  break;
78  case TYPE_INT:
79  rb_ary_push(params, INT2NUM(*(int *)args[i]));
80  break;
81  case -TYPE_INT:
82  rb_ary_push(params, UINT2NUM(*(unsigned int *)args[i]));
83  break;
84  case TYPE_VOIDP:
85  rb_ary_push(params,
86  rb_funcall(cPointer, rb_intern("[]"), 1,
87  PTR2NUM(*(void **)args[i])));
88  break;
89  case TYPE_LONG:
90  rb_ary_push(params, LONG2NUM(*(long *)args[i]));
91  break;
92  case -TYPE_LONG:
93  rb_ary_push(params, ULONG2NUM(*(unsigned long *)args[i]));
94  break;
95  case TYPE_CHAR:
96  rb_ary_push(params, INT2NUM(*(signed char *)args[i]));
97  break;
98  case -TYPE_CHAR:
99  rb_ary_push(params, UINT2NUM(*(unsigned char *)args[i]));
100  break;
101  case TYPE_SHORT:
102  rb_ary_push(params, INT2NUM(*(signed short *)args[i]));
103  break;
104  case -TYPE_SHORT:
105  rb_ary_push(params, UINT2NUM(*(unsigned short *)args[i]));
106  break;
107  case TYPE_DOUBLE:
108  rb_ary_push(params, rb_float_new(*(double *)args[i]));
109  break;
110  case TYPE_FLOAT:
111  rb_ary_push(params, rb_float_new(*(float *)args[i]));
112  break;
113 #if HAVE_LONG_LONG
114  case TYPE_LONG_LONG:
115  rb_ary_push(params, LL2NUM(*(LONG_LONG *)args[i]));
116  break;
117  case -TYPE_LONG_LONG:
118  rb_ary_push(params, ULL2NUM(*(unsigned LONG_LONG *)args[i]));
119  break;
120 #endif
121  default:
122  rb_raise(rb_eRuntimeError, "closure args: %d", type);
123  }
124  }
125 
126  ret = rb_funcall2(self, rb_intern("call"), argc, RARRAY_PTR(params));
127  RB_GC_GUARD(params);
128 
129  type = NUM2INT(ctype);
130  switch (type) {
131  case TYPE_VOID:
132  break;
133  case TYPE_LONG:
134  *(long *)resp = NUM2LONG(ret);
135  break;
136  case -TYPE_LONG:
137  *(unsigned long *)resp = NUM2ULONG(ret);
138  break;
139  case TYPE_CHAR:
140  case TYPE_SHORT:
141  case TYPE_INT:
142  *(ffi_sarg *)resp = NUM2INT(ret);
143  break;
144  case -TYPE_CHAR:
145  case -TYPE_SHORT:
146  case -TYPE_INT:
147  *(ffi_arg *)resp = NUM2UINT(ret);
148  break;
149  case TYPE_VOIDP:
150  *(void **)resp = NUM2PTR(ret);
151  break;
152  case TYPE_DOUBLE:
153  *(double *)resp = NUM2DBL(ret);
154  break;
155  case TYPE_FLOAT:
156  *(float *)resp = (float)NUM2DBL(ret);
157  break;
158 #if HAVE_LONG_LONG
159  case TYPE_LONG_LONG:
160  *(LONG_LONG *)resp = NUM2LL(ret);
161  break;
162  case -TYPE_LONG_LONG:
163  *(unsigned LONG_LONG *)resp = NUM2ULL(ret);
164  break;
165 #endif
166  default:
167  rb_raise(rb_eRuntimeError, "closure retval: %d", type);
168  }
169 }
170 
171 static VALUE
173 {
174  fiddle_closure * closure;
175 
177  &closure_data_type, closure);
178 
179 #if USE_FFI_CLOSURE_ALLOC
180  closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
181 #else
182  closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
183  MAP_ANON | MAP_PRIVATE, -1, 0);
184 #endif
185 
186  return i;
187 }
188 
189 static VALUE
190 initialize(int rbargc, VALUE argv[], VALUE self)
191 {
192  VALUE ret;
193  VALUE args;
194  VALUE abi;
195  fiddle_closure * cl;
196  ffi_cif * cif;
197  ffi_closure *pcl;
198  ffi_status result;
199  int i, argc;
200 
201  if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
202  abi = INT2NUM(FFI_DEFAULT_ABI);
203 
204  Check_Type(args, T_ARRAY);
205 
206  argc = RARRAY_LENINT(args);
207 
208  TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
209 
210  cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));
211 
212  for (i = 0; i < argc; i++) {
213  int type = NUM2INT(RARRAY_PTR(args)[i]);
214  cl->argv[i] = INT2FFI_TYPE(type);
215  }
216  cl->argv[argc] = NULL;
217 
218  rb_iv_set(self, "@ctype", ret);
219  rb_iv_set(self, "@args", args);
220 
221  cif = &cl->cif;
222  pcl = cl->pcl;
223 
224  result = ffi_prep_cif(cif, NUM2INT(abi), argc,
225  INT2FFI_TYPE(NUM2INT(ret)),
226  cl->argv);
227 
228  if (FFI_OK != result)
229  rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
230 
231 #if USE_FFI_CLOSURE_ALLOC
232  result = ffi_prep_closure_loc(pcl, cif, callback,
233  (void *)self, cl->code);
234 #else
235  result = ffi_prep_closure(pcl, cif, callback, (void *)self);
236  cl->code = (void *)pcl;
237  i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
238  if (i) {
239  rb_sys_fail("mprotect");
240  }
241 #endif
242 
243  if (FFI_OK != result)
244  rb_raise(rb_eRuntimeError, "error prepping closure %d", result);
245 
246  return self;
247 }
248 
249 static VALUE
250 to_i(VALUE self)
251 {
252  fiddle_closure * cl;
253  void *code;
254 
255  TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
256 
257  code = cl->code;
258 
259  return PTR2NUM(code);
260 }
261 
262 void
264 {
265 #if 0
266  mFiddle = rb_define_module("Fiddle"); /* let rdoc know about mFiddle */
267 #endif
268 
269  /*
270  * Document-class: Fiddle::Closure
271  *
272  * == Description
273  *
274  * An FFI closure wrapper, for handling callbacks.
275  *
276  * == Example
277  *
278  * closure = Class.new(Fiddle::Closure) {
279  * def call
280  * 10
281  * end
282  * }.new(Fiddle::TYPE_INT, [])
283  * #=> #<#<Class:0x0000000150d308>:0x0000000150d240>
284  * func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
285  * #=> #<Fiddle::Function:0x00000001516e58>
286  * func.call
287  * #=> 10
288  */
290 
292 
293  /*
294  * Document-method: new
295  *
296  * call-seq: new(ret, args, abi = Fiddle::DEFAULT)
297  *
298  * Construct a new Closure object.
299  *
300  * * +ret+ is the C type to be returned
301  * * +args+ is an Array of arguments, passed to the callback function
302  * * +abi+ is the abi of the closure
303  *
304  * If there is an error in preparing the ffi_cif or ffi_prep_closure,
305  * then a RuntimeError will be raised.
306  */
307  rb_define_method(cFiddleClosure, "initialize", initialize, -1);
308 
309  /*
310  * Document-method: to_i
311  *
312  * Returns the memory address for this closure
313  */
314  rb_define_method(cFiddleClosure, "to_i", to_i, 0);
315 }
316 /* vim: set noet sw=4 sts=4 */
RARRAY_PTR(q->result)[0]
rb_funcall2(argv[0], id_yield, argc-1, argv+1)
#define TYPE_VOIDP
Definition: fiddle.h:113
VALUE mFiddle
Definition: fiddle.c:3
code
Definition: tcltklib.c:3373
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2612
rb_funcall(memo->yielder, id_lshift, 1, rb_assoc_new(memo->prev_value, memo->prev_elts))
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1880
int ret
Definition: tcltklib.c:285
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2604
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
RB_GC_GUARD(args)
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:900
#define NUM2ULONG(x)
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:538
#define T_ARRAY
#define xfree
#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:657
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
#define TYPE_CHAR
Definition: fiddle.h:114
#define TYPE_SHORT
Definition: fiddle.h:115
int size
Definition: encoding.c:49
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:59
#define LONG2NUM(x)
i
Definition: enum.c:446
#define TYPE_INT
Definition: fiddle.h:116
#define TYPE_DOUBLE
Definition: fiddle.h:122
#define TYPE_LONG
Definition: fiddle.h:117
#define TypedData_Get_Struct(obj, type, data_type, sval)
#define NUM2DBL(x)
VALUE rb_eRuntimeError
Definition: error.c:547
static VALUE to_i(VALUE self)
Definition: closure.c:250
Check_Type(i, T_ARRAY)
const rb_data_type_t closure_data_type
Definition: closure.c:53
#define PTR2NUM(x)
Definition: dl.h:168
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:24
VALUE * argv
Definition: tcltklib.c:1969
static VALUE initialize(int rbargc, VALUE argv[], VALUE self)
Definition: closure.c:190
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
#define NUM2UINT(x)
int type
Definition: tcltklib.c:112
int argc
Definition: tcltklib.c:1968
ffi_cif cif
Definition: closure.c:8
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
return ptr
Definition: tcltklib.c:789
#define TYPE_FLOAT
Definition: fiddle.h:121
static VALUE allocate(VALUE klass)
Definition: closure.c:172
VALUE cFiddleClosure
Definition: closure.c:3
SSL_CTX * ctx
Definition: ossl_ssl.c:486
#define NUM2LONG(x)
#define TYPE_VOID
Definition: fiddle.h:112
#define rb_float_new(d)
args[0]
Definition: enum.c:585
#define TypedData_Make_Struct(klass, type, data_type, sval)
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1561
#define RARRAY_LENINT(ary)
klass
Definition: tcltklib.c:3496
#define UINT2NUM(x)
#define INT2NUM(x)
void Init_fiddle_closure()
Definition: closure.c:263
#define NUM2INT(x)
#define xcalloc
unsigned long VALUE
Definition: ripper.y:88
void * code
Definition: closure.c:6
VALUE rb_define_module(const char *name)
Definition: class.c:727
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
volatile VALUE result
Definition: enum.c:1989
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
static size_t closure_memsize(const void *ptr)
Definition: closure.c:37
#define ULONG2NUM(x)