Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

closure.c
Go to the documentation of this file.
1 #include <fiddle.h>
2
3 VALUE cFiddleClosure;
4
5 typedef struct {
6 void * code;
7 ffi_closure *pcl;
8 ffi_cif cif;
9 int argc;
10 ffi_type **argv;
11 } fiddle_closure;
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
53 const rb_data_type_t closure_data_type = {
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
172 allocate(VALUE klass)
173 {
174 fiddle_closure * closure;
175
176 VALUE i = TypedData_Make_Struct(klass, fiddle_closure,
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
263 Init_fiddle_closure()
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 */
289 cFiddleClosure = rb_define_class_under(mFiddle, "Closure", rb_cObject);
290
291 rb_define_alloc_func(cFiddleClosure, allocate);
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 */
TYPE_VOIDP
#define TYPE_VOIDP
Definition: fiddle.h:113
fiddle.h
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1288
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:630
NUM2UINT
#define NUM2UINT(x)
Definition: ruby.h:631
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
ULONG2NUM
#define ULONG2NUM(x)
Definition: ruby.h:1319
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:534
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:775
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2609
rb_iv_get
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2601
NUM2PTR
#define NUM2PTR(x)
Definition: dl.h:169
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:676
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:532
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
TYPE_CHAR
#define TYPE_CHAR
Definition: fiddle.h:114
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:523
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
T_ARRAY
#define T_ARRAY
Definition: ruby.h:484
TYPE_SHORT
#define TYPE_SHORT
Definition: fiddle.h:115
callback
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:59
NUM2DBL
#define NUM2DBL(x)
Definition: ruby.h:685
fiddle_closure
Definition: closure.c:5
TYPE_INT
#define TYPE_INT
Definition: fiddle.h:116
TYPE_DOUBLE
#define TYPE_DOUBLE
Definition: fiddle.h:122
TYPE_LONG
#define TYPE_LONG
Definition: fiddle.h:117
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:547
rb_float_new
#define rb_float_new(d)
Definition: internal.h:595
fiddle_closure::argc
int argc
Definition: closure.c:9
to_i
static VALUE to_i(VALUE self)
Definition: closure.c:250
UINT2NUM
#define UINT2NUM(x)
Definition: ruby.h:1298
closure_data_type
const rb_data_type_t closure_data_type
Definition: closure.c:53
PTR2NUM
#define PTR2NUM(x)
Definition: dl.h:168
argc
int argc
Definition: ruby.c:131
fiddle_closure::pcl
ffi_closure * pcl
Definition: closure.c:7
INT2FFI_TYPE
#define INT2FFI_TYPE(_type)
Definition: conversions.h:32
fiddle_closure::argv
ffi_type ** argv
Definition: closure.c:10
dealloc
static void dealloc(void *ptr)
Definition: closure.c:24
rb_const_get
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1880
initialize
static VALUE initialize(int rbargc, VALUE argv[], VALUE self)
Definition: closure.c:190
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
type
int type
Definition: tcltklib.c:112
VALUE
unsigned long VALUE
Definition: ruby.h:88
rb_funcall2
#define rb_funcall2
Definition: ruby.h:1456
result
static VALUE result
Definition: nkf.c:40
fiddle_closure::cif
ffi_cif cif
Definition: closure.c:8
RARRAY_LENINT
#define RARRAY_LENINT(ary)
Definition: ruby.h:884
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1309
TYPE_FLOAT
#define TYPE_FLOAT
Definition: fiddle.h:121
allocate
static VALUE allocate(VALUE klass)
Definition: closure.c:172
cFiddleClosure
VALUE cFiddleClosure
Definition: closure.c:3
size
int size
Definition: encoding.c:49
TYPE_VOID
#define TYPE_VOID
Definition: fiddle.h:112
NUM2ULONG
#define NUM2ULONG(x)
Definition: ruby.h:609
rb_data_type_struct
Definition: ruby.h:966
RARRAY_PTR
#define RARRAY_PTR(a)
Definition: ruby.h:907
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
Init_fiddle_closure
void Init_fiddle_closure()
Definition: closure.c:263
xfree
void void xfree(void *)
fiddle_closure::code
void * code
Definition: closure.c:6
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:746
rb_intern
#define rb_intern(str)
NULL
#define NULL
Definition: _sdbm.c:103
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
closure_memsize
static size_t closure_memsize(const void *ptr)
Definition: closure.c:37
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:600
argv
char ** argv
Definition: ruby.c:132
xcalloc
#define xcalloc
Definition: defines.h:110