fiddle 1.0.0.beta2 → 1.0.4
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/README.md +72 -3
- data/Rakefile +4 -5
- data/bin/downloader.rb +331 -0
- data/bin/extlibs.rb +262 -0
- data/ext/fiddle/closure.c +5 -4
- data/ext/fiddle/conversions.c +205 -16
- data/ext/fiddle/conversions.h +14 -4
- data/ext/fiddle/depend +85 -0
- data/ext/fiddle/extconf.rb +60 -29
- data/ext/fiddle/extlibs +10 -2
- data/ext/fiddle/fiddle.c +133 -34
- data/ext/fiddle/fiddle.h +96 -32
- data/ext/fiddle/function.c +261 -93
- data/ext/fiddle/handle.c +10 -12
- data/ext/fiddle/memory_view.c +254 -0
- data/ext/fiddle/pinned.c +123 -0
- data/ext/fiddle/pointer.c +147 -24
- data/ext/fiddle/win32/fficonfig.h +0 -0
- data/ext/fiddle/win32/libffi-config.rb +1 -1
- data/ext/fiddle/win32/libffi.mk.tmpl +0 -0
- data/fiddle.gemspec +50 -5
- data/lib/fiddle.rb +3 -1
- data/lib/fiddle/cparser.rb +93 -25
- data/lib/fiddle/function.rb +5 -0
- data/lib/fiddle/import.rb +11 -9
- data/lib/fiddle/pack.rb +14 -7
- data/lib/fiddle/struct.rb +267 -43
- data/lib/fiddle/value.rb +18 -9
- data/lib/fiddle/version.rb +3 -0
- metadata +18 -15
- data/.gitignore +0 -13
- data/.travis.yml +0 -5
- data/Gemfile +0 -4
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/ext/fiddle/fiddle.h
CHANGED
@@ -58,38 +58,38 @@
|
|
58
58
|
# error "CHAR_BIT not supported"
|
59
59
|
#endif
|
60
60
|
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
61
|
+
#if SIZEOF_SHORT == 2
|
62
|
+
# define ffi_type_ushort ffi_type_uint16
|
63
|
+
# define ffi_type_sshort ffi_type_sint16
|
64
|
+
#elif SIZEOF_SHORT == 4
|
65
|
+
# define ffi_type_ushort ffi_type_uint32
|
66
|
+
# define ffi_type_sshort ffi_type_sint32
|
67
|
+
#else
|
68
|
+
# error "short size not supported"
|
69
|
+
#endif
|
70
70
|
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
71
|
+
#if SIZEOF_INT == 2
|
72
|
+
# define ffi_type_uint ffi_type_uint16
|
73
|
+
# define ffi_type_sint ffi_type_sint16
|
74
|
+
#elif SIZEOF_INT == 4
|
75
|
+
# define ffi_type_uint ffi_type_uint32
|
76
|
+
# define ffi_type_sint ffi_type_sint32
|
77
|
+
#elif SIZEOF_INT == 8
|
78
|
+
# define ffi_type_uint ffi_type_uint64
|
79
|
+
# define ffi_type_sint ffi_type_sint64
|
80
|
+
#else
|
81
|
+
# error "int size not supported"
|
82
|
+
#endif
|
83
83
|
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
84
|
+
#if SIZEOF_LONG == 4
|
85
|
+
# define ffi_type_ulong ffi_type_uint32
|
86
|
+
# define ffi_type_slong ffi_type_sint32
|
87
|
+
#elif SIZEOF_LONG == 8
|
88
|
+
# define ffi_type_ulong ffi_type_uint64
|
89
|
+
# define ffi_type_slong ffi_type_sint64
|
90
|
+
#else
|
91
|
+
# error "long size not supported"
|
92
|
+
#endif
|
93
93
|
|
94
94
|
#if HAVE_LONG_LONG
|
95
95
|
# if SIZEOF_LONG_LONG == 8
|
@@ -115,12 +115,67 @@
|
|
115
115
|
#endif
|
116
116
|
#define TYPE_FLOAT 7
|
117
117
|
#define TYPE_DOUBLE 8
|
118
|
+
#define TYPE_VARIADIC 9
|
119
|
+
#define TYPE_CONST_STRING 10
|
120
|
+
|
121
|
+
#define TYPE_INT8_T TYPE_CHAR
|
122
|
+
#if SIZEOF_SHORT == 2
|
123
|
+
# define TYPE_INT16_T TYPE_SHORT
|
124
|
+
#elif SIZEOF_INT == 2
|
125
|
+
# define TYPE_INT16_T TYPE_INT
|
126
|
+
#endif
|
127
|
+
#if SIZEOF_SHORT == 4
|
128
|
+
# define TYPE_INT32_T TYPE_SHORT
|
129
|
+
#elif SIZEOF_INT == 4
|
130
|
+
# define TYPE_INT32_T TYPE_INT
|
131
|
+
#elif SIZEOF_LONG == 4
|
132
|
+
# define TYPE_INT32_T TYPE_LONG
|
133
|
+
#endif
|
134
|
+
#if SIZEOF_INT == 8
|
135
|
+
# define TYPE_INT64_T TYPE_INT
|
136
|
+
#elif SIZEOF_LONG == 8
|
137
|
+
# define TYPE_INT64_T TYPE_LONG
|
138
|
+
#elif defined(TYPE_LONG_LONG)
|
139
|
+
# define TYPE_INT64_T TYPE_LONG_LONG
|
140
|
+
#endif
|
141
|
+
|
142
|
+
#ifndef TYPE_SSIZE_T
|
143
|
+
# if SIZEOF_SIZE_T == SIZEOF_INT
|
144
|
+
# define TYPE_SSIZE_T TYPE_INT
|
145
|
+
# elif SIZEOF_SIZE_T == SIZEOF_LONG
|
146
|
+
# define TYPE_SSIZE_T TYPE_LONG
|
147
|
+
# elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
|
148
|
+
# define TYPE_SSIZE_T TYPE_LONG_LONG
|
149
|
+
# endif
|
150
|
+
#endif
|
151
|
+
#define TYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*TYPE_SSIZE_T)
|
152
|
+
|
153
|
+
#ifndef TYPE_PTRDIFF_T
|
154
|
+
# if SIZEOF_PTRDIFF_T == SIZEOF_INT
|
155
|
+
# define TYPE_PTRDIFF_T TYPE_INT
|
156
|
+
# elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
|
157
|
+
# define TYPE_PTRDIFF_T TYPE_LONG
|
158
|
+
# elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
|
159
|
+
# define TYPE_PTRDIFF_T TYPE_LONG_LONG
|
160
|
+
# endif
|
161
|
+
#endif
|
162
|
+
|
163
|
+
#ifndef TYPE_INTPTR_T
|
164
|
+
# if SIZEOF_INTPTR_T == SIZEOF_INT
|
165
|
+
# define TYPE_INTPTR_T TYPE_INT
|
166
|
+
# elif SIZEOF_INTPTR_T == SIZEOF_LONG
|
167
|
+
# define TYPE_INTPTR_T TYPE_LONG
|
168
|
+
# elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
|
169
|
+
# define TYPE_INTPTR_T TYPE_LONG_LONG
|
170
|
+
# endif
|
171
|
+
#endif
|
172
|
+
#define TYPE_UINTPTR_T (-TYPE_INTPTR_T)
|
118
173
|
|
119
174
|
#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
|
120
175
|
|
121
176
|
#define ALIGN_VOIDP ALIGN_OF(void*)
|
122
|
-
#define ALIGN_SHORT ALIGN_OF(short)
|
123
177
|
#define ALIGN_CHAR ALIGN_OF(char)
|
178
|
+
#define ALIGN_SHORT ALIGN_OF(short)
|
124
179
|
#define ALIGN_INT ALIGN_OF(int)
|
125
180
|
#define ALIGN_LONG ALIGN_OF(long)
|
126
181
|
#if HAVE_LONG_LONG
|
@@ -129,8 +184,17 @@
|
|
129
184
|
#define ALIGN_FLOAT ALIGN_OF(float)
|
130
185
|
#define ALIGN_DOUBLE ALIGN_OF(double)
|
131
186
|
|
187
|
+
#define ALIGN_INT8_T ALIGN_OF(int8_t)
|
188
|
+
#define ALIGN_INT16_T ALIGN_OF(int16_t)
|
189
|
+
#define ALIGN_INT32_T ALIGN_OF(int32_t)
|
190
|
+
#define ALIGN_INT64_T ALIGN_OF(int64_t)
|
191
|
+
|
192
|
+
#ifdef HAVE_TYPE_RB_MEMORY_VIEW_T
|
193
|
+
# define FIDDLE_MEMORY_VIEW
|
194
|
+
#endif
|
195
|
+
|
132
196
|
extern VALUE mFiddle;
|
133
|
-
extern VALUE
|
197
|
+
extern VALUE rb_eFiddleDLError;
|
134
198
|
|
135
199
|
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type);
|
136
200
|
|
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
|
@@ -75,72 +77,114 @@ rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
|
|
75
77
|
return rb_class_new_instance(3, argv, cFiddleFunction);
|
76
78
|
}
|
77
79
|
|
78
|
-
static
|
79
|
-
|
80
|
+
static VALUE
|
81
|
+
normalize_argument_types(const char *name,
|
82
|
+
VALUE arg_types,
|
83
|
+
bool *is_variadic)
|
80
84
|
{
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
VALUE normalized_arg_types;
|
86
|
+
int i;
|
87
|
+
int n_arg_types;
|
88
|
+
*is_variadic = false;
|
89
|
+
|
90
|
+
Check_Type(arg_types, T_ARRAY);
|
91
|
+
n_arg_types = RARRAY_LENINT(arg_types);
|
92
|
+
Check_Max_Args(name, n_arg_types);
|
93
|
+
|
94
|
+
normalized_arg_types = rb_ary_new_capa(n_arg_types);
|
95
|
+
for (i = 0; i < n_arg_types; i++) {
|
96
|
+
VALUE arg_type = RARRAY_AREF(arg_types, i);
|
97
|
+
int c_arg_type;
|
98
|
+
arg_type = rb_fiddle_type_ensure(arg_type);
|
99
|
+
c_arg_type = NUM2INT(arg_type);
|
100
|
+
if (c_arg_type == TYPE_VARIADIC) {
|
101
|
+
if (i != n_arg_types - 1) {
|
102
|
+
rb_raise(rb_eArgError,
|
103
|
+
"Fiddle::TYPE_VARIADIC must be the last argument type: "
|
104
|
+
"%"PRIsVALUE,
|
105
|
+
arg_types);
|
106
|
+
}
|
107
|
+
*is_variadic = true;
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
else {
|
111
|
+
(void)INT2FFI_TYPE(c_arg_type); /* raise */
|
112
|
+
}
|
113
|
+
rb_ary_push(normalized_arg_types, INT2FIX(c_arg_type));
|
86
114
|
}
|
87
|
-
|
115
|
+
|
116
|
+
/* freeze to prevent inconsistency at calling #to_int later */
|
117
|
+
OBJ_FREEZE(normalized_arg_types);
|
118
|
+
return normalized_arg_types;
|
88
119
|
}
|
89
120
|
|
90
121
|
static VALUE
|
91
122
|
initialize(int argc, VALUE argv[], VALUE self)
|
92
123
|
{
|
93
124
|
ffi_cif * cif;
|
94
|
-
|
95
|
-
|
96
|
-
VALUE
|
97
|
-
int
|
98
|
-
|
125
|
+
VALUE ptr, arg_types, ret_type, abi, kwargs;
|
126
|
+
VALUE name = Qnil;
|
127
|
+
VALUE need_gvl = Qfalse;
|
128
|
+
int c_ret_type;
|
129
|
+
bool is_variadic = false;
|
130
|
+
ffi_abi c_ffi_abi;
|
99
131
|
void *cfunc;
|
100
132
|
|
101
|
-
rb_scan_args(argc, argv, "31:", &ptr, &
|
133
|
+
rb_scan_args(argc, argv, "31:", &ptr, &arg_types, &ret_type, &abi, &kwargs);
|
134
|
+
rb_iv_set(self, "@closure", ptr);
|
135
|
+
|
136
|
+
if (!NIL_P(kwargs)) {
|
137
|
+
enum {
|
138
|
+
kw_name,
|
139
|
+
kw_need_gvl,
|
140
|
+
kw_max_,
|
141
|
+
};
|
142
|
+
static ID kw[kw_max_];
|
143
|
+
VALUE args[kw_max_];
|
144
|
+
if (!kw[0]) {
|
145
|
+
kw[kw_name] = rb_intern_const("name");
|
146
|
+
kw[kw_need_gvl] = rb_intern_const("need_gvl");
|
147
|
+
}
|
148
|
+
rb_get_kwargs(kwargs, kw, 0, kw_max_, args);
|
149
|
+
if (args[kw_name] != Qundef) {
|
150
|
+
name = args[kw_name];
|
151
|
+
}
|
152
|
+
if (args[kw_need_gvl] != Qundef) {
|
153
|
+
need_gvl = args[kw_need_gvl];
|
154
|
+
}
|
155
|
+
}
|
156
|
+
rb_iv_set(self, "@name", name);
|
157
|
+
rb_iv_set(self, "@need_gvl", need_gvl);
|
158
|
+
|
102
159
|
ptr = rb_Integer(ptr);
|
103
160
|
cfunc = NUM2PTR(ptr);
|
104
161
|
PTR2NUM(cfunc);
|
105
|
-
|
106
|
-
abi = INT2FIX(
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
162
|
+
c_ffi_abi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi);
|
163
|
+
abi = INT2FIX(c_ffi_abi);
|
164
|
+
ret_type = rb_fiddle_type_ensure(ret_type);
|
165
|
+
c_ret_type = NUM2INT(ret_type);
|
166
|
+
(void)INT2FFI_TYPE(c_ret_type); /* raise */
|
167
|
+
ret_type = INT2FIX(c_ret_type);
|
168
|
+
|
169
|
+
arg_types = normalize_argument_types("argument types",
|
170
|
+
arg_types,
|
171
|
+
&is_variadic);
|
172
|
+
#ifndef HAVE_FFI_PREP_CIF_VAR
|
173
|
+
if (is_variadic) {
|
174
|
+
rb_raise(rb_eNotImpError,
|
175
|
+
"ffi_prep_cif_var() is required in libffi "
|
176
|
+
"for variadic arguments");
|
120
177
|
}
|
121
|
-
|
178
|
+
#endif
|
122
179
|
|
123
180
|
rb_iv_set(self, "@ptr", ptr);
|
124
|
-
rb_iv_set(self, "@
|
181
|
+
rb_iv_set(self, "@argument_types", arg_types);
|
125
182
|
rb_iv_set(self, "@return_type", ret_type);
|
126
183
|
rb_iv_set(self, "@abi", abi);
|
127
|
-
|
128
|
-
if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
|
184
|
+
rb_iv_set(self, "@is_variadic", is_variadic ? Qtrue : Qfalse);
|
129
185
|
|
130
186
|
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);
|
187
|
+
cif->arg_types = NULL;
|
144
188
|
|
145
189
|
return self;
|
146
190
|
}
|
@@ -167,56 +211,169 @@ function_call(int argc, VALUE argv[], VALUE self)
|
|
167
211
|
{
|
168
212
|
struct nogvl_ffi_call_args args = { 0 };
|
169
213
|
fiddle_generic *generic_args;
|
170
|
-
VALUE cfunc
|
214
|
+
VALUE cfunc;
|
215
|
+
VALUE abi;
|
216
|
+
VALUE arg_types;
|
217
|
+
VALUE cPointer;
|
218
|
+
VALUE is_variadic;
|
219
|
+
VALUE need_gvl;
|
220
|
+
int n_arg_types;
|
221
|
+
int n_fixed_args = 0;
|
222
|
+
int n_call_args = 0;
|
171
223
|
int i;
|
224
|
+
int i_call;
|
225
|
+
VALUE converted_args = Qnil;
|
172
226
|
VALUE alloc_buffer = 0;
|
173
227
|
|
174
228
|
cfunc = rb_iv_get(self, "@ptr");
|
175
|
-
|
229
|
+
abi = rb_iv_get(self, "@abi");
|
230
|
+
arg_types = rb_iv_get(self, "@argument_types");
|
176
231
|
cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
232
|
+
is_variadic = rb_iv_get(self, "@is_variadic");
|
233
|
+
need_gvl = rb_iv_get(self, "@need_gvl");
|
234
|
+
|
235
|
+
n_arg_types = RARRAY_LENINT(arg_types);
|
236
|
+
n_fixed_args = n_arg_types;
|
237
|
+
if (RTEST(is_variadic)) {
|
238
|
+
if (argc < n_arg_types) {
|
239
|
+
rb_error_arity(argc, n_arg_types, UNLIMITED_ARGUMENTS);
|
240
|
+
}
|
241
|
+
if (((argc - n_arg_types) % 2) != 0) {
|
242
|
+
rb_raise(rb_eArgError,
|
243
|
+
"variadic arguments must be type and value pairs: "
|
244
|
+
"%"PRIsVALUE,
|
245
|
+
rb_ary_new_from_values(argc, argv));
|
246
|
+
}
|
247
|
+
n_call_args = n_arg_types + ((argc - n_arg_types) / 2);
|
181
248
|
}
|
249
|
+
else {
|
250
|
+
if (argc != n_arg_types) {
|
251
|
+
rb_error_arity(argc, n_arg_types, n_arg_types);
|
252
|
+
}
|
253
|
+
n_call_args = n_arg_types;
|
254
|
+
}
|
255
|
+
Check_Max_Args("the number of arguments", n_call_args);
|
182
256
|
|
183
257
|
TypedData_Get_Struct(self, ffi_cif, &function_data_type, args.cif);
|
184
258
|
|
185
|
-
if (
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
259
|
+
if (is_variadic && args.cif->arg_types) {
|
260
|
+
xfree(args.cif->arg_types);
|
261
|
+
args.cif->arg_types = NULL;
|
262
|
+
}
|
263
|
+
|
264
|
+
if (!args.cif->arg_types) {
|
265
|
+
VALUE fixed_arg_types = arg_types;
|
266
|
+
VALUE return_type;
|
267
|
+
int c_return_type;
|
268
|
+
ffi_type *ffi_return_type;
|
269
|
+
ffi_type **ffi_arg_types;
|
270
|
+
ffi_status result;
|
271
|
+
|
272
|
+
arg_types = rb_ary_dup(fixed_arg_types);
|
273
|
+
for (i = n_fixed_args; i < argc; i += 2) {
|
274
|
+
VALUE arg_type = argv[i];
|
275
|
+
int c_arg_type;
|
276
|
+
arg_type = rb_fiddle_type_ensure(arg_type);
|
277
|
+
c_arg_type = NUM2INT(arg_type);
|
278
|
+
(void)INT2FFI_TYPE(c_arg_type); /* raise */
|
279
|
+
rb_ary_push(arg_types, INT2FIX(c_arg_type));
|
280
|
+
}
|
281
|
+
|
282
|
+
return_type = rb_iv_get(self, "@return_type");
|
283
|
+
c_return_type = FIX2INT(return_type);
|
284
|
+
ffi_return_type = INT2FFI_TYPE(c_return_type);
|
285
|
+
|
286
|
+
ffi_arg_types = xcalloc(n_call_args + 1, sizeof(ffi_type *));
|
287
|
+
for (i_call = 0; i_call < n_call_args; i_call++) {
|
288
|
+
VALUE arg_type;
|
289
|
+
int c_arg_type;
|
290
|
+
arg_type = RARRAY_AREF(arg_types, i_call);
|
291
|
+
c_arg_type = FIX2INT(arg_type);
|
292
|
+
ffi_arg_types[i_call] = INT2FFI_TYPE(c_arg_type);
|
293
|
+
}
|
294
|
+
ffi_arg_types[i_call] = NULL;
|
295
|
+
|
296
|
+
if (is_variadic) {
|
297
|
+
#ifdef HAVE_FFI_PREP_CIF_VAR
|
298
|
+
result = ffi_prep_cif_var(args.cif,
|
299
|
+
FIX2INT(abi),
|
300
|
+
n_fixed_args,
|
301
|
+
n_call_args,
|
302
|
+
ffi_return_type,
|
303
|
+
ffi_arg_types);
|
304
|
+
#else
|
305
|
+
/* This code is never used because ffi_prep_cif_var()
|
306
|
+
* availability check is done in #initialize. */
|
307
|
+
result = FFI_BAD_TYPEDEF;
|
308
|
+
#endif
|
309
|
+
}
|
310
|
+
else {
|
311
|
+
result = ffi_prep_cif(args.cif,
|
312
|
+
FIX2INT(abi),
|
313
|
+
n_call_args,
|
314
|
+
ffi_return_type,
|
315
|
+
ffi_arg_types);
|
316
|
+
}
|
317
|
+
if (result != FFI_OK) {
|
318
|
+
xfree(ffi_arg_types);
|
319
|
+
args.cif->arg_types = NULL;
|
320
|
+
rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
|
321
|
+
}
|
192
322
|
}
|
193
323
|
|
194
324
|
generic_args = ALLOCV(alloc_buffer,
|
195
|
-
|
325
|
+
sizeof(fiddle_generic) * n_call_args +
|
326
|
+
sizeof(void *) * (n_call_args + 1));
|
196
327
|
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
|
-
|
328
|
+
sizeof(fiddle_generic) * n_call_args);
|
329
|
+
|
330
|
+
for (i = 0, i_call = 0;
|
331
|
+
i < argc && i_call < n_call_args;
|
332
|
+
i++, i_call++) {
|
333
|
+
VALUE arg_type;
|
334
|
+
int c_arg_type;
|
335
|
+
VALUE original_src;
|
336
|
+
VALUE src;
|
337
|
+
arg_type = RARRAY_AREF(arg_types, i_call);
|
338
|
+
c_arg_type = FIX2INT(arg_type);
|
339
|
+
if (i >= n_fixed_args) {
|
340
|
+
i++;
|
341
|
+
}
|
342
|
+
src = argv[i];
|
343
|
+
|
344
|
+
if (c_arg_type == TYPE_VOIDP) {
|
345
|
+
if (NIL_P(src)) {
|
346
|
+
src = INT2FIX(0);
|
347
|
+
}
|
348
|
+
else if (cPointer != CLASS_OF(src)) {
|
349
|
+
src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
|
350
|
+
if (NIL_P(converted_args)) {
|
351
|
+
converted_args = rb_ary_new();
|
352
|
+
}
|
353
|
+
rb_ary_push(converted_args, src);
|
354
|
+
}
|
355
|
+
src = rb_Integer(src);
|
356
|
+
}
|
357
|
+
|
358
|
+
original_src = src;
|
359
|
+
VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]);
|
360
|
+
if (src != original_src) {
|
361
|
+
if (NIL_P(converted_args)) {
|
362
|
+
converted_args = rb_ary_new();
|
363
|
+
}
|
364
|
+
rb_ary_push(converted_args, src);
|
365
|
+
}
|
366
|
+
args.values[i_call] = (void *)&generic_args[i_call];
|
215
367
|
}
|
216
|
-
args.values[
|
217
|
-
args.fn = NUM2PTR(cfunc);
|
368
|
+
args.values[i_call] = NULL;
|
369
|
+
args.fn = (void(*)(void))NUM2PTR(cfunc);
|
218
370
|
|
219
|
-
(
|
371
|
+
if (RTEST(need_gvl)) {
|
372
|
+
ffi_call(args.cif, args.fn, &(args.retval), args.values);
|
373
|
+
}
|
374
|
+
else {
|
375
|
+
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
|
376
|
+
}
|
220
377
|
|
221
378
|
rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
|
222
379
|
#if defined(_WIN32)
|
@@ -294,6 +451,10 @@ Init_fiddle_function(void)
|
|
294
451
|
* Caller must ensure the underlying function is called in a
|
295
452
|
* thread-safe manner if running in a multi-threaded process.
|
296
453
|
*
|
454
|
+
* Note that it is not thread-safe to use this method to
|
455
|
+
* directly or indirectly call many Ruby C-extension APIs unless
|
456
|
+
* you don't pass +need_gvl: true+ to Fiddle::Function#new.
|
457
|
+
*
|
297
458
|
* For an example see Fiddle::Function
|
298
459
|
*
|
299
460
|
*/
|
@@ -301,13 +462,20 @@ Init_fiddle_function(void)
|
|
301
462
|
|
302
463
|
/*
|
303
464
|
* Document-method: new
|
304
|
-
* call-seq: new(ptr,
|
465
|
+
* call-seq: new(ptr,
|
466
|
+
* args,
|
467
|
+
* ret_type,
|
468
|
+
* abi = DEFAULT,
|
469
|
+
* name: nil,
|
470
|
+
* need_gvl: false)
|
305
471
|
*
|
306
472
|
* Constructs a Function object.
|
307
473
|
* * +ptr+ is a referenced function, of a Fiddle::Handle
|
308
474
|
* * +args+ is an Array of arguments, passed to the +ptr+ function
|
309
475
|
* * +ret_type+ is the return type of the function
|
310
476
|
* * +abi+ is the ABI of the function
|
477
|
+
* * +name+ is the name of the function
|
478
|
+
* * +need_gvl+ is whether GVL is needed to call the function
|
311
479
|
*
|
312
480
|
*/
|
313
481
|
rb_define_method(cFiddleFunction, "initialize", initialize, -1);
|