fiddle 1.0.0.beta1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|