ffi 0.3.0 → 0.4.0
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.
- data/README.rdoc +51 -1
- data/Rakefile +47 -28
- data/ext/ffi_c/AbstractMemory.c +149 -65
- data/ext/ffi_c/AbstractMemory.h +34 -4
- data/ext/ffi_c/AutoPointer.c +15 -18
- data/ext/ffi_c/AutoPointer.h +2 -2
- data/ext/ffi_c/Buffer.c +79 -44
- data/ext/ffi_c/Callback.c +133 -62
- data/ext/ffi_c/Callback.h +11 -5
- data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +88 -24
- data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
- data/ext/ffi_c/Invoker.c +154 -190
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +30 -20
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +67 -28
- data/ext/ffi_c/Platform.c +9 -10
- data/ext/ffi_c/Platform.h +1 -1
- data/ext/ffi_c/Pointer.c +67 -30
- data/ext/ffi_c/Pointer.h +8 -6
- data/ext/ffi_c/Struct.c +202 -267
- data/ext/ffi_c/Struct.h +2 -2
- data/ext/ffi_c/Type.c +230 -0
- data/ext/ffi_c/Type.h +28 -0
- data/ext/ffi_c/Types.c +48 -6
- data/ext/ffi_c/Types.h +8 -2
- data/ext/ffi_c/endian.h +40 -0
- data/ext/ffi_c/extconf.rb +6 -5
- data/ext/ffi_c/ffi.c +21 -44
- data/ext/ffi_c/libffi.bsd.mk +34 -0
- data/ext/ffi_c/libffi.darwin.mk +30 -10
- data/ext/ffi_c/libffi.gnu.mk +29 -0
- data/ext/ffi_c/libffi.mk +4 -2
- data/ext/ffi_c/rbffi.h +6 -8
- data/gen/Rakefile +12 -0
- data/lib/ffi/autopointer.rb +1 -1
- data/lib/ffi/enum.rb +78 -0
- data/lib/ffi/ffi.rb +5 -6
- data/lib/ffi/io.rb +15 -1
- data/lib/ffi/library.rb +79 -18
- data/lib/ffi/pointer.rb +2 -2
- data/lib/ffi/struct.rb +68 -14
- data/lib/ffi/types.rb +6 -3
- data/lib/ffi/variadic.rb +2 -2
- data/lib/ffi.rb +10 -1
- data/spec/ffi/bool_spec.rb +24 -0
- data/spec/ffi/callback_spec.rb +217 -17
- data/spec/ffi/enum_spec.rb +164 -0
- data/spec/ffi/managed_struct_spec.rb +6 -1
- data/spec/ffi/number_spec.rb +30 -0
- data/spec/ffi/pointer_spec.rb +33 -8
- data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
- data/spec/ffi/spec_helper.rb +5 -1
- data/spec/ffi/string_spec.rb +65 -4
- data/spec/ffi/struct_callback_spec.rb +41 -0
- data/spec/ffi/struct_initialize_spec.rb +30 -0
- data/spec/ffi/struct_spec.rb +44 -21
- metadata +31 -69
- data/ext/ffi_c/ffi.mk +0 -23
- data/nbproject/Makefile-Default.mk +0 -57
- data/nbproject/Makefile-impl.mk +0 -123
- data/nbproject/Package-Default.bash +0 -72
- data/nbproject/configurations.xml +0 -293
- data/nbproject/private/configurations.xml +0 -22
- data/nbproject/private/private.xml +0 -7
- data/nbproject/project.properties +0 -0
- data/nbproject/project.xml +0 -15
- data/samples/getlogin.rb +0 -7
- data/samples/getpid.rb +0 -7
- data/samples/gettimeofday.rb +0 -17
- data/samples/hello.rb +0 -6
- data/samples/inotify.rb +0 -59
- data/samples/pty.rb +0 -75
- data/samples/qsort.rb +0 -20
- data/samples/sample_helper.rb +0 -6
data/ext/ffi_c/Invoker.c
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
#include <stdio.h>
|
|
7
7
|
#include <stdint.h>
|
|
8
8
|
#include <stdbool.h>
|
|
9
|
-
#
|
|
9
|
+
#ifndef _WIN32
|
|
10
|
+
# include <unistd.h>
|
|
11
|
+
# include <pthread.h>
|
|
12
|
+
#endif
|
|
10
13
|
#include <errno.h>
|
|
11
14
|
#include <ruby.h>
|
|
12
15
|
|
|
13
16
|
#include <ffi.h>
|
|
14
|
-
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
|
15
|
-
# include <pthread.h>
|
|
16
|
-
#endif
|
|
17
17
|
#include "rbffi.h"
|
|
18
18
|
#include "compat.h"
|
|
19
19
|
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
#include "Platform.h"
|
|
24
24
|
#include "Callback.h"
|
|
25
25
|
#include "Types.h"
|
|
26
|
+
#include "Type.h"
|
|
27
|
+
#include "LastError.h"
|
|
26
28
|
|
|
27
29
|
#if defined(__i386__) && !defined(_WIN32) && !defined(__WIN32__)
|
|
28
30
|
# define USE_RAW
|
|
@@ -32,17 +34,23 @@
|
|
|
32
34
|
#endif
|
|
33
35
|
#define MAX_FIXED_ARITY (3)
|
|
34
36
|
|
|
37
|
+
#ifndef roundup
|
|
38
|
+
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
|
39
|
+
#endif
|
|
40
|
+
|
|
35
41
|
typedef struct MethodHandle MethodHandle;
|
|
36
42
|
typedef struct Invoker Invoker;
|
|
37
43
|
|
|
38
44
|
struct Invoker {
|
|
39
|
-
VALUE
|
|
45
|
+
VALUE address;
|
|
46
|
+
VALUE enums;
|
|
40
47
|
void* function;
|
|
41
48
|
ffi_cif cif;
|
|
42
49
|
int paramCount;
|
|
43
50
|
ffi_type** ffiParamTypes;
|
|
44
51
|
NativeType* paramTypes;
|
|
45
|
-
|
|
52
|
+
Type* returnType;
|
|
53
|
+
VALUE rbReturnType;
|
|
46
54
|
VALUE callbackArray;
|
|
47
55
|
int callbackCount;
|
|
48
56
|
VALUE* callbackParameters;
|
|
@@ -72,16 +80,13 @@ struct MethodHandlePool {
|
|
|
72
80
|
MethodHandle* list;
|
|
73
81
|
};
|
|
74
82
|
#endif /* _WIN32 */
|
|
75
|
-
|
|
76
|
-
int td_errno;
|
|
77
|
-
} ThreadData;
|
|
83
|
+
|
|
78
84
|
static VALUE invoker_allocate(VALUE klass);
|
|
79
|
-
static VALUE invoker_initialize(VALUE self, VALUE
|
|
80
|
-
VALUE returnType, VALUE convention);
|
|
85
|
+
static VALUE invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
|
|
86
|
+
VALUE rbReturnType, VALUE returnType, VALUE convention, VALUE enums);
|
|
81
87
|
static void invoker_mark(Invoker *);
|
|
82
88
|
static void invoker_free(Invoker *);
|
|
83
89
|
static VALUE invoker_call(int argc, VALUE* argv, VALUE self);
|
|
84
|
-
static VALUE invoker_call0(VALUE self);
|
|
85
90
|
static VALUE invoker_arity(VALUE self);
|
|
86
91
|
static void* callback_param(VALUE proc, VALUE cbinfo);
|
|
87
92
|
#ifdef USE_RAW
|
|
@@ -96,19 +101,15 @@ static void attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameter
|
|
|
96
101
|
static MethodHandle* method_handle_alloc(int arity);
|
|
97
102
|
static void method_handle_free(MethodHandle *);
|
|
98
103
|
|
|
99
|
-
static inline ThreadData* thread_data_get(void);
|
|
100
104
|
|
|
101
105
|
#ifndef _WIN32
|
|
102
106
|
static int PageSize;
|
|
103
107
|
#endif
|
|
104
|
-
static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
|
|
105
|
-
static ID to_ptr;
|
|
106
|
-
|
|
107
|
-
#if defined(USE_PTHREAD_LOCAL)
|
|
108
|
-
static pthread_key_t threadDataKey;
|
|
109
|
-
#endif
|
|
110
108
|
|
|
111
|
-
|
|
109
|
+
VALUE rbffi_InvokerClass = Qnil;
|
|
110
|
+
static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
|
|
111
|
+
static ID to_ptr = 0;
|
|
112
|
+
static ID map_symbol_id = 0;
|
|
112
113
|
|
|
113
114
|
#ifdef USE_RAW
|
|
114
115
|
# ifndef __i386__
|
|
@@ -142,12 +143,19 @@ static VALUE
|
|
|
142
143
|
invoker_allocate(VALUE klass)
|
|
143
144
|
{
|
|
144
145
|
Invoker *invoker;
|
|
145
|
-
|
|
146
|
+
VALUE obj = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
|
|
147
|
+
|
|
148
|
+
invoker->rbReturnType = Qnil;
|
|
149
|
+
invoker->callbackArray = Qnil;
|
|
150
|
+
invoker->address = Qnil;
|
|
151
|
+
invoker->enums = Qnil;
|
|
152
|
+
|
|
153
|
+
return obj;
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
static VALUE
|
|
149
|
-
invoker_initialize(VALUE self, VALUE
|
|
150
|
-
VALUE returnType, VALUE convention)
|
|
157
|
+
invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
|
|
158
|
+
VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
|
|
151
159
|
{
|
|
152
160
|
Invoker* invoker = NULL;
|
|
153
161
|
ffi_type* ffiReturnType;
|
|
@@ -156,39 +164,45 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
|
|
|
156
164
|
int i;
|
|
157
165
|
|
|
158
166
|
Check_Type(parameterTypes, T_ARRAY);
|
|
159
|
-
Check_Type(
|
|
167
|
+
Check_Type(rbReturnTypeSymbol, T_SYMBOL);
|
|
160
168
|
Check_Type(convention, T_STRING);
|
|
161
|
-
Check_Type(library, T_DATA);
|
|
162
169
|
Check_Type(function, T_DATA);
|
|
163
170
|
|
|
164
171
|
Data_Get_Struct(self, Invoker, invoker);
|
|
165
|
-
invoker->
|
|
166
|
-
invoker->
|
|
172
|
+
invoker->enums = enums;
|
|
173
|
+
invoker->address = function;
|
|
174
|
+
invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
|
|
167
175
|
invoker->paramCount = RARRAY_LEN(parameterTypes);
|
|
168
176
|
invoker->paramTypes = ALLOC_N(NativeType, invoker->paramCount);
|
|
169
177
|
invoker->ffiParamTypes = ALLOC_N(ffi_type *, invoker->paramCount);
|
|
170
178
|
|
|
171
179
|
for (i = 0; i < invoker->paramCount; ++i) {
|
|
172
180
|
VALUE entry = rb_ary_entry(parameterTypes, i);
|
|
173
|
-
if (rb_obj_is_kind_of(entry,
|
|
181
|
+
if (rb_obj_is_kind_of(entry, rbffi_CallbackInfoClass)) {
|
|
174
182
|
invoker->callbackParameters = REALLOC_N(invoker->callbackParameters, VALUE,
|
|
175
183
|
invoker->callbackCount + 1);
|
|
176
184
|
invoker->callbackParameters[invoker->callbackCount++] = entry;
|
|
177
185
|
invoker->paramTypes[i] = NATIVE_CALLBACK;
|
|
178
186
|
invoker->ffiParamTypes[i] = &ffi_type_pointer;
|
|
179
|
-
} else {
|
|
180
|
-
int paramType =
|
|
187
|
+
} else if (rb_obj_is_kind_of(entry, rbffi_TypeClass)){
|
|
188
|
+
int paramType = rbffi_Type_GetIntValue(entry);
|
|
181
189
|
invoker->paramTypes[i] = paramType;
|
|
182
|
-
invoker->ffiParamTypes[i] =
|
|
190
|
+
invoker->ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
|
|
183
191
|
}
|
|
184
192
|
if (invoker->ffiParamTypes[i] == NULL) {
|
|
185
|
-
rb_raise(
|
|
193
|
+
rb_raise(rb_eTypeError, "Invalid parameter type");
|
|
186
194
|
}
|
|
187
195
|
}
|
|
188
|
-
|
|
189
|
-
|
|
196
|
+
if (!rb_obj_is_kind_of(returnType, rbffi_TypeClass)) {
|
|
197
|
+
rb_raise(rb_eTypeError, "Invalid return type");
|
|
198
|
+
}
|
|
199
|
+
Data_Get_Struct(returnType, Type, invoker->returnType);
|
|
200
|
+
invoker->rbReturnType = rb_obj_is_kind_of(returnType, rbffi_CallbackInfoClass)
|
|
201
|
+
? returnType : rbReturnTypeSymbol;
|
|
202
|
+
|
|
203
|
+
ffiReturnType = invoker->returnType->ffiType;
|
|
190
204
|
if (ffiReturnType == NULL) {
|
|
191
|
-
rb_raise(
|
|
205
|
+
rb_raise(rb_eTypeError, "Invalid return type");
|
|
192
206
|
}
|
|
193
207
|
#if defined(_WIN32) || defined(__WIN32__)
|
|
194
208
|
abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
|
|
@@ -213,25 +227,31 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
|
|
|
213
227
|
}
|
|
214
228
|
|
|
215
229
|
static VALUE
|
|
216
|
-
variadic_invoker_new(VALUE klass, VALUE
|
|
230
|
+
variadic_invoker_new(VALUE klass, VALUE function, VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
|
|
217
231
|
{
|
|
218
232
|
Invoker* invoker = NULL;
|
|
219
233
|
VALUE retval = Qnil;
|
|
220
234
|
|
|
221
|
-
Check_Type(
|
|
235
|
+
Check_Type(rbReturnTypeSymbol, T_SYMBOL);
|
|
222
236
|
Check_Type(convention, T_STRING);
|
|
223
|
-
Check_Type(library, T_DATA);
|
|
224
237
|
Check_Type(function, T_DATA);
|
|
225
238
|
|
|
226
239
|
retval = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
|
|
227
|
-
invoker->
|
|
228
|
-
invoker->
|
|
240
|
+
invoker->enums = enums;
|
|
241
|
+
invoker->address = function;
|
|
242
|
+
invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
|
|
229
243
|
#if defined(_WIN32) || defined(__WIN32__)
|
|
230
244
|
invoker->abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
|
|
231
245
|
#else
|
|
232
246
|
invoker->abi = FFI_DEFAULT_ABI;
|
|
233
247
|
#endif
|
|
234
|
-
|
|
248
|
+
|
|
249
|
+
invoker->rbReturnType = rb_obj_is_kind_of(returnType, rbffi_CallbackInfoClass)
|
|
250
|
+
? returnType : rbReturnTypeSymbol;
|
|
251
|
+
if (!rb_obj_is_kind_of(returnType, rbffi_TypeClass)) {
|
|
252
|
+
rb_raise(rb_eTypeError, "Invalid return type");
|
|
253
|
+
}
|
|
254
|
+
Data_Get_Struct(returnType, Type, invoker->returnType);
|
|
235
255
|
invoker->paramCount = -1;
|
|
236
256
|
return retval;
|
|
237
257
|
}
|
|
@@ -420,7 +440,7 @@ method_handle_free(MethodHandle* method)
|
|
|
420
440
|
#endif /* _WIN32 */
|
|
421
441
|
|
|
422
442
|
typedef union {
|
|
423
|
-
#
|
|
443
|
+
#ifdef USE_RAW
|
|
424
444
|
signed int s8, s16, s32;
|
|
425
445
|
unsigned int u8, u16, u32;
|
|
426
446
|
#else
|
|
@@ -439,10 +459,16 @@ typedef union {
|
|
|
439
459
|
} FFIStorage;
|
|
440
460
|
|
|
441
461
|
static inline int
|
|
442
|
-
getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName)
|
|
462
|
+
getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName, VALUE enums)
|
|
443
463
|
{
|
|
444
464
|
int i;
|
|
445
|
-
if (type
|
|
465
|
+
if (type == T_SYMBOL && enums != Qnil) {
|
|
466
|
+
value = rb_funcall(enums, map_symbol_id, 1, value);
|
|
467
|
+
if (value == Qnil) {
|
|
468
|
+
rb_raise(rb_eTypeError, "Expected a valid enum constant");
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
else if (type != T_FIXNUM && type != T_BIGNUM) {
|
|
446
472
|
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
|
447
473
|
}
|
|
448
474
|
i = NUM2INT(value);
|
|
@@ -500,18 +526,25 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
|
|
|
500
526
|
for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
|
|
501
527
|
int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
|
|
502
528
|
ffiValues[i] = param;
|
|
503
|
-
|
|
504
529
|
switch (paramTypes[i]) {
|
|
505
530
|
case NATIVE_INT8:
|
|
506
|
-
param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char");
|
|
531
|
+
param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
|
|
507
532
|
ADJ(param, INT8);
|
|
508
533
|
break;
|
|
509
534
|
case NATIVE_INT16:
|
|
510
|
-
param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short");
|
|
535
|
+
param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
|
|
511
536
|
ADJ(param, INT16);
|
|
512
537
|
break;
|
|
513
538
|
case NATIVE_INT32:
|
|
514
|
-
|
|
539
|
+
case NATIVE_ENUM:
|
|
540
|
+
param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int", invoker->enums);
|
|
541
|
+
ADJ(param, INT32);
|
|
542
|
+
break;
|
|
543
|
+
case NATIVE_BOOL:
|
|
544
|
+
if (type != T_TRUE && type != T_FALSE) {
|
|
545
|
+
rb_raise(rb_eTypeError, "Expected a Boolean parameter");
|
|
546
|
+
}
|
|
547
|
+
param->s32 = argv[argidx++] == Qtrue;
|
|
515
548
|
ADJ(param, INT32);
|
|
516
549
|
break;
|
|
517
550
|
case NATIVE_UINT8:
|
|
@@ -577,9 +610,9 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
|
|
|
577
610
|
case NATIVE_BUFFER_IN:
|
|
578
611
|
case NATIVE_BUFFER_OUT:
|
|
579
612
|
case NATIVE_BUFFER_INOUT:
|
|
580
|
-
if (type == T_DATA && rb_obj_is_kind_of(argv[argidx],
|
|
613
|
+
if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_AbstractMemoryClass)) {
|
|
581
614
|
param->ptr = ((AbstractMemory *) DATA_PTR(argv[argidx]))->address;
|
|
582
|
-
} else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx],
|
|
615
|
+
} else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_StructClass)) {
|
|
583
616
|
AbstractMemory* memory = ((Struct *) DATA_PTR(argv[argidx]))->pointer;
|
|
584
617
|
param->ptr = memory != NULL ? memory->address : NULL;
|
|
585
618
|
} else if (type == T_STRING) {
|
|
@@ -591,7 +624,7 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
|
|
|
591
624
|
param->ptr = NULL;
|
|
592
625
|
} else if (rb_respond_to(argv[argidx], to_ptr)) {
|
|
593
626
|
VALUE ptr = rb_funcall2(argv[argidx], to_ptr, 0, NULL);
|
|
594
|
-
if (rb_obj_is_kind_of(ptr,
|
|
627
|
+
if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) {
|
|
595
628
|
param->ptr = ((AbstractMemory *) DATA_PTR(ptr))->address;
|
|
596
629
|
} else {
|
|
597
630
|
rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
|
|
@@ -618,77 +651,48 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
|
|
|
618
651
|
}
|
|
619
652
|
}
|
|
620
653
|
static inline VALUE
|
|
621
|
-
ffi_invoke(ffi_cif* cif,
|
|
654
|
+
ffi_invoke(ffi_cif* cif, Invoker* invoker, void** ffiValues)
|
|
622
655
|
{
|
|
623
656
|
FFIStorage retval;
|
|
657
|
+
|
|
624
658
|
#ifdef USE_RAW
|
|
625
|
-
ffi_raw_call(cif, FFI_FN(function), &retval, (ffi_raw *) ffiValues[0]);
|
|
659
|
+
ffi_raw_call(cif, FFI_FN(invoker->function), &retval, (ffi_raw *) ffiValues[0]);
|
|
626
660
|
#else
|
|
627
|
-
ffi_call(cif, FFI_FN(function), &retval, ffiValues);
|
|
661
|
+
ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
|
|
628
662
|
#endif
|
|
629
|
-
|
|
630
|
-
threadData->td_errno = GetLastError();
|
|
631
|
-
#else
|
|
632
|
-
threadData->td_errno = errno;
|
|
633
|
-
#endif
|
|
634
|
-
return rb_FFI_NativeValueToRuby(returnType, &retval);
|
|
635
|
-
}
|
|
636
|
-
static VALUE
|
|
637
|
-
invoker_call(int argc, VALUE* argv, VALUE self)
|
|
638
|
-
{
|
|
639
|
-
Invoker* invoker;
|
|
640
|
-
FFIStorage params[MAX_PARAMETERS];
|
|
641
|
-
void* ffiValues[MAX_PARAMETERS];
|
|
663
|
+
rbffi_save_errno();
|
|
642
664
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
665
|
+
return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
|
|
666
|
+
invoker->enums);
|
|
646
667
|
}
|
|
647
668
|
|
|
648
|
-
static
|
|
649
|
-
|
|
669
|
+
static VALUE
|
|
670
|
+
invoker_call(int argc, VALUE* argv, VALUE self)
|
|
650
671
|
{
|
|
651
672
|
Invoker* invoker;
|
|
652
|
-
|
|
653
|
-
|
|
673
|
+
int argCount;
|
|
674
|
+
FFIStorage params_[MAX_FIXED_ARITY], *params = ¶ms_[0];
|
|
675
|
+
void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
|
|
654
676
|
|
|
655
677
|
Data_Get_Struct(self, Invoker, invoker);
|
|
656
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
657
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
658
|
-
}
|
|
659
678
|
|
|
660
|
-
|
|
661
|
-
invoker_call0(VALUE self)
|
|
662
|
-
{
|
|
663
|
-
Invoker* invoker;
|
|
664
|
-
FFIStorage arg0;
|
|
665
|
-
void* ffiValues[] = { &arg0 };
|
|
666
|
-
|
|
667
|
-
Data_Get_Struct(self, Invoker, invoker);
|
|
668
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
669
|
-
}
|
|
679
|
+
argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
|
|
670
680
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
}
|
|
681
|
+
if (argCount > MAX_FIXED_ARITY) {
|
|
682
|
+
params = ALLOCA_N(FFIStorage, argCount);
|
|
683
|
+
ffiValues = ALLOCA_N(void *, argCount);
|
|
684
|
+
}
|
|
676
685
|
|
|
677
|
-
|
|
678
|
-
invoker_call2(VALUE self, VALUE arg1, VALUE arg2)
|
|
679
|
-
{
|
|
680
|
-
VALUE argv[] = { arg1, arg2 };
|
|
681
|
-
return invoker_callN(self, 2, argv);
|
|
682
|
-
}
|
|
686
|
+
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
683
687
|
|
|
684
|
-
|
|
685
|
-
invoker_call3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
|
|
686
|
-
{
|
|
687
|
-
VALUE argv[] = { arg1, arg2, arg3 };
|
|
688
|
-
return invoker_callN(self, 3, argv);
|
|
688
|
+
return ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
689
689
|
}
|
|
690
690
|
|
|
691
691
|
#ifdef USE_RAW
|
|
692
|
+
|
|
693
|
+
/*
|
|
694
|
+
* attached_method_invoke is used as the <= 3 argument fixed-arity fast path
|
|
695
|
+
*/
|
|
692
696
|
static void
|
|
693
697
|
attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
|
694
698
|
{
|
|
@@ -701,9 +705,12 @@ attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* us
|
|
|
701
705
|
ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)¶meters[1],
|
|
702
706
|
invoker->paramTypes, params, ffiValues);
|
|
703
707
|
}
|
|
704
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
708
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
705
709
|
}
|
|
706
710
|
|
|
711
|
+
/*
|
|
712
|
+
* attached_method_vinvoke is used functions with more than 3 parameters
|
|
713
|
+
*/
|
|
707
714
|
static void
|
|
708
715
|
attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
|
709
716
|
{
|
|
@@ -715,7 +722,7 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* u
|
|
|
715
722
|
VALUE* argv = *(VALUE **) ¶meters[1];
|
|
716
723
|
|
|
717
724
|
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
718
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
725
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
719
726
|
}
|
|
720
727
|
|
|
721
728
|
#else
|
|
@@ -736,7 +743,7 @@ attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
736
743
|
if (invoker->paramCount > 0) {
|
|
737
744
|
ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
|
|
738
745
|
}
|
|
739
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
746
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
740
747
|
}
|
|
741
748
|
#endif /* _WIN32 */
|
|
742
749
|
static void
|
|
@@ -750,21 +757,29 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* use
|
|
|
750
757
|
VALUE* argv = *(VALUE **) parameters[1];
|
|
751
758
|
|
|
752
759
|
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
753
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
760
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
754
761
|
}
|
|
755
762
|
#endif
|
|
763
|
+
|
|
756
764
|
static VALUE
|
|
757
765
|
invoker_attach(VALUE self, VALUE module, VALUE name)
|
|
758
766
|
{
|
|
759
767
|
Invoker* invoker;
|
|
760
768
|
MethodHandle* handle;
|
|
761
769
|
char var[1024];
|
|
770
|
+
|
|
762
771
|
Data_Get_Struct(self, Invoker, invoker);
|
|
772
|
+
if (invoker->paramCount == -1) {
|
|
773
|
+
rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
|
|
774
|
+
}
|
|
775
|
+
|
|
763
776
|
handle = invoker->methodHandle;
|
|
764
|
-
rb_define_module_function(module,
|
|
777
|
+
rb_define_module_function(module, StringValueCStr(name),
|
|
765
778
|
handle->code, handle->arity);
|
|
766
779
|
snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
|
|
767
780
|
rb_cv_set(module, var, self);
|
|
781
|
+
rb_define_method(module, StringValueCStr(name),
|
|
782
|
+
handle->code, handle->arity);
|
|
768
783
|
return self;
|
|
769
784
|
}
|
|
770
785
|
static VALUE
|
|
@@ -781,8 +796,14 @@ invoker_mark(Invoker *invoker)
|
|
|
781
796
|
if (invoker->callbackCount > 0) {
|
|
782
797
|
rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
|
|
783
798
|
}
|
|
784
|
-
if (invoker->
|
|
785
|
-
rb_gc_mark(invoker->
|
|
799
|
+
if (invoker->address != Qnil) {
|
|
800
|
+
rb_gc_mark(invoker->address);
|
|
801
|
+
}
|
|
802
|
+
if (invoker->enums != Qnil) {
|
|
803
|
+
rb_gc_mark(invoker->enums);
|
|
804
|
+
}
|
|
805
|
+
if (invoker->rbReturnType != Qnil) {
|
|
806
|
+
rb_gc_mark(invoker->rbReturnType);
|
|
786
807
|
}
|
|
787
808
|
}
|
|
788
809
|
|
|
@@ -836,11 +857,12 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
836
857
|
|
|
837
858
|
for (i = 0; i < paramCount; ++i) {
|
|
838
859
|
VALUE entry = rb_ary_entry(parameterTypes, i);
|
|
839
|
-
int paramType =
|
|
860
|
+
int paramType = rbffi_Type_GetIntValue(entry);
|
|
840
861
|
switch (paramType) {
|
|
841
862
|
case NATIVE_INT8:
|
|
842
863
|
case NATIVE_INT16:
|
|
843
864
|
case NATIVE_INT32:
|
|
865
|
+
case NATIVE_ENUM:
|
|
844
866
|
paramType = NATIVE_INT32;
|
|
845
867
|
break;
|
|
846
868
|
case NATIVE_UINT8:
|
|
@@ -853,14 +875,14 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
853
875
|
break;
|
|
854
876
|
}
|
|
855
877
|
paramTypes[i] = paramType;
|
|
856
|
-
ffiParamTypes[i] =
|
|
878
|
+
ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
|
|
857
879
|
if (ffiParamTypes[i] == NULL) {
|
|
858
880
|
rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
|
|
859
881
|
}
|
|
860
882
|
argv[i] = rb_ary_entry(parameterValues, i);
|
|
861
883
|
}
|
|
862
884
|
|
|
863
|
-
ffiReturnType =
|
|
885
|
+
ffiReturnType = invoker->returnType->ffiType;
|
|
864
886
|
if (ffiReturnType == NULL) {
|
|
865
887
|
rb_raise(rb_eArgError, "Invalid return type");
|
|
866
888
|
}
|
|
@@ -876,7 +898,7 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
876
898
|
rb_raise(rb_eArgError, "Unknown FFI error");
|
|
877
899
|
}
|
|
878
900
|
ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
|
|
879
|
-
return ffi_invoke(&cif, invoker
|
|
901
|
+
return ffi_invoke(&cif, invoker, ffiValues);
|
|
880
902
|
}
|
|
881
903
|
|
|
882
904
|
static void*
|
|
@@ -886,94 +908,39 @@ callback_param(VALUE proc, VALUE cbInfo)
|
|
|
886
908
|
if (proc == Qnil) {
|
|
887
909
|
return NULL ;
|
|
888
910
|
}
|
|
889
|
-
callback =
|
|
911
|
+
callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
|
|
890
912
|
return ((NativeCallback *) DATA_PTR(callback))->code;
|
|
891
913
|
}
|
|
892
914
|
|
|
893
|
-
#if defined(USE_PTHREAD_LOCAL)
|
|
894
|
-
static ThreadData*
|
|
895
|
-
thread_data_init()
|
|
896
|
-
{
|
|
897
|
-
ThreadData* td = ALLOC_N(ThreadData, 1);
|
|
898
|
-
memset(td, 0, sizeof(*td));
|
|
899
|
-
pthread_setspecific(threadDataKey, td);
|
|
900
|
-
return td;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
static inline ThreadData*
|
|
904
|
-
thread_data_get()
|
|
905
|
-
{
|
|
906
|
-
ThreadData* td = pthread_getspecific(threadDataKey);
|
|
907
|
-
return td != NULL ? td : thread_data_init();
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
static void
|
|
911
|
-
thread_data_free(void *ptr)
|
|
912
|
-
{
|
|
913
|
-
xfree(ptr);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
#else
|
|
917
|
-
static ID thread_data_id;
|
|
918
|
-
|
|
919
|
-
static ThreadData*
|
|
920
|
-
thread_data_init()
|
|
921
|
-
{
|
|
922
|
-
ThreadData* td;
|
|
923
|
-
VALUE obj;
|
|
924
|
-
obj = Data_Make_Struct(rb_cObject, ThreadData, NULL, -1, td);
|
|
925
|
-
rb_thread_local_aset(rb_thread_current(), thread_data_id, obj);
|
|
926
|
-
return td;
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
static inline ThreadData*
|
|
930
|
-
thread_data_get()
|
|
931
|
-
{
|
|
932
|
-
VALUE obj = rb_thread_local_aref(rb_thread_current(), thread_data_id);
|
|
933
|
-
|
|
934
|
-
if (obj != Qnil && TYPE(obj) == T_DATA) {
|
|
935
|
-
return (ThreadData *) DATA_PTR(obj);
|
|
936
|
-
}
|
|
937
|
-
return thread_data_init();
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
#endif
|
|
941
|
-
static VALUE
|
|
942
|
-
get_last_error(VALUE self)
|
|
943
|
-
{
|
|
944
|
-
return INT2NUM(threadData->td_errno);
|
|
945
|
-
}
|
|
946
|
-
static VALUE
|
|
947
|
-
set_last_error(VALUE self, VALUE error)
|
|
948
|
-
{
|
|
949
|
-
return Qnil;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
915
|
void
|
|
953
|
-
|
|
916
|
+
rbffi_Invoker_Init(VALUE moduleFFI)
|
|
954
917
|
{
|
|
955
918
|
ffi_type* ffiValueType;
|
|
956
919
|
int i;
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
920
|
+
|
|
921
|
+
rbffi_InvokerClass = classInvoker = rb_define_class_under(moduleFFI, "Invoker", rb_cObject);
|
|
922
|
+
rb_global_variable(&rbffi_InvokerClass);
|
|
923
|
+
rb_global_variable(&classInvoker);
|
|
924
|
+
|
|
960
925
|
rb_define_alloc_func(classInvoker, invoker_allocate);
|
|
961
|
-
rb_define_method(classInvoker, "initialize", invoker_initialize,
|
|
926
|
+
rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
|
|
962
927
|
rb_define_method(classInvoker, "call", invoker_call, -1);
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
928
|
+
rb_define_alias(classInvoker, "call0", "call");
|
|
929
|
+
rb_define_alias(classInvoker, "call1", "call");
|
|
930
|
+
rb_define_alias(classInvoker, "call2", "call");
|
|
931
|
+
rb_define_alias(classInvoker, "call3", "call");
|
|
967
932
|
rb_define_method(classInvoker, "arity", invoker_arity, 0);
|
|
968
933
|
rb_define_method(classInvoker, "attach", invoker_attach, 2);
|
|
969
934
|
classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
|
|
970
|
-
|
|
935
|
+
rb_global_variable(&classVariadicInvoker);
|
|
936
|
+
|
|
937
|
+
rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 5);
|
|
971
938
|
rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
|
|
939
|
+
rb_define_alias(classVariadicInvoker, "call", "invoke");
|
|
940
|
+
|
|
972
941
|
to_ptr = rb_intern("to_ptr");
|
|
942
|
+
map_symbol_id = rb_intern("__map_symbol");
|
|
973
943
|
|
|
974
|
-
rb_define_module_function(moduleError, "error", get_last_error, 0);
|
|
975
|
-
rb_define_module_function(moduleError, "error=", set_last_error, 1);
|
|
976
|
-
|
|
977
944
|
ffiValueType = (sizeof (VALUE) == sizeof (long))
|
|
978
945
|
? &ffi_type_ulong : &ffi_type_uint64;
|
|
979
946
|
for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
|
|
@@ -986,13 +953,10 @@ rb_FFI_Invoker_Init()
|
|
|
986
953
|
#endif /* _WIN32 */
|
|
987
954
|
|
|
988
955
|
#if defined(USE_PTHREAD_LOCAL)
|
|
989
|
-
pthread_key_create(&threadDataKey, thread_data_free);
|
|
990
956
|
for (i = 0; i < 4; ++i) {
|
|
991
957
|
pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
|
|
992
958
|
}
|
|
993
959
|
pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
|
|
994
|
-
#else
|
|
995
|
-
thread_data_id = rb_intern("ffi_thread_local_data");
|
|
996
960
|
#endif /* USE_PTHREAD_LOCAL */
|
|
997
961
|
|
|
998
962
|
}
|