ffi 0.6.3-x86-mingw32 → 1.0.1-x86-mingw32
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 +1 -0
- data/Rakefile +4 -2
- data/ext/ffi_c/AbstractMemory.c +103 -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 +315 -30
- data/ext/ffi_c/MappedType.c +146 -0
- data/ext/ffi_c/MappedType.h +57 -0
- 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/ext/ffi_c/StructByReference.h +50 -0
- data/ext/ffi_c/StructLayout.c +25 -14
- 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 +24 -28
- 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/lib/ffi_c.so +0 -0
- 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/setup.rb +2 -1
- metadata +15 -6
- data/ext/ffi_c/AutoPointer.c +0 -60
- data/ext/ffi_c/AutoPointer.h +0 -18
- data/lib/1.8/ffi_c.so +0 -0
- data/lib/1.9/ffi_c.so +0 -0
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,61 @@ 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
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
80
|
+
extern int ruby_thread_has_gvl_p(void);
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#ifdef HAVE_RB_THREAD_CALL_WITH_GVL
|
84
|
+
extern void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
|
85
|
+
#endif
|
70
86
|
|
71
87
|
VALUE rbffi_FunctionClass = Qnil;
|
72
88
|
|
73
|
-
|
89
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
90
|
+
static VALUE async_cb_thread = Qnil;
|
91
|
+
#endif
|
92
|
+
|
93
|
+
static ID id_call = 0, id_to_native = 0, id_from_native = 0, id_cbtable = 0, id_cb_ref = 0;
|
94
|
+
|
95
|
+
struct gvl_callback {
|
96
|
+
Closure* closure;
|
97
|
+
void* retval;
|
98
|
+
void** parameters;
|
99
|
+
|
100
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
101
|
+
struct gvl_callback* next;
|
102
|
+
# ifndef _WIN32
|
103
|
+
pthread_cond_t async_cond;
|
104
|
+
pthread_mutex_t async_mutex;
|
105
|
+
# else
|
106
|
+
HANDLE async_event;
|
107
|
+
# endif
|
108
|
+
#endif
|
109
|
+
};
|
110
|
+
|
111
|
+
|
112
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
113
|
+
static struct gvl_callback* async_cb_list = NULL;
|
114
|
+
# ifndef _WIN32
|
115
|
+
static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
|
116
|
+
static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
|
117
|
+
# else
|
118
|
+
static HANDLE async_cb_cond;
|
119
|
+
static CRITICAL_SECTION async_cb_lock;
|
120
|
+
# endif
|
121
|
+
#endif
|
122
|
+
|
74
123
|
|
75
124
|
static VALUE
|
76
125
|
function_allocate(VALUE klass)
|
@@ -80,7 +129,7 @@ function_allocate(VALUE klass)
|
|
80
129
|
|
81
130
|
obj = Data_Make_Struct(klass, Function, function_mark, function_free, fn);
|
82
131
|
|
83
|
-
fn->memory.
|
132
|
+
fn->memory.flags = MEM_RD;
|
84
133
|
|
85
134
|
fn->rbProc = Qnil;
|
86
135
|
fn->rbFunctionInfo = Qnil;
|
@@ -215,6 +264,12 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
215
264
|
}
|
216
265
|
}
|
217
266
|
|
267
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
268
|
+
if (async_cb_thread == Qnil) {
|
269
|
+
async_cb_thread = rb_thread_create(async_cb_event, NULL);
|
270
|
+
}
|
271
|
+
#endif
|
272
|
+
|
218
273
|
fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
|
219
274
|
fn->closure->info = fn;
|
220
275
|
fn->memory.address = fn->closure->code;
|
@@ -222,7 +277,8 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
222
277
|
fn->autorelease = true;
|
223
278
|
|
224
279
|
} else {
|
225
|
-
rb_raise(rb_eTypeError, "wrong argument type
|
280
|
+
rb_raise(rb_eTypeError, "wrong argument type %s, expected pointer or proc",
|
281
|
+
rb_obj_classname(rbProc));
|
226
282
|
}
|
227
283
|
|
228
284
|
fn->rbProc = rbProc;
|
@@ -320,17 +376,205 @@ function_release(VALUE self)
|
|
320
376
|
static void
|
321
377
|
callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
322
378
|
{
|
323
|
-
|
324
|
-
|
379
|
+
struct gvl_callback cb;
|
380
|
+
cb.closure = (Closure *) user_data;
|
381
|
+
cb.retval = retval;
|
382
|
+
cb.parameters = parameters;
|
383
|
+
|
384
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
385
|
+
if (ruby_thread_has_gvl_p()) {
|
386
|
+
#else
|
387
|
+
if (1) {
|
388
|
+
#endif
|
389
|
+
callback_with_gvl(&cb);
|
390
|
+
|
391
|
+
#if defined(HAVE_RUBY_NATIVE_THREAD_P) && defined (HAVE_RB_THREAD_CALL_WITH_GVL)
|
392
|
+
} else if (ruby_native_thread_p()) {
|
393
|
+
rb_thread_call_with_gvl(callback_with_gvl, &cb);
|
394
|
+
#endif
|
395
|
+
#if defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
|
396
|
+
} else {
|
397
|
+
pthread_mutex_init(&cb.async_mutex, NULL);
|
398
|
+
pthread_cond_init(&cb.async_cond, NULL);
|
399
|
+
|
400
|
+
pthread_mutex_lock(&cb.async_mutex);
|
401
|
+
|
402
|
+
// Now signal the async callback thread
|
403
|
+
pthread_mutex_lock(&async_cb_mutex);
|
404
|
+
cb.next = async_cb_list;
|
405
|
+
async_cb_list = &cb;
|
406
|
+
pthread_cond_signal(&async_cb_cond);
|
407
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
408
|
+
|
409
|
+
// Wait for the thread executing the ruby callback to signal it is done
|
410
|
+
pthread_cond_wait(&cb.async_cond, &cb.async_mutex);
|
411
|
+
#elif defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
|
412
|
+
} else {
|
413
|
+
cb.async_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
414
|
+
|
415
|
+
// Now signal the async callback thread
|
416
|
+
EnterCriticalSection(&async_cb_lock);
|
417
|
+
cb.next = async_cb_list;
|
418
|
+
async_cb_list = &cb;
|
419
|
+
LeaveCriticalSection(&async_cb_lock);
|
420
|
+
|
421
|
+
SetEvent(async_cb_cond);
|
422
|
+
|
423
|
+
// Wait for the thread executing the ruby callback to signal it is done
|
424
|
+
WaitForSingleObject(cb.async_event, INFINITE);
|
425
|
+
CloseHandle(cb.async_event);
|
426
|
+
#endif
|
427
|
+
}
|
428
|
+
}
|
429
|
+
|
430
|
+
#if defined(DEFER_ASYNC_CALLBACK)
|
431
|
+
struct async_wait {
|
432
|
+
void* cb;
|
433
|
+
bool stop;
|
434
|
+
};
|
435
|
+
|
436
|
+
static VALUE async_cb_wait(void *);
|
437
|
+
static void async_cb_stop(void *);
|
438
|
+
|
439
|
+
static VALUE
|
440
|
+
async_cb_event(void)
|
441
|
+
{
|
442
|
+
struct async_wait w = { 0 };
|
443
|
+
|
444
|
+
w.stop = false;
|
445
|
+
while (!w.stop) {
|
446
|
+
rb_thread_blocking_region(async_cb_wait, &w, async_cb_stop, &w);
|
447
|
+
if (w.cb != NULL) {
|
448
|
+
// Start up a new ruby thread to run the ruby callback
|
449
|
+
rb_thread_create(async_cb_call, w.cb);
|
450
|
+
}
|
451
|
+
}
|
452
|
+
|
453
|
+
return Qnil;
|
454
|
+
}
|
455
|
+
|
456
|
+
#ifdef _WIN32
|
457
|
+
static VALUE
|
458
|
+
async_cb_wait(void *data)
|
459
|
+
{
|
460
|
+
struct async_wait* w = (struct async_wait *) data;
|
461
|
+
|
462
|
+
w->cb = NULL;
|
463
|
+
|
464
|
+
EnterCriticalSection(&async_cb_lock);
|
465
|
+
|
466
|
+
while (!w->stop && async_cb_list == NULL) {
|
467
|
+
LeaveCriticalSection(&async_cb_lock);
|
468
|
+
WaitForSingleObject(async_cb_cond, INFINITE);
|
469
|
+
EnterCriticalSection(&async_cb_lock);
|
470
|
+
}
|
471
|
+
|
472
|
+
if (async_cb_list != NULL) {
|
473
|
+
w->cb = async_cb_list;
|
474
|
+
async_cb_list = async_cb_list->next;
|
475
|
+
}
|
476
|
+
|
477
|
+
LeaveCriticalSection(&async_cb_lock);
|
478
|
+
|
479
|
+
return Qnil;
|
480
|
+
}
|
481
|
+
|
482
|
+
static void
|
483
|
+
async_cb_stop(void *data)
|
484
|
+
{
|
485
|
+
struct async_wait* w = (struct async_wait *) data;
|
486
|
+
|
487
|
+
EnterCriticalSection(&async_cb_lock);
|
488
|
+
w->stop = true;
|
489
|
+
LeaveCriticalSection(&async_cb_lock);
|
490
|
+
SetEvent(async_cb_cond);
|
491
|
+
}
|
492
|
+
|
493
|
+
#else
|
494
|
+
static VALUE
|
495
|
+
async_cb_wait(void *data)
|
496
|
+
{
|
497
|
+
struct async_wait* w = (struct async_wait *) data;
|
498
|
+
|
499
|
+
w->cb = NULL;
|
500
|
+
|
501
|
+
pthread_mutex_lock(&async_cb_mutex);
|
502
|
+
|
503
|
+
while (!w->stop && async_cb_list == NULL) {
|
504
|
+
pthread_cond_wait(&async_cb_cond, &async_cb_mutex);
|
505
|
+
}
|
506
|
+
|
507
|
+
if (async_cb_list != NULL) {
|
508
|
+
w->cb = async_cb_list;
|
509
|
+
async_cb_list = async_cb_list->next;
|
510
|
+
}
|
511
|
+
|
512
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
513
|
+
|
514
|
+
return Qnil;
|
515
|
+
}
|
516
|
+
|
517
|
+
static void
|
518
|
+
async_cb_stop(void *data)
|
519
|
+
{
|
520
|
+
struct async_wait* w = (struct async_wait *) data;
|
521
|
+
|
522
|
+
pthread_mutex_lock(&async_cb_mutex);
|
523
|
+
w->stop = true;
|
524
|
+
pthread_cond_signal(&async_cb_cond);
|
525
|
+
pthread_mutex_unlock(&async_cb_mutex);
|
526
|
+
}
|
527
|
+
#endif
|
528
|
+
|
529
|
+
static VALUE
|
530
|
+
async_cb_call(void *data)
|
531
|
+
{
|
532
|
+
struct gvl_callback* cb = (struct gvl_callback *) data;
|
533
|
+
|
534
|
+
callback_with_gvl(cb);
|
535
|
+
|
536
|
+
// Signal the original native thread that the ruby code has completed
|
537
|
+
#ifdef _WIN32
|
538
|
+
SetEvent(cb->async_event);
|
539
|
+
#else
|
540
|
+
pthread_mutex_lock(&cb->async_mutex);
|
541
|
+
pthread_cond_signal(&cb->async_cond);
|
542
|
+
pthread_mutex_unlock(&cb->async_mutex);
|
543
|
+
#endif
|
544
|
+
|
545
|
+
return Qnil;
|
546
|
+
}
|
547
|
+
|
548
|
+
#endif
|
549
|
+
|
550
|
+
|
551
|
+
static void*
|
552
|
+
callback_with_gvl(void* data)
|
553
|
+
{
|
554
|
+
struct gvl_callback* cb = (struct gvl_callback *) data;
|
555
|
+
|
556
|
+
Function* fn = (Function *) cb->closure->info;
|
325
557
|
FunctionType *cbInfo = fn->info;
|
558
|
+
Type* returnType = cbInfo->returnType;
|
559
|
+
void* retval = cb->retval;
|
560
|
+
void** parameters = cb->parameters;
|
326
561
|
VALUE* rbParams;
|
562
|
+
VALUE rbReturnType = cbInfo->rbReturnType;
|
327
563
|
VALUE rbReturnValue;
|
328
564
|
int i;
|
329
565
|
|
330
566
|
rbParams = ALLOCA_N(VALUE, cbInfo->parameterCount);
|
331
567
|
for (i = 0; i < cbInfo->parameterCount; ++i) {
|
332
568
|
VALUE param;
|
333
|
-
|
569
|
+
Type* paramType = cbInfo->parameterTypes[i];
|
570
|
+
VALUE rbParamType = rb_ary_entry(cbInfo->rbParameterTypes, i);
|
571
|
+
|
572
|
+
if (unlikely(paramType->nativeType == NATIVE_MAPPED)) {
|
573
|
+
paramType = ((MappedType *) paramType)->type;
|
574
|
+
rbParamType = ((MappedType *) paramType)->rbType;
|
575
|
+
}
|
576
|
+
|
577
|
+
switch (paramType->nativeType) {
|
334
578
|
case NATIVE_INT8:
|
335
579
|
param = INT2NUM(*(int8_t *) parameters[i]);
|
336
580
|
break;
|
@@ -379,19 +623,36 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
379
623
|
|
380
624
|
case NATIVE_FUNCTION:
|
381
625
|
case NATIVE_CALLBACK:
|
382
|
-
|
383
|
-
|
626
|
+
case NATIVE_STRUCT:
|
627
|
+
param = rbffi_NativeValue_ToRuby(paramType, rbParamType, parameters[i], Qnil);
|
384
628
|
break;
|
629
|
+
|
385
630
|
default:
|
386
631
|
param = Qnil;
|
387
632
|
break;
|
388
633
|
}
|
634
|
+
|
635
|
+
// Convert the native value into a custom ruby value
|
636
|
+
if (unlikely(cbInfo->parameterTypes[i]->nativeType == NATIVE_MAPPED)) {
|
637
|
+
VALUE values[] = { param, Qnil };
|
638
|
+
param = rb_funcall2(((MappedType *) cbInfo->parameterTypes[i])->rbConverter, id_from_native, 2, values);
|
639
|
+
}
|
640
|
+
|
389
641
|
rbParams[i] = param;
|
390
642
|
}
|
643
|
+
|
391
644
|
rbReturnValue = rb_funcall2(fn->rbProc, id_call, cbInfo->parameterCount, rbParams);
|
645
|
+
|
646
|
+
if (unlikely(returnType->nativeType == NATIVE_MAPPED)) {
|
647
|
+
VALUE values[] = { rbReturnValue, Qnil };
|
648
|
+
rbReturnValue = rb_funcall2(((MappedType *) returnType)->rbConverter, id_to_native, 2, values);
|
649
|
+
rbReturnType = ((MappedType *) returnType)->rbType;
|
650
|
+
returnType = ((MappedType* ) returnType)->type;
|
651
|
+
}
|
652
|
+
|
392
653
|
if (rbReturnValue == Qnil || TYPE(rbReturnValue) == T_NIL) {
|
393
|
-
memset(retval, 0,
|
394
|
-
} else switch (
|
654
|
+
memset(retval, 0, returnType->ffiType->size);
|
655
|
+
} else switch (returnType->nativeType) {
|
395
656
|
case NATIVE_INT8:
|
396
657
|
case NATIVE_INT16:
|
397
658
|
case NATIVE_INT32:
|
@@ -442,7 +703,7 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
442
703
|
} else if (rb_obj_is_kind_of(rbReturnValue, rb_cProc) || rb_respond_to(rbReturnValue, id_call)) {
|
443
704
|
VALUE function;
|
444
705
|
|
445
|
-
function = rbffi_Function_ForProc(
|
706
|
+
function = rbffi_Function_ForProc(rbReturnType, rbReturnValue);
|
446
707
|
|
447
708
|
*((void **) retval) = ((AbstractMemory *) DATA_PTR(function))->address;
|
448
709
|
} else {
|
@@ -450,10 +711,28 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
450
711
|
}
|
451
712
|
break;
|
452
713
|
|
714
|
+
case NATIVE_STRUCT:
|
715
|
+
if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_StructClass)) {
|
716
|
+
AbstractMemory* memory = ((Struct *) DATA_PTR(rbReturnValue))->pointer;
|
717
|
+
|
718
|
+
if (memory->address != NULL) {
|
719
|
+
memcpy(retval, memory->address, returnType->ffiType->size);
|
720
|
+
|
721
|
+
} else {
|
722
|
+
memset(retval, 0, returnType->ffiType->size);
|
723
|
+
}
|
724
|
+
|
725
|
+
} else {
|
726
|
+
memset(retval, 0, returnType->ffiType->size);
|
727
|
+
}
|
728
|
+
break;
|
729
|
+
|
453
730
|
default:
|
454
731
|
*((ffi_arg *) retval) = 0;
|
455
732
|
break;
|
456
733
|
}
|
734
|
+
|
735
|
+
return NULL;
|
457
736
|
}
|
458
737
|
|
459
738
|
|
@@ -492,5 +771,11 @@ rbffi_Function_Init(VALUE moduleFFI)
|
|
492
771
|
id_call = rb_intern("call");
|
493
772
|
id_cbtable = rb_intern("@__ffi_callback_table__");
|
494
773
|
id_cb_ref = rb_intern("@__ffi_callback__");
|
774
|
+
id_to_native = rb_intern("to_native");
|
775
|
+
id_from_native = rb_intern("from_native");
|
776
|
+
#ifdef _WIN32
|
777
|
+
InitializeCriticalSection(&async_cb_lock);
|
778
|
+
async_cb_cond = CreateEvent(NULL, FALSE, FALSE, NULL);
|
779
|
+
#endif
|
495
780
|
}
|
496
781
|
|