ffi 0.6.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ffi might be problematic. Click here for more details.
- data/History.txt +7 -0
- data/LICENSE +10 -21
- data/README.rdoc +70 -0
- data/Rakefile +56 -84
- data/ext/ffi_c/AbstractMemory.c +56 -38
- data/ext/ffi_c/AbstractMemory.h +15 -22
- data/ext/ffi_c/Buffer.c +61 -22
- data/ext/ffi_c/Call.c +52 -540
- data/ext/ffi_c/Call.h +1 -1
- data/ext/ffi_c/DataConverter.c +62 -0
- data/ext/ffi_c/DynamicLibrary.c +21 -1
- data/ext/ffi_c/Function.c +252 -30
- data/ext/ffi_c/MappedType.c +146 -0
- data/{libtest/FunctionTest.c → ext/ffi_c/MappedType.h} +32 -25
- data/ext/ffi_c/MemoryPointer.c +12 -33
- data/ext/ffi_c/Platform.c +2 -0
- data/ext/ffi_c/Pointer.c +66 -28
- data/ext/ffi_c/Struct.c +19 -306
- data/ext/ffi_c/Struct.h +6 -0
- data/ext/ffi_c/StructByReference.c +150 -0
- data/{libtest/LastErrorTest.c → ext/ffi_c/StructByReference.h} +30 -21
- data/ext/ffi_c/StructLayout.c +26 -16
- data/ext/ffi_c/Type.c +39 -68
- data/ext/ffi_c/Type.h +12 -22
- data/ext/ffi_c/Types.c +20 -5
- data/ext/ffi_c/Types.h +7 -7
- data/ext/ffi_c/Variadic.c +21 -17
- data/ext/ffi_c/extconf.rb +4 -0
- data/ext/ffi_c/ffi.c +8 -2
- data/ext/ffi_c/rbffi.h +1 -0
- data/lib/ffi/autopointer.rb +23 -22
- data/lib/ffi/enum.rb +36 -21
- data/lib/ffi/errno.rb +20 -0
- data/lib/ffi/ffi.rb +13 -80
- data/lib/ffi/io.rb +12 -20
- data/lib/ffi/library.rb +109 -92
- data/lib/ffi/managedstruct.rb +1 -1
- data/lib/ffi/memorypointer.rb +15 -21
- data/lib/ffi/platform.rb +27 -33
- data/lib/ffi/pointer.rb +14 -21
- data/lib/ffi/struct.rb +98 -49
- data/lib/ffi/struct_layout_builder.rb +158 -0
- data/lib/ffi/types.rb +99 -128
- data/lib/ffi/union.rb +20 -0
- data/lib/ffi/variadic.rb +33 -22
- data/spec/ffi/async_callback_spec.rb +23 -0
- data/spec/ffi/callback_spec.rb +62 -0
- data/spec/ffi/custom_param_type.rb +31 -0
- data/spec/ffi/custom_type_spec.rb +73 -0
- data/spec/ffi/enum_spec.rb +19 -0
- data/spec/ffi/ffi_spec.rb +24 -0
- data/spec/ffi/pointer_spec.rb +15 -0
- data/spec/ffi/rbx/memory_pointer_spec.rb +7 -1
- data/spec/ffi/strptr_spec.rb +36 -0
- data/spec/ffi/struct_packed_spec.rb +46 -0
- data/spec/ffi/struct_spec.rb +19 -5
- data/spec/ffi/typedef_spec.rb +14 -0
- data/tasks/ann.rake +80 -0
- data/tasks/extension.rake +25 -0
- data/tasks/gem.rake +200 -0
- data/tasks/git.rake +41 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +301 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +139 -131
- data/README.md +0 -109
- data/ext/ffi_c/AutoPointer.c +0 -60
- data/ext/ffi_c/AutoPointer.h +0 -18
- data/ext/ffi_c/Ffi_c.iml +0 -12
- data/ffi.gemspec +0 -18
- data/gen/log +0 -1
- data/lib/Lib.iml +0 -21
- data/libtest/Benchmark.c +0 -73
- data/libtest/BoolTest.c +0 -52
- data/libtest/BufferTest.c +0 -52
- data/libtest/ClosureTest.c +0 -173
- data/libtest/EnumTest.c +0 -55
- data/libtest/GNUmakefile +0 -141
- data/libtest/GlobalVariable.c +0 -56
- data/libtest/NumberTest.c +0 -145
- data/libtest/PointerTest.c +0 -84
- data/libtest/ReferenceTest.c +0 -44
- data/libtest/StringTest.c +0 -55
- data/libtest/StructTest.c +0 -247
- data/libtest/UnionTest.c +0 -64
- data/libtest/VariadicTest.c +0 -57
- data/spec/ffi/Ffi.iml +0 -12
data/ext/ffi_c/Call.h
CHANGED
@@ -69,7 +69,7 @@ typedef union {
|
|
69
69
|
|
70
70
|
extern void rbffi_Call_Init(VALUE moduleFFI);
|
71
71
|
|
72
|
-
extern void rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount,
|
72
|
+
extern void rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
|
73
73
|
FFIStorage* paramStorage, void** ffiValues,
|
74
74
|
VALUE* callbackParameters, int callbackCount, VALUE enums);
|
75
75
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
#include <ffi.h>
|
5
|
+
#include "rbffi.h"
|
6
|
+
|
7
|
+
#include "Type.h"
|
8
|
+
#include "MappedType.h"
|
9
|
+
|
10
|
+
|
11
|
+
VALUE rbffi_DataConverterClass = Qnil;
|
12
|
+
static ID id_native_type_ivar;
|
13
|
+
|
14
|
+
static VALUE
|
15
|
+
conv_native_type(int argc, VALUE* argv, VALUE self)
|
16
|
+
{
|
17
|
+
if (argc == 0) {
|
18
|
+
if (!rb_ivar_defined(self, id_native_type_ivar)) {
|
19
|
+
rb_raise(rb_eNotImpError, "native_type method not overridden and no native_type set");
|
20
|
+
}
|
21
|
+
|
22
|
+
return rb_ivar_get(self, id_native_type_ivar);
|
23
|
+
|
24
|
+
} else if (argc == 1) {
|
25
|
+
VALUE type = rbffi_Type_Find(argv[0]);
|
26
|
+
|
27
|
+
rb_ivar_set(self, id_native_type_ivar, type);
|
28
|
+
|
29
|
+
return type;
|
30
|
+
|
31
|
+
} else {
|
32
|
+
rb_raise(rb_eArgError, "incorrect arguments");
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
static VALUE
|
37
|
+
conv_to_native(VALUE self, VALUE value, VALUE ctx)
|
38
|
+
{
|
39
|
+
return value;
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE
|
43
|
+
conv_from_native(VALUE self, VALUE value, VALUE ctx)
|
44
|
+
{
|
45
|
+
return value;
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
void
|
51
|
+
rbffi_DataConverter_Init(VALUE moduleFFI)
|
52
|
+
{
|
53
|
+
rbffi_DataConverterClass = rb_define_module_under(moduleFFI, "DataConverter");
|
54
|
+
|
55
|
+
rb_define_method(rbffi_DataConverterClass, "native_type", conv_native_type, -1);
|
56
|
+
rb_define_method(rbffi_DataConverterClass, "to_native", conv_to_native, 2);
|
57
|
+
rb_define_method(rbffi_DataConverterClass, "from_native", conv_from_native, 2);
|
58
|
+
|
59
|
+
id_native_type_ivar = rb_intern("@native_type");
|
60
|
+
}
|
61
|
+
|
62
|
+
|
data/ext/ffi_c/DynamicLibrary.c
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2008-2010 Wayne Meissner
|
3
|
+
*
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This file is part of ruby-ffi.
|
7
|
+
*
|
8
|
+
* This code is free software: you can redistribute it and/or modify it under
|
9
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
10
|
+
* published by the Free Software Foundation.
|
11
|
+
*
|
12
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
13
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
14
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
15
|
+
* version 3 for more details.
|
16
|
+
*
|
17
|
+
* You should have received a copy of the GNU Lesser General Public License
|
18
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
1
21
|
#include <sys/types.h>
|
2
22
|
#include <stdio.h>
|
3
23
|
#include <stdint.h>
|
@@ -156,7 +176,7 @@ symbol_new(VALUE library, void* address, VALUE name)
|
|
156
176
|
sym->memory.address = address;
|
157
177
|
sym->memory.size = LONG_MAX;
|
158
178
|
sym->memory.typeSize = 1;
|
159
|
-
sym->memory.
|
179
|
+
sym->memory.flags = MEM_RD | MEM_WR;
|
160
180
|
sym->library = library;
|
161
181
|
sym->name = name;
|
162
182
|
|
data/ext/ffi_c/Function.c
CHANGED
@@ -1,28 +1,21 @@
|
|
1
1
|
/*
|
2
2
|
* Copyright (c) 2009, Wayne Meissner
|
3
|
+
|
3
4
|
* All rights reserved.
|
4
5
|
*
|
5
|
-
*
|
6
|
-
*
|
6
|
+
* This file is part of ruby-ffi.
|
7
|
+
*
|
8
|
+
* This code is free software: you can redistribute it and/or modify it under
|
9
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
10
|
+
* published by the Free Software Foundation.
|
7
11
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
* and/or other materials provided with the distribution.
|
13
|
-
* * The name of the author or authors may not be used to endorse or promote
|
14
|
-
* products derived from this software without specific prior written permission.
|
12
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
13
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
14
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
15
|
+
* version 3 for more details.
|
15
16
|
*
|
16
|
-
*
|
17
|
-
*
|
18
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
20
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
17
|
+
* You should have received a copy of the GNU Lesser General Public License
|
18
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
26
19
|
*/
|
27
20
|
|
28
21
|
#include "MethodHandle.h"
|
@@ -39,6 +32,10 @@
|
|
39
32
|
#include <ruby.h>
|
40
33
|
|
41
34
|
#include <ffi.h>
|
35
|
+
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
|
36
|
+
#include <pthread.h>
|
37
|
+
#endif
|
38
|
+
|
42
39
|
#include "rbffi.h"
|
43
40
|
#include "compat.h"
|
44
41
|
|
@@ -51,6 +48,7 @@
|
|
51
48
|
#include "Call.h"
|
52
49
|
#include "ClosurePool.h"
|
53
50
|
#include "Function.h"
|
51
|
+
#include "MappedType.h"
|
54
52
|
|
55
53
|
typedef struct Function_ {
|
56
54
|
AbstractMemory memory;
|
@@ -67,10 +65,60 @@ static void function_free(Function *);
|
|
67
65
|
static VALUE function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc);
|
68
66
|
static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data);
|
69
67
|
static bool callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
|
68
|
+
static void* callback_with_gvl(void* data);
|
69
|
+
|
70
|
+
#if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
71
|
+
# define DEFER_ASYNC_CALLBACK 1
|
72
|
+
#endif
|
73
|
+
|
74
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
75
|
+
static VALUE async_cb_event(void);
|
76
|
+
static VALUE async_cb_call(void *);
|
77
|
+
#endif
|
78
|
+
|
79
|
+
#if defined(HAVE_NATIVETHREAD) && defined (HAVE_RB_THREAD_BLOCKING_REGION)
|
80
|
+
# define DEFER_ASYNC_CALLBACK
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
84
|
+
extern int ruby_thread_has_gvl_p(void);
|
85
|
+
#endif
|
86
|
+
|
87
|
+
#ifdef HAVE_RB_THREAD_CALL_WITH_GVL
|
88
|
+
extern void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
|
89
|
+
#endif
|
70
90
|
|
71
91
|
VALUE rbffi_FunctionClass = Qnil;
|
72
92
|
|
73
|
-
|
93
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
94
|
+
static VALUE async_cb_thread = Qnil;
|
95
|
+
#endif
|
96
|
+
|
97
|
+
static ID id_call = 0, id_to_native = 0, id_from_native = 0, id_cbtable = 0, id_cb_ref = 0;
|
98
|
+
|
99
|
+
struct gvl_callback {
|
100
|
+
Closure* closure;
|
101
|
+
void* retval;
|
102
|
+
void** parameters;
|
103
|
+
|
104
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
105
|
+
struct gvl_callback* next;
|
106
|
+
# ifndef _WIN32
|
107
|
+
pthread_cond_t async_cond;
|
108
|
+
pthread_mutex_t async_mutex;
|
109
|
+
# endif
|
110
|
+
#endif
|
111
|
+
};
|
112
|
+
|
113
|
+
|
114
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
115
|
+
static struct gvl_callback* async_cb_list = NULL;
|
116
|
+
# ifndef _WIN32
|
117
|
+
static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
|
118
|
+
static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
|
119
|
+
# endif
|
120
|
+
#endif
|
121
|
+
|
74
122
|
|
75
123
|
static VALUE
|
76
124
|
function_allocate(VALUE klass)
|
@@ -80,7 +128,7 @@ function_allocate(VALUE klass)
|
|
80
128
|
|
81
129
|
obj = Data_Make_Struct(klass, Function, function_mark, function_free, fn);
|
82
130
|
|
83
|
-
fn->memory.
|
131
|
+
fn->memory.flags = MEM_RD;
|
84
132
|
|
85
133
|
fn->rbProc = Qnil;
|
86
134
|
fn->rbFunctionInfo = Qnil;
|
@@ -215,6 +263,12 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
215
263
|
}
|
216
264
|
}
|
217
265
|
|
266
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
267
|
+
if (async_cb_thread == Qnil) {
|
268
|
+
async_cb_thread = rb_thread_create(async_cb_event, NULL);
|
269
|
+
}
|
270
|
+
#endif
|
271
|
+
|
218
272
|
fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
|
219
273
|
fn->closure->info = fn;
|
220
274
|
fn->memory.address = fn->closure->code;
|
@@ -222,7 +276,8 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
222
276
|
fn->autorelease = true;
|
223
277
|
|
224
278
|
} else {
|
225
|
-
rb_raise(rb_eTypeError, "wrong argument type
|
279
|
+
rb_raise(rb_eTypeError, "wrong argument type %s, expected pointer or proc",
|
280
|
+
rb_obj_classname(rbProc));
|
226
281
|
}
|
227
282
|
|
228
283
|
fn->rbProc = rbProc;
|
@@ -320,17 +375,147 @@ function_release(VALUE self)
|
|
320
375
|
static void
|
321
376
|
callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
322
377
|
{
|
323
|
-
|
324
|
-
|
378
|
+
struct gvl_callback cb;
|
379
|
+
cb.closure = (Closure *) user_data;
|
380
|
+
cb.retval = retval;
|
381
|
+
cb.parameters = parameters;
|
382
|
+
|
383
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
384
|
+
if (ruby_thread_has_gvl_p()) {
|
385
|
+
#else
|
386
|
+
if (1) {
|
387
|
+
#endif
|
388
|
+
callback_with_gvl(&cb);
|
389
|
+
|
390
|
+
#if defined(HAVE_RUBY_NATIVE_THREAD_P) && defined (HAVE_RB_THREAD_CALL_WITH_GVL)
|
391
|
+
} else if (ruby_native_thread_p()) {
|
392
|
+
rb_thread_call_with_gvl(callback_with_gvl, &cb);
|
393
|
+
#endif
|
394
|
+
#if defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
|
395
|
+
} else {
|
396
|
+
pthread_mutex_init(&cb.async_mutex, NULL);
|
397
|
+
pthread_cond_init(&cb.async_cond, NULL);
|
398
|
+
|
399
|
+
pthread_mutex_lock(&cb.async_mutex);
|
400
|
+
|
401
|
+
// Now signal the async callback thread
|
402
|
+
pthread_mutex_lock(&async_cb_mutex);
|
403
|
+
cb.next = async_cb_list;
|
404
|
+
async_cb_list = &cb;
|
405
|
+
pthread_cond_signal(&async_cb_cond);
|
406
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
407
|
+
|
408
|
+
// Wait for the thread executing the ruby callback to signal it is done
|
409
|
+
pthread_cond_wait(&cb.async_cond, &cb.async_mutex);
|
410
|
+
#endif
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
415
|
+
struct async_wait {
|
416
|
+
void* cb;
|
417
|
+
bool stop;
|
418
|
+
};
|
419
|
+
|
420
|
+
static VALUE async_cb_wait(void *);
|
421
|
+
static void async_cb_stop(void *);
|
422
|
+
|
423
|
+
static VALUE
|
424
|
+
async_cb_event(void)
|
425
|
+
{
|
426
|
+
struct async_wait w = { 0 };
|
427
|
+
|
428
|
+
w.stop = false;
|
429
|
+
while (!w.stop) {
|
430
|
+
rb_thread_blocking_region(async_cb_wait, &w, async_cb_stop, &w);
|
431
|
+
if (w.cb != NULL) {
|
432
|
+
// Start up a new ruby thread to run the ruby callback
|
433
|
+
rb_thread_create(async_cb_call, w.cb);
|
434
|
+
}
|
435
|
+
}
|
436
|
+
|
437
|
+
return Qnil;
|
438
|
+
}
|
439
|
+
|
440
|
+
static VALUE
|
441
|
+
async_cb_wait(void *data)
|
442
|
+
{
|
443
|
+
struct async_wait* w = (struct async_wait *) data;
|
444
|
+
|
445
|
+
w->cb = NULL;
|
446
|
+
|
447
|
+
pthread_mutex_lock(&async_cb_mutex);
|
448
|
+
|
449
|
+
while (!w->stop && async_cb_list == NULL) {
|
450
|
+
pthread_cond_wait(&async_cb_cond, &async_cb_mutex);
|
451
|
+
}
|
452
|
+
|
453
|
+
if (async_cb_list != NULL) {
|
454
|
+
w->cb = async_cb_list;
|
455
|
+
async_cb_list = async_cb_list->next;
|
456
|
+
}
|
457
|
+
|
458
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
459
|
+
|
460
|
+
return Qnil;
|
461
|
+
}
|
462
|
+
|
463
|
+
static void
|
464
|
+
async_cb_stop(void *data)
|
465
|
+
{
|
466
|
+
struct async_wait* w = (struct async_wait *) data;
|
467
|
+
|
468
|
+
pthread_mutex_lock(&async_cb_mutex);
|
469
|
+
w->stop = true;
|
470
|
+
pthread_cond_signal(&async_cb_cond);
|
471
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
472
|
+
}
|
473
|
+
|
474
|
+
static VALUE
|
475
|
+
async_cb_call(void *data)
|
476
|
+
{
|
477
|
+
struct gvl_callback* cb = (struct gvl_callback *) data;
|
478
|
+
|
479
|
+
callback_with_gvl(cb);
|
480
|
+
|
481
|
+
// Signal the original native thread that the ruby code has completed
|
482
|
+
pthread_mutex_lock(&cb->async_mutex);
|
483
|
+
pthread_cond_signal(&cb->async_cond);
|
484
|
+
pthread_mutex_unlock(&cb->async_mutex);
|
485
|
+
|
486
|
+
return Qnil;
|
487
|
+
}
|
488
|
+
|
489
|
+
#endif
|
490
|
+
|
491
|
+
|
492
|
+
static void*
|
493
|
+
callback_with_gvl(void* data)
|
494
|
+
{
|
495
|
+
struct gvl_callback* cb = (struct gvl_callback *) data;
|
496
|
+
|
497
|
+
Function* fn = (Function *) cb->closure->info;
|
325
498
|
FunctionType *cbInfo = fn->info;
|
499
|
+
Type* returnType = cbInfo->returnType;
|
500
|
+
void* retval = cb->retval;
|
501
|
+
void** parameters = cb->parameters;
|
326
502
|
VALUE* rbParams;
|
503
|
+
VALUE rbReturnType = cbInfo->rbReturnType;
|
327
504
|
VALUE rbReturnValue;
|
328
505
|
int i;
|
329
506
|
|
330
507
|
rbParams = ALLOCA_N(VALUE, cbInfo->parameterCount);
|
331
508
|
for (i = 0; i < cbInfo->parameterCount; ++i) {
|
332
509
|
VALUE param;
|
333
|
-
|
510
|
+
Type* paramType = cbInfo->parameterTypes[i];
|
511
|
+
VALUE rbParamType = rb_ary_entry(cbInfo->rbParameterTypes, i);
|
512
|
+
|
513
|
+
if (unlikely(paramType->nativeType == NATIVE_MAPPED)) {
|
514
|
+
paramType = ((MappedType *) paramType)->type;
|
515
|
+
rbParamType = ((MappedType *) paramType)->rbType;
|
516
|
+
}
|
517
|
+
|
518
|
+
switch (paramType->nativeType) {
|
334
519
|
case NATIVE_INT8:
|
335
520
|
param = INT2NUM(*(int8_t *) parameters[i]);
|
336
521
|
break;
|
@@ -379,19 +564,36 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
379
564
|
|
380
565
|
case NATIVE_FUNCTION:
|
381
566
|
case NATIVE_CALLBACK:
|
382
|
-
|
383
|
-
|
567
|
+
case NATIVE_STRUCT:
|
568
|
+
param = rbffi_NativeValue_ToRuby(paramType, rbParamType, parameters[i], Qnil);
|
384
569
|
break;
|
570
|
+
|
385
571
|
default:
|
386
572
|
param = Qnil;
|
387
573
|
break;
|
388
574
|
}
|
575
|
+
|
576
|
+
// Convert the native value into a custom ruby value
|
577
|
+
if (unlikely(cbInfo->parameterTypes[i]->nativeType == NATIVE_MAPPED)) {
|
578
|
+
VALUE values[] = { param, Qnil };
|
579
|
+
param = rb_funcall2(((MappedType *) cbInfo->parameterTypes[i])->rbConverter, id_from_native, 2, values);
|
580
|
+
}
|
581
|
+
|
389
582
|
rbParams[i] = param;
|
390
583
|
}
|
584
|
+
|
391
585
|
rbReturnValue = rb_funcall2(fn->rbProc, id_call, cbInfo->parameterCount, rbParams);
|
586
|
+
|
587
|
+
if (unlikely(returnType->nativeType == NATIVE_MAPPED)) {
|
588
|
+
VALUE values[] = { rbReturnValue, Qnil };
|
589
|
+
rbReturnValue = rb_funcall2(((MappedType *) returnType)->rbConverter, id_to_native, 2, values);
|
590
|
+
rbReturnType = ((MappedType *) returnType)->rbType;
|
591
|
+
returnType = ((MappedType* ) returnType)->type;
|
592
|
+
}
|
593
|
+
|
392
594
|
if (rbReturnValue == Qnil || TYPE(rbReturnValue) == T_NIL) {
|
393
|
-
memset(retval, 0,
|
394
|
-
} else switch (
|
595
|
+
memset(retval, 0, returnType->ffiType->size);
|
596
|
+
} else switch (returnType->nativeType) {
|
395
597
|
case NATIVE_INT8:
|
396
598
|
case NATIVE_INT16:
|
397
599
|
case NATIVE_INT32:
|
@@ -442,7 +644,7 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
442
644
|
} else if (rb_obj_is_kind_of(rbReturnValue, rb_cProc) || rb_respond_to(rbReturnValue, id_call)) {
|
443
645
|
VALUE function;
|
444
646
|
|
445
|
-
function = rbffi_Function_ForProc(
|
647
|
+
function = rbffi_Function_ForProc(rbReturnType, rbReturnValue);
|
446
648
|
|
447
649
|
*((void **) retval) = ((AbstractMemory *) DATA_PTR(function))->address;
|
448
650
|
} else {
|
@@ -450,10 +652,28 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
450
652
|
}
|
451
653
|
break;
|
452
654
|
|
655
|
+
case NATIVE_STRUCT:
|
656
|
+
if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_StructClass)) {
|
657
|
+
AbstractMemory* memory = ((Struct *) DATA_PTR(rbReturnValue))->pointer;
|
658
|
+
|
659
|
+
if (memory->address != NULL) {
|
660
|
+
memcpy(retval, memory->address, returnType->ffiType->size);
|
661
|
+
|
662
|
+
} else {
|
663
|
+
memset(retval, 0, returnType->ffiType->size);
|
664
|
+
}
|
665
|
+
|
666
|
+
} else {
|
667
|
+
memset(retval, 0, returnType->ffiType->size);
|
668
|
+
}
|
669
|
+
break;
|
670
|
+
|
453
671
|
default:
|
454
672
|
*((ffi_arg *) retval) = 0;
|
455
673
|
break;
|
456
674
|
}
|
675
|
+
|
676
|
+
return NULL;
|
457
677
|
}
|
458
678
|
|
459
679
|
|
@@ -492,5 +712,7 @@ rbffi_Function_Init(VALUE moduleFFI)
|
|
492
712
|
id_call = rb_intern("call");
|
493
713
|
id_cbtable = rb_intern("@__ffi_callback_table__");
|
494
714
|
id_cb_ref = rb_intern("@__ffi_callback__");
|
715
|
+
id_to_native = rb_intern("to_native");
|
716
|
+
id_from_native = rb_intern("from_native");
|
495
717
|
}
|
496
718
|
|