ffi 0.3.5 → 0.4.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.

Files changed (59) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +34 -26
  3. data/ext/ffi_c/AbstractMemory.c +73 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +19 -20
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +148 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +26 -19
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +49 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +47 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +20 -43
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/lib/ffi.rb +10 -1
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +78 -17
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/spec/ffi/bool_spec.rb +24 -0
  47. data/spec/ffi/callback_spec.rb +217 -17
  48. data/spec/ffi/enum_spec.rb +164 -0
  49. data/spec/ffi/managed_struct_spec.rb +6 -1
  50. data/spec/ffi/number_spec.rb +30 -0
  51. data/spec/ffi/pointer_spec.rb +33 -8
  52. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  53. data/spec/ffi/spec_helper.rb +5 -1
  54. data/spec/ffi/string_spec.rb +65 -4
  55. data/spec/ffi/struct_callback_spec.rb +41 -0
  56. data/spec/ffi/struct_initialize_spec.rb +30 -0
  57. data/spec/ffi/struct_spec.rb +19 -20
  58. metadata +29 -52
  59. data/ext/ffi_c/ffi.mk +0 -23
@@ -12,7 +12,7 @@ typedef struct Library {
12
12
  void* handle;
13
13
  } Library;
14
14
 
15
- extern void rb_FFI_NativeLibrary_Init(void);
15
+ extern void rbffi_DynamicLibrary_Init(VALUE ffiModule);
16
16
 
17
17
  #ifdef __cplusplus
18
18
  }
@@ -6,14 +6,14 @@
6
6
  #include <stdio.h>
7
7
  #include <stdint.h>
8
8
  #include <stdbool.h>
9
- #include <unistd.h>
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
@@ -40,13 +42,15 @@ typedef struct MethodHandle MethodHandle;
40
42
  typedef struct Invoker Invoker;
41
43
 
42
44
  struct Invoker {
43
- VALUE library;
45
+ VALUE address;
46
+ VALUE enums;
44
47
  void* function;
45
48
  ffi_cif cif;
46
49
  int paramCount;
47
50
  ffi_type** ffiParamTypes;
48
51
  NativeType* paramTypes;
49
- NativeType returnType;
52
+ Type* returnType;
53
+ VALUE rbReturnType;
50
54
  VALUE callbackArray;
51
55
  int callbackCount;
52
56
  VALUE* callbackParameters;
@@ -76,16 +80,13 @@ struct MethodHandlePool {
76
80
  MethodHandle* list;
77
81
  };
78
82
  #endif /* _WIN32 */
79
- typedef struct ThreadData {
80
- int td_errno;
81
- } ThreadData;
83
+
82
84
  static VALUE invoker_allocate(VALUE klass);
83
- static VALUE invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
84
- VALUE returnType, VALUE convention);
85
+ static VALUE invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
86
+ VALUE rbReturnType, VALUE returnType, VALUE convention, VALUE enums);
85
87
  static void invoker_mark(Invoker *);
86
88
  static void invoker_free(Invoker *);
87
89
  static VALUE invoker_call(int argc, VALUE* argv, VALUE self);
88
- static VALUE invoker_call0(VALUE self);
89
90
  static VALUE invoker_arity(VALUE self);
90
91
  static void* callback_param(VALUE proc, VALUE cbinfo);
91
92
  #ifdef USE_RAW
@@ -100,19 +101,15 @@ static void attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameter
100
101
  static MethodHandle* method_handle_alloc(int arity);
101
102
  static void method_handle_free(MethodHandle *);
102
103
 
103
- static inline ThreadData* thread_data_get(void);
104
104
 
105
105
  #ifndef _WIN32
106
106
  static int PageSize;
107
107
  #endif
108
- static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
109
- static ID to_ptr;
110
108
 
111
- #if defined(USE_PTHREAD_LOCAL)
112
- static pthread_key_t threadDataKey;
113
- #endif
114
-
115
- #define threadData (thread_data_get())
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;
116
113
 
117
114
  #ifdef USE_RAW
118
115
  # ifndef __i386__
@@ -146,12 +143,19 @@ static VALUE
146
143
  invoker_allocate(VALUE klass)
147
144
  {
148
145
  Invoker *invoker;
149
- return Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
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;
150
154
  }
151
155
 
152
156
  static VALUE
153
- invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
154
- VALUE returnType, VALUE convention)
157
+ invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
158
+ VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
155
159
  {
156
160
  Invoker* invoker = NULL;
157
161
  ffi_type* ffiReturnType;
@@ -160,39 +164,45 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
160
164
  int i;
161
165
 
162
166
  Check_Type(parameterTypes, T_ARRAY);
163
- Check_Type(returnType, T_FIXNUM);
167
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
164
168
  Check_Type(convention, T_STRING);
165
- Check_Type(library, T_DATA);
166
169
  Check_Type(function, T_DATA);
167
170
 
168
171
  Data_Get_Struct(self, Invoker, invoker);
169
- invoker->library = library;
170
- invoker->function = rb_FFI_AbstractMemory_cast(function, rb_FFI_Pointer_class)->address;
172
+ invoker->enums = enums;
173
+ invoker->address = function;
174
+ invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
171
175
  invoker->paramCount = RARRAY_LEN(parameterTypes);
172
176
  invoker->paramTypes = ALLOC_N(NativeType, invoker->paramCount);
173
177
  invoker->ffiParamTypes = ALLOC_N(ffi_type *, invoker->paramCount);
174
178
 
175
179
  for (i = 0; i < invoker->paramCount; ++i) {
176
180
  VALUE entry = rb_ary_entry(parameterTypes, i);
177
- if (rb_obj_is_kind_of(entry, rb_FFI_CallbackInfo_class)) {
181
+ if (rb_obj_is_kind_of(entry, rbffi_CallbackInfoClass)) {
178
182
  invoker->callbackParameters = REALLOC_N(invoker->callbackParameters, VALUE,
179
183
  invoker->callbackCount + 1);
180
184
  invoker->callbackParameters[invoker->callbackCount++] = entry;
181
185
  invoker->paramTypes[i] = NATIVE_CALLBACK;
182
186
  invoker->ffiParamTypes[i] = &ffi_type_pointer;
183
- } else {
184
- int paramType = FIX2INT(entry);
187
+ } else if (rb_obj_is_kind_of(entry, rbffi_TypeClass)){
188
+ int paramType = rbffi_Type_GetIntValue(entry);
185
189
  invoker->paramTypes[i] = paramType;
186
- invoker->ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
190
+ invoker->ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
187
191
  }
188
192
  if (invoker->ffiParamTypes[i] == NULL) {
189
- rb_raise(rb_eArgError, "Invalid parameter type");
193
+ rb_raise(rb_eTypeError, "Invalid parameter type");
190
194
  }
191
195
  }
192
- invoker->returnType = FIX2INT(returnType);
193
- ffiReturnType = rb_FFI_NativeTypeToFFI(invoker->returnType);
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;
194
204
  if (ffiReturnType == NULL) {
195
- rb_raise(rb_eArgError, "Invalid return type");
205
+ rb_raise(rb_eTypeError, "Invalid return type");
196
206
  }
197
207
  #if defined(_WIN32) || defined(__WIN32__)
198
208
  abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
@@ -217,25 +227,31 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
217
227
  }
218
228
 
219
229
  static VALUE
220
- variadic_invoker_new(VALUE klass, VALUE library, VALUE function, VALUE returnType, VALUE convention)
230
+ variadic_invoker_new(VALUE klass, VALUE function, VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
221
231
  {
222
232
  Invoker* invoker = NULL;
223
233
  VALUE retval = Qnil;
224
234
 
225
- Check_Type(returnType, T_FIXNUM);
235
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
226
236
  Check_Type(convention, T_STRING);
227
- Check_Type(library, T_DATA);
228
237
  Check_Type(function, T_DATA);
229
238
 
230
239
  retval = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
231
- invoker->library = library;
232
- invoker->function = rb_FFI_AbstractMemory_cast(function, rb_FFI_Pointer_class)->address;
240
+ invoker->enums = enums;
241
+ invoker->address = function;
242
+ invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
233
243
  #if defined(_WIN32) || defined(__WIN32__)
234
244
  invoker->abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
235
245
  #else
236
246
  invoker->abi = FFI_DEFAULT_ABI;
237
247
  #endif
238
- invoker->returnType = FIX2INT(returnType);
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);
239
255
  invoker->paramCount = -1;
240
256
  return retval;
241
257
  }
@@ -424,7 +440,7 @@ method_handle_free(MethodHandle* method)
424
440
  #endif /* _WIN32 */
425
441
 
426
442
  typedef union {
427
- #if BYTE_ORDER == LITTLE_ENDIAN
443
+ #ifdef USE_RAW
428
444
  signed int s8, s16, s32;
429
445
  unsigned int u8, u16, u32;
430
446
  #else
@@ -443,10 +459,16 @@ typedef union {
443
459
  } FFIStorage;
444
460
 
445
461
  static inline int
446
- 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)
447
463
  {
448
464
  int i;
449
- if (type != T_FIXNUM && type != T_BIGNUM) {
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) {
450
472
  rb_raise(rb_eTypeError, "Expected an Integer parameter");
451
473
  }
452
474
  i = NUM2INT(value);
@@ -504,18 +526,25 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
504
526
  for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
505
527
  int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
506
528
  ffiValues[i] = param;
507
-
508
529
  switch (paramTypes[i]) {
509
530
  case NATIVE_INT8:
510
- param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char");
531
+ param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
511
532
  ADJ(param, INT8);
512
533
  break;
513
534
  case NATIVE_INT16:
514
- param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short");
535
+ param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
515
536
  ADJ(param, INT16);
516
537
  break;
517
538
  case NATIVE_INT32:
518
- param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int");
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;
519
548
  ADJ(param, INT32);
520
549
  break;
521
550
  case NATIVE_UINT8:
@@ -581,9 +610,9 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
581
610
  case NATIVE_BUFFER_IN:
582
611
  case NATIVE_BUFFER_OUT:
583
612
  case NATIVE_BUFFER_INOUT:
584
- if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rb_FFI_AbstractMemory_class)) {
613
+ if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_AbstractMemoryClass)) {
585
614
  param->ptr = ((AbstractMemory *) DATA_PTR(argv[argidx]))->address;
586
- } else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rb_FFI_Struct_class)) {
615
+ } else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_StructClass)) {
587
616
  AbstractMemory* memory = ((Struct *) DATA_PTR(argv[argidx]))->pointer;
588
617
  param->ptr = memory != NULL ? memory->address : NULL;
589
618
  } else if (type == T_STRING) {
@@ -595,7 +624,7 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
595
624
  param->ptr = NULL;
596
625
  } else if (rb_respond_to(argv[argidx], to_ptr)) {
597
626
  VALUE ptr = rb_funcall2(argv[argidx], to_ptr, 0, NULL);
598
- if (rb_obj_is_kind_of(ptr, rb_FFI_AbstractMemory_class) && TYPE(ptr) == T_DATA) {
627
+ if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) {
599
628
  param->ptr = ((AbstractMemory *) DATA_PTR(ptr))->address;
600
629
  } else {
601
630
  rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
@@ -622,81 +651,48 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
622
651
  }
623
652
  }
624
653
  static inline VALUE
625
- ffi_invoke(ffi_cif* cif, void* function, NativeType returnType, void** ffiValues)
654
+ ffi_invoke(ffi_cif* cif, Invoker* invoker, void** ffiValues)
626
655
  {
627
656
  FFIStorage retval;
628
- int error = 0;
629
657
 
630
658
  #ifdef USE_RAW
631
- ffi_raw_call(cif, FFI_FN(function), &retval, (ffi_raw *) ffiValues[0]);
659
+ ffi_raw_call(cif, FFI_FN(invoker->function), &retval, (ffi_raw *) ffiValues[0]);
632
660
  #else
633
- ffi_call(cif, FFI_FN(function), &retval, ffiValues);
661
+ ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
634
662
  #endif
635
- #if defined(_WIN32) || defined(__WIN32__)
636
- error = GetLastError();
637
- #else
638
- error = errno;
639
- #endif
640
- threadData->td_errno = error;
663
+ rbffi_save_errno();
641
664
 
642
- return rb_FFI_NativeValueToRuby(returnType, &retval);
665
+ return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
666
+ invoker->enums);
643
667
  }
668
+
644
669
  static VALUE
645
670
  invoker_call(int argc, VALUE* argv, VALUE self)
646
671
  {
647
672
  Invoker* invoker;
648
- FFIStorage params[MAX_PARAMETERS];
649
- void* ffiValues[MAX_PARAMETERS];
673
+ int argCount;
674
+ FFIStorage params_[MAX_FIXED_ARITY], *params = &params_[0];
675
+ void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
650
676
 
651
677
  Data_Get_Struct(self, Invoker, invoker);
652
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
653
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
654
- }
655
678
 
656
- static inline VALUE
657
- invoker_callN(VALUE self, int argc, VALUE* argv)
658
- {
659
- Invoker* invoker;
660
- FFIStorage params[3];
661
- void* ffiValues[3];
662
-
663
- Data_Get_Struct(self, Invoker, invoker);
664
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
665
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
666
- }
667
-
668
- static VALUE
669
- invoker_call0(VALUE self)
670
- {
671
- Invoker* invoker;
672
- FFIStorage arg0;
673
- void* ffiValues[] = { &arg0 };
674
-
675
- Data_Get_Struct(self, Invoker, invoker);
676
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
677
- }
679
+ argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
678
680
 
679
- static VALUE
680
- invoker_call1(VALUE self, VALUE arg1)
681
- {
682
- return invoker_callN(self, 1, &arg1);
683
- }
681
+ if (argCount > MAX_FIXED_ARITY) {
682
+ params = ALLOCA_N(FFIStorage, argCount);
683
+ ffiValues = ALLOCA_N(void *, argCount);
684
+ }
684
685
 
685
- static VALUE
686
- invoker_call2(VALUE self, VALUE arg1, VALUE arg2)
687
- {
688
- VALUE argv[] = { arg1, arg2 };
689
- return invoker_callN(self, 2, argv);
690
- }
686
+ ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
691
687
 
692
- static VALUE
693
- invoker_call3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
694
- {
695
- VALUE argv[] = { arg1, arg2, arg3 };
696
- return invoker_callN(self, 3, argv);
688
+ return ffi_invoke(&invoker->cif, invoker, ffiValues);
697
689
  }
698
690
 
699
691
  #ifdef USE_RAW
692
+
693
+ /*
694
+ * attached_method_invoke is used as the <= 3 argument fixed-arity fast path
695
+ */
700
696
  static void
701
697
  attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
702
698
  {
@@ -709,9 +705,12 @@ attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* us
709
705
  ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)&parameters[1],
710
706
  invoker->paramTypes, params, ffiValues);
711
707
  }
712
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
708
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
713
709
  }
714
710
 
711
+ /*
712
+ * attached_method_vinvoke is used functions with more than 3 parameters
713
+ */
715
714
  static void
716
715
  attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
717
716
  {
@@ -723,7 +722,7 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* u
723
722
  VALUE* argv = *(VALUE **) &parameters[1];
724
723
 
725
724
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
726
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
725
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
727
726
  }
728
727
 
729
728
  #else
@@ -744,7 +743,7 @@ attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
744
743
  if (invoker->paramCount > 0) {
745
744
  ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
746
745
  }
747
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
746
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
748
747
  }
749
748
  #endif /* _WIN32 */
750
749
  static void
@@ -758,21 +757,29 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* use
758
757
  VALUE* argv = *(VALUE **) parameters[1];
759
758
 
760
759
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
761
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
760
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
762
761
  }
763
762
  #endif
763
+
764
764
  static VALUE
765
765
  invoker_attach(VALUE self, VALUE module, VALUE name)
766
766
  {
767
767
  Invoker* invoker;
768
768
  MethodHandle* handle;
769
769
  char var[1024];
770
+
770
771
  Data_Get_Struct(self, Invoker, invoker);
772
+ if (invoker->paramCount == -1) {
773
+ rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
774
+ }
775
+
771
776
  handle = invoker->methodHandle;
772
- rb_define_module_function(module, StringValuePtr(name),
777
+ rb_define_module_function(module, StringValueCStr(name),
773
778
  handle->code, handle->arity);
774
779
  snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
775
780
  rb_cv_set(module, var, self);
781
+ rb_define_method(module, StringValueCStr(name),
782
+ handle->code, handle->arity);
776
783
  return self;
777
784
  }
778
785
  static VALUE
@@ -789,8 +796,14 @@ invoker_mark(Invoker *invoker)
789
796
  if (invoker->callbackCount > 0) {
790
797
  rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
791
798
  }
792
- if (invoker->library != Qnil) {
793
- rb_gc_mark(invoker->library);
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);
794
807
  }
795
808
  }
796
809
 
@@ -844,11 +857,12 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
844
857
 
845
858
  for (i = 0; i < paramCount; ++i) {
846
859
  VALUE entry = rb_ary_entry(parameterTypes, i);
847
- int paramType = FIX2INT(entry);
860
+ int paramType = rbffi_Type_GetIntValue(entry);
848
861
  switch (paramType) {
849
862
  case NATIVE_INT8:
850
863
  case NATIVE_INT16:
851
864
  case NATIVE_INT32:
865
+ case NATIVE_ENUM:
852
866
  paramType = NATIVE_INT32;
853
867
  break;
854
868
  case NATIVE_UINT8:
@@ -861,14 +875,14 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
861
875
  break;
862
876
  }
863
877
  paramTypes[i] = paramType;
864
- ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
878
+ ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
865
879
  if (ffiParamTypes[i] == NULL) {
866
880
  rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
867
881
  }
868
882
  argv[i] = rb_ary_entry(parameterValues, i);
869
883
  }
870
884
 
871
- ffiReturnType = rb_FFI_NativeTypeToFFI(invoker->returnType);
885
+ ffiReturnType = invoker->returnType->ffiType;
872
886
  if (ffiReturnType == NULL) {
873
887
  rb_raise(rb_eArgError, "Invalid return type");
874
888
  }
@@ -884,7 +898,7 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
884
898
  rb_raise(rb_eArgError, "Unknown FFI error");
885
899
  }
886
900
  ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
887
- return ffi_invoke(&cif, invoker->function, invoker->returnType, ffiValues);
901
+ return ffi_invoke(&cif, invoker, ffiValues);
888
902
  }
889
903
 
890
904
  static void*
@@ -894,94 +908,39 @@ callback_param(VALUE proc, VALUE cbInfo)
894
908
  if (proc == Qnil) {
895
909
  return NULL ;
896
910
  }
897
- callback = rb_FFI_NativeCallback_for_proc(proc, cbInfo);
911
+ callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
898
912
  return ((NativeCallback *) DATA_PTR(callback))->code;
899
913
  }
900
914
 
901
- #if defined(USE_PTHREAD_LOCAL)
902
- static ThreadData*
903
- thread_data_init()
904
- {
905
- ThreadData* td = ALLOC_N(ThreadData, 1);
906
- memset(td, 0, sizeof(*td));
907
- pthread_setspecific(threadDataKey, td);
908
- return td;
909
- }
910
-
911
- static inline ThreadData*
912
- thread_data_get()
913
- {
914
- ThreadData* td = pthread_getspecific(threadDataKey);
915
- return td != NULL ? td : thread_data_init();
916
- }
917
-
918
- static void
919
- thread_data_free(void *ptr)
920
- {
921
- xfree(ptr);
922
- }
923
-
924
- #else
925
- static ID thread_data_id;
926
-
927
- static ThreadData*
928
- thread_data_init()
929
- {
930
- ThreadData* td;
931
- VALUE obj;
932
- obj = Data_Make_Struct(rb_cObject, ThreadData, NULL, -1, td);
933
- rb_thread_local_aset(rb_thread_current(), thread_data_id, obj);
934
- return td;
935
- }
936
-
937
- static inline ThreadData*
938
- thread_data_get()
939
- {
940
- VALUE obj = rb_thread_local_aref(rb_thread_current(), thread_data_id);
941
-
942
- if (obj != Qnil && TYPE(obj) == T_DATA) {
943
- return (ThreadData *) DATA_PTR(obj);
944
- }
945
- return thread_data_init();
946
- }
947
-
948
- #endif
949
- static VALUE
950
- get_last_error(VALUE self)
951
- {
952
- return INT2NUM(threadData->td_errno);
953
- }
954
- static VALUE
955
- set_last_error(VALUE self, VALUE error)
956
- {
957
- return Qnil;
958
- }
959
-
960
915
  void
961
- rb_FFI_Invoker_Init()
916
+ rbffi_Invoker_Init(VALUE moduleFFI)
962
917
  {
963
918
  ffi_type* ffiValueType;
964
919
  int i;
965
- VALUE moduleFFI = rb_define_module("FFI");
966
- VALUE moduleError = rb_define_module_under(moduleFFI, "LastError");
967
- classInvoker = rb_define_class_under(moduleFFI, "Invoker", rb_cObject);
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
+
968
925
  rb_define_alloc_func(classInvoker, invoker_allocate);
969
- rb_define_method(classInvoker, "initialize", invoker_initialize, 5);
926
+ rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
970
927
  rb_define_method(classInvoker, "call", invoker_call, -1);
971
- rb_define_method(classInvoker, "call0", invoker_call0, 0);
972
- rb_define_method(classInvoker, "call1", invoker_call1, 1);
973
- rb_define_method(classInvoker, "call2", invoker_call2, 2);
974
- rb_define_method(classInvoker, "call3", invoker_call3, 3);
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");
975
932
  rb_define_method(classInvoker, "arity", invoker_arity, 0);
976
933
  rb_define_method(classInvoker, "attach", invoker_attach, 2);
977
934
  classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
978
- rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 4);
935
+ rb_global_variable(&classVariadicInvoker);
936
+
937
+ rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 5);
979
938
  rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
939
+ rb_define_alias(classVariadicInvoker, "call", "invoke");
940
+
980
941
  to_ptr = rb_intern("to_ptr");
942
+ map_symbol_id = rb_intern("__map_symbol");
981
943
 
982
- rb_define_module_function(moduleError, "error", get_last_error, 0);
983
- rb_define_module_function(moduleError, "error=", set_last_error, 1);
984
-
985
944
  ffiValueType = (sizeof (VALUE) == sizeof (long))
986
945
  ? &ffi_type_ulong : &ffi_type_uint64;
987
946
  for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
@@ -994,13 +953,10 @@ rb_FFI_Invoker_Init()
994
953
  #endif /* _WIN32 */
995
954
 
996
955
  #if defined(USE_PTHREAD_LOCAL)
997
- pthread_key_create(&threadDataKey, thread_data_free);
998
956
  for (i = 0; i < 4; ++i) {
999
957
  pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
1000
958
  }
1001
959
  pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
1002
- #else
1003
- thread_data_id = rb_intern("ffi_thread_local_data");
1004
960
  #endif /* USE_PTHREAD_LOCAL */
1005
961
 
1006
962
  }