Ruby 2.0.0p353(2013-11-22revision43784)

- 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(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
47 const rb_data_type_t closure_data_type = {
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
166 allocate(VALUE klass)
167 {
168 fiddle_closure * closure;
169
170 VALUE i = TypedData_Make_Struct(klass, fiddle_closure,
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
257 Init_fiddle_closure()
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 */
283 cFiddleClosure = rb_define_class_under(mFiddle, "Closure", rb_cObject);
284
285 rb_define_alloc_func(cFiddleClosure, allocate);
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 */
RARRAY_PTR
RARRAY_PTR(q->result)[0]
TYPE_VOIDP
#define TYPE_VOIDP
Definition: fiddle.h:113
fiddle.h
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
code
code
Definition: tcltklib.c:3381
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2591
rb_const_get
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1876
i
ssize_t i
Definition: bigdecimal.c:5655
ret
int ret
Definition: tcltklib.c:280
rb_iv_get
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2583
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
NUM2ULONG
#define NUM2ULONG(x)
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:465
T_ARRAY
#define T_ARRAY
xfree
#define xfree
NUM2PTR
#define NUM2PTR(x)
Definition: dl.h:169
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
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:545
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
TYPE_CHAR
#define TYPE_CHAR
Definition: fiddle.h:114
TYPE_SHORT
#define TYPE_SHORT
Definition: fiddle.h:115
callback
void callback(ffi_cif *cif, void *resp, void **args, void *ctx)
Definition: closure.c:53
args
VALUE VALUE args
Definition: tcltklib.c:2561
LONG2NUM
#define LONG2NUM(x)
fiddle_closure
Definition: closure.c:5
rb_float_new
static VALUE rb_float_new(double d)
Definition: ripper.y:790
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
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
NUM2DBL
#define NUM2DBL(x)
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:510
fiddle_closure::argc
int argc
Definition: closure.c:9
to_i
static VALUE to_i(VALUE self)
Definition: closure.c:244
Check_Type
#define Check_Type(v, t)
closure_data_type
const rb_data_type_t closure_data_type
Definition: closure.c:47
PTR2NUM
#define PTR2NUM(x)
Definition: dl.h:168
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:18
argv
VALUE * argv
Definition: tcltklib.c:1971
result
q result
Definition: tcltklib.c:7070
initialize
static VALUE initialize(int rbargc, VALUE argv[], VALUE self)
Definition: closure.c:184
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
NUM2UINT
#define NUM2UINT(x)
RB_GC_GUARD
#define RB_GC_GUARD(v)
type
int type
Definition: tcltklib.c:111
argc
int argc
Definition: tcltklib.c:1970
fiddle_closure::cif
ffi_cif cif
Definition: closure.c:8
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1899
ptr
return ptr
Definition: tcltklib.c:784
TYPE_FLOAT
#define TYPE_FLOAT
Definition: fiddle.h:121
allocate
static VALUE allocate(VALUE klass)
Definition: closure.c:166
cFiddleClosure
VALUE cFiddleClosure
Definition: closure.c:3
size
int size
Definition: encoding.c:52
NUM2LONG
#define NUM2LONG(x)
TYPE_VOID
#define TYPE_VOID
Definition: fiddle.h:112
rb_data_type_struct
Definition: ripper.y:960
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
RARRAY_LENINT
#define RARRAY_LENINT(ary)
klass
klass
Definition: tcltklib.c:3504
UINT2NUM
#define UINT2NUM(x)
INT2NUM
#define INT2NUM(x)
Init_fiddle_closure
void Init_fiddle_closure()
Definition: closure.c:257
NUM2INT
#define NUM2INT(x)
xcalloc
#define xcalloc
rb_funcall2
VALUE rb_funcall2(VALUE, ID, int, const VALUE *)
Calls a method.
Definition: vm_eval.c:805
VALUE
unsigned long VALUE
Definition: ripper.y:104
fiddle_closure::code
void * code
Definition: closure.c:6
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:617
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:1344
closure_memsize
static size_t closure_memsize(const void *ptr)
Definition: closure.c:31
ULONG2NUM
#define ULONG2NUM(x)