ffi 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +47 -28
  3. data/ext/ffi_c/AbstractMemory.c +149 -65
  4. data/ext/ffi_c/AbstractMemory.h +34 -4
  5. data/ext/ffi_c/AutoPointer.c +15 -18
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +79 -44
  8. data/ext/ffi_c/Callback.c +133 -62
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +88 -24
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +154 -190
  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 +30 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +67 -28
  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 +67 -30
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +202 -267
  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 +48 -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 +21 -44
  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/gen/Rakefile +12 -0
  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 +79 -18
  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/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. data/samples/sample_helper.rb +0 -6
data/ext/ffi_c/Invoker.c CHANGED
@@ -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
@@ -32,17 +34,23 @@
32
34
  #endif
33
35
  #define MAX_FIXED_ARITY (3)
34
36
 
37
+ #ifndef roundup
38
+ # define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
39
+ #endif
40
+
35
41
  typedef struct MethodHandle MethodHandle;
36
42
  typedef struct Invoker Invoker;
37
43
 
38
44
  struct Invoker {
39
- VALUE library;
45
+ VALUE address;
46
+ VALUE enums;
40
47
  void* function;
41
48
  ffi_cif cif;
42
49
  int paramCount;
43
50
  ffi_type** ffiParamTypes;
44
51
  NativeType* paramTypes;
45
- NativeType returnType;
52
+ Type* returnType;
53
+ VALUE rbReturnType;
46
54
  VALUE callbackArray;
47
55
  int callbackCount;
48
56
  VALUE* callbackParameters;
@@ -72,16 +80,13 @@ struct MethodHandlePool {
72
80
  MethodHandle* list;
73
81
  };
74
82
  #endif /* _WIN32 */
75
- typedef struct ThreadData {
76
- int td_errno;
77
- } ThreadData;
83
+
78
84
  static VALUE invoker_allocate(VALUE klass);
79
- static VALUE invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
80
- VALUE returnType, VALUE convention);
85
+ static VALUE invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
86
+ VALUE rbReturnType, VALUE returnType, VALUE convention, VALUE enums);
81
87
  static void invoker_mark(Invoker *);
82
88
  static void invoker_free(Invoker *);
83
89
  static VALUE invoker_call(int argc, VALUE* argv, VALUE self);
84
- static VALUE invoker_call0(VALUE self);
85
90
  static VALUE invoker_arity(VALUE self);
86
91
  static void* callback_param(VALUE proc, VALUE cbinfo);
87
92
  #ifdef USE_RAW
@@ -96,19 +101,15 @@ static void attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameter
96
101
  static MethodHandle* method_handle_alloc(int arity);
97
102
  static void method_handle_free(MethodHandle *);
98
103
 
99
- static inline ThreadData* thread_data_get(void);
100
104
 
101
105
  #ifndef _WIN32
102
106
  static int PageSize;
103
107
  #endif
104
- static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
105
- static ID to_ptr;
106
-
107
- #if defined(USE_PTHREAD_LOCAL)
108
- static pthread_key_t threadDataKey;
109
- #endif
110
108
 
111
- #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;
112
113
 
113
114
  #ifdef USE_RAW
114
115
  # ifndef __i386__
@@ -142,12 +143,19 @@ static VALUE
142
143
  invoker_allocate(VALUE klass)
143
144
  {
144
145
  Invoker *invoker;
145
- 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;
146
154
  }
147
155
 
148
156
  static VALUE
149
- invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
150
- VALUE returnType, VALUE convention)
157
+ invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
158
+ VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
151
159
  {
152
160
  Invoker* invoker = NULL;
153
161
  ffi_type* ffiReturnType;
@@ -156,39 +164,45 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
156
164
  int i;
157
165
 
158
166
  Check_Type(parameterTypes, T_ARRAY);
159
- Check_Type(returnType, T_FIXNUM);
167
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
160
168
  Check_Type(convention, T_STRING);
161
- Check_Type(library, T_DATA);
162
169
  Check_Type(function, T_DATA);
163
170
 
164
171
  Data_Get_Struct(self, Invoker, invoker);
165
- invoker->library = library;
166
- 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;
167
175
  invoker->paramCount = RARRAY_LEN(parameterTypes);
168
176
  invoker->paramTypes = ALLOC_N(NativeType, invoker->paramCount);
169
177
  invoker->ffiParamTypes = ALLOC_N(ffi_type *, invoker->paramCount);
170
178
 
171
179
  for (i = 0; i < invoker->paramCount; ++i) {
172
180
  VALUE entry = rb_ary_entry(parameterTypes, i);
173
- if (rb_obj_is_kind_of(entry, rb_FFI_CallbackInfo_class)) {
181
+ if (rb_obj_is_kind_of(entry, rbffi_CallbackInfoClass)) {
174
182
  invoker->callbackParameters = REALLOC_N(invoker->callbackParameters, VALUE,
175
183
  invoker->callbackCount + 1);
176
184
  invoker->callbackParameters[invoker->callbackCount++] = entry;
177
185
  invoker->paramTypes[i] = NATIVE_CALLBACK;
178
186
  invoker->ffiParamTypes[i] = &ffi_type_pointer;
179
- } else {
180
- int paramType = FIX2INT(entry);
187
+ } else if (rb_obj_is_kind_of(entry, rbffi_TypeClass)){
188
+ int paramType = rbffi_Type_GetIntValue(entry);
181
189
  invoker->paramTypes[i] = paramType;
182
- invoker->ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
190
+ invoker->ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
183
191
  }
184
192
  if (invoker->ffiParamTypes[i] == NULL) {
185
- rb_raise(rb_eArgError, "Invalid parameter type");
193
+ rb_raise(rb_eTypeError, "Invalid parameter type");
186
194
  }
187
195
  }
188
- invoker->returnType = FIX2INT(returnType);
189
- 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;
190
204
  if (ffiReturnType == NULL) {
191
- rb_raise(rb_eArgError, "Invalid return type");
205
+ rb_raise(rb_eTypeError, "Invalid return type");
192
206
  }
193
207
  #if defined(_WIN32) || defined(__WIN32__)
194
208
  abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
@@ -213,25 +227,31 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
213
227
  }
214
228
 
215
229
  static VALUE
216
- 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)
217
231
  {
218
232
  Invoker* invoker = NULL;
219
233
  VALUE retval = Qnil;
220
234
 
221
- Check_Type(returnType, T_FIXNUM);
235
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
222
236
  Check_Type(convention, T_STRING);
223
- Check_Type(library, T_DATA);
224
237
  Check_Type(function, T_DATA);
225
238
 
226
239
  retval = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
227
- invoker->library = library;
228
- 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;
229
243
  #if defined(_WIN32) || defined(__WIN32__)
230
244
  invoker->abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
231
245
  #else
232
246
  invoker->abi = FFI_DEFAULT_ABI;
233
247
  #endif
234
- 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);
235
255
  invoker->paramCount = -1;
236
256
  return retval;
237
257
  }
@@ -420,7 +440,7 @@ method_handle_free(MethodHandle* method)
420
440
  #endif /* _WIN32 */
421
441
 
422
442
  typedef union {
423
- #if BYTE_ORDER == LITTLE_ENDIAN
443
+ #ifdef USE_RAW
424
444
  signed int s8, s16, s32;
425
445
  unsigned int u8, u16, u32;
426
446
  #else
@@ -439,10 +459,16 @@ typedef union {
439
459
  } FFIStorage;
440
460
 
441
461
  static inline int
442
- 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)
443
463
  {
444
464
  int i;
445
- 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) {
446
472
  rb_raise(rb_eTypeError, "Expected an Integer parameter");
447
473
  }
448
474
  i = NUM2INT(value);
@@ -500,18 +526,25 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
500
526
  for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
501
527
  int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
502
528
  ffiValues[i] = param;
503
-
504
529
  switch (paramTypes[i]) {
505
530
  case NATIVE_INT8:
506
- param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char");
531
+ param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
507
532
  ADJ(param, INT8);
508
533
  break;
509
534
  case NATIVE_INT16:
510
- param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short");
535
+ param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
511
536
  ADJ(param, INT16);
512
537
  break;
513
538
  case NATIVE_INT32:
514
- 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;
515
548
  ADJ(param, INT32);
516
549
  break;
517
550
  case NATIVE_UINT8:
@@ -577,9 +610,9 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
577
610
  case NATIVE_BUFFER_IN:
578
611
  case NATIVE_BUFFER_OUT:
579
612
  case NATIVE_BUFFER_INOUT:
580
- 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)) {
581
614
  param->ptr = ((AbstractMemory *) DATA_PTR(argv[argidx]))->address;
582
- } 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)) {
583
616
  AbstractMemory* memory = ((Struct *) DATA_PTR(argv[argidx]))->pointer;
584
617
  param->ptr = memory != NULL ? memory->address : NULL;
585
618
  } else if (type == T_STRING) {
@@ -591,7 +624,7 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
591
624
  param->ptr = NULL;
592
625
  } else if (rb_respond_to(argv[argidx], to_ptr)) {
593
626
  VALUE ptr = rb_funcall2(argv[argidx], to_ptr, 0, NULL);
594
- 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) {
595
628
  param->ptr = ((AbstractMemory *) DATA_PTR(ptr))->address;
596
629
  } else {
597
630
  rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
@@ -618,77 +651,48 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
618
651
  }
619
652
  }
620
653
  static inline VALUE
621
- ffi_invoke(ffi_cif* cif, void* function, NativeType returnType, void** ffiValues)
654
+ ffi_invoke(ffi_cif* cif, Invoker* invoker, void** ffiValues)
622
655
  {
623
656
  FFIStorage retval;
657
+
624
658
  #ifdef USE_RAW
625
- 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]);
626
660
  #else
627
- ffi_call(cif, FFI_FN(function), &retval, ffiValues);
661
+ ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
628
662
  #endif
629
- #if defined(_WIN32) || defined(__WIN32__)
630
- threadData->td_errno = GetLastError();
631
- #else
632
- threadData->td_errno = errno;
633
- #endif
634
- return rb_FFI_NativeValueToRuby(returnType, &retval);
635
- }
636
- static VALUE
637
- invoker_call(int argc, VALUE* argv, VALUE self)
638
- {
639
- Invoker* invoker;
640
- FFIStorage params[MAX_PARAMETERS];
641
- void* ffiValues[MAX_PARAMETERS];
663
+ rbffi_save_errno();
642
664
 
643
- Data_Get_Struct(self, Invoker, invoker);
644
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
645
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
665
+ return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
666
+ invoker->enums);
646
667
  }
647
668
 
648
- static inline VALUE
649
- invoker_callN(VALUE self, int argc, VALUE* argv)
669
+ static VALUE
670
+ invoker_call(int argc, VALUE* argv, VALUE self)
650
671
  {
651
672
  Invoker* invoker;
652
- FFIStorage params[3];
653
- void* ffiValues[3];
673
+ int argCount;
674
+ FFIStorage params_[MAX_FIXED_ARITY], *params = &params_[0];
675
+ void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
654
676
 
655
677
  Data_Get_Struct(self, Invoker, invoker);
656
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
657
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
658
- }
659
678
 
660
- static VALUE
661
- invoker_call0(VALUE self)
662
- {
663
- Invoker* invoker;
664
- FFIStorage arg0;
665
- void* ffiValues[] = { &arg0 };
666
-
667
- Data_Get_Struct(self, Invoker, invoker);
668
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
669
- }
679
+ argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
670
680
 
671
- static VALUE
672
- invoker_call1(VALUE self, VALUE arg1)
673
- {
674
- return invoker_callN(self, 1, &arg1);
675
- }
681
+ if (argCount > MAX_FIXED_ARITY) {
682
+ params = ALLOCA_N(FFIStorage, argCount);
683
+ ffiValues = ALLOCA_N(void *, argCount);
684
+ }
676
685
 
677
- static VALUE
678
- invoker_call2(VALUE self, VALUE arg1, VALUE arg2)
679
- {
680
- VALUE argv[] = { arg1, arg2 };
681
- return invoker_callN(self, 2, argv);
682
- }
686
+ ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
683
687
 
684
- static VALUE
685
- invoker_call3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
686
- {
687
- VALUE argv[] = { arg1, arg2, arg3 };
688
- return invoker_callN(self, 3, argv);
688
+ return ffi_invoke(&invoker->cif, invoker, ffiValues);
689
689
  }
690
690
 
691
691
  #ifdef USE_RAW
692
+
693
+ /*
694
+ * attached_method_invoke is used as the <= 3 argument fixed-arity fast path
695
+ */
692
696
  static void
693
697
  attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
694
698
  {
@@ -701,9 +705,12 @@ attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* us
701
705
  ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)&parameters[1],
702
706
  invoker->paramTypes, params, ffiValues);
703
707
  }
704
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
708
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
705
709
  }
706
710
 
711
+ /*
712
+ * attached_method_vinvoke is used functions with more than 3 parameters
713
+ */
707
714
  static void
708
715
  attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
709
716
  {
@@ -715,7 +722,7 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* u
715
722
  VALUE* argv = *(VALUE **) &parameters[1];
716
723
 
717
724
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
718
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
725
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
719
726
  }
720
727
 
721
728
  #else
@@ -736,7 +743,7 @@ attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
736
743
  if (invoker->paramCount > 0) {
737
744
  ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
738
745
  }
739
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
746
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
740
747
  }
741
748
  #endif /* _WIN32 */
742
749
  static void
@@ -750,21 +757,29 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* use
750
757
  VALUE* argv = *(VALUE **) parameters[1];
751
758
 
752
759
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
753
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
760
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
754
761
  }
755
762
  #endif
763
+
756
764
  static VALUE
757
765
  invoker_attach(VALUE self, VALUE module, VALUE name)
758
766
  {
759
767
  Invoker* invoker;
760
768
  MethodHandle* handle;
761
769
  char var[1024];
770
+
762
771
  Data_Get_Struct(self, Invoker, invoker);
772
+ if (invoker->paramCount == -1) {
773
+ rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
774
+ }
775
+
763
776
  handle = invoker->methodHandle;
764
- rb_define_module_function(module, StringValuePtr(name),
777
+ rb_define_module_function(module, StringValueCStr(name),
765
778
  handle->code, handle->arity);
766
779
  snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
767
780
  rb_cv_set(module, var, self);
781
+ rb_define_method(module, StringValueCStr(name),
782
+ handle->code, handle->arity);
768
783
  return self;
769
784
  }
770
785
  static VALUE
@@ -781,8 +796,14 @@ invoker_mark(Invoker *invoker)
781
796
  if (invoker->callbackCount > 0) {
782
797
  rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
783
798
  }
784
- if (invoker->library != Qnil) {
785
- 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);
786
807
  }
787
808
  }
788
809
 
@@ -836,11 +857,12 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
836
857
 
837
858
  for (i = 0; i < paramCount; ++i) {
838
859
  VALUE entry = rb_ary_entry(parameterTypes, i);
839
- int paramType = FIX2INT(entry);
860
+ int paramType = rbffi_Type_GetIntValue(entry);
840
861
  switch (paramType) {
841
862
  case NATIVE_INT8:
842
863
  case NATIVE_INT16:
843
864
  case NATIVE_INT32:
865
+ case NATIVE_ENUM:
844
866
  paramType = NATIVE_INT32;
845
867
  break;
846
868
  case NATIVE_UINT8:
@@ -853,14 +875,14 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
853
875
  break;
854
876
  }
855
877
  paramTypes[i] = paramType;
856
- ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
878
+ ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
857
879
  if (ffiParamTypes[i] == NULL) {
858
880
  rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
859
881
  }
860
882
  argv[i] = rb_ary_entry(parameterValues, i);
861
883
  }
862
884
 
863
- ffiReturnType = rb_FFI_NativeTypeToFFI(invoker->returnType);
885
+ ffiReturnType = invoker->returnType->ffiType;
864
886
  if (ffiReturnType == NULL) {
865
887
  rb_raise(rb_eArgError, "Invalid return type");
866
888
  }
@@ -876,7 +898,7 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
876
898
  rb_raise(rb_eArgError, "Unknown FFI error");
877
899
  }
878
900
  ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
879
- return ffi_invoke(&cif, invoker->function, invoker->returnType, ffiValues);
901
+ return ffi_invoke(&cif, invoker, ffiValues);
880
902
  }
881
903
 
882
904
  static void*
@@ -886,94 +908,39 @@ callback_param(VALUE proc, VALUE cbInfo)
886
908
  if (proc == Qnil) {
887
909
  return NULL ;
888
910
  }
889
- callback = rb_FFI_NativeCallback_for_proc(proc, cbInfo);
911
+ callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
890
912
  return ((NativeCallback *) DATA_PTR(callback))->code;
891
913
  }
892
914
 
893
- #if defined(USE_PTHREAD_LOCAL)
894
- static ThreadData*
895
- thread_data_init()
896
- {
897
- ThreadData* td = ALLOC_N(ThreadData, 1);
898
- memset(td, 0, sizeof(*td));
899
- pthread_setspecific(threadDataKey, td);
900
- return td;
901
- }
902
-
903
- static inline ThreadData*
904
- thread_data_get()
905
- {
906
- ThreadData* td = pthread_getspecific(threadDataKey);
907
- return td != NULL ? td : thread_data_init();
908
- }
909
-
910
- static void
911
- thread_data_free(void *ptr)
912
- {
913
- xfree(ptr);
914
- }
915
-
916
- #else
917
- static ID thread_data_id;
918
-
919
- static ThreadData*
920
- thread_data_init()
921
- {
922
- ThreadData* td;
923
- VALUE obj;
924
- obj = Data_Make_Struct(rb_cObject, ThreadData, NULL, -1, td);
925
- rb_thread_local_aset(rb_thread_current(), thread_data_id, obj);
926
- return td;
927
- }
928
-
929
- static inline ThreadData*
930
- thread_data_get()
931
- {
932
- VALUE obj = rb_thread_local_aref(rb_thread_current(), thread_data_id);
933
-
934
- if (obj != Qnil && TYPE(obj) == T_DATA) {
935
- return (ThreadData *) DATA_PTR(obj);
936
- }
937
- return thread_data_init();
938
- }
939
-
940
- #endif
941
- static VALUE
942
- get_last_error(VALUE self)
943
- {
944
- return INT2NUM(threadData->td_errno);
945
- }
946
- static VALUE
947
- set_last_error(VALUE self, VALUE error)
948
- {
949
- return Qnil;
950
- }
951
-
952
915
  void
953
- rb_FFI_Invoker_Init()
916
+ rbffi_Invoker_Init(VALUE moduleFFI)
954
917
  {
955
918
  ffi_type* ffiValueType;
956
919
  int i;
957
- VALUE moduleFFI = rb_define_module("FFI");
958
- VALUE moduleError = rb_define_module_under(moduleFFI, "LastError");
959
- 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
+
960
925
  rb_define_alloc_func(classInvoker, invoker_allocate);
961
- rb_define_method(classInvoker, "initialize", invoker_initialize, 5);
926
+ rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
962
927
  rb_define_method(classInvoker, "call", invoker_call, -1);
963
- rb_define_method(classInvoker, "call0", invoker_call0, 0);
964
- rb_define_method(classInvoker, "call1", invoker_call1, 1);
965
- rb_define_method(classInvoker, "call2", invoker_call2, 2);
966
- 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");
967
932
  rb_define_method(classInvoker, "arity", invoker_arity, 0);
968
933
  rb_define_method(classInvoker, "attach", invoker_attach, 2);
969
934
  classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
970
- 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);
971
938
  rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
939
+ rb_define_alias(classVariadicInvoker, "call", "invoke");
940
+
972
941
  to_ptr = rb_intern("to_ptr");
942
+ map_symbol_id = rb_intern("__map_symbol");
973
943
 
974
- rb_define_module_function(moduleError, "error", get_last_error, 0);
975
- rb_define_module_function(moduleError, "error=", set_last_error, 1);
976
-
977
944
  ffiValueType = (sizeof (VALUE) == sizeof (long))
978
945
  ? &ffi_type_ulong : &ffi_type_uint64;
979
946
  for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
@@ -986,13 +953,10 @@ rb_FFI_Invoker_Init()
986
953
  #endif /* _WIN32 */
987
954
 
988
955
  #if defined(USE_PTHREAD_LOCAL)
989
- pthread_key_create(&threadDataKey, thread_data_free);
990
956
  for (i = 0; i < 4; ++i) {
991
957
  pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
992
958
  }
993
959
  pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
994
- #else
995
- thread_data_id = rb_intern("ffi_thread_local_data");
996
960
  #endif /* USE_PTHREAD_LOCAL */
997
961
 
998
962
  }