Skip to content

Commit 02b783d

Browse files
authored
Merge pull request #6697 from ahorek/ffi1_15_1
[ffi] update to 1.15.1
2 parents b537e2a + a7dc227 commit 02b783d

File tree

9 files changed

+136
-22
lines changed

9 files changed

+136
-22
lines changed

lib/pom.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def log(message=nil)
2222
['cmath', '1.0.0'],
2323
['csv', '3.1.2'],
2424
['e2mmap', '0.1.0'],
25-
['ffi', '1.14.2'],
25+
['ffi', '1.15.1'],
2626
['fileutils', '1.4.1'],
2727
['forwardable', '1.2.0'],
2828
['ipaddr', '1.2.2'],

lib/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ DO NOT MODIFIY - GENERATED CODE
9999
<dependency>
100100
<groupId>rubygems</groupId>
101101
<artifactId>ffi</artifactId>
102-
<version>1.14.2</version>
102+
<version>1.15.1</version>
103103
<type>gem</type>
104104
<scope>provided</scope>
105105
<exclusions>
@@ -564,7 +564,7 @@ DO NOT MODIFIY - GENERATED CODE
564564
<include>specifications/cmath-1.0.0*</include>
565565
<include>specifications/csv-3.1.2*</include>
566566
<include>specifications/e2mmap-0.1.0*</include>
567-
<include>specifications/ffi-1.14.2*</include>
567+
<include>specifications/ffi-1.15.1*</include>
568568
<include>specifications/fileutils-1.4.1*</include>
569569
<include>specifications/forwardable-1.2.0*</include>
570570
<include>specifications/ipaddr-1.2.2*</include>
@@ -603,7 +603,7 @@ DO NOT MODIFIY - GENERATED CODE
603603
<include>gems/cmath-1.0.0*/**/*</include>
604604
<include>gems/csv-3.1.2*/**/*</include>
605605
<include>gems/e2mmap-0.1.0*/**/*</include>
606-
<include>gems/ffi-1.14.2*/**/*</include>
606+
<include>gems/ffi-1.15.1*/**/*</include>
607607
<include>gems/fileutils-1.4.1*/**/*</include>
608608
<include>gems/forwardable-1.2.0*/**/*</include>
609609
<include>gems/ipaddr-1.2.2*/**/*</include>
@@ -642,7 +642,7 @@ DO NOT MODIFIY - GENERATED CODE
642642
<include>cache/cmath-1.0.0*</include>
643643
<include>cache/csv-3.1.2*</include>
644644
<include>cache/e2mmap-0.1.0*</include>
645-
<include>cache/ffi-1.14.2*</include>
645+
<include>cache/ffi-1.15.1*</include>
646646
<include>cache/fileutils-1.4.1*</include>
647647
<include>cache/forwardable-1.2.0*</include>
648648
<include>cache/ipaddr-1.2.2*</include>

spec/ffi/async_callback_spec.rb

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,35 @@ module LibTest
1919
skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
2020
v = 0xdeadbeef
2121
called = false
22-
cb = Proc.new {|i| v = i; called = true }
22+
cb = Proc.new {|i| v = i; called = Thread.current }
2323
LibTest.testAsyncCallback(cb, 0x7fffffff)
24-
expect(called).to be true
24+
expect(called).to be_kind_of(Thread)
25+
expect(called).to_not eq(Thread.current)
2526
expect(v).to eq(0x7fffffff)
2627
end
2728

2829
it "called a second time" do
2930
skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
30-
v = 0xdeadbeef
31-
called = false
32-
cb = Proc.new {|i| v = i; called = true }
33-
LibTest.testAsyncCallback(cb, 0x7fffffff)
34-
expect(called).to be true
35-
expect(v).to eq(0x7fffffff)
31+
v = 1
32+
th1 = th2 = false
33+
LibTest.testAsyncCallback(2) { |i| v += i; th1 = Thread.current }
34+
LibTest.testAsyncCallback(3) { |i| v += i; th2 = Thread.current }
35+
expect(th1).to be_kind_of(Thread)
36+
expect(th2).to be_kind_of(Thread)
37+
expect(th1).to_not eq(Thread.current)
38+
expect(th2).to_not eq(Thread.current)
39+
expect(th1).to_not eq(th2)
40+
expect(v).to eq(6)
41+
end
42+
43+
it "sets the name of the thread that runs the callback" do
44+
skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
45+
skip "not yet supported on JRuby" if RUBY_ENGINE == "jruby"
46+
47+
callback_runner_thread = nil
48+
49+
LibTest.testAsyncCallback(proc { callback_runner_thread = Thread.current }, 0)
50+
51+
expect(callback_runner_thread.name).to eq("FFI Callback Runner")
3652
end
3753
end

spec/ffi/callback_spec.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class S8F32S32 < FFI::Struct
4949
callback :cbVrU32, [ ], :uint
5050
callback :cbVrL, [ ], :long
5151
callback :cbVrUL, [ ], :ulong
52+
callback :cbVrF, [ ], :float
53+
callback :cbVrD, [ ], :double
5254
callback :cbVrS64, [ ], :long_long
5355
callback :cbVrU64, [ ], :ulong_long
5456
callback :cbVrP, [], :pointer
@@ -70,6 +72,8 @@ class S8F32S32 < FFI::Struct
7072
attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
7173
attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
7274
attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
75+
attach_function :testCallbackVrF, :testClosureVrF, [ :cbVrF ], :float
76+
attach_function :testCallbackVrD, :testClosureVrD, [ :cbVrD ], :double
7377
attach_function :testCallbackVrL, :testClosureVrL, [ :cbVrL ], :long
7478
attach_function :testCallbackVrZ, :testClosureVrZ, [ :cbVrZ ], :bool
7579
attach_function :testCallbackVrUL, :testClosureVrL, [ :cbVrUL ], :ulong
@@ -86,7 +90,6 @@ class S8F32S32 < FFI::Struct
8690
attach_variable :pVrS8, :gvar_pointer, :pointer
8791
attach_function :testGVarCallbackVrS8, :testClosureVrB, [ :pointer ], :char
8892
attach_function :testOptionalCallbackCrV, :testOptionalClosureBrV, [ :cbCrV, :char ], :void
89-
9093
end
9194

9295
it "returning :char (0)" do
@@ -261,6 +264,14 @@ class S8F32S32 < FFI::Struct
261264
expect(LibTest.testCallbackVrZ { true }).to be true
262265
end
263266

267+
it "returning float" do
268+
expect(LibTest.testCallbackVrF { 1.234567890123456789 }).to be_within(1E-7).of(1.234567890123456789)
269+
end
270+
271+
it "returning double" do
272+
expect(LibTest.testCallbackVrD { 1.234567890123456789 }).to be_within(1E-15).of(1.234567890123456789)
273+
end
274+
264275
it "returning :pointer (nil)" do
265276
expect(LibTest.testCallbackVrP { nil }).to be_null
266277
end

spec/ffi/fixtures/ClosureTest.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,38 @@
66

77
#include <stdlib.h>
88
#include <stdbool.h>
9+
#include <stdarg.h>
910
#ifndef _WIN32
1011
# include <pthread.h>
1112
#else
1213
# include <windows.h>
1314
# include <process.h>
1415
#endif
1516

17+
double testClosureVrDva(double d, ...) {
18+
va_list args;
19+
double (*closure)(void);
20+
21+
va_start(args, d);
22+
closure = va_arg(args, double (*)(void));
23+
va_end(args);
24+
25+
return d + closure();
26+
}
27+
28+
long testClosureVrILva(int i, long l, ...) {
29+
va_list args;
30+
int (*cl1)(int);
31+
long (*cl2)(long);
32+
33+
va_start(args, l);
34+
cl1 = va_arg(args, int (*)(int));
35+
cl2 = va_arg(args, long (*)(long));
36+
va_end(args);
37+
38+
return cl1(i) + cl2(l);
39+
}
40+
1641
#define R(T, rtype) rtype testClosureVr##T(rtype (*closure)(void)) { \
1742
return closure != NULL ? (*closure)() : (rtype) 0; \
1843
}

spec/ffi/fixtures/FunctionTest.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#ifdef _WIN32
88
#include <windows.h>
9+
#include <process.h>
910
#endif
1011

1112
#ifndef _WIN32
@@ -115,17 +116,26 @@ static void* asyncThreadCall(void *data)
115116
return NULL;
116117
}
117118

119+
#ifdef _WIN32
120+
static void
121+
asyncThreadCall_win32(void *arg)
122+
{
123+
asyncThreadCall(arg);
124+
}
125+
#endif
126+
118127
void testAsyncCallback(void (*fn)(int), int value)
119128
{
120-
#ifndef _WIN32
121-
pthread_t t;
122129
struct async_data d;
123130
d.fn = fn;
124131
d.value = value;
132+
#ifndef _WIN32
133+
pthread_t t;
125134
pthread_create(&t, NULL, asyncThreadCall, &d);
126135
pthread_join(t, NULL);
127136
#else
128-
(*fn)(value);
137+
HANDLE hThread = (HANDLE) _beginthread(asyncThreadCall_win32, 0, &d);
138+
WaitForSingleObject(hThread, INFINITE);
129139
#endif
130140
}
131141

spec/ffi/fork_spec.rb

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,59 @@
88
if Process.respond_to?(:fork)
99
describe "Callback in conjunction with fork()" do
1010

11-
module LibTest
11+
libtest = Module.new do
1212
extend FFI::Library
1313
ffi_lib TestLibrary::PATH
1414

1515
callback :cbVrL, [ ], :long
1616
attach_function :testCallbackVrL, :testClosureVrL, [ :cbVrL ], :long
17+
AsyncIntCallback = callback [ :int ], :void
18+
attach_function :testAsyncCallback, [ AsyncIntCallback, :int ], :void, blocking: true
1719
end
1820

1921
it "works with forked process and GC" do
20-
expect(LibTest.testCallbackVrL { 12345 }).to eq(12345)
22+
expect(libtest.testCallbackVrL { 12345 }).to eq(12345)
2123
fork do
22-
expect(LibTest.testCallbackVrL { 12345 }).to eq(12345)
24+
expect(libtest.testCallbackVrL { 12345 }).to eq(12345)
25+
Process.exit 42
2326
end
24-
expect(LibTest.testCallbackVrL { 12345 }).to eq(12345)
27+
expect(libtest.testCallbackVrL { 12345 }).to eq(12345)
2528
GC.start
29+
30+
expect(Process.wait2[1].exitstatus).to eq(42)
2631
end
2732

2833
it "works with forked process and free()" do
2934
cbf = FFI::Function.new(FFI::Type::LONG, []) { 234 }
3035

3136
fork do
3237
cbf.free
38+
Process.exit 43
3339
end
3440

35-
expect(LibTest.testCallbackVrL(cbf)).to eq(234)
41+
expect(libtest.testCallbackVrL(cbf)).to eq(234)
3642
cbf.free
43+
44+
expect(Process.wait2[1].exitstatus).to eq(43)
45+
end
46+
47+
def run_async_callback(libtest)
48+
recv = nil
49+
libtest.testAsyncCallback(proc { |r| recv = r }, 23)
50+
expect(recv).to eq(23)
51+
end
52+
53+
it "async thread dispatch works after forking" do
54+
run_async_callback(libtest)
55+
56+
fork do
57+
run_async_callback(libtest)
58+
Process.exit 44
59+
end
60+
61+
run_async_callback(libtest)
62+
63+
expect(Process.wait2[1].exitstatus).to eq(44)
3764
end
3865
end
3966
end

spec/ffi/function_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ module LibTest
2121
expect(fn.call).to eql 5
2222
end
2323

24+
context 'when called with a block' do
25+
it 'creates a thread for dispatching callbacks and sets its name' do
26+
skip 'this is MRI-specific' if RUBY_ENGINE == 'truffleruby' || RUBY_ENGINE == 'jruby'
27+
FFI::Function.new(:int, []) { 5 } # Trigger initialization
28+
29+
expect(Thread.list.map(&:name)).to include('FFI Callback Dispatcher')
30+
end
31+
end
32+
2433
it 'raises an error when passing a wrong signature' do
2534
expect { FFI::Function.new([], :int).new { } }.to raise_error TypeError
2635
end

spec/ffi/variadic_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@ module LibTest
1313
enum :enum_type2, [:c3, 42, :c4]
1414
attach_function :pack_varargs, [ :buffer_out, :string, :varargs ], :void
1515
attach_function :pack_varargs2, [ :buffer_out, :enum_type1, :string, :varargs ], :enum_type1
16+
callback :cbVrD, [ ], :double
17+
callback :cbVrI, [:int], :int
18+
callback :cbVrL, [:long], :long
1619

1720
attach_function :testBlockingOpen, [ ], :pointer
1821
attach_function :testBlockingRWva, [ :pointer, :char, :varargs ], :char, :blocking => true
1922
attach_function :testBlockingWRva, [ :pointer, :char, :varargs ], :char, :blocking => true
2023
attach_function :testBlockingClose, [ :pointer ], :void
24+
attach_function :testCallbackVrDva, :testClosureVrDva, [ :double, :varargs ], :double
25+
attach_function :testCallbackVrILva, :testClosureVrILva, [ :int, :long, :varargs ], :long
2126
end
2227

2328
it "takes enum arguments" do
@@ -77,6 +82,17 @@ module LibTest
7782
end
7883
end
7984

85+
it "call variadic with callback argument" do
86+
pr = proc { 42.0 }
87+
expect(LibTest.testCallbackVrDva(3.0, :cbVrD, pr)).to be_within(0.0000001).of(45.0)
88+
end
89+
90+
it "call variadic with several callback arguments" do
91+
pr1 = proc { |i| i + 1 }
92+
pr2 = proc { |l| l + 2 }
93+
expect(LibTest.testCallbackVrILva(5, 6, :cbVrI, pr1, :cbVrL, pr2)).to eq(14)
94+
end
95+
8096
module Varargs
8197
PACK_VALUES = {
8298
'c' => [ 0x12 ],

0 commit comments

Comments
 (0)