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.

Files changed (64) hide show
  1. data/History.txt +7 -0
  2. data/LICENSE +10 -21
  3. data/README.rdoc +1 -0
  4. data/Rakefile +4 -2
  5. data/ext/ffi_c/AbstractMemory.c +103 -38
  6. data/ext/ffi_c/AbstractMemory.h +15 -22
  7. data/ext/ffi_c/Buffer.c +61 -22
  8. data/ext/ffi_c/Call.c +52 -540
  9. data/ext/ffi_c/Call.h +1 -1
  10. data/ext/ffi_c/DataConverter.c +62 -0
  11. data/ext/ffi_c/DynamicLibrary.c +21 -1
  12. data/ext/ffi_c/Function.c +315 -30
  13. data/ext/ffi_c/MappedType.c +146 -0
  14. data/ext/ffi_c/MappedType.h +57 -0
  15. data/ext/ffi_c/MemoryPointer.c +12 -33
  16. data/ext/ffi_c/Platform.c +2 -0
  17. data/ext/ffi_c/Pointer.c +66 -28
  18. data/ext/ffi_c/Struct.c +19 -306
  19. data/ext/ffi_c/Struct.h +6 -0
  20. data/ext/ffi_c/StructByReference.c +150 -0
  21. data/ext/ffi_c/StructByReference.h +50 -0
  22. data/ext/ffi_c/StructLayout.c +25 -14
  23. data/ext/ffi_c/Type.c +39 -68
  24. data/ext/ffi_c/Type.h +12 -22
  25. data/ext/ffi_c/Types.c +20 -5
  26. data/ext/ffi_c/Types.h +7 -7
  27. data/ext/ffi_c/Variadic.c +21 -17
  28. data/ext/ffi_c/extconf.rb +4 -0
  29. data/ext/ffi_c/ffi.c +8 -2
  30. data/ext/ffi_c/rbffi.h +1 -0
  31. data/lib/ffi/autopointer.rb +23 -22
  32. data/lib/ffi/enum.rb +36 -21
  33. data/lib/ffi/errno.rb +20 -0
  34. data/lib/ffi/ffi.rb +13 -80
  35. data/lib/ffi/io.rb +12 -20
  36. data/lib/ffi/library.rb +109 -92
  37. data/lib/ffi/managedstruct.rb +1 -1
  38. data/lib/ffi/memorypointer.rb +15 -21
  39. data/lib/ffi/platform.rb +24 -28
  40. data/lib/ffi/pointer.rb +14 -21
  41. data/lib/ffi/struct.rb +98 -49
  42. data/lib/ffi/struct_layout_builder.rb +158 -0
  43. data/lib/ffi/types.rb +99 -128
  44. data/lib/ffi/union.rb +20 -0
  45. data/lib/ffi/variadic.rb +33 -22
  46. data/lib/ffi_c.so +0 -0
  47. data/spec/ffi/async_callback_spec.rb +23 -0
  48. data/spec/ffi/callback_spec.rb +62 -0
  49. data/spec/ffi/custom_param_type.rb +31 -0
  50. data/spec/ffi/custom_type_spec.rb +73 -0
  51. data/spec/ffi/enum_spec.rb +19 -0
  52. data/spec/ffi/ffi_spec.rb +24 -0
  53. data/spec/ffi/pointer_spec.rb +15 -0
  54. data/spec/ffi/rbx/memory_pointer_spec.rb +7 -1
  55. data/spec/ffi/strptr_spec.rb +36 -0
  56. data/spec/ffi/struct_packed_spec.rb +46 -0
  57. data/spec/ffi/struct_spec.rb +19 -5
  58. data/spec/ffi/typedef_spec.rb +14 -0
  59. data/tasks/setup.rb +2 -1
  60. metadata +15 -6
  61. data/ext/ffi_c/AutoPointer.c +0 -60
  62. data/ext/ffi_c/AutoPointer.h +0 -18
  63. data/lib/1.8/ffi_c.so +0 -0
  64. data/lib/1.9/ffi_c.so +0 -0
@@ -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, NativeType* paramTypes,
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
+
@@ -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.access = MEM_RD | MEM_WR;
179
+ sym->memory.flags = MEM_RD | MEM_WR;
160
180
  sym->library = library;
161
181
  sym->name = name;
162
182
 
@@ -1,28 +1,21 @@
1
1
  /*
2
2
  * Copyright (c) 2009, Wayne Meissner
3
+
3
4
  * All rights reserved.
4
5
  *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
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
- * * Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- * * Redistributions in binary form must reproduce the above copyright notice
11
- * this list of conditions and the following disclaimer in the documentation
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
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
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
- static ID id_call = 0, id_cbtable = 0, id_cb_ref = 0;
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.access = MEM_RD;
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. Expected pointer or proc");
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
- Closure* closure = (Closure *) user_data;
324
- Function* fn = (Function *) closure->info;
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
- switch (cbInfo->parameterTypes[i]->nativeType) {
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
- param = rbffi_NativeValue_ToRuby(cbInfo->parameterTypes[i],
383
- rb_ary_entry(cbInfo->rbParameterTypes, i), parameters[i], Qnil);
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, cbInfo->ffiReturnType->size);
394
- } else switch (cbInfo->returnType->nativeType) {
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(cbInfo->rbReturnType, rbReturnValue);
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