ffi 1.0.2 → 1.0.3
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/History.txt +3 -0
- data/Rakefile +7 -7
- data/ext/ffi_c/AbstractMemory.c +5 -6
- data/ext/ffi_c/Call.c +69 -24
- data/ext/ffi_c/ClosurePool.c +13 -55
- data/ext/ffi_c/Function.c +79 -20
- data/ext/ffi_c/MethodHandle.c +12 -24
- data/ext/ffi_c/Pointer.c +9 -3
- data/ext/ffi_c/Thread.c +169 -0
- data/ext/ffi_c/Thread.h +64 -0
- data/ext/ffi_c/Type.c +8 -2
- data/ext/ffi_c/Types.c +3 -4
- data/ext/ffi_c/Types.h +1 -1
- data/ext/ffi_c/Variadic.c +25 -22
- data/ext/ffi_c/extconf.rb +5 -5
- data/spec/ffi/async_callback_spec.rb +2 -2
- data/spec/ffi/function_spec.rb +22 -8
- data/spec/ffi/pointer_spec.rb +33 -29
- data/spec/ffi/spec_helper.rb +16 -2
- data/spec/ffi/string_spec.rb +29 -13
- data/spec/ffi/struct_initialize_spec.rb +16 -1
- metadata +12 -43
- data/lib/ffi_c.bundle +0 -0
data/ext/ffi_c/MethodHandle.c
CHANGED
@@ -1,28 +1,20 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2009, Wayne Meissner
|
2
|
+
* Copyright (c) 2009, 2010 Wayne Meissner
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
5
|
-
*
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
5
|
+
* This file is part of ruby-ffi.
|
7
6
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* this list of conditions and the following disclaimer in the documentation
|
12
|
-
* and/or other materials provided with the distribution.
|
13
|
-
* * The name of the author or authors may not be used to endorse or promote
|
14
|
-
* products derived from this software without specific prior written permission.
|
7
|
+
* This code is free software: you can redistribute it and/or modify it under
|
8
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
9
|
+
* published by the Free Software Foundation.
|
15
10
|
*
|
16
|
-
*
|
17
|
-
*
|
18
|
-
*
|
19
|
-
*
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
23
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
14
|
+
* version 3 for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Lesser General Public License
|
17
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
26
18
|
*/
|
27
19
|
|
28
20
|
#include <sys/param.h>
|
@@ -57,10 +49,6 @@
|
|
57
49
|
|
58
50
|
#define MAX_METHOD_FIXED_ARITY (6)
|
59
51
|
|
60
|
-
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
61
|
-
# define USE_PTHREAD_LOCAL
|
62
|
-
#endif
|
63
|
-
|
64
52
|
#ifndef roundup
|
65
53
|
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
66
54
|
#endif
|
data/ext/ffi_c/Pointer.c
CHANGED
@@ -162,13 +162,19 @@ ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
|
|
162
162
|
static VALUE
|
163
163
|
ptr_inspect(VALUE self)
|
164
164
|
{
|
165
|
+
char buf[100];
|
165
166
|
Pointer* ptr;
|
166
167
|
|
167
168
|
Data_Get_Struct(self, Pointer, ptr);
|
168
169
|
|
169
|
-
|
170
|
-
|
171
|
-
|
170
|
+
if (ptr->memory.size != LONG_MAX) {
|
171
|
+
snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>",
|
172
|
+
rb_obj_classname(self), ptr->memory.address, ptr->memory.size);
|
173
|
+
} else {
|
174
|
+
snprintf(buf, sizeof(buf), "#<%s address=%p>", rb_obj_classname(self), ptr->memory.address);
|
175
|
+
}
|
176
|
+
|
177
|
+
return rb_str_new2(buf);
|
172
178
|
}
|
173
179
|
|
174
180
|
static VALUE
|
data/ext/ffi_c/Thread.c
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2010 Wayne Meissner
|
3
|
+
*
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This file is part of ruby-ffi.
|
7
|
+
*
|
8
|
+
* This code is free software: you can redistribute it and/or modify it under
|
9
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
10
|
+
* published by the Free Software Foundation.
|
11
|
+
*
|
12
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
13
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
14
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
15
|
+
* version 3 for more details.
|
16
|
+
*
|
17
|
+
* You should have received a copy of the GNU Lesser General Public License
|
18
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
#include <stdbool.h>
|
22
|
+
|
23
|
+
#ifndef _WIN32
|
24
|
+
# include <pthread.h>
|
25
|
+
# include <errno.h>
|
26
|
+
#endif
|
27
|
+
#include <fcntl.h>
|
28
|
+
#include "Thread.h"
|
29
|
+
|
30
|
+
|
31
|
+
#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
|
32
|
+
rbffi_thread_t rbffi_active_thread;
|
33
|
+
|
34
|
+
rbffi_thread_t
|
35
|
+
rbffi_thread_self()
|
36
|
+
{
|
37
|
+
rbffi_thread_t self;
|
38
|
+
self.id = pthread_self();
|
39
|
+
self.valid = true;
|
40
|
+
|
41
|
+
return self;
|
42
|
+
}
|
43
|
+
|
44
|
+
bool
|
45
|
+
rbffi_thread_equal(rbffi_thread_t* lhs, rbffi_thread_t* rhs)
|
46
|
+
{
|
47
|
+
return lhs->valid && rhs->valid && pthread_equal(lhs->id, rhs->id);
|
48
|
+
}
|
49
|
+
|
50
|
+
bool
|
51
|
+
rbffi_thread_has_gvl_p(void)
|
52
|
+
{
|
53
|
+
return rbffi_active_thread.valid && pthread_equal(rbffi_active_thread.id, pthread_self());
|
54
|
+
}
|
55
|
+
#endif // HAVE_RUBY_THREAD_HAS_GVL_P
|
56
|
+
|
57
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
58
|
+
struct BlockingThread {
|
59
|
+
pthread_t tid;
|
60
|
+
VALUE (*fn)(void *);
|
61
|
+
void *data;
|
62
|
+
void (*ubf)(void *);
|
63
|
+
void *data2;
|
64
|
+
VALUE retval;
|
65
|
+
int wrfd;
|
66
|
+
int rdfd;
|
67
|
+
};
|
68
|
+
|
69
|
+
typedef struct BlockingCall_ {
|
70
|
+
void* function;
|
71
|
+
void* info;
|
72
|
+
void **ffiValues;
|
73
|
+
void* retval;
|
74
|
+
} BlockingCall;
|
75
|
+
|
76
|
+
static void*
|
77
|
+
rbffi_blocking_thread(void* args)
|
78
|
+
{
|
79
|
+
struct BlockingThread* thr = (struct BlockingThread *) args;
|
80
|
+
char c = 1;
|
81
|
+
VALUE retval;
|
82
|
+
|
83
|
+
retval = (*thr->fn)(thr->data);
|
84
|
+
|
85
|
+
pthread_testcancel();
|
86
|
+
|
87
|
+
thr->retval = retval;
|
88
|
+
|
89
|
+
write(thr->wrfd, &c, sizeof(c));
|
90
|
+
|
91
|
+
return NULL;
|
92
|
+
}
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
wait_for_thread(void *data)
|
96
|
+
{
|
97
|
+
struct BlockingThread* thr = (struct BlockingThread *) data;
|
98
|
+
char c;
|
99
|
+
|
100
|
+
if (read(thr->rdfd, &c, 1) < 1) {
|
101
|
+
rb_thread_wait_fd(thr->rdfd);
|
102
|
+
while (read(thr->rdfd, &c, 1) < 1 && rb_io_wait_readable(thr->rdfd) == Qtrue) {
|
103
|
+
;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE
|
111
|
+
cleanup_blocking_thread(void *data, VALUE exc)
|
112
|
+
{
|
113
|
+
struct BlockingThread* thr = (struct BlockingThread *) data;
|
114
|
+
|
115
|
+
if (thr->ubf != (void (*)(void *)) -1) {
|
116
|
+
(*thr->ubf)(thr->data2);
|
117
|
+
} else {
|
118
|
+
pthread_kill(thr->tid, SIGVTALRM);
|
119
|
+
}
|
120
|
+
|
121
|
+
return exc;
|
122
|
+
}
|
123
|
+
|
124
|
+
VALUE
|
125
|
+
rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2)
|
126
|
+
{
|
127
|
+
struct BlockingThread* thr;
|
128
|
+
int fd[2];
|
129
|
+
VALUE exc;
|
130
|
+
|
131
|
+
if (pipe(fd) < 0) {
|
132
|
+
rb_raise(rb_eSystemCallError, "pipe(2) failed");
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
|
136
|
+
|
137
|
+
thr = ALLOC_N(struct BlockingThread, 1);
|
138
|
+
thr->rdfd = fd[0];
|
139
|
+
thr->wrfd = fd[1];
|
140
|
+
thr->fn = func;
|
141
|
+
thr->data = data1;
|
142
|
+
thr->ubf = ubf;
|
143
|
+
thr->data2 = data2;
|
144
|
+
thr->retval = Qnil;
|
145
|
+
|
146
|
+
if (pthread_create(&thr->tid, NULL, rbffi_blocking_thread, thr) != 0) {
|
147
|
+
close(fd[0]);
|
148
|
+
close(fd[1]);
|
149
|
+
xfree(thr);
|
150
|
+
rb_raise(rb_eSystemCallError, "pipe(2) failed");
|
151
|
+
return Qnil;
|
152
|
+
}
|
153
|
+
|
154
|
+
exc = rb_rescue2(wait_for_thread, (VALUE) thr, cleanup_blocking_thread, (VALUE) thr,
|
155
|
+
rb_eException);
|
156
|
+
|
157
|
+
pthread_join(thr->tid, NULL);
|
158
|
+
close(fd[1]);
|
159
|
+
close(fd[0]);
|
160
|
+
xfree(thr);
|
161
|
+
|
162
|
+
if (exc != Qnil) {
|
163
|
+
rb_exc_raise(exc);
|
164
|
+
}
|
165
|
+
|
166
|
+
return thr->retval;
|
167
|
+
}
|
168
|
+
|
169
|
+
#endif // HAVE_RB_THREAD_BLOCKING_REGION
|
data/ext/ffi_c/Thread.h
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2010 Wayne Meissner
|
3
|
+
*
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This file is part of ruby-ffi.
|
7
|
+
*
|
8
|
+
* This code is free software: you can redistribute it and/or modify it under
|
9
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
10
|
+
* published by the Free Software Foundation.
|
11
|
+
*
|
12
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
13
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
14
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
15
|
+
* version 3 for more details.
|
16
|
+
*
|
17
|
+
* You should have received a copy of the GNU Lesser General Public License
|
18
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
#ifndef THREAD_H
|
22
|
+
#define THREAD_H
|
23
|
+
|
24
|
+
#include <stdbool.h>
|
25
|
+
#include <ruby.h>
|
26
|
+
#include "extconf.h"
|
27
|
+
|
28
|
+
#ifdef __cplusplus
|
29
|
+
extern "C" {
|
30
|
+
#endif
|
31
|
+
|
32
|
+
|
33
|
+
#ifdef HAVE_RUBY_THREAD_HAS_GVL_P
|
34
|
+
# define rbffi_thread_has_gvl_p ruby_thread_has_gvl_p
|
35
|
+
#else
|
36
|
+
|
37
|
+
#include <pthread.h>
|
38
|
+
|
39
|
+
typedef struct {
|
40
|
+
pthread_t id;
|
41
|
+
bool valid;
|
42
|
+
} rbffi_thread_t;
|
43
|
+
|
44
|
+
extern rbffi_thread_t rbffi_active_thread;
|
45
|
+
rbffi_thread_t rbffi_thread_self();
|
46
|
+
bool rbffi_thread_equal(rbffi_thread_t* lhs, rbffi_thread_t* rhs);
|
47
|
+
bool rbffi_thread_has_gvl_p(void);
|
48
|
+
|
49
|
+
#endif
|
50
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
51
|
+
# define rbffi_thread_blocking_region rb_thread_blocking_region
|
52
|
+
#else
|
53
|
+
|
54
|
+
VALUE rbffi_thread_blocking_region(VALUE (*func)(void *), void *data1, void (*ubf)(void *), void *data2);
|
55
|
+
|
56
|
+
#endif
|
57
|
+
|
58
|
+
|
59
|
+
#ifdef __cplusplus
|
60
|
+
}
|
61
|
+
#endif
|
62
|
+
|
63
|
+
#endif /* THREAD_H */
|
64
|
+
|
data/ext/ffi_c/Type.c
CHANGED
@@ -95,12 +95,15 @@ type_alignment(VALUE self)
|
|
95
95
|
static VALUE
|
96
96
|
type_inspect(VALUE self)
|
97
97
|
{
|
98
|
+
char buf[100];
|
98
99
|
Type *type;
|
99
100
|
|
100
101
|
Data_Get_Struct(self, Type, type);
|
101
102
|
|
102
|
-
|
103
|
+
snprintf(buf, sizeof(buf), "#<%s:%p size=%d alignment=%d>",
|
103
104
|
rb_obj_classname(self), type, (int) type->ffiType->size, (int) type->ffiType->alignment);
|
105
|
+
|
106
|
+
return rb_str_new2(buf);
|
104
107
|
}
|
105
108
|
|
106
109
|
static VALUE
|
@@ -128,11 +131,14 @@ builtin_type_free(BuiltinType *type)
|
|
128
131
|
static VALUE
|
129
132
|
builtin_type_inspect(VALUE self)
|
130
133
|
{
|
134
|
+
char buf[100];
|
131
135
|
BuiltinType *type;
|
132
136
|
|
133
137
|
Data_Get_Struct(self, BuiltinType, type);
|
134
|
-
|
138
|
+
snprintf(buf, sizeof(buf), "#<%s:%s size=%d alignment=%d>",
|
135
139
|
rb_obj_classname(self), type->name, (int) type->type.ffiType->size, type->type.ffiType->alignment);
|
140
|
+
|
141
|
+
return rb_str_new2(buf);
|
136
142
|
}
|
137
143
|
|
138
144
|
int
|
data/ext/ffi_c/Types.c
CHANGED
@@ -41,7 +41,7 @@ static ID id_from_native = 0;
|
|
41
41
|
|
42
42
|
|
43
43
|
VALUE
|
44
|
-
rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr
|
44
|
+
rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr)
|
45
45
|
{
|
46
46
|
switch (type->nativeType) {
|
47
47
|
case NATIVE_VOID:
|
@@ -100,11 +100,10 @@ rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr, VALUE enums)
|
|
100
100
|
case NATIVE_MAPPED: {
|
101
101
|
// For mapped types, first convert to the real native type, then upcall to
|
102
102
|
// ruby to convert to the expected return type
|
103
|
-
MappedType* m;
|
103
|
+
MappedType* m = (MappedType *) type;
|
104
104
|
VALUE values[2];
|
105
105
|
|
106
|
-
|
107
|
-
values[0] = rbffi_NativeValue_ToRuby(m->type, m->rbType, ptr, enums);
|
106
|
+
values[0] = rbffi_NativeValue_ToRuby(m->type, m->rbType, ptr);
|
108
107
|
values[1] = Qnil;
|
109
108
|
|
110
109
|
return rb_funcall2(m->rbConverter, id_from_native, 2, values);
|
data/ext/ffi_c/Types.h
CHANGED
@@ -76,7 +76,7 @@ typedef enum {
|
|
76
76
|
#include <ffi.h>
|
77
77
|
#include "Type.h"
|
78
78
|
|
79
|
-
VALUE rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr
|
79
|
+
VALUE rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr);
|
80
80
|
void rbffi_Types_Init(VALUE moduleFFI);
|
81
81
|
|
82
82
|
#ifdef __cplusplus
|
data/ext/ffi_c/Variadic.c
CHANGED
@@ -1,28 +1,20 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2008
|
2
|
+
* Copyright (c) 2008-2010 Wayne Meissner
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
5
|
-
*
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
5
|
+
* This file is part of ruby-ffi.
|
7
6
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* this list of conditions and the following disclaimer in the documentation
|
12
|
-
* and/or other materials provided with the distribution.
|
13
|
-
* * The name of the author or authors may not be used to endorse or promote
|
14
|
-
* products derived from this software without specific prior written permission.
|
7
|
+
* This code is free software: you can redistribute it and/or modify it under
|
8
|
+
* the terms of the GNU Lesser General Public License version 3 only, as
|
9
|
+
* published by the Free Software Foundation.
|
15
10
|
*
|
16
|
-
*
|
17
|
-
*
|
18
|
-
*
|
19
|
-
*
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
23
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
|
+
* This code is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
14
|
+
* version 3 for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Lesser General Public License
|
17
|
+
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
26
18
|
*/
|
27
19
|
|
28
20
|
#include <sys/param.h>
|
@@ -44,6 +36,7 @@
|
|
44
36
|
#include "LastError.h"
|
45
37
|
#include "MethodHandle.h"
|
46
38
|
#include "Call.h"
|
39
|
+
#include "Thread.h"
|
47
40
|
|
48
41
|
typedef struct VariadicInvoker_ {
|
49
42
|
VALUE rbAddress;
|
@@ -159,7 +152,9 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
159
152
|
VALUE* argv;
|
160
153
|
int paramCount = 0, i;
|
161
154
|
ffi_status ffiStatus;
|
162
|
-
|
155
|
+
#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
|
156
|
+
rbffi_thread_t oldThread;
|
157
|
+
#endif
|
163
158
|
Check_Type(parameterTypes, T_ARRAY);
|
164
159
|
Check_Type(parameterValues, T_ARRAY);
|
165
160
|
|
@@ -229,12 +224,20 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
|
229
224
|
|
230
225
|
rbffi_SetupCallParams(paramCount, argv, -1, paramTypes, params,
|
231
226
|
ffiValues, NULL, 0, invoker->rbEnums);
|
227
|
+
#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
|
228
|
+
oldThread = rbffi_active_thread;
|
229
|
+
rbffi_active_thread = rbffi_thread_self();
|
230
|
+
#endif
|
232
231
|
|
233
232
|
ffi_call(&cif, invoker->function, retval, ffiValues);
|
234
233
|
|
234
|
+
#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
|
235
|
+
rbffi_active_thread = oldThread;
|
236
|
+
#endif
|
237
|
+
|
235
238
|
rbffi_save_errno();
|
236
239
|
|
237
|
-
return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, retval
|
240
|
+
return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, retval);
|
238
241
|
}
|
239
242
|
|
240
243
|
|