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.
@@ -58,38 +58,38 @@
58
58
  # error "CHAR_BIT not supported"
59
59
  #endif
60
60
 
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
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
- # 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
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
- # 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
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 rb_eFiddleError;
197
+ extern VALUE rb_eFiddleDLError;
134
198
 
135
199
  VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type);
136
200
 
@@ -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
- if ((size_t)(len) < MAX_ARGS) { \
23
- /* OK */ \
24
- } \
25
- else { \
26
- rb_raise(rb_eTypeError, \
27
- name" is so large that it can cause integer overflow (%"fmt"d)", \
28
- (len)); \
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 *ptr = p;
35
- if (ptr->arg_types) xfree(ptr->arg_types);
36
- xfree(ptr);
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 int
79
- parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
80
+ static VALUE
81
+ normalize_argument_types(const char *name,
82
+ VALUE arg_types,
83
+ bool *is_variadic)
80
84
  {
81
- if (key == ID2SYM(rb_intern("name"))) {
82
- rb_iv_set(self, "@name", value);
83
- } else {
84
- rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE,
85
- RB_OBJ_STRING(key));
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
- return ST_CONTINUE;
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
- ffi_type **arg_types, *rtype;
95
- ffi_status result;
96
- VALUE ptr, args, ret_type, abi, kwds, ary;
97
- int i, len;
98
- int nabi;
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, &args, &ret_type, &abi, &kwds);
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
- nabi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi);
106
- abi = INT2FIX(nabi);
107
- i = NUM2INT(ret_type);
108
- rtype = INT2FFI_TYPE(i);
109
- ret_type = INT2FIX(i);
110
-
111
- Check_Type(args, T_ARRAY);
112
- len = RARRAY_LENINT(args);
113
- Check_Max_Args("args", len);
114
- ary = rb_ary_subseq(args, 0, len);
115
- for (i = 0; i < RARRAY_LEN(args); i++) {
116
- VALUE a = RARRAY_PTR(args)[i];
117
- int type = NUM2INT(a);
118
- (void)INT2FFI_TYPE(type); /* raise */
119
- if (INT2FIX(type) != a) rb_ary_store(ary, i, INT2FIX(type));
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
- OBJ_FREEZE(ary);
178
+ #endif
122
179
 
123
180
  rb_iv_set(self, "@ptr", ptr);
124
- rb_iv_set(self, "@args", args);
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, types, cPointer;
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
- types = rb_iv_get(self, "@args");
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
- Check_Max_Args("number of arguments", argc);
179
- if (argc != (i = RARRAY_LENINT(types))) {
180
- rb_error_arity(argc, i, i);
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 (rb_safe_level() >= 1) {
186
- for (i = 0; i < argc; i++) {
187
- VALUE src = argv[i];
188
- if (OBJ_TAINTED(src)) {
189
- rb_raise(rb_eSecurityError, "tainted parameter not allowed");
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
- (size_t)(argc + 1) * sizeof(void *) + (size_t)argc * sizeof(fiddle_generic));
325
+ sizeof(fiddle_generic) * n_call_args +
326
+ sizeof(void *) * (n_call_args + 1));
196
327
  args.values = (void **)((char *)generic_args +
197
- (size_t)argc * sizeof(fiddle_generic));
198
-
199
- for (i = 0; i < argc; i++) {
200
- VALUE type = RARRAY_AREF(types, i);
201
- VALUE src = argv[i];
202
- int argtype = FIX2INT(type);
203
-
204
- if (argtype == TYPE_VOIDP) {
205
- if(NIL_P(src)) {
206
- src = INT2FIX(0);
207
- } else if(cPointer != CLASS_OF(src)) {
208
- src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
209
- }
210
- src = rb_Integer(src);
211
- }
212
-
213
- VALUE2GENERIC(argtype, src, &generic_args[i]);
214
- args.values[i] = (void *)&generic_args[i];
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[argc] = NULL;
217
- args.fn = NUM2PTR(cfunc);
368
+ args.values[i_call] = NULL;
369
+ args.fn = (void(*)(void))NUM2PTR(cfunc);
218
370
 
219
- (void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
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, args, ret_type, abi = DEFAULT)
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);