ffi 1.0.9 → 1.0.10

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 (56) hide show
  1. data/Rakefile +4 -4
  2. data/ext/ffi_c/AbstractMemory.c +367 -14
  3. data/ext/ffi_c/AbstractMemory.h +4 -0
  4. data/ext/ffi_c/ArrayType.c +28 -0
  5. data/ext/ffi_c/Buffer.c +101 -25
  6. data/ext/ffi_c/Call.c +8 -5
  7. data/ext/ffi_c/ClosurePool.c +9 -8
  8. data/ext/ffi_c/DataConverter.c +29 -0
  9. data/ext/ffi_c/DynamicLibrary.c +64 -1
  10. data/ext/ffi_c/Function.c +111 -10
  11. data/ext/ffi_c/FunctionInfo.c +13 -1
  12. data/ext/ffi_c/LastError.c +16 -0
  13. data/ext/ffi_c/MappedType.c +22 -0
  14. data/ext/ffi_c/MemoryPointer.c +11 -1
  15. data/ext/ffi_c/MethodHandle.c +18 -11
  16. data/ext/ffi_c/Platform.c +9 -3
  17. data/ext/ffi_c/Pointer.c +98 -0
  18. data/ext/ffi_c/Struct.c +4 -4
  19. data/ext/ffi_c/Struct.h +2 -1
  20. data/ext/ffi_c/StructLayout.c +2 -2
  21. data/ext/ffi_c/Thread.c +124 -1
  22. data/ext/ffi_c/Type.c +108 -17
  23. data/ext/ffi_c/Types.c +9 -2
  24. data/ext/ffi_c/Variadic.c +5 -4
  25. data/ext/ffi_c/compat.h +8 -0
  26. data/ext/ffi_c/endian.h +7 -1
  27. data/ext/ffi_c/extconf.rb +46 -35
  28. data/ext/ffi_c/ffi.c +5 -0
  29. data/ext/ffi_c/libffi.darwin.mk +15 -15
  30. data/ext/ffi_c/libffi.gnu.mk +3 -3
  31. data/ext/ffi_c/libffi.mk +4 -4
  32. data/lib/ffi.rb +13 -9
  33. data/lib/ffi/autopointer.rb +88 -26
  34. data/lib/ffi/enum.rb +42 -0
  35. data/lib/ffi/errno.rb +6 -1
  36. data/lib/ffi/ffi.rb +1 -0
  37. data/lib/ffi/io.rb +13 -2
  38. data/lib/ffi/library.rb +212 -19
  39. data/lib/ffi/memorypointer.rb +1 -33
  40. data/lib/ffi/platform.rb +23 -7
  41. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  42. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  43. data/lib/ffi/platform/x86_64-freebsd/types.conf +126 -0
  44. data/lib/ffi/platform/x86_64-netbsd/types.conf +126 -0
  45. data/lib/ffi/pointer.rb +44 -0
  46. data/lib/ffi/struct.rb +1 -1
  47. data/lib/ffi/struct_layout_builder.rb +2 -1
  48. data/lib/ffi/tools/const_generator.rb +72 -17
  49. data/lib/ffi/types.rb +21 -1
  50. data/spec/ffi/rbx/memory_pointer_spec.rb +4 -2
  51. data/spec/ffi/struct_spec.rb +10 -0
  52. data/spec/ffi/typedef_spec.rb +11 -0
  53. data/tasks/extension.rake +0 -1
  54. data/tasks/gem.rake +0 -1
  55. data/tasks/yard.rake +11 -0
  56. metadata +15 -8
@@ -88,7 +88,7 @@ memptr_malloc(VALUE self, long size, long count, bool clear)
88
88
  return Qnil;
89
89
  }
90
90
  p->autorelease = true;
91
- p->memory.typeSize = size;
91
+ p->memory.typeSize = (int) size;
92
92
  p->memory.size = msize;
93
93
  /* ensure the memory is aligned on at least a 8 byte boundary */
94
94
  p->memory.address = (char *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);;
@@ -135,6 +135,15 @@ memptr_mark(Pointer* ptr)
135
135
  rb_gc_mark(ptr->rbParent);
136
136
  }
137
137
 
138
+ static VALUE
139
+ memptr_s_from_string(VALUE klass, VALUE s)
140
+ {
141
+ VALUE args[] = { INT2FIX(1), LONG2NUM(RSTRING_LEN(s) + 1), Qfalse };
142
+ VALUE obj = rb_class_new_instance(3, args, klass);
143
+ rb_funcall(obj, rb_intern("put_string"), 2, INT2FIX(0), s);
144
+
145
+ return obj;
146
+ }
138
147
 
139
148
  void
140
149
  rbffi_MemoryPointer_Init(VALUE moduleFFI)
@@ -144,5 +153,6 @@ rbffi_MemoryPointer_Init(VALUE moduleFFI)
144
153
 
145
154
  rb_define_alloc_func(rbffi_MemoryPointerClass, memptr_allocate);
146
155
  rb_define_method(rbffi_MemoryPointerClass, "initialize", memptr_initialize, -1);
156
+ rb_define_singleton_method(rbffi_MemoryPointerClass, "from_string", memptr_s_from_string, 1);
147
157
  }
148
158
 
@@ -67,7 +67,7 @@
67
67
 
68
68
 
69
69
  static bool prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
70
- static int trampoline_size(void);
70
+ static long trampoline_size(void);
71
71
 
72
72
  #if defined(__x86_64__) && defined(__GNUC__)
73
73
  # define CUSTOM_TRAMPOLINE 1
@@ -143,14 +143,14 @@ prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t er
143
143
  }
144
144
 
145
145
 
146
- static int
146
+ static long
147
147
  trampoline_size(void)
148
148
  {
149
149
  return sizeof(METHOD_CLOSURE);
150
150
  }
151
151
 
152
152
  /*
153
- * attached_method_vinvoke is used functions with more than 6 parameters, or
153
+ * attached_method_invoke is used functions with more than 6 parameters, or
154
154
  * with struct param or return values
155
155
  */
156
156
  static void
@@ -211,7 +211,13 @@ static VALUE
211
211
  custom_trampoline(int argc, VALUE* argv, VALUE self, Closure* handle)
212
212
  {
213
213
  FunctionType* fnInfo = (FunctionType *) handle->info;
214
- return (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
214
+ VALUE rbReturnValue;
215
+
216
+ RB_GC_GUARD(rbReturnValue) = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
217
+ RB_GC_GUARD_PTR(argv);
218
+ RB_GC_GUARD(self);
219
+
220
+ return rbReturnValue;
215
221
  }
216
222
 
217
223
  #elif defined(__i386__) && 0
@@ -258,11 +264,11 @@ custom_trampoline(caddr_t args, Closure* handle)
258
264
 
259
265
  extern void ffi_trampoline(int argc, VALUE* argv, VALUE self);
260
266
  extern void ffi_trampoline_end(void);
261
- static int trampoline_offsets(int *, int *);
267
+ static int trampoline_offsets(long *, long *);
262
268
 
263
- static int trampoline_ctx_offset, trampoline_func_offset;
269
+ static long trampoline_ctx_offset, trampoline_func_offset;
264
270
 
265
- static int
271
+ static long
266
272
  trampoline_offset(int off, const long value)
267
273
  {
268
274
  caddr_t ptr;
@@ -276,7 +282,7 @@ trampoline_offset(int off, const long value)
276
282
  }
277
283
 
278
284
  static int
279
- trampoline_offsets(int* ctxOffset, int* fnOffset)
285
+ trampoline_offsets(long* ctxOffset, long* fnOffset)
280
286
  {
281
287
  *ctxOffset = trampoline_offset(0, TRAMPOLINE_CTX_MAGIC);
282
288
  if (*ctxOffset == -1) {
@@ -304,7 +310,7 @@ prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t er
304
310
  return true;
305
311
  }
306
312
 
307
- static int
313
+ static long
308
314
  trampoline_size(void)
309
315
  {
310
316
  return (caddr_t) &ffi_trampoline_end - (caddr_t) &ffi_trampoline;
@@ -316,14 +322,15 @@ trampoline_size(void)
316
322
  void
317
323
  rbffi_MethodHandle_Init(VALUE module)
318
324
  {
319
- defaultClosurePool = rbffi_ClosurePool_New(trampoline_size(), prep_trampoline, NULL);
325
+ ffi_status ffiStatus;
326
+ defaultClosurePool = rbffi_ClosurePool_New((int) trampoline_size(), prep_trampoline, NULL);
320
327
 
321
328
  #if defined(CUSTOM_TRAMPOLINE)
322
329
  if (trampoline_offsets(&trampoline_ctx_offset, &trampoline_func_offset) != 0) {
323
330
  rb_raise(rb_eFatal, "Could not locate offsets in trampoline code");
324
331
  }
325
332
  #else
326
- ffi_status ffiStatus = ffi_prep_cif(&mh_cif, FFI_DEFAULT_ABI, 3, &ffi_type_ulong,
333
+ ffiStatus = ffi_prep_cif(&mh_cif, FFI_DEFAULT_ABI, 3, &ffi_type_ulong,
327
334
  methodHandleParamTypes);
328
335
  if (ffiStatus != FFI_OK) {
329
336
  rb_raise(rb_eFatal, "ffi_prep_cif failed. status=%#x", ffiStatus);
@@ -26,6 +26,9 @@
26
26
  #include <ctype.h>
27
27
  #include "endian.h"
28
28
  #include "Platform.h"
29
+ #if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)
30
+ #include <gnu/lib-names.h>
31
+ #endif
29
32
 
30
33
  static VALUE PlatformModule = Qnil;
31
34
 
@@ -34,13 +37,13 @@ static VALUE PlatformModule = Qnil;
34
37
  * system installed ruby incorrectly reports 'host_cpu' as 'powerpc' when running
35
38
  * on intel.
36
39
  */
37
- #if defined(__x86_64__) || defined(__x86_64) || defined(__amd64)
40
+ #if defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(_M_X64) || defined(_M_AMD64)
38
41
  # define CPU "x86_64"
39
42
 
40
- #elif defined(__i386__) || defined(__i386)
43
+ #elif defined(__i386__) || defined(__i386) || defined(_M_IX86)
41
44
  # define CPU "i386"
42
45
 
43
- #elif defined(__ppc64__) || defined(__powerpc64__)
46
+ #elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC)
44
47
  # define CPU "ppc64"
45
48
 
46
49
  #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc)
@@ -93,6 +96,9 @@ rbffi_Platform_Init(VALUE moduleFFI)
93
96
  rb_define_const(PlatformModule, "LITTLE_ENDIAN", INT2FIX(LITTLE_ENDIAN));
94
97
  rb_define_const(PlatformModule, "BIG_ENDIAN", INT2FIX(BIG_ENDIAN));
95
98
  rb_define_const(PlatformModule, "CPU", rb_str_new2(CPU));
99
+ #if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)
100
+ rb_define_const(PlatformModule, "GNU_LIBC", rb_str_new2(LIBC_SO));
101
+ #endif
96
102
  export_primitive_types(PlatformModule);
97
103
  }
98
104
 
@@ -68,6 +68,17 @@ ptr_allocate(VALUE klass)
68
68
  return obj;
69
69
  }
70
70
 
71
+ /*
72
+ * @overload initialize(pointer)
73
+ * @param [Pointer] pointer another pointer to initialize from
74
+ * Create a new pointer from another {Pointer}.
75
+ * @overload initialize(type, address)
76
+ * @param [Type] type type for pointer
77
+ * @param [Integer] address base address for pointer
78
+ * Create a new pointer from a {Type} and a base adresse
79
+ * @return [self]
80
+ * A new instance of Pointer.
81
+ */
71
82
  static VALUE
72
83
  ptr_initialize(int argc, VALUE* argv, VALUE self)
73
84
  {
@@ -117,6 +128,16 @@ ptr_initialize(int argc, VALUE* argv, VALUE self)
117
128
  return self;
118
129
  }
119
130
 
131
+ /*
132
+ * call-seq: ptr.initialize_copy(other)
133
+ * @param [Pointer] other source for cloning or dupping
134
+ * @return [self]
135
+ * @raise {RuntimeError} if +other+ is an unbounded memory area, or is unreable/unwritable
136
+ * @raise {NoMemError} if failed to allocate memory for new object
137
+ * DO NOT CALL THIS METHOD.
138
+ *
139
+ * This method is internally used by #dup and #clone. Memory contents is copied from +other+.
140
+ */
120
141
  static VALUE
121
142
  ptr_initialize_copy(VALUE self, VALUE other)
122
143
  {
@@ -179,6 +200,13 @@ slice(VALUE self, long offset, long size)
179
200
  return retval;
180
201
  }
181
202
 
203
+ /*
204
+ * Document-method: +
205
+ * call-seq: ptr + offset
206
+ * @param [Numeric] offset
207
+ * @return [Pointer]
208
+ * Return a new {Pointer} from an existing pointer and an +offset+.
209
+ */
182
210
  static VALUE
183
211
  ptr_plus(VALUE self, VALUE offset)
184
212
  {
@@ -190,12 +218,25 @@ ptr_plus(VALUE self, VALUE offset)
190
218
  return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off);
191
219
  }
192
220
 
221
+ /*
222
+ * call-seq: ptr.slice(offset, length)
223
+ * @param [Numeric] offset
224
+ * @param [Numeric] length
225
+ * @return [Pointer]
226
+ * Return a new {Pointer} from an existing one. This pointer points on same contents
227
+ * from +offset+ for a length +length+.
228
+ */
193
229
  static VALUE
194
230
  ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
195
231
  {
196
232
  return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength));
197
233
  }
198
234
 
235
+ /*
236
+ * call-seq: ptr.inspect
237
+ * @return [String]
238
+ * Inspect pointer object.
239
+ */
199
240
  static VALUE
200
241
  ptr_inspect(VALUE self)
201
242
  {
@@ -214,6 +255,12 @@ ptr_inspect(VALUE self)
214
255
  return rb_str_new2(buf);
215
256
  }
216
257
 
258
+ /*
259
+ * Document-method: null?
260
+ * call-seq: ptr.null?
261
+ * @return [Boolean]
262
+ * Return +true+ if +self+ is a {NULL} pointer.
263
+ */
217
264
  static VALUE
218
265
  ptr_null_p(VALUE self)
219
266
  {
@@ -224,6 +271,12 @@ ptr_null_p(VALUE self)
224
271
  return ptr->memory.address == NULL ? Qtrue : Qfalse;
225
272
  }
226
273
 
274
+ /*
275
+ * Document-method: ==
276
+ * call-seq: ptr == other
277
+ * @param [Pointer] other
278
+ * Check equality between +self+ and +other+. Equality is tested on {#address}.
279
+ */
227
280
  static VALUE
228
281
  ptr_equals(VALUE self, VALUE other)
229
282
  {
@@ -234,6 +287,11 @@ ptr_equals(VALUE self, VALUE other)
234
287
  return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse;
235
288
  }
236
289
 
290
+ /*
291
+ * call-seq: ptr.address
292
+ * @return [Numeric] pointer's base address
293
+ * Return +self+'s base address (alias: #to_i).
294
+ */
237
295
  static VALUE
238
296
  ptr_address(VALUE self)
239
297
  {
@@ -250,6 +308,15 @@ ptr_address(VALUE self)
250
308
  # define SWAPPED_ORDER LITTLE_ENDIAN
251
309
  #endif
252
310
 
311
+ /*
312
+ * Get or set +self+'s endianness
313
+ * @overload ptr.order
314
+ * @return [:big, :little] endianness of +self+
315
+ * @overload ptr.order(order)
316
+ * @param [Symbol] order endianness to set (+:little+, +:big+ or +:network+). +:big+ and +:network+
317
+ * are synonymous.
318
+ * @return [self]
319
+ */
253
320
  static VALUE
254
321
  ptr_order(int argc, VALUE* argv, VALUE self)
255
322
  {
@@ -289,6 +356,11 @@ ptr_order(int argc, VALUE* argv, VALUE self)
289
356
  }
290
357
 
291
358
 
359
+ /*
360
+ * call-seq: ptr.free
361
+ * @return [self]
362
+ * Free memory pointed by +self+.
363
+ */
292
364
  static VALUE
293
365
  ptr_free(VALUE self)
294
366
  {
@@ -307,6 +379,12 @@ ptr_free(VALUE self)
307
379
  return self;
308
380
  }
309
381
 
382
+ /*
383
+ * call-seq: ptr.autorelease = autorelease
384
+ * @param [Boolean] autorelease
385
+ * @return [Boolean] +autorelease+
386
+ * Set +autorelease+ attribute. See also Autorelease section.
387
+ */
310
388
  static VALUE
311
389
  ptr_autorelease(VALUE self, VALUE autorelease)
312
390
  {
@@ -318,6 +396,11 @@ ptr_autorelease(VALUE self, VALUE autorelease)
318
396
  return autorelease;
319
397
  }
320
398
 
399
+ /*
400
+ * call-seq: ptr.autorelease?
401
+ * @return [Boolean]
402
+ * Get +autorelease+ attribute. See also Autorelease section.
403
+ */
321
404
  static VALUE
322
405
  ptr_autorelease_p(VALUE self)
323
406
  {
@@ -350,7 +433,19 @@ rbffi_Pointer_Init(VALUE moduleFFI)
350
433
  {
351
434
  VALUE rbNullAddress = ULL2NUM(0);
352
435
 
436
+ /*
437
+ * Document-class: FFI::Pointer < FFI::AbstractMemory
438
+ * Pointer class is used to manage C pointers with ease. A {Pointer} object is defined by his
439
+ * {#address} (as a C pointer). It permits additions with an integer for pointer arithmetic.
440
+ *
441
+ * ==Autorelease
442
+ * A pointer object may autorelease his contents when freed (by default). This behaviour may be
443
+ * changed with {#autorelease=} method.
444
+ */
353
445
  rbffi_PointerClass = rb_define_class_under(moduleFFI, "Pointer", rbffi_AbstractMemoryClass);
446
+ /*
447
+ * Document-variable: Pointer
448
+ */
354
449
  rb_global_variable(&rbffi_PointerClass);
355
450
 
356
451
  rb_define_alloc_func(rbffi_PointerClass, ptr_allocate);
@@ -370,6 +465,9 @@ rbffi_Pointer_Init(VALUE moduleFFI)
370
465
  rb_define_method(rbffi_PointerClass, "free", ptr_free, 0);
371
466
 
372
467
  rbffi_NullPointerSingleton = rb_class_new_instance(1, &rbNullAddress, rbffi_PointerClass);
468
+ /*
469
+ * NULL pointer
470
+ */
373
471
  rb_define_const(rbffi_PointerClass, "NULL", rbffi_NullPointerSingleton);
374
472
  }
375
473
 
@@ -47,7 +47,7 @@ typedef struct InlineArray_ {
47
47
  MemoryOp *op;
48
48
  Type* componentType;
49
49
  ArrayType* arrayType;
50
- unsigned int length;
50
+ int length;
51
51
  } InlineArray;
52
52
 
53
53
 
@@ -97,7 +97,7 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
97
97
 
98
98
  /* Call up into ruby code to adjust the layout */
99
99
  if (nargs > 1) {
100
- s->rbLayout = rb_funcall2(CLASS_OF(self), id_layout, RARRAY_LEN(rest), RARRAY_PTR(rest));
100
+ s->rbLayout = rb_funcall2(CLASS_OF(self), id_layout, (int) RARRAY_LEN(rest), RARRAY_PTR(rest));
101
101
  } else {
102
102
  s->rbLayout = struct_class_layout(klass);
103
103
  }
@@ -354,7 +354,7 @@ struct_set_pointer(VALUE self, VALUE pointer)
354
354
  Data_Get_Struct(pointer, AbstractMemory, memory);
355
355
  layout = struct_layout(self);
356
356
 
357
- if (layout->base.ffiType->size > memory->size) {
357
+ if ((int) layout->base.ffiType->size > memory->size) {
358
358
  rb_raise(rb_eArgError, "memory of %ld bytes too small for struct %s (expected at least %ld)",
359
359
  memory->size, rb_obj_classname(self), (long) layout->base.ffiType->size);
360
360
  }
@@ -495,7 +495,7 @@ inline_array_offset(InlineArray* array, int index)
495
495
  rb_raise(rb_eIndexError, "index %d out of bounds", index);
496
496
  }
497
497
 
498
- return array->field->offset + (index * array->componentType->ffiType->size);
498
+ return (int) array->field->offset + (index * (int) array->componentType->ffiType->size);
499
499
  }
500
500
 
501
501
  static VALUE
@@ -22,6 +22,7 @@
22
22
  #ifndef RBFFI_STRUCT_H
23
23
  #define RBFFI_STRUCT_H
24
24
 
25
+ #include "extconf.h"
25
26
  #include "AbstractMemory.h"
26
27
  #include "Type.h"
27
28
  #ifdef RUBY_1_9
@@ -59,7 +60,7 @@ extern "C" {
59
60
  struct StructLayout_ {
60
61
  Type base;
61
62
  StructField** fields;
62
- unsigned int fieldCount;
63
+ int fieldCount;
63
64
  int size;
64
65
  int align;
65
66
  ffi_type** ffiTypes;
@@ -348,7 +348,7 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
348
348
  int i;
349
349
 
350
350
  Data_Get_Struct(self, StructLayout, layout);
351
- layout->fieldCount = RARRAY_LEN(fields);
351
+ layout->fieldCount = (int) RARRAY_LEN(fields);
352
352
  layout->rbFieldMap = rb_hash_new();
353
353
  layout->rbFieldNames = rb_ary_new2(layout->fieldCount);
354
354
  layout->size = NUM2INT(size);
@@ -374,8 +374,8 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
374
374
  }
375
375
  rbName = rb_funcall2(rbField, rb_intern("name"), 0, NULL);
376
376
 
377
- field = layout->fields[i];
378
377
  Data_Get_Struct(rbField, StructField, field);
378
+ layout->fields[i] = field;
379
379
 
380
380
  if (field->type == NULL || field->type->ffiType == NULL) {
381
381
  rb_raise(rb_eRuntimeError, "type of field %d not supported", i);
@@ -25,6 +25,7 @@
25
25
  # include <errno.h>
26
26
  # include <signal.h>
27
27
  #else
28
+ # define _WINSOCKAPI_
28
29
  # include <windows.h>
29
30
  #endif
30
31
  #include <fcntl.h>
@@ -179,6 +180,113 @@ rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(voi
179
180
  }
180
181
 
181
182
  #else
183
+ /* win32 implementation */
184
+
185
+ struct BlockingThread {
186
+ HANDLE tid;
187
+ VALUE (*fn)(void *);
188
+ void *data;
189
+ void (*ubf)(void *);
190
+ void *data2;
191
+ VALUE retval;
192
+ int wrfd;
193
+ int rdfd;
194
+ };
195
+
196
+ static DWORD __stdcall
197
+ rbffi_blocking_thread(LPVOID args)
198
+ {
199
+ struct BlockingThread* thr = (struct BlockingThread *) args;
200
+ char c = 1;
201
+ VALUE retval;
202
+
203
+ retval = (*thr->fn)(thr->data);
204
+ thr->retval = retval;
205
+
206
+ write(thr->wrfd, &c, sizeof(c));
207
+
208
+ return 0;
209
+ }
210
+
211
+ static VALUE
212
+ wait_for_thread(void *data)
213
+ {
214
+ struct BlockingThread* thr = (struct BlockingThread *) data;
215
+ char c, res;
216
+ fd_set rfds;
217
+
218
+ FD_ZERO(&rfds);
219
+ FD_SET(thr->rdfd, &rfds);
220
+ rb_thread_select(thr->rdfd + 1, &rfds, NULL, NULL, NULL);
221
+ read(thr->rdfd, &c, 1);
222
+ return Qnil;
223
+ }
224
+
225
+ static VALUE
226
+ cleanup_blocking_thread(void *data, VALUE exc)
227
+ {
228
+ struct BlockingThread* thr = (struct BlockingThread *) data;
229
+
230
+ if (thr->ubf != (void (*)(void *)) -1) {
231
+ (*thr->ubf)(thr->data2);
232
+ } else {
233
+ TerminateThread(thr->tid, 0);
234
+ }
235
+
236
+ return exc;
237
+ }
238
+
239
+ VALUE
240
+ rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2)
241
+ {
242
+ struct BlockingThread* thr;
243
+ int fd[2];
244
+ VALUE exc;
245
+ DWORD state;
246
+ DWORD res;
247
+
248
+ if (_pipe(fd, 1024, O_BINARY) == -1) {
249
+ rb_raise(rb_eSystemCallError, "_pipe() failed");
250
+ return Qnil;
251
+ }
252
+
253
+ thr = ALLOC_N(struct BlockingThread, 1);
254
+ thr->rdfd = fd[0];
255
+ thr->wrfd = fd[1];
256
+ thr->fn = func;
257
+ thr->data = data1;
258
+ thr->ubf = ubf;
259
+ thr->data2 = data2;
260
+ thr->retval = Qnil;
261
+
262
+ thr->tid = CreateThread(NULL, 0, rbffi_blocking_thread, thr, 0, NULL);
263
+ if (!thr->tid) {
264
+ close(fd[0]);
265
+ close(fd[1]);
266
+ xfree(thr);
267
+ rb_raise(rb_eSystemCallError, "CreateThread() failed");
268
+ return Qnil;
269
+ }
270
+
271
+ exc = rb_rescue2(wait_for_thread, (VALUE) thr, cleanup_blocking_thread, (VALUE) thr,
272
+ rb_eException);
273
+
274
+ /* The thread should be finished, already. */
275
+ WaitForSingleObject(thr->tid, INFINITE);
276
+ CloseHandle(thr->tid);
277
+ close(fd[1]);
278
+ close(fd[0]);
279
+ xfree(thr);
280
+
281
+ if (exc != Qnil) {
282
+ rb_exc_raise(exc);
283
+ }
284
+
285
+ return thr->retval;
286
+ }
287
+
288
+
289
+ #if 0
182
290
 
183
291
  /*
184
292
  * FIXME: someone needs to implement something similar to the posix pipe based
@@ -187,8 +295,23 @@ rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(voi
187
295
  VALUE
188
296
  rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2)
189
297
  {
190
- return (*func)(data1);
298
+ #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
299
+ rbffi_thread_t oldThread;
300
+ #endif
301
+ VALUE res;
302
+ #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
303
+ oldThread = rbffi_active_thread;
304
+ rbffi_active_thread = rbffi_thread_self();
305
+ #endif
306
+
307
+ res = (*func)(data1);
308
+
309
+ #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
310
+ rbffi_active_thread = oldThread;
311
+ #endif
312
+ return res;
191
313
  }
314
+ #endif
192
315
 
193
316
  #endif /* !_WIN32 */
194
317