fiddle 1.0.0.beta1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE.txt +20 -19
- data/README.md +74 -6
- data/Rakefile +4 -6
- data/bin/downloader.rb +331 -0
- data/bin/extlibs.rb +262 -0
- data/ext/fiddle/closure.c +6 -5
- data/ext/fiddle/conversions.c +161 -16
- data/ext/fiddle/conversions.h +14 -4
- data/ext/fiddle/depend +83 -0
- data/ext/fiddle/extconf.rb +68 -31
- data/ext/fiddle/extlibs +13 -2
- data/ext/fiddle/fiddle.c +46 -35
- data/ext/fiddle/fiddle.h +35 -1
- data/ext/fiddle/function.c +220 -81
- data/ext/fiddle/handle.c +10 -12
- data/ext/fiddle/pinned.c +123 -0
- data/ext/fiddle/pointer.c +106 -24
- data/ext/fiddle/win32/fficonfig.h +0 -0
- data/ext/fiddle/win32/libffi-config.rb +2 -2
- data/ext/fiddle/win32/libffi.mk.tmpl +0 -0
- data/fiddle.gemspec +50 -8
- data/lib/fiddle.rb +4 -2
- data/lib/fiddle/closure.rb +1 -1
- data/lib/fiddle/cparser.rb +33 -3
- data/lib/fiddle/function.rb +1 -1
- data/lib/fiddle/import.rb +12 -10
- data/lib/fiddle/pack.rb +16 -9
- data/lib/fiddle/struct.rb +268 -44
- data/lib/fiddle/types.rb +1 -1
- data/lib/fiddle/value.rb +19 -10
- data/lib/fiddle/version.rb +3 -0
- metadata +18 -30
- data/.gitignore +0 -12
- data/.travis.yml +0 -5
- data/Gemfile +0 -4
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/ext/fiddle/function.c
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
#include <fiddle.h>
|
2
2
|
#include <ruby/thread.h>
|
3
3
|
|
4
|
+
#include <stdbool.h>
|
5
|
+
|
4
6
|
#ifdef PRIsVALUE
|
5
7
|
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
6
8
|
# define RB_OBJ_STRING(obj) (obj)
|
@@ -19,21 +21,21 @@ VALUE cFiddleFunction;
|
|
19
21
|
#define Check_Max_Args_Long(name, len) \
|
20
22
|
Check_Max_Args_(name, len, "l")
|
21
23
|
#define Check_Max_Args_(name, len, fmt) \
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
}
|
24
|
+
do { \
|
25
|
+
if ((size_t)(len) >= MAX_ARGS) { \
|
26
|
+
rb_raise(rb_eTypeError, \
|
27
|
+
"%s is so large " \
|
28
|
+
"that it can cause integer overflow (%"fmt"d)", \
|
29
|
+
(name), (len)); \
|
30
|
+
} \
|
31
|
+
} while (0)
|
30
32
|
|
31
33
|
static void
|
32
34
|
deallocate(void *p)
|
33
35
|
{
|
34
|
-
ffi_cif *
|
35
|
-
if (
|
36
|
-
xfree(
|
36
|
+
ffi_cif *cif = p;
|
37
|
+
if (cif->arg_types) xfree(cif->arg_types);
|
38
|
+
xfree(cif);
|
37
39
|
}
|
38
40
|
|
39
41
|
static size_t
|
@@ -87,60 +89,91 @@ parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
|
|
87
89
|
return ST_CONTINUE;
|
88
90
|
}
|
89
91
|
|
92
|
+
static VALUE
|
93
|
+
normalize_argument_types(const char *name,
|
94
|
+
VALUE arg_types,
|
95
|
+
bool *is_variadic)
|
96
|
+
{
|
97
|
+
VALUE normalized_arg_types;
|
98
|
+
int i;
|
99
|
+
int n_arg_types;
|
100
|
+
*is_variadic = false;
|
101
|
+
|
102
|
+
Check_Type(arg_types, T_ARRAY);
|
103
|
+
n_arg_types = RARRAY_LENINT(arg_types);
|
104
|
+
Check_Max_Args(name, n_arg_types);
|
105
|
+
|
106
|
+
normalized_arg_types = rb_ary_new_capa(n_arg_types);
|
107
|
+
for (i = 0; i < n_arg_types; i++) {
|
108
|
+
VALUE arg_type = RARRAY_AREF(arg_types, i);
|
109
|
+
int c_arg_type;
|
110
|
+
arg_type = rb_fiddle_type_ensure(arg_type);
|
111
|
+
c_arg_type = NUM2INT(arg_type);
|
112
|
+
if (c_arg_type == TYPE_VARIADIC) {
|
113
|
+
if (i != n_arg_types - 1) {
|
114
|
+
rb_raise(rb_eArgError,
|
115
|
+
"Fiddle::TYPE_VARIADIC must be the last argument type: "
|
116
|
+
"%"PRIsVALUE,
|
117
|
+
arg_types);
|
118
|
+
}
|
119
|
+
*is_variadic = true;
|
120
|
+
break;
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
(void)INT2FFI_TYPE(c_arg_type); /* raise */
|
124
|
+
}
|
125
|
+
rb_ary_push(normalized_arg_types, INT2FIX(c_arg_type));
|
126
|
+
}
|
127
|
+
|
128
|
+
/* freeze to prevent inconsistency at calling #to_int later */
|
129
|
+
OBJ_FREEZE(normalized_arg_types);
|
130
|
+
return normalized_arg_types;
|
131
|
+
}
|
132
|
+
|
90
133
|
static VALUE
|
91
134
|
initialize(int argc, VALUE argv[], VALUE self)
|
92
135
|
{
|
93
136
|
ffi_cif * cif;
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
int nabi;
|
137
|
+
VALUE ptr, arg_types, ret_type, abi, kwds;
|
138
|
+
int c_ret_type;
|
139
|
+
bool is_variadic = false;
|
140
|
+
ffi_abi c_ffi_abi;
|
99
141
|
void *cfunc;
|
100
142
|
|
101
|
-
rb_scan_args(argc, argv, "31:", &ptr, &
|
143
|
+
rb_scan_args(argc, argv, "31:", &ptr, &arg_types, &ret_type, &abi, &kwds);
|
144
|
+
rb_iv_set(self, "@closure", ptr);
|
145
|
+
|
102
146
|
ptr = rb_Integer(ptr);
|
103
147
|
cfunc = NUM2PTR(ptr);
|
104
148
|
PTR2NUM(cfunc);
|
105
|
-
|
106
|
-
abi = INT2FIX(
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
149
|
+
c_ffi_abi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi);
|
150
|
+
abi = INT2FIX(c_ffi_abi);
|
151
|
+
ret_type = rb_fiddle_type_ensure(ret_type);
|
152
|
+
c_ret_type = NUM2INT(ret_type);
|
153
|
+
(void)INT2FFI_TYPE(c_ret_type); /* raise */
|
154
|
+
ret_type = INT2FIX(c_ret_type);
|
155
|
+
|
156
|
+
arg_types = normalize_argument_types("argument types",
|
157
|
+
arg_types,
|
158
|
+
&is_variadic);
|
159
|
+
#ifndef HAVE_FFI_PREP_CIF_VAR
|
160
|
+
if (is_variadic) {
|
161
|
+
rb_raise(rb_eNotImpError,
|
162
|
+
"ffi_prep_cif_var() is required in libffi "
|
163
|
+
"for variadic arguments");
|
120
164
|
}
|
121
|
-
|
165
|
+
#endif
|
122
166
|
|
123
167
|
rb_iv_set(self, "@ptr", ptr);
|
124
|
-
rb_iv_set(self, "@
|
168
|
+
rb_iv_set(self, "@argument_types", arg_types);
|
125
169
|
rb_iv_set(self, "@return_type", ret_type);
|
126
170
|
rb_iv_set(self, "@abi", abi);
|
171
|
+
rb_iv_set(self, "@is_variadic", is_variadic ? Qtrue : Qfalse);
|
127
172
|
|
128
173
|
if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
|
129
174
|
|
130
175
|
TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
|
131
|
-
|
132
|
-
arg_types = xcalloc(len + 1, sizeof(ffi_type *));
|
133
|
-
|
134
|
-
for (i = 0; i < RARRAY_LEN(args); i++) {
|
135
|
-
int type = NUM2INT(RARRAY_AREF(args, i));
|
136
|
-
arg_types[i] = INT2FFI_TYPE(type);
|
137
|
-
}
|
138
|
-
arg_types[len] = NULL;
|
139
|
-
|
140
|
-
result = ffi_prep_cif(cif, nabi, len, rtype, arg_types);
|
141
|
-
|
142
|
-
if (result)
|
143
|
-
rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
|
176
|
+
cif->arg_types = NULL;
|
144
177
|
|
145
178
|
return self;
|
146
179
|
}
|
@@ -167,54 +200,160 @@ function_call(int argc, VALUE argv[], VALUE self)
|
|
167
200
|
{
|
168
201
|
struct nogvl_ffi_call_args args = { 0 };
|
169
202
|
fiddle_generic *generic_args;
|
170
|
-
VALUE cfunc
|
203
|
+
VALUE cfunc;
|
204
|
+
VALUE abi;
|
205
|
+
VALUE arg_types;
|
206
|
+
VALUE cPointer;
|
207
|
+
VALUE is_variadic;
|
208
|
+
int n_arg_types;
|
209
|
+
int n_fixed_args = 0;
|
210
|
+
int n_call_args = 0;
|
171
211
|
int i;
|
212
|
+
int i_call;
|
213
|
+
VALUE converted_args = Qnil;
|
172
214
|
VALUE alloc_buffer = 0;
|
173
215
|
|
174
216
|
cfunc = rb_iv_get(self, "@ptr");
|
175
|
-
|
217
|
+
abi = rb_iv_get(self, "@abi");
|
218
|
+
arg_types = rb_iv_get(self, "@argument_types");
|
176
219
|
cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
220
|
+
is_variadic = rb_iv_get(self, "@is_variadic");
|
221
|
+
|
222
|
+
n_arg_types = RARRAY_LENINT(arg_types);
|
223
|
+
n_fixed_args = n_arg_types;
|
224
|
+
if (RTEST(is_variadic)) {
|
225
|
+
if (argc < n_arg_types) {
|
226
|
+
rb_error_arity(argc, n_arg_types, UNLIMITED_ARGUMENTS);
|
227
|
+
}
|
228
|
+
if (((argc - n_arg_types) % 2) != 0) {
|
229
|
+
rb_raise(rb_eArgError,
|
230
|
+
"variadic arguments must be type and value pairs: "
|
231
|
+
"%"PRIsVALUE,
|
232
|
+
rb_ary_new_from_values(argc, argv));
|
233
|
+
}
|
234
|
+
n_call_args = n_arg_types + ((argc - n_arg_types) / 2);
|
181
235
|
}
|
236
|
+
else {
|
237
|
+
if (argc != n_arg_types) {
|
238
|
+
rb_error_arity(argc, n_arg_types, n_arg_types);
|
239
|
+
}
|
240
|
+
n_call_args = n_arg_types;
|
241
|
+
}
|
242
|
+
Check_Max_Args("the number of arguments", n_call_args);
|
182
243
|
|
183
244
|
TypedData_Get_Struct(self, ffi_cif, &function_data_type, args.cif);
|
184
245
|
|
185
|
-
if (
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
246
|
+
if (is_variadic && args.cif->arg_types) {
|
247
|
+
xfree(args.cif->arg_types);
|
248
|
+
args.cif->arg_types = NULL;
|
249
|
+
}
|
250
|
+
|
251
|
+
if (!args.cif->arg_types) {
|
252
|
+
VALUE fixed_arg_types = arg_types;
|
253
|
+
VALUE return_type;
|
254
|
+
int c_return_type;
|
255
|
+
ffi_type *ffi_return_type;
|
256
|
+
ffi_type **ffi_arg_types;
|
257
|
+
ffi_status result;
|
258
|
+
|
259
|
+
arg_types = rb_ary_dup(fixed_arg_types);
|
260
|
+
for (i = n_fixed_args; i < argc; i += 2) {
|
261
|
+
VALUE arg_type = argv[i];
|
262
|
+
int c_arg_type;
|
263
|
+
arg_type = rb_fiddle_type_ensure(arg_type);
|
264
|
+
c_arg_type = NUM2INT(arg_type);
|
265
|
+
(void)INT2FFI_TYPE(c_arg_type); /* raise */
|
266
|
+
rb_ary_push(arg_types, INT2FIX(c_arg_type));
|
267
|
+
}
|
268
|
+
|
269
|
+
return_type = rb_iv_get(self, "@return_type");
|
270
|
+
c_return_type = FIX2INT(return_type);
|
271
|
+
ffi_return_type = INT2FFI_TYPE(c_return_type);
|
272
|
+
|
273
|
+
ffi_arg_types = xcalloc(n_call_args + 1, sizeof(ffi_type *));
|
274
|
+
for (i_call = 0; i_call < n_call_args; i_call++) {
|
275
|
+
VALUE arg_type;
|
276
|
+
int c_arg_type;
|
277
|
+
arg_type = RARRAY_AREF(arg_types, i_call);
|
278
|
+
c_arg_type = FIX2INT(arg_type);
|
279
|
+
ffi_arg_types[i_call] = INT2FFI_TYPE(c_arg_type);
|
280
|
+
}
|
281
|
+
ffi_arg_types[i_call] = NULL;
|
282
|
+
|
283
|
+
if (is_variadic) {
|
284
|
+
#ifdef HAVE_FFI_PREP_CIF_VAR
|
285
|
+
result = ffi_prep_cif_var(args.cif,
|
286
|
+
FIX2INT(abi),
|
287
|
+
n_fixed_args,
|
288
|
+
n_call_args,
|
289
|
+
ffi_return_type,
|
290
|
+
ffi_arg_types);
|
291
|
+
#else
|
292
|
+
/* This code is never used because ffi_prep_cif_var()
|
293
|
+
* availability check is done in #initialize. */
|
294
|
+
result = FFI_BAD_TYPEDEF;
|
295
|
+
#endif
|
296
|
+
}
|
297
|
+
else {
|
298
|
+
result = ffi_prep_cif(args.cif,
|
299
|
+
FIX2INT(abi),
|
300
|
+
n_call_args,
|
301
|
+
ffi_return_type,
|
302
|
+
ffi_arg_types);
|
303
|
+
}
|
304
|
+
if (result != FFI_OK) {
|
305
|
+
xfree(ffi_arg_types);
|
306
|
+
args.cif->arg_types = NULL;
|
307
|
+
rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
|
308
|
+
}
|
192
309
|
}
|
193
310
|
|
194
311
|
generic_args = ALLOCV(alloc_buffer,
|
195
|
-
|
312
|
+
sizeof(fiddle_generic) * n_call_args +
|
313
|
+
sizeof(void *) * (n_call_args + 1));
|
196
314
|
args.values = (void **)((char *)generic_args +
|
197
|
-
|
198
|
-
|
199
|
-
for (i = 0
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
315
|
+
sizeof(fiddle_generic) * n_call_args);
|
316
|
+
|
317
|
+
for (i = 0, i_call = 0;
|
318
|
+
i < argc && i_call < n_call_args;
|
319
|
+
i++, i_call++) {
|
320
|
+
VALUE arg_type;
|
321
|
+
int c_arg_type;
|
322
|
+
VALUE original_src;
|
323
|
+
VALUE src;
|
324
|
+
arg_type = RARRAY_AREF(arg_types, i_call);
|
325
|
+
c_arg_type = FIX2INT(arg_type);
|
326
|
+
if (i >= n_fixed_args) {
|
327
|
+
i++;
|
328
|
+
}
|
329
|
+
src = argv[i];
|
330
|
+
|
331
|
+
if (c_arg_type == TYPE_VOIDP) {
|
332
|
+
if (NIL_P(src)) {
|
333
|
+
src = INT2FIX(0);
|
334
|
+
}
|
335
|
+
else if (cPointer != CLASS_OF(src)) {
|
336
|
+
src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
|
337
|
+
if (NIL_P(converted_args)) {
|
338
|
+
converted_args = rb_ary_new();
|
339
|
+
}
|
340
|
+
rb_ary_push(converted_args, src);
|
341
|
+
}
|
342
|
+
src = rb_Integer(src);
|
343
|
+
}
|
344
|
+
|
345
|
+
original_src = src;
|
346
|
+
VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]);
|
347
|
+
if (src != original_src) {
|
348
|
+
if (NIL_P(converted_args)) {
|
349
|
+
converted_args = rb_ary_new();
|
350
|
+
}
|
351
|
+
rb_ary_push(converted_args, src);
|
352
|
+
}
|
353
|
+
args.values[i_call] = (void *)&generic_args[i_call];
|
215
354
|
}
|
216
|
-
args.values[
|
217
|
-
args.fn = NUM2PTR(cfunc);
|
355
|
+
args.values[i_call] = NULL;
|
356
|
+
args.fn = (void(*)(void))NUM2PTR(cfunc);
|
218
357
|
|
219
358
|
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
|
220
359
|
|
data/ext/fiddle/handle.c
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
#include <fiddle.h>
|
3
3
|
|
4
|
-
#define SafeStringValueCStr(v) (rb_check_safe_obj(rb_string_value(&v)), StringValueCStr(v))
|
5
|
-
|
6
4
|
VALUE rb_cHandle;
|
7
5
|
|
8
6
|
struct dl_handle {
|
@@ -76,14 +74,14 @@ rb_fiddle_handle_close(VALUE self)
|
|
76
74
|
/* Check dlclose for successful return value */
|
77
75
|
if(ret) {
|
78
76
|
#if defined(HAVE_DLERROR)
|
79
|
-
rb_raise(
|
77
|
+
rb_raise(rb_eFiddleDLError, "%s", dlerror());
|
80
78
|
#else
|
81
|
-
rb_raise(
|
79
|
+
rb_raise(rb_eFiddleDLError, "could not close handle");
|
82
80
|
#endif
|
83
81
|
}
|
84
82
|
return INT2NUM(ret);
|
85
83
|
}
|
86
|
-
rb_raise(
|
84
|
+
rb_raise(rb_eFiddleDLError, "dlclose() called too many times");
|
87
85
|
|
88
86
|
UNREACHABLE;
|
89
87
|
}
|
@@ -145,11 +143,11 @@ rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
|
|
145
143
|
cflag = RTLD_LAZY | RTLD_GLOBAL;
|
146
144
|
break;
|
147
145
|
case 1:
|
148
|
-
clib = NIL_P(lib) ? NULL :
|
146
|
+
clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
|
149
147
|
cflag = RTLD_LAZY | RTLD_GLOBAL;
|
150
148
|
break;
|
151
149
|
case 2:
|
152
|
-
clib = NIL_P(lib) ? NULL :
|
150
|
+
clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
|
153
151
|
cflag = NUM2INT(flag);
|
154
152
|
break;
|
155
153
|
default:
|
@@ -179,12 +177,12 @@ rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
|
|
179
177
|
ptr = dlopen(clib, cflag);
|
180
178
|
#if defined(HAVE_DLERROR)
|
181
179
|
if( !ptr && (err = dlerror()) ){
|
182
|
-
rb_raise(
|
180
|
+
rb_raise(rb_eFiddleDLError, "%s", err);
|
183
181
|
}
|
184
182
|
#else
|
185
183
|
if( !ptr ){
|
186
184
|
err = dlerror();
|
187
|
-
rb_raise(
|
185
|
+
rb_raise(rb_eFiddleDLError, "%s", err);
|
188
186
|
}
|
189
187
|
#endif
|
190
188
|
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
|
@@ -280,7 +278,7 @@ rb_fiddle_handle_sym(VALUE self, VALUE sym)
|
|
280
278
|
|
281
279
|
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
|
282
280
|
if( ! fiddle_handle->open ){
|
283
|
-
rb_raise(
|
281
|
+
rb_raise(rb_eFiddleDLError, "closed handle");
|
284
282
|
}
|
285
283
|
|
286
284
|
return fiddle_handle_sym(fiddle_handle->ptr, sym);
|
@@ -319,7 +317,7 @@ fiddle_handle_sym(void *handle, VALUE symbol)
|
|
319
317
|
# define CHECK_DLERROR
|
320
318
|
#endif
|
321
319
|
void (*func)();
|
322
|
-
const char *name =
|
320
|
+
const char *name = StringValueCStr(symbol);
|
323
321
|
|
324
322
|
#ifdef HAVE_DLERROR
|
325
323
|
dlerror();
|
@@ -368,7 +366,7 @@ fiddle_handle_sym(void *handle, VALUE symbol)
|
|
368
366
|
}
|
369
367
|
#endif
|
370
368
|
if( !func ){
|
371
|
-
rb_raise(
|
369
|
+
rb_raise(rb_eFiddleDLError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
|
372
370
|
}
|
373
371
|
|
374
372
|
return PTR2NUM(func);
|
data/ext/fiddle/pinned.c
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#include <fiddle.h>
|
2
|
+
|
3
|
+
VALUE rb_cPinned;
|
4
|
+
VALUE rb_eFiddleClearedReferenceError;
|
5
|
+
|
6
|
+
struct pinned_data {
|
7
|
+
VALUE ptr;
|
8
|
+
};
|
9
|
+
|
10
|
+
static void
|
11
|
+
pinned_mark(void *ptr)
|
12
|
+
{
|
13
|
+
struct pinned_data *data = (struct pinned_data*)ptr;
|
14
|
+
/* Ensure reference is pinned */
|
15
|
+
if (data->ptr) {
|
16
|
+
rb_gc_mark(data->ptr);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
static size_t
|
21
|
+
pinned_memsize(const void *ptr)
|
22
|
+
{
|
23
|
+
return sizeof(struct pinned_data);
|
24
|
+
}
|
25
|
+
|
26
|
+
static const rb_data_type_t pinned_data_type = {
|
27
|
+
"fiddle/pinned",
|
28
|
+
{pinned_mark, xfree, pinned_memsize, },
|
29
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
30
|
+
};
|
31
|
+
|
32
|
+
static VALUE
|
33
|
+
allocate(VALUE klass)
|
34
|
+
{
|
35
|
+
struct pinned_data *data;
|
36
|
+
VALUE obj = TypedData_Make_Struct(klass, struct pinned_data, &pinned_data_type, data);
|
37
|
+
data->ptr = 0;
|
38
|
+
return obj;
|
39
|
+
}
|
40
|
+
|
41
|
+
/*
|
42
|
+
* call-seq:
|
43
|
+
* Fiddle::Pinned.new(object) => pinned_object
|
44
|
+
*
|
45
|
+
* Create a new pinned object reference. The Fiddle::Pinned instance will
|
46
|
+
* prevent the GC from moving +object+.
|
47
|
+
*/
|
48
|
+
static VALUE
|
49
|
+
initialize(VALUE self, VALUE ref)
|
50
|
+
{
|
51
|
+
struct pinned_data *data;
|
52
|
+
TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
|
53
|
+
RB_OBJ_WRITE(self, &data->ptr, ref);
|
54
|
+
return self;
|
55
|
+
}
|
56
|
+
|
57
|
+
/*
|
58
|
+
* call-seq: ref
|
59
|
+
*
|
60
|
+
* Return the object that this pinned instance references.
|
61
|
+
*/
|
62
|
+
static VALUE
|
63
|
+
ref(VALUE self)
|
64
|
+
{
|
65
|
+
struct pinned_data *data;
|
66
|
+
TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
|
67
|
+
if (data->ptr) {
|
68
|
+
return data->ptr;
|
69
|
+
} else {
|
70
|
+
rb_raise(rb_eFiddleClearedReferenceError, "`ref` called on a cleared object");
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
/*
|
75
|
+
* call-seq: clear
|
76
|
+
*
|
77
|
+
* Clear the reference to the object this is pinning.
|
78
|
+
*/
|
79
|
+
static VALUE
|
80
|
+
clear(VALUE self)
|
81
|
+
{
|
82
|
+
struct pinned_data *data;
|
83
|
+
TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
|
84
|
+
data->ptr = 0;
|
85
|
+
return self;
|
86
|
+
}
|
87
|
+
|
88
|
+
/*
|
89
|
+
* call-seq: cleared?
|
90
|
+
*
|
91
|
+
* Returns true if the reference has been cleared, otherwise returns false.
|
92
|
+
*/
|
93
|
+
static VALUE
|
94
|
+
cleared_p(VALUE self)
|
95
|
+
{
|
96
|
+
struct pinned_data *data;
|
97
|
+
TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
|
98
|
+
if (data->ptr) {
|
99
|
+
return Qfalse;
|
100
|
+
} else {
|
101
|
+
return Qtrue;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
extern VALUE rb_eFiddleError;
|
106
|
+
|
107
|
+
void
|
108
|
+
Init_fiddle_pinned(void)
|
109
|
+
{
|
110
|
+
rb_cPinned = rb_define_class_under(mFiddle, "Pinned", rb_cObject);
|
111
|
+
rb_define_alloc_func(rb_cPinned, allocate);
|
112
|
+
rb_define_method(rb_cPinned, "initialize", initialize, 1);
|
113
|
+
rb_define_method(rb_cPinned, "ref", ref, 0);
|
114
|
+
rb_define_method(rb_cPinned, "clear", clear, 0);
|
115
|
+
rb_define_method(rb_cPinned, "cleared?", cleared_p, 0);
|
116
|
+
|
117
|
+
/*
|
118
|
+
* Document-class: Fiddle::ClearedReferenceError
|
119
|
+
*
|
120
|
+
* Cleared reference exception
|
121
|
+
*/
|
122
|
+
rb_eFiddleClearedReferenceError = rb_define_class_under(mFiddle, "ClearedReferenceError", rb_eFiddleError);
|
123
|
+
}
|