ffi 0.3.1 → 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 +38 -28
- data/ext/ffi_c/AbstractMemory.c +74 -70
- data/ext/ffi_c/AbstractMemory.h +8 -4
- data/ext/ffi_c/AutoPointer.c +8 -9
- data/ext/ffi_c/AutoPointer.h +2 -2
- data/ext/ffi_c/Buffer.c +42 -24
- data/ext/ffi_c/Callback.c +85 -33
- data/ext/ffi_c/Callback.h +11 -5
- data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
- data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
- data/ext/ffi_c/Invoker.c +152 -192
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +27 -20
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +51 -47
- data/ext/ffi_c/Platform.c +9 -10
- data/ext/ffi_c/Platform.h +1 -1
- data/ext/ffi_c/Pointer.c +52 -21
- data/ext/ffi_c/Pointer.h +8 -6
- data/ext/ffi_c/Struct.c +70 -61
- 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,81 +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;
|
|
624
|
-
int error = 0;
|
|
625
657
|
|
|
626
658
|
#ifdef USE_RAW
|
|
627
|
-
ffi_raw_call(cif, FFI_FN(function), &retval, (ffi_raw *) ffiValues[0]);
|
|
628
|
-
#else
|
|
629
|
-
ffi_call(cif, FFI_FN(function), &retval, ffiValues);
|
|
630
|
-
#endif
|
|
631
|
-
#if defined(_WIN32) || defined(__WIN32__)
|
|
632
|
-
error = GetLastError();
|
|
659
|
+
ffi_raw_call(cif, FFI_FN(invoker->function), &retval, (ffi_raw *) ffiValues[0]);
|
|
633
660
|
#else
|
|
634
|
-
|
|
661
|
+
ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
|
|
635
662
|
#endif
|
|
636
|
-
|
|
663
|
+
rbffi_save_errno();
|
|
637
664
|
|
|
638
|
-
return
|
|
665
|
+
return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
|
|
666
|
+
invoker->enums);
|
|
639
667
|
}
|
|
668
|
+
|
|
640
669
|
static VALUE
|
|
641
670
|
invoker_call(int argc, VALUE* argv, VALUE self)
|
|
642
671
|
{
|
|
643
672
|
Invoker* invoker;
|
|
644
|
-
|
|
645
|
-
|
|
673
|
+
int argCount;
|
|
674
|
+
FFIStorage params_[MAX_FIXED_ARITY], *params = ¶ms_[0];
|
|
675
|
+
void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
|
|
646
676
|
|
|
647
677
|
Data_Get_Struct(self, Invoker, invoker);
|
|
648
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
649
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
650
|
-
}
|
|
651
678
|
|
|
652
|
-
|
|
653
|
-
invoker_callN(VALUE self, int argc, VALUE* argv)
|
|
654
|
-
{
|
|
655
|
-
Invoker* invoker;
|
|
656
|
-
FFIStorage params[3];
|
|
657
|
-
void* ffiValues[3];
|
|
658
|
-
|
|
659
|
-
Data_Get_Struct(self, Invoker, invoker);
|
|
660
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
661
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
static VALUE
|
|
665
|
-
invoker_call0(VALUE self)
|
|
666
|
-
{
|
|
667
|
-
Invoker* invoker;
|
|
668
|
-
FFIStorage arg0;
|
|
669
|
-
void* ffiValues[] = { &arg0 };
|
|
670
|
-
|
|
671
|
-
Data_Get_Struct(self, Invoker, invoker);
|
|
672
|
-
return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
|
|
673
|
-
}
|
|
679
|
+
argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
|
|
674
680
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
681
|
+
if (argCount > MAX_FIXED_ARITY) {
|
|
682
|
+
params = ALLOCA_N(FFIStorage, argCount);
|
|
683
|
+
ffiValues = ALLOCA_N(void *, argCount);
|
|
684
|
+
}
|
|
680
685
|
|
|
681
|
-
|
|
682
|
-
invoker_call2(VALUE self, VALUE arg1, VALUE arg2)
|
|
683
|
-
{
|
|
684
|
-
VALUE argv[] = { arg1, arg2 };
|
|
685
|
-
return invoker_callN(self, 2, argv);
|
|
686
|
-
}
|
|
686
|
+
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
687
687
|
|
|
688
|
-
|
|
689
|
-
invoker_call3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
|
|
690
|
-
{
|
|
691
|
-
VALUE argv[] = { arg1, arg2, arg3 };
|
|
692
|
-
return invoker_callN(self, 3, argv);
|
|
688
|
+
return ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
693
689
|
}
|
|
694
690
|
|
|
695
691
|
#ifdef USE_RAW
|
|
692
|
+
|
|
693
|
+
/*
|
|
694
|
+
* attached_method_invoke is used as the <= 3 argument fixed-arity fast path
|
|
695
|
+
*/
|
|
696
696
|
static void
|
|
697
697
|
attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
|
698
698
|
{
|
|
@@ -705,9 +705,12 @@ attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* us
|
|
|
705
705
|
ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)¶meters[1],
|
|
706
706
|
invoker->paramTypes, params, ffiValues);
|
|
707
707
|
}
|
|
708
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
708
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
+
/*
|
|
712
|
+
* attached_method_vinvoke is used functions with more than 3 parameters
|
|
713
|
+
*/
|
|
711
714
|
static void
|
|
712
715
|
attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
|
713
716
|
{
|
|
@@ -719,7 +722,7 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* u
|
|
|
719
722
|
VALUE* argv = *(VALUE **) ¶meters[1];
|
|
720
723
|
|
|
721
724
|
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
722
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
725
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
723
726
|
}
|
|
724
727
|
|
|
725
728
|
#else
|
|
@@ -740,7 +743,7 @@ attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
740
743
|
if (invoker->paramCount > 0) {
|
|
741
744
|
ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
|
|
742
745
|
}
|
|
743
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
746
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
744
747
|
}
|
|
745
748
|
#endif /* _WIN32 */
|
|
746
749
|
static void
|
|
@@ -754,21 +757,29 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* use
|
|
|
754
757
|
VALUE* argv = *(VALUE **) parameters[1];
|
|
755
758
|
|
|
756
759
|
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
|
757
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker
|
|
760
|
+
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
|
758
761
|
}
|
|
759
762
|
#endif
|
|
763
|
+
|
|
760
764
|
static VALUE
|
|
761
765
|
invoker_attach(VALUE self, VALUE module, VALUE name)
|
|
762
766
|
{
|
|
763
767
|
Invoker* invoker;
|
|
764
768
|
MethodHandle* handle;
|
|
765
769
|
char var[1024];
|
|
770
|
+
|
|
766
771
|
Data_Get_Struct(self, Invoker, invoker);
|
|
772
|
+
if (invoker->paramCount == -1) {
|
|
773
|
+
rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
|
|
774
|
+
}
|
|
775
|
+
|
|
767
776
|
handle = invoker->methodHandle;
|
|
768
|
-
rb_define_module_function(module,
|
|
777
|
+
rb_define_module_function(module, StringValueCStr(name),
|
|
769
778
|
handle->code, handle->arity);
|
|
770
779
|
snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
|
|
771
780
|
rb_cv_set(module, var, self);
|
|
781
|
+
rb_define_method(module, StringValueCStr(name),
|
|
782
|
+
handle->code, handle->arity);
|
|
772
783
|
return self;
|
|
773
784
|
}
|
|
774
785
|
static VALUE
|
|
@@ -785,8 +796,14 @@ invoker_mark(Invoker *invoker)
|
|
|
785
796
|
if (invoker->callbackCount > 0) {
|
|
786
797
|
rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
|
|
787
798
|
}
|
|
788
|
-
if (invoker->
|
|
789
|
-
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);
|
|
790
807
|
}
|
|
791
808
|
}
|
|
792
809
|
|
|
@@ -840,11 +857,12 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
840
857
|
|
|
841
858
|
for (i = 0; i < paramCount; ++i) {
|
|
842
859
|
VALUE entry = rb_ary_entry(parameterTypes, i);
|
|
843
|
-
int paramType =
|
|
860
|
+
int paramType = rbffi_Type_GetIntValue(entry);
|
|
844
861
|
switch (paramType) {
|
|
845
862
|
case NATIVE_INT8:
|
|
846
863
|
case NATIVE_INT16:
|
|
847
864
|
case NATIVE_INT32:
|
|
865
|
+
case NATIVE_ENUM:
|
|
848
866
|
paramType = NATIVE_INT32;
|
|
849
867
|
break;
|
|
850
868
|
case NATIVE_UINT8:
|
|
@@ -857,14 +875,14 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
857
875
|
break;
|
|
858
876
|
}
|
|
859
877
|
paramTypes[i] = paramType;
|
|
860
|
-
ffiParamTypes[i] =
|
|
878
|
+
ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
|
|
861
879
|
if (ffiParamTypes[i] == NULL) {
|
|
862
880
|
rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
|
|
863
881
|
}
|
|
864
882
|
argv[i] = rb_ary_entry(parameterValues, i);
|
|
865
883
|
}
|
|
866
884
|
|
|
867
|
-
ffiReturnType =
|
|
885
|
+
ffiReturnType = invoker->returnType->ffiType;
|
|
868
886
|
if (ffiReturnType == NULL) {
|
|
869
887
|
rb_raise(rb_eArgError, "Invalid return type");
|
|
870
888
|
}
|
|
@@ -880,7 +898,7 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
|
880
898
|
rb_raise(rb_eArgError, "Unknown FFI error");
|
|
881
899
|
}
|
|
882
900
|
ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
|
|
883
|
-
return ffi_invoke(&cif, invoker
|
|
901
|
+
return ffi_invoke(&cif, invoker, ffiValues);
|
|
884
902
|
}
|
|
885
903
|
|
|
886
904
|
static void*
|
|
@@ -890,94 +908,39 @@ callback_param(VALUE proc, VALUE cbInfo)
|
|
|
890
908
|
if (proc == Qnil) {
|
|
891
909
|
return NULL ;
|
|
892
910
|
}
|
|
893
|
-
callback =
|
|
911
|
+
callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
|
|
894
912
|
return ((NativeCallback *) DATA_PTR(callback))->code;
|
|
895
913
|
}
|
|
896
914
|
|
|
897
|
-
#if defined(USE_PTHREAD_LOCAL)
|
|
898
|
-
static ThreadData*
|
|
899
|
-
thread_data_init()
|
|
900
|
-
{
|
|
901
|
-
ThreadData* td = ALLOC_N(ThreadData, 1);
|
|
902
|
-
memset(td, 0, sizeof(*td));
|
|
903
|
-
pthread_setspecific(threadDataKey, td);
|
|
904
|
-
return td;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
static inline ThreadData*
|
|
908
|
-
thread_data_get()
|
|
909
|
-
{
|
|
910
|
-
ThreadData* td = pthread_getspecific(threadDataKey);
|
|
911
|
-
return td != NULL ? td : thread_data_init();
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
static void
|
|
915
|
-
thread_data_free(void *ptr)
|
|
916
|
-
{
|
|
917
|
-
xfree(ptr);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
#else
|
|
921
|
-
static ID thread_data_id;
|
|
922
|
-
|
|
923
|
-
static ThreadData*
|
|
924
|
-
thread_data_init()
|
|
925
|
-
{
|
|
926
|
-
ThreadData* td;
|
|
927
|
-
VALUE obj;
|
|
928
|
-
obj = Data_Make_Struct(rb_cObject, ThreadData, NULL, -1, td);
|
|
929
|
-
rb_thread_local_aset(rb_thread_current(), thread_data_id, obj);
|
|
930
|
-
return td;
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
static inline ThreadData*
|
|
934
|
-
thread_data_get()
|
|
935
|
-
{
|
|
936
|
-
VALUE obj = rb_thread_local_aref(rb_thread_current(), thread_data_id);
|
|
937
|
-
|
|
938
|
-
if (obj != Qnil && TYPE(obj) == T_DATA) {
|
|
939
|
-
return (ThreadData *) DATA_PTR(obj);
|
|
940
|
-
}
|
|
941
|
-
return thread_data_init();
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
#endif
|
|
945
|
-
static VALUE
|
|
946
|
-
get_last_error(VALUE self)
|
|
947
|
-
{
|
|
948
|
-
return INT2NUM(threadData->td_errno);
|
|
949
|
-
}
|
|
950
|
-
static VALUE
|
|
951
|
-
set_last_error(VALUE self, VALUE error)
|
|
952
|
-
{
|
|
953
|
-
return Qnil;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
915
|
void
|
|
957
|
-
|
|
916
|
+
rbffi_Invoker_Init(VALUE moduleFFI)
|
|
958
917
|
{
|
|
959
918
|
ffi_type* ffiValueType;
|
|
960
919
|
int i;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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
|
+
|
|
964
925
|
rb_define_alloc_func(classInvoker, invoker_allocate);
|
|
965
|
-
rb_define_method(classInvoker, "initialize", invoker_initialize,
|
|
926
|
+
rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
|
|
966
927
|
rb_define_method(classInvoker, "call", invoker_call, -1);
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
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");
|
|
971
932
|
rb_define_method(classInvoker, "arity", invoker_arity, 0);
|
|
972
933
|
rb_define_method(classInvoker, "attach", invoker_attach, 2);
|
|
973
934
|
classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
|
|
974
|
-
|
|
935
|
+
rb_global_variable(&classVariadicInvoker);
|
|
936
|
+
|
|
937
|
+
rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 5);
|
|
975
938
|
rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
|
|
939
|
+
rb_define_alias(classVariadicInvoker, "call", "invoke");
|
|
940
|
+
|
|
976
941
|
to_ptr = rb_intern("to_ptr");
|
|
942
|
+
map_symbol_id = rb_intern("__map_symbol");
|
|
977
943
|
|
|
978
|
-
rb_define_module_function(moduleError, "error", get_last_error, 0);
|
|
979
|
-
rb_define_module_function(moduleError, "error=", set_last_error, 1);
|
|
980
|
-
|
|
981
944
|
ffiValueType = (sizeof (VALUE) == sizeof (long))
|
|
982
945
|
? &ffi_type_ulong : &ffi_type_uint64;
|
|
983
946
|
for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
|
|
@@ -990,13 +953,10 @@ rb_FFI_Invoker_Init()
|
|
|
990
953
|
#endif /* _WIN32 */
|
|
991
954
|
|
|
992
955
|
#if defined(USE_PTHREAD_LOCAL)
|
|
993
|
-
pthread_key_create(&threadDataKey, thread_data_free);
|
|
994
956
|
for (i = 0; i < 4; ++i) {
|
|
995
957
|
pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
|
|
996
958
|
}
|
|
997
959
|
pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
|
|
998
|
-
#else
|
|
999
|
-
thread_data_id = rb_intern("ffi_thread_local_data");
|
|
1000
960
|
#endif /* USE_PTHREAD_LOCAL */
|
|
1001
961
|
|
|
1002
962
|
}
|