ffi 1.9.10 → 1.9.11

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.

@@ -64,6 +64,7 @@ typedef struct VariadicInvoker_ {
64
64
  ffi_abi abi;
65
65
  void* function;
66
66
  int paramCount;
67
+ bool blocking;
67
68
  } VariadicInvoker;
68
69
 
69
70
 
@@ -84,6 +85,7 @@ variadic_allocate(VALUE klass)
84
85
  invoker->rbAddress = Qnil;
85
86
  invoker->rbEnums = Qnil;
86
87
  invoker->rbReturnType = Qnil;
88
+ invoker->blocking = false;
87
89
 
88
90
  return obj;
89
91
  }
@@ -115,6 +117,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE
115
117
  invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums")));
116
118
  invoker->rbAddress = rbFunction;
117
119
  invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address;
120
+ invoker->blocking = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("blocking"))));
118
121
 
119
122
  #if defined(X86_WIN32)
120
123
  rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL);
@@ -253,7 +256,28 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues)
253
256
  ffiValues, NULL, 0, invoker->rbEnums);
254
257
 
255
258
  rbffi_frame_push(&frame);
259
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
260
+ /* In Call.c, blocking: true is supported on older ruby variants
261
+ * without rb_thread_call_without_gvl by allocating on the heap instead
262
+ * of the stack. Since this functionality is being added later,
263
+ * we’re skipping support for old rubies here. */
264
+ if(unlikely(invoker->blocking)) {
265
+ rbffi_blocking_call_t* bc;
266
+ bc = ALLOCA_N(rbffi_blocking_call_t, 1);
267
+ bc->retval = retval;
268
+ bc->function = invoker->function;
269
+ bc->ffiValues = ffiValues;
270
+ bc->params = params;
271
+ bc->frame = &frame;
272
+ bc->cif = cif;
273
+
274
+ rb_rescue2(rbffi_do_blocking_call, (VALUE) bc, rbffi_save_frame_exception, (VALUE) &frame, rb_eException, (VALUE) 0);
275
+ } else {
276
+ ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues);
277
+ }
278
+ #else
256
279
  ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues);
280
+ #endif
257
281
  rbffi_frame_pop(&frame);
258
282
 
259
283
  rbffi_save_errno();
@@ -75,9 +75,4 @@
75
75
  # define RB_GC_GUARD(x) (x)
76
76
  #endif
77
77
 
78
- #ifndef RB_GC_GUARD_PTR
79
- # define RB_GC_GUARD_PTR(x) (x)
80
- #endif
81
-
82
78
  #endif /* RBFFI_COMPAT_H */
83
-
@@ -76,6 +76,7 @@ static void ffi_prep_args(char *stack,
76
76
  void **p_argv;
77
77
  char *argp;
78
78
  ffi_type **p_arg;
79
+ int ecif_test;
79
80
 
80
81
  #ifdef FFI_MIPS_N32
81
82
  /* If more than 8 double words are used, the remainder go
@@ -92,10 +93,11 @@ static void ffi_prep_args(char *stack,
92
93
  memset(stack, 0, bytes);
93
94
 
94
95
  #ifdef FFI_MIPS_N32
95
- if ( ecif->cif->rstruct_flag != 0 )
96
+ ecif_test = ecif->cif->rstruct_flag != 0;
96
97
  #else
97
- if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
98
+ ecif_test = ecif->cif->rtype->type == FFI_TYPE_STRUCT;
98
99
  #endif
100
+ if (ecif_test)
99
101
  {
100
102
  *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
101
103
  argp += sizeof(ffi_arg);
@@ -7,7 +7,7 @@
7
7
 
8
8
  #include <sys/types.h>
9
9
 
10
- #if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || defined(__GLIBC__)
10
+ #if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || defined(__GLIBC__) || defined(__HAIKU__)
11
11
  # include <endian.h>
12
12
  # if !defined(LITTLE_ENDIAN) && defined(__LITTLE_ENDIAN)
13
13
  # define LITTLE_ENDIAN __LITTLE_ENDIAN
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.required_ruby_version = '>= 1.8.7'
18
18
  s.add_development_dependency 'rake', '~> 10.1'
19
19
  s.add_development_dependency 'rake-compiler', '~> 0.9'
20
- s.add_development_dependency 'rake-compiler-dock', '~> 0.4.0'
20
+ s.add_development_dependency 'rake-compiler-dock', '~> 0.5.2'
21
21
  s.add_development_dependency 'rspec', '~> 2.14.1'
22
22
  s.add_development_dependency 'rubygems-tasks', "~> 0.2.4"
23
23
  end
@@ -34,27 +34,29 @@ module FFI
34
34
  extend DataConverter
35
35
 
36
36
  # @overload initialize(pointer, method)
37
- # @param [Pointer] pointer
38
- # @param [Method] method
39
- # @return [self]
40
- # The passed Method will be invoked at GC time.
37
+ # @param pointer [Pointer]
38
+ # @param method [Method]
39
+ # @return [self]
40
+ # The passed Method will be invoked at GC time.
41
41
  # @overload initialize(pointer, proc)
42
- # @param [Pointer] pointer
43
- # @return [self]
44
- # The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
45
- # @note WARNING: passing a proc _may_ cause your pointer to never be GC'd, unless you're
46
- # careful to avoid trapping a reference to the pointer in the proc. See the test
47
- # specs for examples.
42
+ # @param pointer [Pointer]
43
+ # @return [self]
44
+ # The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
45
+ # @note WARNING: passing a proc _may_ cause your pointer to never be
46
+ # GC'd, unless you're careful to avoid trapping a reference to the
47
+ # pointer in the proc. See the test specs for examples.
48
48
  # @overload initialize(pointer) { |p| ... }
49
- # @param [Pointer] pointer
50
- # @yieldparam [Pointer] p +pointer+ passed to the block
51
- # @return [self]
52
- # The passed block will be invoked at GC time.
53
- # @note WARNING: passing a block will cause your pointer to never be GC'd. This is bad.
49
+ # @param pointer [Pointer]
50
+ # @yieldparam [Pointer] p +pointer+ passed to the block
51
+ # @return [self]
52
+ # The passed block will be invoked at GC time.
53
+ # @note
54
+ # WARNING: passing a block will cause your pointer to never be GC'd.
55
+ # This is bad.
54
56
  # @overload initialize(pointer)
55
- # @param [Pointer] pointer
56
- # @return [self]
57
- # The pointer's release() class method will be invoked at GC time.
57
+ # @param pointer [Pointer]
58
+ # @return [self]
59
+ # The pointer's release() class method will be invoked at GC time.
58
60
  #
59
61
  # @note The safest, and therefore preferred, calling
60
62
  # idiom is to pass a Method as the second parameter. Example usage:
@@ -79,11 +81,15 @@ module FFI
79
81
  || ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
80
82
 
81
83
  @releaser = if proc
82
- raise RuntimeError.new("proc must be callable") unless proc.respond_to?(:call)
84
+ if not proc.respond_to?(:call)
85
+ raise RuntimeError.new("proc must be callable")
86
+ end
83
87
  CallableReleaser.new(ptr, proc)
84
88
 
85
89
  else
86
- raise RuntimeError.new("no release method defined") unless self.class.respond_to?(:release)
90
+ if not self.class.respond_to?(:release)
91
+ raise RuntimeError.new("no release method defined")
92
+ end
87
93
  DefaultReleaser.new(ptr, self.class)
88
94
  end
89
95
 
@@ -143,16 +149,15 @@ module FFI
143
149
  def call(*args)
144
150
  release(@ptr) if @autorelease && @ptr
145
151
  end
146
-
147
152
  end
148
153
 
149
- # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined without Proc
150
- # or Method. In this case, the pointer to release must be of a class derived from
151
- # AutoPointer with a +#release+ class method.
154
+ # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined
155
+ # without Proc or Method. In this case, the pointer to release must be of
156
+ # a class derived from AutoPointer with a {release} class method.
152
157
  class DefaultReleaser < Releaser
153
158
  # @param [Pointer] ptr
154
159
  # @return [nil]
155
- # Release +ptr+ by using his #release class method.
160
+ # Release +ptr+ using the {release} class method of its class.
156
161
  def release(ptr)
157
162
  @proc.release(ptr)
158
163
  end
@@ -161,7 +166,9 @@ module FFI
161
166
  # CallableReleaser is a {Releaser} used when an {AutoPointer} is defined with a
162
167
  # Proc or a Method.
163
168
  class CallableReleaser < Releaser
164
- # Release +ptr+ by using Proc or Method defined at +ptr+ {AutoPointer#initialize initialization}.
169
+ # Release +ptr+ by using Proc or Method defined at +ptr+
170
+ # {AutoPointer#initialize initialization}.
171
+ #
165
172
  # @param [Pointer] ptr
166
173
  # @return [nil]
167
174
  def release(ptr)
@@ -175,7 +182,9 @@ module FFI
175
182
  # @return [Type::POINTER]
176
183
  # @raise {RuntimeError} if class does not implement a +#release+ method
177
184
  def self.native_type
178
- raise RuntimeError.new("no release method defined for #{self.inspect}") unless self.respond_to?(:release)
185
+ if not self.respond_to?(:release)
186
+ raise RuntimeError.new("no release method defined for #{self.inspect}")
187
+ end
179
188
  Type::POINTER
180
189
  end
181
190
 
@@ -146,7 +146,7 @@ module FFI
146
146
  def symbol_map
147
147
  @kv_map
148
148
  end
149
-
149
+
150
150
  alias to_h symbol_map
151
151
  alias to_hash symbol_map
152
152
 
@@ -168,7 +168,5 @@ module FFI
168
168
  def from_native(val, ctx)
169
169
  @vk_map[val] || val
170
170
  end
171
-
172
171
  end
173
-
174
172
  end
@@ -109,6 +109,7 @@ module FFI
109
109
 
110
110
  libnames.each do |libname|
111
111
  begin
112
+ orig = libname
112
113
  lib = FFI::DynamicLibrary.open(libname, lib_flags)
113
114
  break if lib
114
115
 
@@ -121,10 +122,22 @@ module FFI
121
122
  end
122
123
  end
123
124
 
125
+ # TODO better library lookup logic
126
+ unless libname.start_with?("/")
127
+ path = ['/usr/lib/','/usr/local/lib/'].find do |pth|
128
+ File.exist?(pth + libname)
129
+ end
130
+ if path
131
+ libname = path + libname
132
+ retry
133
+ end
134
+ end
135
+
124
136
  if ldscript
125
137
  retry
126
138
  else
127
- errors[libname] = ex
139
+ libr = (orig == libname ? orig : "#{orig} #{libname}")
140
+ errors[libr] = ex
128
141
  end
129
142
  end
130
143
  end
@@ -33,7 +33,7 @@
33
33
  require 'ffi/platform'
34
34
  module FFI
35
35
  class Pointer
36
-
36
+
37
37
  # Pointer size
38
38
  SIZE = Platform::ADDRESS_SIZE / 8
39
39
 
@@ -341,7 +341,7 @@ module FFI
341
341
  # @raise if Ruby 1.8
342
342
  # Add hash +spec+ to +builder+.
343
343
  def hash_layout(builder, spec)
344
- raise "Ruby version not supported" if RUBY_VERSION =~ /1\.8\.*/
344
+ raise "Ruby version not supported" if RUBY_VERSION =~ /^1\.8\..*/
345
345
  spec[0].each do |name, type|
346
346
  builder.add name, find_field_type(type), nil
347
347
  end
@@ -1,7 +1,7 @@
1
1
  require 'tempfile'
2
2
 
3
3
  module FFI
4
-
4
+
5
5
  # @private
6
6
  class TypesGenerator
7
7
 
@@ -65,7 +65,7 @@ module FFI
65
65
  typedefs = `#{cmd} #{io.path}`
66
66
  end
67
67
  end
68
-
68
+
69
69
  code = ""
70
70
 
71
71
  typedefs.each_line do |type|
@@ -73,11 +73,11 @@ module FFI
73
73
  next unless type =~ /typedef/
74
74
  # Ignore unions or structs
75
75
  next if type =~ /union|struct/
76
-
76
+
77
77
  # strip off the starting typedef and ending ;
78
78
  type.gsub!(/^(.*typedef\s*)/, "")
79
79
  type.gsub!(/\s*;\s*$/, "")
80
-
80
+
81
81
  parts = type.split(/\s+/)
82
82
  def_type = parts.join(" ")
83
83
 
@@ -99,7 +99,7 @@ module FFI
99
99
  else
100
100
  final_type = parts.pop
101
101
  end
102
-
102
+
103
103
  def_type = case type
104
104
  when /__QI__/ then "char"
105
105
  when /__HI__/ then "short"
@@ -114,7 +114,7 @@ module FFI
114
114
  final_type = parts.pop
115
115
  def_type = parts.join(" ")
116
116
  end
117
-
117
+
118
118
  if type = TYPE_MAP[def_type]
119
119
  code << "rbx.platform.typedef.#{final_type} = #{type}\n"
120
120
  TYPE_MAP[final_type] = TYPE_MAP[def_type]
@@ -129,7 +129,6 @@ module FFI
129
129
 
130
130
  code
131
131
  end
132
-
133
132
  end
134
133
  end
135
134
 
@@ -65,7 +65,6 @@ module FFI
65
65
 
66
66
  elsif name.is_a?(DataConverter)
67
67
  (type_map || TypeDefs)[name] = Type::Mapped.new(name)
68
-
69
68
  else
70
69
  raise TypeError, "unable to resolve type '#{name}'"
71
70
  end
@@ -149,19 +148,24 @@ module FFI
149
148
  :varargs => Type::VARARGS,
150
149
  })
151
150
 
152
-
151
+ # This will convert a pointer to a Ruby string (just like `:string`), but
152
+ # also allow to work with the pointer itself. This is useful when you want
153
+ # a Ruby string already containing a copy of the data, but also the pointer
154
+ # to the data for you to do something with it, like freeing it, in case the
155
+ # library handed the memory to off to the caller (Ruby-FFI).
156
+ #
157
+ # It's {typedef}'d as +:strptr+.
153
158
  class StrPtrConverter
154
159
  extend DataConverter
155
160
  native_type Type::POINTER
156
161
 
157
162
  # @param [Pointer] val
158
- # @param ctx
163
+ # @param ctx not used
159
164
  # @return [Array(String, Pointer)]
160
165
  # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
161
166
  def self.from_native(val, ctx)
162
167
  [ val.null? ? nil : val.get_string(0), val ]
163
168
  end
164
-
165
169
  end
166
170
 
167
171
  typedef(StrPtrConverter, :strptr)
@@ -1,4 +1,4 @@
1
1
  module FFI
2
- VERSION = '1.9.10'
2
+ VERSION = '1.9.11'
3
3
  end
4
4
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  #ifdef _WIN32
8
8
  #include <windows.h>
9
- #define sleep(x) Sleep(x)
9
+ #define sleep(x) Sleep((x)*1000)
10
10
  #endif
11
11
 
12
12
  #ifndef _WIN32
@@ -60,3 +60,40 @@ void pack_varargs(s64* buf, const char* fmt, ...)
60
60
  va_end(ap);
61
61
  }
62
62
 
63
+ int pack_varargs2(s64* buf, int retval, const char* fmt, ...)
64
+ {
65
+ va_list ap;
66
+ int c;
67
+ double d;
68
+ va_start(ap, fmt);
69
+ while ((c = *fmt++)) {
70
+ switch (c) {
71
+ case 'c':
72
+ case 's':
73
+ case 'i':
74
+ *buf++ = va_arg(ap, s32);
75
+ break;
76
+ case 'l':
77
+ *buf++ = va_arg(ap, long);
78
+ break;
79
+ case 'j':
80
+ *buf++ = va_arg(ap, s64);
81
+ break;
82
+ case 'f':
83
+ case 'd':
84
+ d = va_arg(ap, double);
85
+ memcpy(buf++, &d, sizeof(d));
86
+ break;
87
+ case 'C':
88
+ case 'S':
89
+ case 'I':
90
+ *buf++ = va_arg(ap, u32);
91
+ break;
92
+ case 'L':
93
+ *buf++ = va_arg(ap, unsigned long);
94
+ break;
95
+ }
96
+ }
97
+ va_end(ap);
98
+ return retval + 1;
99
+ }
@@ -50,6 +50,21 @@ P(D, double);
50
50
  P(P, const void*);
51
51
  P(UL, unsigned long);
52
52
 
53
+ #if defined(_WIN32) && !defined(_WIN64)
54
+ bool __stdcall testClosureStdcall(long *a1, void __stdcall(*closure)(void *, long), long a2) { \
55
+ void* sp_pre;
56
+ void* sp_post;
57
+
58
+ asm volatile (" movl %%esp,%0" : "=g" (sp_pre));
59
+ (*closure)(a1, a2);
60
+ asm volatile (" movl %%esp,%0" : "=g" (sp_post));
61
+
62
+ /* %esp before pushing parameters on the stack and after the call returns
63
+ * should be equal, if both sides respects the stdcall convention */
64
+ return sp_pre == sp_post;
65
+ }
66
+ #endif
67
+
53
68
  void testOptionalClosureBrV(void (*closure)(char), char a1)
54
69
  {
55
70
  if (closure) {