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.
- data/Rakefile +4 -4
- data/ext/ffi_c/AbstractMemory.c +367 -14
- data/ext/ffi_c/AbstractMemory.h +4 -0
- data/ext/ffi_c/ArrayType.c +28 -0
- data/ext/ffi_c/Buffer.c +101 -25
- data/ext/ffi_c/Call.c +8 -5
- data/ext/ffi_c/ClosurePool.c +9 -8
- data/ext/ffi_c/DataConverter.c +29 -0
- data/ext/ffi_c/DynamicLibrary.c +64 -1
- data/ext/ffi_c/Function.c +111 -10
- data/ext/ffi_c/FunctionInfo.c +13 -1
- data/ext/ffi_c/LastError.c +16 -0
- data/ext/ffi_c/MappedType.c +22 -0
- data/ext/ffi_c/MemoryPointer.c +11 -1
- data/ext/ffi_c/MethodHandle.c +18 -11
- data/ext/ffi_c/Platform.c +9 -3
- data/ext/ffi_c/Pointer.c +98 -0
- data/ext/ffi_c/Struct.c +4 -4
- data/ext/ffi_c/Struct.h +2 -1
- data/ext/ffi_c/StructLayout.c +2 -2
- data/ext/ffi_c/Thread.c +124 -1
- data/ext/ffi_c/Type.c +108 -17
- data/ext/ffi_c/Types.c +9 -2
- data/ext/ffi_c/Variadic.c +5 -4
- data/ext/ffi_c/compat.h +8 -0
- data/ext/ffi_c/endian.h +7 -1
- data/ext/ffi_c/extconf.rb +46 -35
- data/ext/ffi_c/ffi.c +5 -0
- data/ext/ffi_c/libffi.darwin.mk +15 -15
- data/ext/ffi_c/libffi.gnu.mk +3 -3
- data/ext/ffi_c/libffi.mk +4 -4
- data/lib/ffi.rb +13 -9
- data/lib/ffi/autopointer.rb +88 -26
- data/lib/ffi/enum.rb +42 -0
- data/lib/ffi/errno.rb +6 -1
- data/lib/ffi/ffi.rb +1 -0
- data/lib/ffi/io.rb +13 -2
- data/lib/ffi/library.rb +212 -19
- data/lib/ffi/memorypointer.rb +1 -33
- data/lib/ffi/platform.rb +23 -7
- data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
- data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
- data/lib/ffi/platform/x86_64-freebsd/types.conf +126 -0
- data/lib/ffi/platform/x86_64-netbsd/types.conf +126 -0
- data/lib/ffi/pointer.rb +44 -0
- data/lib/ffi/struct.rb +1 -1
- data/lib/ffi/struct_layout_builder.rb +2 -1
- data/lib/ffi/tools/const_generator.rb +72 -17
- data/lib/ffi/types.rb +21 -1
- data/spec/ffi/rbx/memory_pointer_spec.rb +4 -2
- data/spec/ffi/struct_spec.rb +10 -0
- data/spec/ffi/typedef_spec.rb +11 -0
- data/tasks/extension.rake +0 -1
- data/tasks/gem.rake +0 -1
- data/tasks/yard.rake +11 -0
- metadata +15 -8
data/ext/ffi_c/MemoryPointer.c
CHANGED
@@ -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
|
|
data/ext/ffi_c/MethodHandle.c
CHANGED
@@ -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
|
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
|
146
|
+
static long
|
147
147
|
trampoline_size(void)
|
148
148
|
{
|
149
149
|
return sizeof(METHOD_CLOSURE);
|
150
150
|
}
|
151
151
|
|
152
152
|
/*
|
153
|
-
*
|
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
|
-
|
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(
|
267
|
+
static int trampoline_offsets(long *, long *);
|
262
268
|
|
263
|
-
static
|
269
|
+
static long trampoline_ctx_offset, trampoline_func_offset;
|
264
270
|
|
265
|
-
static
|
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(
|
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
|
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
|
-
|
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
|
-
|
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);
|
data/ext/ffi_c/Platform.c
CHANGED
@@ -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
|
|
data/ext/ffi_c/Pointer.c
CHANGED
@@ -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
|
|
data/ext/ffi_c/Struct.c
CHANGED
@@ -47,7 +47,7 @@ typedef struct InlineArray_ {
|
|
47
47
|
MemoryOp *op;
|
48
48
|
Type* componentType;
|
49
49
|
ArrayType* arrayType;
|
50
|
-
|
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
|
data/ext/ffi_c/Struct.h
CHANGED
@@ -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
|
-
|
63
|
+
int fieldCount;
|
63
64
|
int size;
|
64
65
|
int align;
|
65
66
|
ffi_type** ffiTypes;
|
data/ext/ffi_c/StructLayout.c
CHANGED
@@ -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);
|
data/ext/ffi_c/Thread.c
CHANGED
@@ -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
|
-
|
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
|
|