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.
- checksums.yaml +4 -4
- data/README.md +52 -1
- 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 +62 -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 +48 -5
- data/lib/fiddle.rb +3 -1
- data/lib/fiddle/cparser.rb +90 -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 +15 -12
- data/.gitignore +0 -13
- data/.travis.yml +0 -7
- data/Gemfile +0 -4
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/ext/fiddle/extlibs
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
|
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
|
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
|
data/ext/fiddle/fiddle.c
CHANGED
@@ -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
|
-
|
7
|
-
|
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
|
-
#
|
28
|
-
|
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
|
-
|
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: */
|
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);
|