fiddle 1.0.0 → 1.0.5

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.
@@ -1,5 +1,13 @@
1
- http://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz \
1
+ ver = 3.2.1
2
+ pkg = libffi-$(ver)
3
+
4
+ https://ftp.osuosl.org/pub/blfs/conglomeration/libffi/$(pkg).tar.gz \
2
5
  md5:83b89587607e3eb65c70d361f13bab43 \
3
6
  sha512:980ca30a8d76f963fca722432b1fe5af77d7a4e4d2eac5144fbc5374d4c596609a293440573f4294207e1bdd9fda80ad1e1cafb2ffb543df5a275bc3bd546483 \
4
7
  #
5
- win32/libffi-3.2.1-mswin.patch -p0
8
+ win32/$(pkg)-mswin.patch -p0
9
+
10
+ $(pkg)/config.guess -> /tool/config.guess
11
+ $(pkg)/config.sub -> /tool/config.sub
12
+
13
+ ! chdir: $(pkg)| autoconf || exit 0
@@ -1,41 +1,15 @@
1
1
  #include <fiddle.h>
2
2
 
3
3
  VALUE mFiddle;
4
+ VALUE rb_eFiddleDLError;
4
5
  VALUE rb_eFiddleError;
5
6
 
6
- #ifndef TYPE_SSIZE_T
7
- # if SIZEOF_SIZE_T == SIZEOF_INT
8
- # define TYPE_SSIZE_T TYPE_INT
9
- # elif SIZEOF_SIZE_T == SIZEOF_LONG
10
- # define TYPE_SSIZE_T TYPE_LONG
11
- # elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
12
- # define TYPE_SSIZE_T TYPE_LONG_LONG
13
- # endif
14
- #endif
15
- #define TYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*TYPE_SSIZE_T)
16
-
17
- #ifndef TYPE_PTRDIFF_T
18
- # if SIZEOF_PTRDIFF_T == SIZEOF_INT
19
- # define TYPE_PTRDIFF_T TYPE_INT
20
- # elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
21
- # define TYPE_PTRDIFF_T TYPE_LONG
22
- # elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
23
- # define TYPE_PTRDIFF_T TYPE_LONG_LONG
24
- # endif
25
- #endif
7
+ void Init_fiddle_pointer(void);
8
+ void Init_fiddle_pinned(void);
26
9
 
27
- #ifndef TYPE_INTPTR_T
28
- # if SIZEOF_INTPTR_T == SIZEOF_INT
29
- # define TYPE_INTPTR_T TYPE_INT
30
- # elif SIZEOF_INTPTR_T == SIZEOF_LONG
31
- # define TYPE_INTPTR_T TYPE_LONG
32
- # elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
33
- # define TYPE_INTPTR_T TYPE_LONG_LONG
34
- # endif
10
+ #ifdef FIDDLE_MEMORY_VIEW
11
+ void Init_fiddle_memory_view(void);
35
12
  #endif
36
- #define TYPE_UINTPTR_T (-TYPE_INTPTR_T)
37
-
38
- void Init_fiddle_pointer(void);
39
13
 
40
14
  /*
41
15
  * call-seq: Fiddle.malloc(size)
@@ -47,8 +21,7 @@ static VALUE
47
21
  rb_fiddle_malloc(VALUE self, VALUE size)
48
22
  {
49
23
  void *ptr;
50
-
51
- ptr = (void*)ruby_xmalloc(NUM2SIZET(size));
24
+ ptr = (void*)ruby_xcalloc(1, NUM2SIZET(size));
52
25
  return PTR2NUM(ptr);
53
26
  }
54
27
 
@@ -163,12 +136,33 @@ Init_fiddle(void)
163
136
  */
164
137
  mFiddle = rb_define_module("Fiddle");
165
138
 
139
+ /*
140
+ * Document-class: Fiddle::Error
141
+ *
142
+ * Generic error class for Fiddle
143
+ */
144
+ rb_eFiddleError = rb_define_class_under(mFiddle, "Error", rb_eStandardError);
145
+
146
+ /*
147
+ * Ruby installed by RubyInstaller for Windows always require
148
+ * bundled Fiddle because ruby_installer/runtime/dll_directory.rb
149
+ * requires Fiddle. It's used by
150
+ * rubygems/defaults/operating_system.rb. It means that the
151
+ * bundled Fiddle is always required on initialization.
152
+ *
153
+ * We just remove existing Fiddle::DLError here to override
154
+ * the bundled Fiddle.
155
+ */
156
+ if (rb_const_defined(mFiddle, rb_intern("DLError"))) {
157
+ rb_const_remove(mFiddle, rb_intern("DLError"));
158
+ }
159
+
166
160
  /*
167
161
  * Document-class: Fiddle::DLError
168
162
  *
169
163
  * standard dynamic load exception
170
164
  */
171
- rb_eFiddleError = rb_define_class_under(mFiddle, "DLError", rb_eStandardError);
165
+ rb_eFiddleDLError = rb_define_class_under(mFiddle, "DLError", rb_eFiddleError);
172
166
 
173
167
  /* Document-const: TYPE_VOID
174
168
  *
@@ -214,6 +208,38 @@ Init_fiddle(void)
214
208
  rb_define_const(mFiddle, "TYPE_LONG_LONG", INT2NUM(TYPE_LONG_LONG));
215
209
  #endif
216
210
 
211
+ #ifdef TYPE_INT8_T
212
+ /* Document-const: TYPE_INT8_T
213
+ *
214
+ * C type - int8_t
215
+ */
216
+ rb_define_const(mFiddle, "TYPE_INT8_T", INT2NUM(TYPE_INT8_T));
217
+ #endif
218
+
219
+ #ifdef TYPE_INT16_T
220
+ /* Document-const: TYPE_INT16_T
221
+ *
222
+ * C type - int16_t
223
+ */
224
+ rb_define_const(mFiddle, "TYPE_INT16_T", INT2NUM(TYPE_INT16_T));
225
+ #endif
226
+
227
+ #ifdef TYPE_INT32_T
228
+ /* Document-const: TYPE_INT32_T
229
+ *
230
+ * C type - int32_t
231
+ */
232
+ rb_define_const(mFiddle, "TYPE_INT32_T", INT2NUM(TYPE_INT32_T));
233
+ #endif
234
+
235
+ #ifdef TYPE_INT64_T
236
+ /* Document-const: TYPE_INT64_T
237
+ *
238
+ * C type - int64_t
239
+ */
240
+ rb_define_const(mFiddle, "TYPE_INT64_T", INT2NUM(TYPE_INT64_T));
241
+ #endif
242
+
217
243
  /* Document-const: TYPE_FLOAT
218
244
  *
219
245
  * C type - float
@@ -226,6 +252,20 @@ Init_fiddle(void)
226
252
  */
227
253
  rb_define_const(mFiddle, "TYPE_DOUBLE", INT2NUM(TYPE_DOUBLE));
228
254
 
255
+ #ifdef HAVE_FFI_PREP_CIF_VAR
256
+ /* Document-const: TYPE_VARIADIC
257
+ *
258
+ * C type - ...
259
+ */
260
+ rb_define_const(mFiddle, "TYPE_VARIADIC", INT2NUM(TYPE_VARIADIC));
261
+ #endif
262
+
263
+ /* Document-const: TYPE_CONST_STRING
264
+ *
265
+ * C type - const char* ('\0' terminated const char*)
266
+ */
267
+ rb_define_const(mFiddle, "TYPE_CONST_STRING", INT2NUM(TYPE_CONST_STRING));
268
+
229
269
  /* Document-const: TYPE_SIZE_T
230
270
  *
231
271
  * C type - size_t
@@ -294,6 +334,30 @@ Init_fiddle(void)
294
334
  rb_define_const(mFiddle, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG));
295
335
  #endif
296
336
 
337
+ /* Document-const: ALIGN_INT8_T
338
+ *
339
+ * The alignment size of a int8_t
340
+ */
341
+ rb_define_const(mFiddle, "ALIGN_INT8_T", INT2NUM(ALIGN_INT8_T));
342
+
343
+ /* Document-const: ALIGN_INT16_T
344
+ *
345
+ * The alignment size of a int16_t
346
+ */
347
+ rb_define_const(mFiddle, "ALIGN_INT16_T", INT2NUM(ALIGN_INT16_T));
348
+
349
+ /* Document-const: ALIGN_INT32_T
350
+ *
351
+ * The alignment size of a int32_t
352
+ */
353
+ rb_define_const(mFiddle, "ALIGN_INT32_T", INT2NUM(ALIGN_INT32_T));
354
+
355
+ /* Document-const: ALIGN_INT64_T
356
+ *
357
+ * The alignment size of a int64_t
358
+ */
359
+ rb_define_const(mFiddle, "ALIGN_INT64_T", INT2NUM(ALIGN_INT64_T));
360
+
297
361
  /* Document-const: ALIGN_FLOAT
298
362
  *
299
363
  * The alignment size of a float
@@ -384,6 +448,30 @@ Init_fiddle(void)
384
448
  rb_define_const(mFiddle, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG)));
385
449
  #endif
386
450
 
451
+ /* Document-const: SIZEOF_INT8_T
452
+ *
453
+ * size of a int8_t
454
+ */
455
+ rb_define_const(mFiddle, "SIZEOF_INT8_T", INT2NUM(sizeof(int8_t)));
456
+
457
+ /* Document-const: SIZEOF_INT16_T
458
+ *
459
+ * size of a int16_t
460
+ */
461
+ rb_define_const(mFiddle, "SIZEOF_INT16_T", INT2NUM(sizeof(int16_t)));
462
+
463
+ /* Document-const: SIZEOF_INT32_T
464
+ *
465
+ * size of a int32_t
466
+ */
467
+ rb_define_const(mFiddle, "SIZEOF_INT32_T", INT2NUM(sizeof(int32_t)));
468
+
469
+ /* Document-const: SIZEOF_INT64_T
470
+ *
471
+ * size of a int64_t
472
+ */
473
+ rb_define_const(mFiddle, "SIZEOF_INT64_T", INT2NUM(sizeof(int64_t)));
474
+
387
475
  /* Document-const: SIZEOF_FLOAT
388
476
  *
389
477
  * size of a float
@@ -426,6 +514,12 @@ Init_fiddle(void)
426
514
  */
427
515
  rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t)));
428
516
 
517
+ /* Document-const: SIZEOF_CONST_STRING
518
+ *
519
+ * size of a const char*
520
+ */
521
+ rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));
522
+
429
523
  /* Document-const: RUBY_FREE
430
524
  *
431
525
  * Address of the ruby_xfree() function
@@ -450,5 +544,10 @@ Init_fiddle(void)
450
544
  Init_fiddle_closure();
451
545
  Init_fiddle_handle();
452
546
  Init_fiddle_pointer();
547
+ Init_fiddle_pinned();
548
+
549
+ #ifdef FIDDLE_MEMORY_VIEW
550
+ Init_fiddle_memory_view();
551
+ #endif
453
552
  }
454
553
  /* vim: set noet sws=4 sw=4: */
@@ -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);