ffi 1.10.0 → 1.11.1
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.gitmodules +2 -1
- data/.travis.yml +17 -18
- data/CHANGELOG.md +33 -0
- data/Gemfile +1 -1
- data/README.md +20 -17
- data/Rakefile +10 -83
- data/appveyor.yml +6 -1
- data/ext/ffi_c/Call.c +16 -33
- data/ext/ffi_c/Call.h +2 -5
- data/ext/ffi_c/Function.c +24 -108
- data/ext/ffi_c/Platform.c +0 -47
- data/ext/ffi_c/Thread.c +6 -222
- data/ext/ffi_c/Thread.h +2 -13
- data/ext/ffi_c/Type.c +0 -18
- data/ext/ffi_c/Type.h +0 -1
- data/ext/ffi_c/Variadic.c +9 -15
- data/ext/ffi_c/extconf.rb +34 -20
- data/ext/ffi_c/ffi.c +3 -8
- data/ext/ffi_c/libffi/configure.ac +5 -1
- data/ext/ffi_c/libffi/include/ffi_common.h +1 -1
- data/ext/ffi_c/libffi/src/aarch64/ffi.c +2 -2
- data/ext/ffi_c/libffi/src/frv/ffi.c +1 -1
- data/ext/ffi_c/libffi/src/metag/ffi.c +1 -1
- data/ext/ffi_c/libffi/src/moxie/ffi.c +1 -1
- data/ext/ffi_c/libffi/src/riscv/ffi.c +42 -6
- data/ext/ffi_c/libffi/src/riscv/ffitarget.h +1 -0
- data/ext/ffi_c/libffi/src/riscv/sysv.S +86 -7
- data/ext/ffi_c/libffi/src/x86/ffi.c +2 -1
- data/ext/ffi_c/libffi/src/x86/ffiw64.c +1 -1
- data/ext/ffi_c/libffi/src/x86/sysv.S +88 -2
- data/ext/ffi_c/libffi/src/x86/unix64.S +41 -0
- data/ext/ffi_c/rbffi.h +0 -2
- data/ffi.gemspec +11 -4
- data/lib/ffi/data_converter.rb +67 -0
- data/lib/ffi/ffi.rb +1 -0
- data/lib/ffi/platform.rb +2 -0
- data/lib/ffi/pointer.rb +1 -1
- data/lib/ffi/struct.rb +3 -63
- data/lib/ffi/struct_by_reference.rb +72 -0
- data/lib/ffi/struct_layout.rb +96 -0
- data/lib/ffi/tools/const_generator.rb +5 -4
- data/lib/ffi/tools/generator.rb +47 -2
- data/lib/ffi/tools/generator_task.rb +13 -17
- data/lib/ffi/tools/struct_generator.rb +4 -4
- data/lib/ffi/types.rb +1 -1
- data/lib/ffi/version.rb +1 -1
- metadata +18 -13
- data/ext/ffi_c/DataConverter.c +0 -91
- data/ext/ffi_c/StructByReference.c +0 -190
- data/ext/ffi_c/StructByReference.h +0 -50
data/ext/ffi_c/Call.h
CHANGED
@@ -48,7 +48,7 @@ extern "C" {
|
|
48
48
|
#if (defined(__i386__) || defined(__x86_64__)) && !(defined(_WIN32) || defined(__WIN32__))
|
49
49
|
# define BYPASS_FFI 1
|
50
50
|
#endif
|
51
|
-
|
51
|
+
|
52
52
|
typedef union {
|
53
53
|
#ifdef USE_RAW
|
54
54
|
signed int s8, s16, s32;
|
@@ -70,7 +70,7 @@ typedef union {
|
|
70
70
|
double f64;
|
71
71
|
long double ld;
|
72
72
|
} FFIStorage;
|
73
|
-
|
73
|
+
|
74
74
|
extern void rbffi_Call_Init(VALUE moduleFFI);
|
75
75
|
|
76
76
|
extern void rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
|
@@ -94,9 +94,6 @@ typedef struct rbffi_blocking_call {
|
|
94
94
|
void **ffiValues;
|
95
95
|
void* retval;
|
96
96
|
void* params;
|
97
|
-
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
98
|
-
void* stkretval;
|
99
|
-
#endif
|
100
97
|
} rbffi_blocking_call_t;
|
101
98
|
|
102
99
|
VALUE rbffi_do_blocking_call(void* data);
|
data/ext/ffi_c/Function.c
CHANGED
@@ -47,9 +47,7 @@
|
|
47
47
|
# endif
|
48
48
|
#endif
|
49
49
|
#include <ruby.h>
|
50
|
-
#if defined(HAVE_RUBY_THREAD_H)
|
51
50
|
#include <ruby/thread.h>
|
52
|
-
#endif
|
53
51
|
|
54
52
|
#include <ffi.h>
|
55
53
|
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
|
@@ -101,10 +99,27 @@ static VALUE async_cb_event(void *);
|
|
101
99
|
static VALUE async_cb_call(void *);
|
102
100
|
#endif
|
103
101
|
|
104
|
-
#ifdef
|
105
|
-
extern
|
102
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
103
|
+
extern int ruby_thread_has_gvl_p(void);
|
104
|
+
#define rbffi_thread_has_gvl_p(frame) ruby_thread_has_gvl_p()
|
105
|
+
#else
|
106
|
+
static int rbffi_thread_has_gvl_p(rbffi_frame_t *frame)
|
107
|
+
{
|
108
|
+
return frame != NULL && frame->has_gvl;
|
109
|
+
}
|
106
110
|
#endif
|
107
111
|
|
112
|
+
#ifdef HAVE_RUBY_NATIVE_THREAD_P
|
113
|
+
extern int ruby_native_thread_p(void);
|
114
|
+
#define rbffi_native_thread_p(frame) ruby_native_thread_p()
|
115
|
+
#else
|
116
|
+
static int rbffi_native_thread_p(rbffi_frame_t *frame)
|
117
|
+
{
|
118
|
+
return frame != NULL;
|
119
|
+
}
|
120
|
+
#endif
|
121
|
+
|
122
|
+
|
108
123
|
VALUE rbffi_FunctionClass = Qnil;
|
109
124
|
|
110
125
|
#if defined(DEFER_ASYNC_CALLBACK)
|
@@ -136,15 +151,9 @@ static struct gvl_callback* async_cb_list = NULL;
|
|
136
151
|
# ifndef _WIN32
|
137
152
|
static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
|
138
153
|
static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
|
139
|
-
# if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
140
|
-
static int async_cb_pipe[2];
|
141
|
-
# endif
|
142
154
|
# else
|
143
155
|
static HANDLE async_cb_cond;
|
144
156
|
static CRITICAL_SECTION async_cb_lock;
|
145
|
-
# if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
146
|
-
static int async_cb_pipe[2];
|
147
|
-
# endif
|
148
157
|
# endif
|
149
158
|
#endif
|
150
159
|
|
@@ -323,16 +332,8 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
323
332
|
|
324
333
|
#if defined(DEFER_ASYNC_CALLBACK)
|
325
334
|
if (async_cb_thread == Qnil) {
|
326
|
-
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)) && defined(_WIN32)
|
327
|
-
_pipe(async_cb_pipe, 1024, O_BINARY);
|
328
|
-
#elif !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
329
|
-
pipe(async_cb_pipe);
|
330
|
-
fcntl(async_cb_pipe[0], F_SETFL, fcntl(async_cb_pipe[0], F_GETFL) | O_NONBLOCK);
|
331
|
-
fcntl(async_cb_pipe[1], F_SETFL, fcntl(async_cb_pipe[1], F_GETFL) | O_NONBLOCK);
|
332
|
-
#endif
|
333
335
|
async_cb_thread = rb_thread_create(async_cb_event, NULL);
|
334
336
|
}
|
335
|
-
|
336
337
|
#endif
|
337
338
|
|
338
339
|
fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
|
@@ -474,13 +475,13 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
474
475
|
cb.frame = rbffi_frame_current();
|
475
476
|
|
476
477
|
if (cb.frame != NULL) cb.frame->exc = Qnil;
|
477
|
-
if (cb.frame != NULL && cb.frame->has_gvl) {
|
478
|
-
callback_with_gvl(&cb);
|
479
478
|
|
480
|
-
|
481
|
-
|
479
|
+
if (rbffi_native_thread_p(cb.frame)) {
|
480
|
+
if(rbffi_thread_has_gvl_p(cb.frame)) {
|
481
|
+
callback_with_gvl(&cb);
|
482
|
+
} else {
|
482
483
|
rb_thread_call_with_gvl(callback_with_gvl, &cb);
|
483
|
-
|
484
|
+
}
|
484
485
|
#if defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
|
485
486
|
} else {
|
486
487
|
bool empty = false;
|
@@ -494,17 +495,8 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
494
495
|
cb.next = async_cb_list;
|
495
496
|
async_cb_list = &cb;
|
496
497
|
|
497
|
-
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
498
|
-
pthread_mutex_unlock(&async_cb_mutex);
|
499
|
-
/* Only signal if the list was empty */
|
500
|
-
if (empty) {
|
501
|
-
char c;
|
502
|
-
write(async_cb_pipe[1], &c, 1);
|
503
|
-
}
|
504
|
-
#else
|
505
498
|
pthread_cond_signal(&async_cb_cond);
|
506
499
|
pthread_mutex_unlock(&async_cb_mutex);
|
507
|
-
#endif
|
508
500
|
|
509
501
|
/* Wait for the thread executing the ruby callback to signal it is done */
|
510
502
|
pthread_mutex_lock(&cb.async_mutex);
|
@@ -528,15 +520,7 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
|
528
520
|
async_cb_list = &cb;
|
529
521
|
LeaveCriticalSection(&async_cb_lock);
|
530
522
|
|
531
|
-
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
532
|
-
/* Only signal if the list was empty */
|
533
|
-
if (empty) {
|
534
|
-
char c;
|
535
|
-
write(async_cb_pipe[1], &c, 1);
|
536
|
-
}
|
537
|
-
#else
|
538
523
|
SetEvent(async_cb_cond);
|
539
|
-
#endif
|
540
524
|
|
541
525
|
/* Wait for the thread executing the ruby callback to signal it is done */
|
542
526
|
WaitForSingleObject(cb.async_event, INFINITE);
|
@@ -554,7 +538,6 @@ struct async_wait {
|
|
554
538
|
static void * async_cb_wait(void *);
|
555
539
|
static void async_cb_stop(void *);
|
556
540
|
|
557
|
-
#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
558
541
|
static VALUE
|
559
542
|
async_cb_event(void* unused)
|
560
543
|
{
|
@@ -562,11 +545,7 @@ async_cb_event(void* unused)
|
|
562
545
|
|
563
546
|
w.stop = false;
|
564
547
|
while (!w.stop) {
|
565
|
-
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
566
548
|
rb_thread_call_without_gvl(async_cb_wait, &w, async_cb_stop, &w);
|
567
|
-
#else
|
568
|
-
rb_thread_blocking_region(async_cb_wait, &w, async_cb_stop, &w);
|
569
|
-
#endif
|
570
549
|
if (w.cb != NULL) {
|
571
550
|
/* Start up a new ruby thread to run the ruby callback */
|
572
551
|
rb_thread_create(async_cb_call, w.cb);
|
@@ -576,69 +555,6 @@ async_cb_event(void* unused)
|
|
576
555
|
return Qnil;
|
577
556
|
}
|
578
557
|
|
579
|
-
#elif defined(_WIN32)
|
580
|
-
static VALUE
|
581
|
-
async_cb_event(void* unused)
|
582
|
-
{
|
583
|
-
while (true) {
|
584
|
-
struct gvl_callback* cb;
|
585
|
-
char buf[64];
|
586
|
-
fd_set rfds;
|
587
|
-
|
588
|
-
FD_ZERO(&rfds);
|
589
|
-
FD_SET(async_cb_pipe[0], &rfds);
|
590
|
-
rb_thread_select(async_cb_pipe[0] + 1, &rfds, NULL, NULL, NULL);
|
591
|
-
read(async_cb_pipe[0], buf, sizeof(buf));
|
592
|
-
|
593
|
-
EnterCriticalSection(&async_cb_lock);
|
594
|
-
cb = async_cb_list;
|
595
|
-
async_cb_list = NULL;
|
596
|
-
LeaveCriticalSection(&async_cb_lock);
|
597
|
-
|
598
|
-
while (cb != NULL) {
|
599
|
-
struct gvl_callback* next = cb->next;
|
600
|
-
/* Start up a new ruby thread to run the ruby callback */
|
601
|
-
rb_thread_create(async_cb_call, cb);
|
602
|
-
cb = next;
|
603
|
-
}
|
604
|
-
}
|
605
|
-
|
606
|
-
return Qnil;
|
607
|
-
}
|
608
|
-
#else
|
609
|
-
static VALUE
|
610
|
-
async_cb_event(void* unused)
|
611
|
-
{
|
612
|
-
while (true) {
|
613
|
-
struct gvl_callback* cb;
|
614
|
-
char buf[64];
|
615
|
-
|
616
|
-
if (read(async_cb_pipe[0], buf, sizeof(buf)) < 0) {
|
617
|
-
rb_thread_wait_fd(async_cb_pipe[0]);
|
618
|
-
while (read(async_cb_pipe[0], buf, sizeof (buf)) < 0) {
|
619
|
-
if (rb_io_wait_readable(async_cb_pipe[0]) != Qtrue) {
|
620
|
-
return Qfalse;
|
621
|
-
}
|
622
|
-
}
|
623
|
-
}
|
624
|
-
|
625
|
-
pthread_mutex_lock(&async_cb_mutex);
|
626
|
-
cb = async_cb_list;
|
627
|
-
async_cb_list = NULL;
|
628
|
-
pthread_mutex_unlock(&async_cb_mutex);
|
629
|
-
|
630
|
-
while (cb != NULL) {
|
631
|
-
struct gvl_callback* next = cb->next;
|
632
|
-
/* Start up a new ruby thread to run the ruby callback */
|
633
|
-
rb_thread_create(async_cb_call, cb);
|
634
|
-
cb = next;
|
635
|
-
}
|
636
|
-
}
|
637
|
-
|
638
|
-
return Qnil;
|
639
|
-
}
|
640
|
-
#endif
|
641
|
-
|
642
558
|
#ifdef _WIN32
|
643
559
|
static void *
|
644
560
|
async_cb_wait(void *data)
|
data/ext/ffi_c/Platform.c
CHANGED
@@ -49,51 +49,6 @@
|
|
49
49
|
|
50
50
|
static VALUE PlatformModule = Qnil;
|
51
51
|
|
52
|
-
/*
|
53
|
-
* Determine the cpu type at compile time - useful for MacOSX where the the
|
54
|
-
* system installed ruby incorrectly reports 'host_cpu' as 'powerpc' when running
|
55
|
-
* on intel.
|
56
|
-
*/
|
57
|
-
#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(_M_X64) || defined(_M_AMD64)
|
58
|
-
# define CPU "x86_64"
|
59
|
-
|
60
|
-
#elif defined(__i386__) || defined(__i386) || defined(_M_IX86)
|
61
|
-
# define CPU "i386"
|
62
|
-
|
63
|
-
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC)
|
64
|
-
# define CPU "ppc64"
|
65
|
-
|
66
|
-
#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc)
|
67
|
-
# define CPU "ppc"
|
68
|
-
|
69
|
-
/*
|
70
|
-
* Need to check for __sparcv9 first, because __sparc will be defined either way.
|
71
|
-
* Note that __sparcv9 seems to only be set for Solaris. On Linux, __sparc will
|
72
|
-
* be set, along with __arch64__ if a 64-bit platform.
|
73
|
-
*/
|
74
|
-
#elif defined(__sparcv9__) || defined(__sparcv9)
|
75
|
-
# define CPU "sparcv9"
|
76
|
-
|
77
|
-
#elif defined(__sparc__) || defined(__sparc)
|
78
|
-
# if defined(__arch64__)
|
79
|
-
# define CPU "sparcv9"
|
80
|
-
# else
|
81
|
-
# define CPU "sparc"
|
82
|
-
# endif
|
83
|
-
|
84
|
-
#elif defined(__arm__) || defined(__arm)
|
85
|
-
# define CPU "arm"
|
86
|
-
|
87
|
-
#elif defined(__mips__) || defined(__mips)
|
88
|
-
# define CPU "mips"
|
89
|
-
|
90
|
-
#elif defined(__s390__)
|
91
|
-
# define CPU "s390"
|
92
|
-
|
93
|
-
#else
|
94
|
-
# define CPU "unknown"
|
95
|
-
#endif
|
96
|
-
|
97
52
|
static void
|
98
53
|
export_primitive_types(VALUE module)
|
99
54
|
{
|
@@ -120,10 +75,8 @@ rbffi_Platform_Init(VALUE moduleFFI)
|
|
120
75
|
rb_define_const(PlatformModule, "BYTE_ORDER", INT2FIX(BYTE_ORDER));
|
121
76
|
rb_define_const(PlatformModule, "LITTLE_ENDIAN", INT2FIX(LITTLE_ENDIAN));
|
122
77
|
rb_define_const(PlatformModule, "BIG_ENDIAN", INT2FIX(BIG_ENDIAN));
|
123
|
-
rb_define_const(PlatformModule, "CPU", rb_str_new2(CPU));
|
124
78
|
#if defined(__GNU__) || defined(__GLIBC__)
|
125
79
|
rb_define_const(PlatformModule, "GNU_LIBC", rb_str_new2(LIBC_SO));
|
126
80
|
#endif
|
127
81
|
export_primitive_types(PlatformModule);
|
128
82
|
}
|
129
|
-
|
data/ext/ffi_c/Thread.c
CHANGED
@@ -70,13 +70,15 @@ rbffi_frame_current(void)
|
|
70
70
|
#endif
|
71
71
|
}
|
72
72
|
|
73
|
-
void
|
73
|
+
void
|
74
74
|
rbffi_frame_push(rbffi_frame_t* frame)
|
75
75
|
{
|
76
76
|
memset(frame, 0, sizeof(*frame));
|
77
|
+
#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
|
77
78
|
frame->has_gvl = true;
|
79
|
+
#endif
|
78
80
|
frame->exc = Qnil;
|
79
|
-
|
81
|
+
|
80
82
|
#ifdef _WIN32
|
81
83
|
frame->prev = TlsGetValue(frame_thread_key);
|
82
84
|
TlsSetValue(frame_thread_key, frame);
|
@@ -87,7 +89,7 @@ rbffi_frame_push(rbffi_frame_t* frame)
|
|
87
89
|
#endif
|
88
90
|
}
|
89
91
|
|
90
|
-
void
|
92
|
+
void
|
91
93
|
rbffi_frame_pop(rbffi_frame_t* frame)
|
92
94
|
{
|
93
95
|
#ifdef _WIN32
|
@@ -97,224 +99,6 @@ rbffi_frame_pop(rbffi_frame_t* frame)
|
|
97
99
|
#endif
|
98
100
|
}
|
99
101
|
|
100
|
-
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
|
101
|
-
|
102
|
-
#if !defined(_WIN32)
|
103
|
-
|
104
|
-
struct BlockingThread {
|
105
|
-
pthread_t tid;
|
106
|
-
VALUE (*fn)(void *);
|
107
|
-
void *data;
|
108
|
-
void (*ubf)(void *);
|
109
|
-
void *data2;
|
110
|
-
VALUE retval;
|
111
|
-
int wrfd;
|
112
|
-
int rdfd;
|
113
|
-
};
|
114
|
-
|
115
|
-
static void*
|
116
|
-
rbffi_blocking_thread(void* args)
|
117
|
-
{
|
118
|
-
struct BlockingThread* thr = (struct BlockingThread *) args;
|
119
|
-
char c = 1;
|
120
|
-
VALUE retval;
|
121
|
-
|
122
|
-
retval = (*thr->fn)(thr->data);
|
123
|
-
|
124
|
-
pthread_testcancel();
|
125
|
-
|
126
|
-
thr->retval = retval;
|
127
|
-
|
128
|
-
write(thr->wrfd, &c, sizeof(c));
|
129
|
-
|
130
|
-
return NULL;
|
131
|
-
}
|
132
|
-
|
133
|
-
static VALUE
|
134
|
-
wait_for_thread(void *data)
|
135
|
-
{
|
136
|
-
struct BlockingThread* thr = (struct BlockingThread *) data;
|
137
|
-
char c;
|
138
|
-
|
139
|
-
if (read(thr->rdfd, &c, 1) < 1) {
|
140
|
-
rb_thread_wait_fd(thr->rdfd);
|
141
|
-
while (read(thr->rdfd, &c, 1) < 1 && rb_io_wait_readable(thr->rdfd) == Qtrue) {
|
142
|
-
;
|
143
|
-
}
|
144
|
-
}
|
145
|
-
|
146
|
-
return Qnil;
|
147
|
-
}
|
148
|
-
|
149
|
-
static VALUE
|
150
|
-
cleanup_blocking_thread(void *data, VALUE exc)
|
151
|
-
{
|
152
|
-
struct BlockingThread* thr = (struct BlockingThread *) data;
|
153
|
-
|
154
|
-
if (thr->ubf != (void (*)(void *)) -1) {
|
155
|
-
(*thr->ubf)(thr->data2);
|
156
|
-
} else {
|
157
|
-
pthread_kill(thr->tid, SIGVTALRM);
|
158
|
-
}
|
159
|
-
|
160
|
-
return exc;
|
161
|
-
}
|
162
|
-
|
163
|
-
VALUE
|
164
|
-
rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2)
|
165
|
-
{
|
166
|
-
struct BlockingThread* thr;
|
167
|
-
int fd[2];
|
168
|
-
VALUE exc;
|
169
|
-
|
170
|
-
if (pipe(fd) < 0) {
|
171
|
-
rb_raise(rb_eSystemCallError, "pipe(2) failed");
|
172
|
-
return Qnil;
|
173
|
-
}
|
174
|
-
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
|
175
|
-
|
176
|
-
thr = ALLOC_N(struct BlockingThread, 1);
|
177
|
-
thr->rdfd = fd[0];
|
178
|
-
thr->wrfd = fd[1];
|
179
|
-
thr->fn = func;
|
180
|
-
thr->data = data1;
|
181
|
-
thr->ubf = ubf;
|
182
|
-
thr->data2 = data2;
|
183
|
-
thr->retval = Qnil;
|
184
|
-
|
185
|
-
if (pthread_create(&thr->tid, NULL, rbffi_blocking_thread, thr) != 0) {
|
186
|
-
close(fd[0]);
|
187
|
-
close(fd[1]);
|
188
|
-
xfree(thr);
|
189
|
-
rb_raise(rb_eSystemCallError, "pipe(2) failed");
|
190
|
-
return Qnil;
|
191
|
-
}
|
192
|
-
|
193
|
-
exc = rb_rescue2(wait_for_thread, (VALUE) thr, cleanup_blocking_thread, (VALUE) thr,
|
194
|
-
rb_eException);
|
195
|
-
|
196
|
-
pthread_join(thr->tid, NULL);
|
197
|
-
close(fd[1]);
|
198
|
-
close(fd[0]);
|
199
|
-
xfree(thr);
|
200
|
-
|
201
|
-
if (exc != Qnil) {
|
202
|
-
rb_exc_raise(exc);
|
203
|
-
}
|
204
|
-
|
205
|
-
return thr->retval;
|
206
|
-
}
|
207
|
-
|
208
|
-
#else
|
209
|
-
/* win32 implementation */
|
210
|
-
|
211
|
-
struct BlockingThread {
|
212
|
-
HANDLE tid;
|
213
|
-
VALUE (*fn)(void *);
|
214
|
-
void *data;
|
215
|
-
void (*ubf)(void *);
|
216
|
-
void *data2;
|
217
|
-
VALUE retval;
|
218
|
-
int wrfd;
|
219
|
-
int rdfd;
|
220
|
-
};
|
221
|
-
|
222
|
-
static DWORD __stdcall
|
223
|
-
rbffi_blocking_thread(LPVOID args)
|
224
|
-
{
|
225
|
-
struct BlockingThread* thr = (struct BlockingThread *) args;
|
226
|
-
char c = 1;
|
227
|
-
VALUE retval;
|
228
|
-
|
229
|
-
retval = (*thr->fn)(thr->data);
|
230
|
-
thr->retval = retval;
|
231
|
-
|
232
|
-
write(thr->wrfd, &c, sizeof(c));
|
233
|
-
|
234
|
-
return 0;
|
235
|
-
}
|
236
|
-
|
237
|
-
static VALUE
|
238
|
-
wait_for_thread(void *data)
|
239
|
-
{
|
240
|
-
struct BlockingThread* thr = (struct BlockingThread *) data;
|
241
|
-
char c, res;
|
242
|
-
fd_set rfds;
|
243
|
-
|
244
|
-
FD_ZERO(&rfds);
|
245
|
-
FD_SET(thr->rdfd, &rfds);
|
246
|
-
rb_thread_select(thr->rdfd + 1, &rfds, NULL, NULL, NULL);
|
247
|
-
read(thr->rdfd, &c, 1);
|
248
|
-
return Qnil;
|
249
|
-
}
|
250
|
-
|
251
|
-
static VALUE
|
252
|
-
cleanup_blocking_thread(void *data, VALUE exc)
|
253
|
-
{
|
254
|
-
struct BlockingThread* thr = (struct BlockingThread *) data;
|
255
|
-
|
256
|
-
if (thr->ubf != (void (*)(void *)) -1) {
|
257
|
-
(*thr->ubf)(thr->data2);
|
258
|
-
} else {
|
259
|
-
TerminateThread(thr->tid, 0);
|
260
|
-
}
|
261
|
-
|
262
|
-
return exc;
|
263
|
-
}
|
264
|
-
|
265
|
-
VALUE
|
266
|
-
rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2)
|
267
|
-
{
|
268
|
-
struct BlockingThread* thr;
|
269
|
-
int fd[2];
|
270
|
-
VALUE exc;
|
271
|
-
DWORD state;
|
272
|
-
DWORD res;
|
273
|
-
|
274
|
-
if (_pipe(fd, 1024, O_BINARY) == -1) {
|
275
|
-
rb_raise(rb_eSystemCallError, "_pipe() failed");
|
276
|
-
return Qnil;
|
277
|
-
}
|
278
|
-
|
279
|
-
thr = ALLOC_N(struct BlockingThread, 1);
|
280
|
-
thr->rdfd = fd[0];
|
281
|
-
thr->wrfd = fd[1];
|
282
|
-
thr->fn = func;
|
283
|
-
thr->data = data1;
|
284
|
-
thr->ubf = ubf;
|
285
|
-
thr->data2 = data2;
|
286
|
-
thr->retval = Qnil;
|
287
|
-
|
288
|
-
thr->tid = CreateThread(NULL, 0, rbffi_blocking_thread, thr, 0, NULL);
|
289
|
-
if (!thr->tid) {
|
290
|
-
close(fd[0]);
|
291
|
-
close(fd[1]);
|
292
|
-
xfree(thr);
|
293
|
-
rb_raise(rb_eSystemCallError, "CreateThread() failed");
|
294
|
-
return Qnil;
|
295
|
-
}
|
296
|
-
|
297
|
-
exc = rb_rescue2(wait_for_thread, (VALUE) thr, cleanup_blocking_thread, (VALUE) thr,
|
298
|
-
rb_eException);
|
299
|
-
|
300
|
-
/* The thread should be finished, already. */
|
301
|
-
WaitForSingleObject(thr->tid, INFINITE);
|
302
|
-
CloseHandle(thr->tid);
|
303
|
-
close(fd[1]);
|
304
|
-
close(fd[0]);
|
305
|
-
xfree(thr);
|
306
|
-
|
307
|
-
if (exc != Qnil) {
|
308
|
-
rb_exc_raise(exc);
|
309
|
-
}
|
310
|
-
|
311
|
-
return thr->retval;
|
312
|
-
}
|
313
|
-
|
314
|
-
#endif /* !_WIN32 */
|
315
|
-
|
316
|
-
#endif /* HAVE_RB_THREAD_BLOCKING_REGION */
|
317
|
-
|
318
102
|
#ifndef _WIN32
|
319
103
|
static struct thread_data* thread_data_init(void);
|
320
104
|
|
@@ -348,6 +132,6 @@ rbffi_Thread_Init(VALUE moduleFFI)
|
|
348
132
|
#ifdef _WIN32
|
349
133
|
frame_thread_key = TlsAlloc();
|
350
134
|
#else
|
351
|
-
pthread_key_create(&thread_data_key, thread_data_free);
|
135
|
+
pthread_key_create(&thread_data_key, thread_data_free);
|
352
136
|
#endif
|
353
137
|
}
|