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/Buffer.c
CHANGED
|
@@ -18,14 +18,31 @@ static void buffer_release(Buffer* ptr);
|
|
|
18
18
|
static void buffer_mark(Buffer* ptr);
|
|
19
19
|
static VALUE buffer_free(VALUE self);
|
|
20
20
|
|
|
21
|
-
static VALUE
|
|
22
|
-
#define BUFFER(obj) ((Buffer *)
|
|
21
|
+
static VALUE BufferClass = Qnil;
|
|
22
|
+
#define BUFFER(obj) ((Buffer *) rbffi_AbstractMemory_Cast((obj), BufferClass))
|
|
23
23
|
|
|
24
24
|
static VALUE
|
|
25
25
|
buffer_allocate(VALUE klass)
|
|
26
26
|
{
|
|
27
27
|
Buffer* buffer;
|
|
28
|
-
|
|
28
|
+
VALUE obj;
|
|
29
|
+
|
|
30
|
+
obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer);
|
|
31
|
+
buffer->parent = Qnil;
|
|
32
|
+
buffer->memory.ops = &rbffi_AbstractMemoryOps;
|
|
33
|
+
|
|
34
|
+
return obj;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static void
|
|
38
|
+
buffer_release(Buffer* ptr)
|
|
39
|
+
{
|
|
40
|
+
if (ptr->storage != NULL) {
|
|
41
|
+
free(ptr->storage);
|
|
42
|
+
ptr->storage = NULL;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
xfree(ptr);
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
static VALUE
|
|
@@ -33,28 +50,30 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
|
|
|
33
50
|
{
|
|
34
51
|
VALUE size = Qnil, count = Qnil, clear = Qnil;
|
|
35
52
|
Buffer* p;
|
|
36
|
-
unsigned long msize;
|
|
37
|
-
void* memory;
|
|
38
53
|
int nargs;
|
|
39
54
|
|
|
55
|
+
Data_Get_Struct(self, Buffer, p);
|
|
56
|
+
|
|
40
57
|
nargs = rb_scan_args(argc, argv, "12", &size, &count, &clear);
|
|
41
|
-
|
|
42
|
-
memory =
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
p->type_size = rbffi_type_size(size);
|
|
59
|
+
p->memory.size = p->type_size * (nargs > 1 ? NUM2LONG(count) : 1);
|
|
60
|
+
|
|
61
|
+
p->storage = malloc(p->memory.size + 7);
|
|
62
|
+
if (p->storage == NULL) {
|
|
63
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
|
|
45
64
|
}
|
|
46
|
-
|
|
47
|
-
p->storage = memory;
|
|
48
|
-
p->memory.size = msize;
|
|
65
|
+
|
|
49
66
|
/* ensure the memory is aligned on at least a 8 byte boundary */
|
|
50
|
-
p->memory.address = (void *) (((uintptr_t)
|
|
51
|
-
|
|
52
|
-
if (nargs > 2 && RTEST(clear) && p->memory.size > 0) {
|
|
67
|
+
p->memory.address = (void *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);
|
|
68
|
+
|
|
69
|
+
if (nargs > 2 && (RTEST(clear) || clear == Qnil) && p->memory.size > 0) {
|
|
53
70
|
memset(p->memory.address, 0, p->memory.size);
|
|
54
71
|
}
|
|
72
|
+
|
|
55
73
|
if (rb_block_given_p()) {
|
|
56
|
-
return
|
|
74
|
+
return rb_ensure(rb_yield, self, buffer_free, self);
|
|
57
75
|
}
|
|
76
|
+
|
|
58
77
|
return self;
|
|
59
78
|
}
|
|
60
79
|
|
|
@@ -73,18 +92,41 @@ buffer_plus(VALUE self, VALUE offset)
|
|
|
73
92
|
long off = NUM2LONG(offset);
|
|
74
93
|
|
|
75
94
|
checkBounds(&ptr->memory, off, 1);
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
|
|
96
|
+
retval = Data_Make_Struct(BufferClass, Buffer, buffer_mark, -1, p);
|
|
97
|
+
p->memory.address = ptr->memory.address + off;
|
|
78
98
|
p->memory.size = ptr->memory.size - off;
|
|
99
|
+
p->memory.ops = &rbffi_AbstractMemoryOps;
|
|
79
100
|
p->parent = self;
|
|
101
|
+
|
|
80
102
|
return retval;
|
|
81
103
|
}
|
|
82
104
|
|
|
105
|
+
static VALUE
|
|
106
|
+
buffer_aref(VALUE self, VALUE offset)
|
|
107
|
+
{
|
|
108
|
+
Buffer* ptr;
|
|
109
|
+
|
|
110
|
+
Data_Get_Struct(self, Buffer, ptr);
|
|
111
|
+
return buffer_plus(self, INT2FIX(ptr->type_size * NUM2INT(offset)));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static VALUE
|
|
115
|
+
buffer_type_size(VALUE self)
|
|
116
|
+
{
|
|
117
|
+
Buffer* ptr;
|
|
118
|
+
|
|
119
|
+
Data_Get_Struct(self, Buffer, ptr);
|
|
120
|
+
return INT2NUM(ptr->type_size);
|
|
121
|
+
}
|
|
122
|
+
|
|
83
123
|
static VALUE
|
|
84
124
|
buffer_inspect(VALUE self)
|
|
85
125
|
{
|
|
86
126
|
char tmp[100];
|
|
127
|
+
|
|
87
128
|
snprintf(tmp, sizeof(tmp), "#<Buffer size=%ld>", BUFFER(self)->memory.size);
|
|
129
|
+
|
|
88
130
|
return rb_str_new2(tmp);
|
|
89
131
|
}
|
|
90
132
|
|
|
@@ -92,45 +134,38 @@ buffer_inspect(VALUE self)
|
|
|
92
134
|
static VALUE
|
|
93
135
|
buffer_free(VALUE self)
|
|
94
136
|
{
|
|
95
|
-
Buffer* ptr
|
|
96
|
-
if (ptr->parent == Qnil && ptr->storage != NULL) {
|
|
97
|
-
free(ptr->storage);
|
|
98
|
-
ptr->storage = NULL;
|
|
99
|
-
}
|
|
100
|
-
return self;
|
|
101
|
-
}
|
|
137
|
+
Buffer* ptr;
|
|
102
138
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
{
|
|
106
|
-
if (ptr->parent == Qnil && ptr->storage != NULL) {
|
|
139
|
+
Data_Get_Struct(self, Buffer, ptr);
|
|
140
|
+
if (ptr->storage != NULL) {
|
|
107
141
|
free(ptr->storage);
|
|
108
142
|
ptr->storage = NULL;
|
|
109
143
|
}
|
|
110
|
-
|
|
144
|
+
|
|
145
|
+
return self;
|
|
111
146
|
}
|
|
112
147
|
|
|
113
148
|
static void
|
|
114
149
|
buffer_mark(Buffer* ptr)
|
|
115
150
|
{
|
|
116
|
-
|
|
117
|
-
rb_gc_mark(ptr->parent);
|
|
118
|
-
}
|
|
151
|
+
rb_gc_mark(ptr->parent);
|
|
119
152
|
}
|
|
120
153
|
|
|
121
154
|
void
|
|
122
|
-
|
|
155
|
+
rbffi_Buffer_Init(VALUE moduleFFI)
|
|
123
156
|
{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
157
|
+
BufferClass = rb_define_class_under(moduleFFI, "Buffer", rbffi_AbstractMemoryClass);
|
|
158
|
+
|
|
159
|
+
rb_global_variable(&BufferClass);
|
|
160
|
+
rb_define_alloc_func(BufferClass, buffer_allocate);
|
|
127
161
|
|
|
128
|
-
rb_define_singleton_method(
|
|
129
|
-
rb_define_singleton_method(
|
|
130
|
-
rb_define_singleton_method(
|
|
162
|
+
rb_define_singleton_method(BufferClass, "alloc_inout", buffer_alloc_inout, -1);
|
|
163
|
+
rb_define_singleton_method(BufferClass, "alloc_out", buffer_alloc_inout, -1);
|
|
164
|
+
rb_define_singleton_method(BufferClass, "alloc_in", buffer_alloc_inout, -1);
|
|
131
165
|
|
|
132
|
-
rb_define_method(
|
|
133
|
-
rb_define_method(
|
|
134
|
-
rb_define_method(
|
|
166
|
+
rb_define_method(BufferClass, "initialize", buffer_initialize, -1);
|
|
167
|
+
rb_define_method(BufferClass, "inspect", buffer_inspect, 0);
|
|
168
|
+
rb_define_method(BufferClass, "type_size", buffer_type_size, 0);
|
|
169
|
+
rb_define_method(BufferClass, "[]", buffer_aref, 1);
|
|
170
|
+
rb_define_method(BufferClass, "+", buffer_plus, 1);
|
|
135
171
|
}
|
|
136
|
-
|
data/ext/ffi_c/Callback.c
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
#include "MemoryPointer.h"
|
|
11
11
|
#include "Callback.h"
|
|
12
12
|
#include "Types.h"
|
|
13
|
+
#include "Type.h"
|
|
13
14
|
#include "rbffi.h"
|
|
14
15
|
#include "compat.h"
|
|
15
16
|
#include "extconf.h"
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
static void
|
|
19
|
-
static void CallbackInfo_free(CallbackInfo *);
|
|
18
|
+
static void cbinfo_mark(CallbackInfo* cbInfo);
|
|
19
|
+
static void cbinfo_free(CallbackInfo *);
|
|
20
20
|
|
|
21
21
|
#if defined(HAVE_LIBFFI) && !defined(HAVE_FFI_CLOSURE_ALLOC)
|
|
22
22
|
static void* ffi_closure_alloc(size_t size, void** code);
|
|
@@ -26,36 +26,67 @@ ffi_status ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
|
|
|
26
26
|
void* user_data, void* code);
|
|
27
27
|
#endif /* HAVE_FFI_CLOSURE_ALLOC */
|
|
28
28
|
|
|
29
|
-
static VALUE
|
|
30
|
-
static VALUE
|
|
31
|
-
static ID
|
|
29
|
+
static VALUE CallbackInfoClass = Qnil;
|
|
30
|
+
static VALUE NativeCallbackClass = Qnil;
|
|
31
|
+
static ID id_call = Qnil, id_cbtable = Qnil;
|
|
32
|
+
|
|
33
|
+
VALUE rbffi_CallbackInfoClass = Qnil;
|
|
34
|
+
|
|
35
|
+
static VALUE
|
|
36
|
+
cbinfo_allocate(VALUE klass)
|
|
37
|
+
{
|
|
38
|
+
CallbackInfo* cbInfo;
|
|
39
|
+
VALUE obj = Data_Make_Struct(klass, CallbackInfo, cbinfo_mark, cbinfo_free, cbInfo);
|
|
40
|
+
|
|
41
|
+
cbInfo->type.ffiType = &ffi_type_pointer;
|
|
42
|
+
cbInfo->type.size = ffi_type_pointer.size;
|
|
43
|
+
cbInfo->type.alignment = ffi_type_pointer.alignment;
|
|
44
|
+
cbInfo->type.nativeType = NATIVE_CALLBACK;
|
|
45
|
+
cbInfo->rbReturnType = Qnil;
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
return obj;
|
|
48
|
+
}
|
|
34
49
|
|
|
35
50
|
static VALUE
|
|
36
|
-
|
|
51
|
+
cbinfo_initialize(VALUE self, VALUE rbReturnType, VALUE rbParamTypes)
|
|
37
52
|
{
|
|
38
53
|
CallbackInfo *cbInfo;
|
|
39
|
-
|
|
40
|
-
int paramCount = RARRAY_LEN(rbParamTypes);
|
|
54
|
+
int paramCount;
|
|
41
55
|
ffi_status status;
|
|
42
56
|
int i;
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
Check_Type(rbParamTypes, T_ARRAY);
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
paramCount = RARRAY_LEN(rbParamTypes);
|
|
62
|
+
|
|
63
|
+
Data_Get_Struct(self, CallbackInfo, cbInfo);
|
|
45
64
|
cbInfo->parameterCount = paramCount;
|
|
46
|
-
cbInfo->parameterTypes = xcalloc(paramCount, sizeof(
|
|
65
|
+
cbInfo->parameterTypes = xcalloc(paramCount, sizeof(*cbInfo->parameterTypes));
|
|
47
66
|
cbInfo->ffiParameterTypes = xcalloc(paramCount, sizeof(ffi_type *));
|
|
67
|
+
Data_Get_Struct(rbReturnType, Type, cbInfo->returnType);
|
|
68
|
+
cbInfo->rbReturnType = rbReturnType;
|
|
69
|
+
cbInfo->rbParameterTypes = rbParamTypes;
|
|
70
|
+
|
|
48
71
|
for (i = 0; i < paramCount; ++i) {
|
|
49
|
-
|
|
50
|
-
|
|
72
|
+
VALUE entry = rb_ary_entry(rbParamTypes, i);
|
|
73
|
+
if (!rb_obj_is_kind_of(entry, rbffi_TypeClass)) {
|
|
74
|
+
rb_raise(rb_eTypeError, "Invalid parameter type");
|
|
75
|
+
}
|
|
76
|
+
Data_Get_Struct(entry, Type, cbInfo->parameterTypes[i]);
|
|
77
|
+
cbInfo->ffiParameterTypes[i] = cbInfo->parameterTypes[i]->ffiType;
|
|
51
78
|
if (cbInfo->ffiParameterTypes[i] == NULL) {
|
|
52
|
-
rb_raise(rb_eArgError, "Unknown argument type: %#x", cbInfo->parameterTypes[i]);
|
|
79
|
+
rb_raise(rb_eArgError, "Unknown argument type: %#x", cbInfo->parameterTypes[i]->nativeType);
|
|
53
80
|
}
|
|
54
81
|
}
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
|
|
83
|
+
if (!rb_obj_is_kind_of(rbReturnType, rbffi_TypeClass)) {
|
|
84
|
+
rb_raise(rb_eTypeError, "Invalid return type");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cbInfo->ffiReturnType = cbInfo->returnType->ffiType;
|
|
57
88
|
if (cbInfo->ffiReturnType == NULL) {
|
|
58
|
-
rb_raise(rb_eArgError, "Unknown return type: %#x", cbInfo->returnType);
|
|
89
|
+
rb_raise(rb_eArgError, "Unknown return type: %#x", cbInfo->returnType->nativeType);
|
|
59
90
|
}
|
|
60
91
|
#if defined(_WIN32) && defined(notyet)
|
|
61
92
|
cbInfo->abi = (flags & STDCALL) ? FFI_STDCALL : FFI_DEFAULT_ABI;
|
|
@@ -74,38 +105,35 @@ CallbackInfo_new(VALUE klass, VALUE rbReturnType, VALUE rbParamTypes)
|
|
|
74
105
|
default:
|
|
75
106
|
rb_raise(rb_eArgError, "Unknown FFI error");
|
|
76
107
|
}
|
|
77
|
-
return
|
|
108
|
+
return self;
|
|
78
109
|
}
|
|
79
110
|
|
|
80
111
|
static void
|
|
81
|
-
|
|
112
|
+
cbinfo_mark(CallbackInfo* cbInfo)
|
|
82
113
|
{
|
|
114
|
+
rb_gc_mark(cbInfo->rbReturnType);
|
|
115
|
+
rb_gc_mark(cbInfo->rbParameterTypes);
|
|
83
116
|
}
|
|
84
117
|
|
|
85
118
|
static void
|
|
86
|
-
|
|
119
|
+
cbinfo_free(CallbackInfo* cbInfo)
|
|
87
120
|
{
|
|
88
|
-
if (cbInfo != NULL) {
|
|
89
|
-
|
|
90
|
-
xfree(cbInfo->parameterTypes);
|
|
91
|
-
cbInfo->parameterTypes = NULL;
|
|
92
|
-
}
|
|
93
|
-
if (cbInfo->ffiParameterTypes != NULL) {
|
|
94
|
-
xfree(cbInfo->ffiParameterTypes);
|
|
95
|
-
cbInfo->ffiParameterTypes = NULL;
|
|
96
|
-
}
|
|
97
|
-
xfree(cbInfo);
|
|
121
|
+
if (cbInfo->parameterTypes != NULL) {
|
|
122
|
+
xfree(cbInfo->parameterTypes);
|
|
98
123
|
}
|
|
124
|
+
if (cbInfo->ffiParameterTypes != NULL) {
|
|
125
|
+
xfree(cbInfo->ffiParameterTypes);
|
|
126
|
+
}
|
|
127
|
+
xfree(cbInfo);
|
|
99
128
|
}
|
|
100
129
|
|
|
101
130
|
static void
|
|
102
131
|
native_callback_free(NativeCallback* cb)
|
|
103
132
|
{
|
|
104
|
-
if (cb != NULL) {
|
|
105
|
-
|
|
106
|
-
ffi_closure_free(cb->ffi_closure);
|
|
107
|
-
}
|
|
133
|
+
if (cb->ffi_closure != NULL) {
|
|
134
|
+
ffi_closure_free(cb->ffi_closure);
|
|
108
135
|
}
|
|
136
|
+
xfree(cb);
|
|
109
137
|
}
|
|
110
138
|
|
|
111
139
|
static void
|
|
@@ -127,7 +155,7 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
127
155
|
rbParams = ALLOCA_N(VALUE, cbInfo->parameterCount);
|
|
128
156
|
for (i = 0; i < cbInfo->parameterCount; ++i) {
|
|
129
157
|
VALUE param;
|
|
130
|
-
switch (cbInfo->parameterTypes[i]) {
|
|
158
|
+
switch (cbInfo->parameterTypes[i]->nativeType) {
|
|
131
159
|
case NATIVE_INT8:
|
|
132
160
|
param = INT2NUM(*(int8_t *) parameters[i]);
|
|
133
161
|
break;
|
|
@@ -162,7 +190,14 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
162
190
|
param = rb_tainted_str_new2(*(char **) parameters[i]);
|
|
163
191
|
break;
|
|
164
192
|
case NATIVE_POINTER:
|
|
165
|
-
param =
|
|
193
|
+
param = rbffi_Pointer_NewInstance(*(void **) parameters[i]);
|
|
194
|
+
break;
|
|
195
|
+
case NATIVE_BOOL:
|
|
196
|
+
param = (*(void **) parameters[i]) ? Qtrue : Qfalse;
|
|
197
|
+
break;
|
|
198
|
+
case NATIVE_CALLBACK:
|
|
199
|
+
param = rbffi_NativeValue_ToRuby(cbInfo->parameterTypes[i],
|
|
200
|
+
rb_ary_entry(cbInfo->rbParameterTypes, i), parameters[i], Qnil);
|
|
166
201
|
break;
|
|
167
202
|
default:
|
|
168
203
|
param = Qnil;
|
|
@@ -170,10 +205,10 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
170
205
|
}
|
|
171
206
|
rbParams[i] = param;
|
|
172
207
|
}
|
|
173
|
-
rbReturnValue = rb_funcall2(cb->rbProc,
|
|
208
|
+
rbReturnValue = rb_funcall2(cb->rbProc, id_call, cbInfo->parameterCount, rbParams);
|
|
174
209
|
if (rbReturnValue == Qnil || TYPE(rbReturnValue) == T_NIL) {
|
|
175
210
|
memset(retval, 0, cbInfo->ffiReturnType->size);
|
|
176
|
-
} else switch (cbInfo->returnType) {
|
|
211
|
+
} else switch (cbInfo->returnType->nativeType) {
|
|
177
212
|
case NATIVE_INT8:
|
|
178
213
|
case NATIVE_INT16:
|
|
179
214
|
case NATIVE_INT32:
|
|
@@ -197,58 +232,89 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
|
|
|
197
232
|
*((double *) retval) = NUM2DBL(rbReturnValue);
|
|
198
233
|
break;
|
|
199
234
|
case NATIVE_POINTER:
|
|
200
|
-
if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue,
|
|
235
|
+
if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_PointerClass)) {
|
|
201
236
|
*((void **) retval) = ((AbstractMemory *) DATA_PTR(rbReturnValue))->address;
|
|
202
237
|
} else {
|
|
203
238
|
// Default to returning NULL if not a value pointer object. handles nil case as well
|
|
204
239
|
*((void **) retval) = NULL;
|
|
205
240
|
}
|
|
206
241
|
break;
|
|
242
|
+
case NATIVE_BOOL:
|
|
243
|
+
*((ffi_sarg *) retval) = TYPE(rbReturnValue) == T_TRUE ? 1 : 0;
|
|
244
|
+
break;
|
|
245
|
+
case NATIVE_CALLBACK:
|
|
246
|
+
if (rb_obj_is_kind_of(rbReturnValue, rb_cProc) || rb_respond_to(rbReturnValue, id_call)) {
|
|
247
|
+
VALUE callback;
|
|
248
|
+
|
|
249
|
+
callback = rbffi_NativeCallback_ForProc(rbReturnValue, cbInfo->rbReturnType);
|
|
250
|
+
|
|
251
|
+
*((void **) retval) = ((NativeCallback *) DATA_PTR(callback))->code;
|
|
252
|
+
} else {
|
|
253
|
+
*((void **) retval) = NULL;
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
|
|
207
257
|
default:
|
|
258
|
+
*((ffi_arg *) retval) = 0;
|
|
208
259
|
break;
|
|
209
260
|
}
|
|
210
261
|
}
|
|
211
262
|
|
|
263
|
+
static VALUE
|
|
264
|
+
native_callback_allocate(VALUE klass)
|
|
265
|
+
{
|
|
266
|
+
NativeCallback* closure;
|
|
267
|
+
VALUE obj;
|
|
268
|
+
|
|
269
|
+
obj = Data_Make_Struct(klass, NativeCallback, native_callback_mark, native_callback_free, closure);
|
|
270
|
+
closure->rbCallbackInfo = Qnil;
|
|
271
|
+
closure->rbProc = Qnil;
|
|
272
|
+
|
|
273
|
+
return obj;
|
|
274
|
+
}
|
|
275
|
+
|
|
212
276
|
VALUE
|
|
213
|
-
|
|
277
|
+
rbffi_NativeCallback_NewInstance(VALUE rbCallbackInfo, VALUE rbProc)
|
|
214
278
|
{
|
|
215
279
|
NativeCallback* closure = NULL;
|
|
216
|
-
CallbackInfo* cbInfo
|
|
280
|
+
CallbackInfo* cbInfo;
|
|
281
|
+
VALUE obj;
|
|
217
282
|
ffi_status status;
|
|
218
|
-
|
|
219
|
-
|
|
283
|
+
|
|
284
|
+
Data_Get_Struct(rbCallbackInfo, CallbackInfo, cbInfo);
|
|
285
|
+
obj = Data_Make_Struct(NativeCallbackClass, NativeCallback, native_callback_mark, native_callback_free, closure);
|
|
286
|
+
closure->cbInfo = cbInfo;
|
|
287
|
+
closure->rbProc = rbProc;
|
|
288
|
+
closure->rbCallbackInfo = rbCallbackInfo;
|
|
289
|
+
|
|
220
290
|
closure->ffi_closure = ffi_closure_alloc(sizeof(*closure->ffi_closure), &closure->code);
|
|
221
291
|
if (closure->ffi_closure == NULL) {
|
|
222
|
-
xfree(closure);
|
|
223
292
|
rb_raise(rb_eNoMemError, "Failed to allocate FFI native closure");
|
|
224
293
|
}
|
|
225
|
-
|
|
226
|
-
closure->rbProc = rbProc;
|
|
227
|
-
closure->rbCallbackInfo = rbCallbackInfo;
|
|
294
|
+
|
|
228
295
|
status = ffi_prep_closure_loc(closure->ffi_closure, &cbInfo->ffi_cif,
|
|
229
296
|
native_callback_invoke, closure, closure->code);
|
|
230
297
|
if (status != FFI_OK) {
|
|
231
|
-
ffi_closure_free(closure->ffi_closure);
|
|
232
|
-
xfree(closure);
|
|
233
298
|
rb_raise(rb_eArgError, "ffi_prep_closure_loc failed");
|
|
234
299
|
}
|
|
235
|
-
|
|
300
|
+
|
|
301
|
+
return obj;
|
|
236
302
|
}
|
|
237
303
|
|
|
238
304
|
VALUE
|
|
239
|
-
|
|
305
|
+
rbffi_NativeCallback_ForProc(VALUE proc, VALUE cbInfo)
|
|
240
306
|
{
|
|
241
307
|
VALUE callback;
|
|
242
|
-
VALUE cbTable = RTEST(rb_ivar_defined(proc,
|
|
308
|
+
VALUE cbTable = RTEST(rb_ivar_defined(proc, id_cbtable)) ? rb_ivar_get(proc, id_cbtable) : Qnil;
|
|
243
309
|
if (cbTable == Qnil) {
|
|
244
310
|
cbTable = rb_hash_new();
|
|
245
|
-
rb_ivar_set(proc,
|
|
311
|
+
rb_ivar_set(proc, id_cbtable, cbTable);
|
|
246
312
|
}
|
|
247
313
|
callback = rb_hash_aref(cbTable, cbInfo);
|
|
248
314
|
if (callback != Qnil) {
|
|
249
315
|
return callback;
|
|
250
316
|
}
|
|
251
|
-
callback =
|
|
317
|
+
callback = rbffi_NativeCallback_NewInstance(cbInfo, proc);
|
|
252
318
|
rb_hash_aset(cbTable, cbInfo, callback);
|
|
253
319
|
return callback;
|
|
254
320
|
}
|
|
@@ -292,12 +358,17 @@ ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
|
|
|
292
358
|
#endif /* HAVE_FFI_CLOSURE_ALLOC */
|
|
293
359
|
|
|
294
360
|
void
|
|
295
|
-
|
|
361
|
+
rbffi_Callback_Init(VALUE moduleFFI)
|
|
296
362
|
{
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
363
|
+
rbffi_CallbackInfoClass = CallbackInfoClass = rb_define_class_under(moduleFFI, "CallbackInfo", rbffi_TypeClass);
|
|
364
|
+
rb_global_variable(&rbffi_CallbackInfoClass);
|
|
365
|
+
|
|
366
|
+
rb_define_alloc_func(CallbackInfoClass, cbinfo_allocate);
|
|
367
|
+
rb_define_method(CallbackInfoClass, "initialize", cbinfo_initialize, 2);
|
|
368
|
+
|
|
369
|
+
NativeCallbackClass = rb_define_class_under(moduleFFI, "NativeCallback", rb_cObject);
|
|
370
|
+
rb_global_variable(&NativeCallbackClass);
|
|
371
|
+
rb_define_alloc_func(NativeCallbackClass, native_callback_allocate);
|
|
372
|
+
id_call = rb_intern("call");
|
|
373
|
+
id_cbtable = rb_intern("@__ffi_callback_table__");
|
|
303
374
|
}
|
data/ext/ffi_c/Callback.h
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#define _CALLBACK_H
|
|
3
3
|
|
|
4
4
|
#include "Types.h"
|
|
5
|
+
#include "Type.h"
|
|
5
6
|
|
|
6
7
|
#ifdef __cplusplus
|
|
7
8
|
extern "C" {
|
|
@@ -9,8 +10,12 @@ extern "C" {
|
|
|
9
10
|
#include <ffi.h>
|
|
10
11
|
|
|
11
12
|
typedef struct {
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
Type type; // The native type of a CallbackInfo object
|
|
14
|
+
VALUE rbReturnType;
|
|
15
|
+
VALUE rbParameterTypes;
|
|
16
|
+
|
|
17
|
+
Type* returnType;
|
|
18
|
+
Type** parameterTypes;
|
|
14
19
|
ffi_type* ffiReturnType;
|
|
15
20
|
ffi_type** ffiParameterTypes;
|
|
16
21
|
ffi_cif ffi_cif;
|
|
@@ -29,9 +34,10 @@ typedef struct {
|
|
|
29
34
|
VALUE rbProc;
|
|
30
35
|
} NativeCallback;
|
|
31
36
|
|
|
32
|
-
extern VALUE
|
|
33
|
-
extern
|
|
34
|
-
extern VALUE
|
|
37
|
+
extern VALUE rbffi_CallbackInfoClass;
|
|
38
|
+
extern void rbffi_Callback_Init(VALUE ffiModule);
|
|
39
|
+
extern VALUE rbffi_NativeCallback_NewInstance(VALUE, VALUE);
|
|
40
|
+
extern VALUE rbffi_NativeCallback_ForProc(VALUE proc, VALUE cbInfo);
|
|
35
41
|
|
|
36
42
|
#ifdef __cplusplus
|
|
37
43
|
}
|