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.

@@ -6,14 +6,17 @@
6
6
 
7
7
  #ifdef _WIN32
8
8
  #include <windows.h>
9
- #define sleep(x) Sleep(x)
10
9
  #endif
11
10
 
12
11
  #ifndef _WIN32
13
12
  #include <unistd.h>
14
13
  #include <pthread.h>
14
+ #include <stdarg.h>
15
+ #include <stdlib.h>
15
16
  #endif
16
17
 
18
+ #include "PipeHelper.h"
19
+
17
20
  int testAdd(int a, int b)
18
21
  {
19
22
  return a + b;
@@ -24,10 +27,79 @@ int testFunctionAdd(int a, int b, int (*f)(int, int))
24
27
  return f(a, b);
25
28
  };
26
29
 
27
- void testBlocking(int seconds) {
28
- sleep(seconds);
30
+ struct testBlockingData {
31
+ FD_TYPE pipe1[2];
32
+ FD_TYPE pipe2[2];
29
33
  };
30
34
 
35
+ struct testBlockingData *testBlockingOpen()
36
+ {
37
+ struct testBlockingData *self = malloc(sizeof(struct testBlockingData));
38
+
39
+ if( pipeHelperCreatePipe(self->pipe1) == -1 ) return NULL;
40
+ if( pipeHelperCreatePipe(self->pipe2) == -1 ) return NULL;
41
+ return self;
42
+ }
43
+
44
+ char testBlockingWR(struct testBlockingData *self, char c) {
45
+ if( pipeHelperWriteChar(self->pipe1[1], c) != 1)
46
+ return 0;
47
+ return pipeHelperReadChar(self->pipe2[0], 10);
48
+ }
49
+
50
+ char testBlockingRW(struct testBlockingData *self, char c) {
51
+ char d = pipeHelperReadChar(self->pipe1[0], 10);
52
+ if( pipeHelperWriteChar(self->pipe2[1], c) != 1)
53
+ return 0;
54
+ return d;
55
+ }
56
+
57
+ void testBlockingClose(struct testBlockingData *self) {
58
+ pipeHelperClosePipe(self->pipe1[0]);
59
+ pipeHelperClosePipe(self->pipe1[1]);
60
+ pipeHelperClosePipe(self->pipe2[0]);
61
+ pipeHelperClosePipe(self->pipe2[1]);
62
+ free(self);
63
+ }
64
+
65
+ static int sum_varargs(va_list args) {
66
+ char sum = 0;
67
+ int arg;
68
+ while ((arg = va_arg(args, int)) != 0) {
69
+ sum += arg;
70
+ }
71
+ va_end(args);
72
+ return sum;
73
+ }
74
+
75
+ /* Write c to pipe1 and return the value read from pipe2, or 0 if there’s
76
+ * an error such as a timeout, or if c does not equal the sum of the
77
+ * zero-terminated list of char arguments. */
78
+ char testBlockingWRva(struct testBlockingData *self, char c, ...) {
79
+ va_list args;
80
+ va_start(args, c);
81
+ if (sum_varargs(args) != c) {
82
+ return 0;
83
+ }
84
+
85
+ if( pipeHelperWriteChar(self->pipe1[1], c) != 1)
86
+ return 0;
87
+ return pipeHelperReadChar(self->pipe2[0], 10);
88
+ }
89
+
90
+ char testBlockingRWva(struct testBlockingData *self, char c, ...) {
91
+ va_list args;
92
+ va_start(args, c);
93
+ if (sum_varargs(args) != c) {
94
+ return 0;
95
+ }
96
+
97
+ char d = pipeHelperReadChar(self->pipe1[0], 10);
98
+ if( pipeHelperWriteChar(self->pipe2[1], c) != 1)
99
+ return 0;
100
+ return d;
101
+ }
102
+
31
103
  struct async_data {
32
104
  void (*fn)(int);
33
105
  int value;
@@ -55,4 +127,16 @@ void testAsyncCallback(void (*fn)(int), int value)
55
127
  #else
56
128
  (*fn)(value);
57
129
  #endif
58
- }
130
+ }
131
+
132
+ #if defined(_WIN32) && !defined(_WIN64)
133
+ struct StructUCDP {
134
+ unsigned char a1;
135
+ double a2;
136
+ void *a3;
137
+ };
138
+
139
+ void __stdcall testStdcallManyParams(long *a1, char a2, short int a3, int a4, __int64 a5,
140
+ struct StructUCDP a6, struct StructUCDP *a7, float a8, double a9) {
141
+ }
142
+ #endif
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright (c) 2015 Lars Kanis. All rights reserved.
3
+ *
4
+ * For licensing, see LICENSE.SPECS
5
+ */
6
+
7
+ #ifndef PIPEHELPER_H
8
+ #define PIPEHELPER_H
9
+
10
+ #ifdef _WIN32
11
+ #define FD_TYPE HANDLE
12
+ #else
13
+ #define FD_TYPE int
14
+ #endif
15
+
16
+ int pipeHelperCreatePipe(FD_TYPE pipefd[2]);
17
+ char pipeHelperReadChar(FD_TYPE fd, int timeout);
18
+ int pipeHelperWriteChar(FD_TYPE fd, char c);
19
+ void pipeHelperClosePipe(FD_TYPE fd);
20
+
21
+ #endif
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright (c) 2015 Lars Kanis. All rights reserved.
3
+ *
4
+ * For licensing, see LICENSE.SPECS
5
+ */
6
+
7
+ #ifndef _WIN32
8
+ #include <unistd.h>
9
+ #include <sys/time.h>
10
+ #include "PipeHelper.h"
11
+
12
+ int pipeHelperCreatePipe(FD_TYPE pipefd[2])
13
+ {
14
+ return pipe(pipefd);
15
+ }
16
+
17
+ char pipeHelperReadChar(FD_TYPE fd, int timeout)
18
+ {
19
+ char d;
20
+ struct timeval time = {timeout, 0}; // timeout after x seconds
21
+ fd_set read_fds;
22
+ FD_ZERO(&read_fds);
23
+ FD_SET(fd, &read_fds);
24
+
25
+ if(select(fd + 1, &read_fds, NULL, NULL, &time) <= 0)
26
+ return 0;
27
+
28
+ if( read(fd, &d, 1) != 1)
29
+ return 0;
30
+ return d;
31
+ }
32
+
33
+ int pipeHelperWriteChar(FD_TYPE fd, char c)
34
+ {
35
+ return write(fd, &c, 1);
36
+ }
37
+
38
+ void pipeHelperClosePipe(FD_TYPE fd) {
39
+ close(fd);
40
+ }
41
+ #endif
@@ -0,0 +1,72 @@
1
+ /*
2
+ * Copyright (c) 2007 Wayne Meissner. All rights reserved.
3
+ *
4
+ * For licensing, see LICENSE.SPECS
5
+ */
6
+
7
+ #ifdef _WIN32
8
+ #include <windows.h>
9
+ #include "PipeHelper.h"
10
+
11
+ int pipeHelperCreatePipe(FD_TYPE pipefd[2])
12
+ {
13
+ char name[ MAX_PATH ];
14
+ static int pipe_idx = 0;
15
+ sprintf( name, "\\\\.\\Pipe\\pipeHelper-%u-%i",
16
+ (unsigned int)GetCurrentProcessId(), pipe_idx++ );
17
+
18
+ pipefd[0] = CreateNamedPipe( name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
19
+ PIPE_TYPE_BYTE | PIPE_WAIT,
20
+ 1, // Number of pipes
21
+ 5, // Out buffer size
22
+ 5, // In buffer size
23
+ 60 * 1000, // Timeout in ms
24
+ NULL );
25
+ if(pipefd[0] == INVALID_HANDLE_VALUE)
26
+ return -1;
27
+
28
+ pipefd[1] = CreateFile( name, GENERIC_WRITE, 0, NULL,
29
+ OPEN_EXISTING,
30
+ FILE_ATTRIBUTE_NORMAL,
31
+ NULL);
32
+
33
+ if(pipefd[1] == INVALID_HANDLE_VALUE) {
34
+ CloseHandle( pipefd[0] );
35
+ return -1;
36
+ }
37
+ return 0;
38
+ }
39
+
40
+ char pipeHelperReadChar(FD_TYPE fd, int timeout)
41
+ {
42
+ char d;
43
+ OVERLAPPED ovl;
44
+ ZeroMemory(&ovl, sizeof(ovl));
45
+ ovl.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
46
+ if( ReadFile(fd, &d, 1, NULL, &ovl) == 0) {
47
+ DWORD recvd = 0;;
48
+ DWORD res = WaitForSingleObject(ovl.hEvent, timeout * 1000);
49
+ if( res != WAIT_OBJECT_0 ) {
50
+ CloseHandle(ovl.hEvent);
51
+ return 0;
52
+ }
53
+ if( GetOverlappedResult(fd, &ovl, &recvd, FALSE) == 0 ) {
54
+ CloseHandle(ovl.hEvent);
55
+ return 0;
56
+ }
57
+ }
58
+ CloseHandle(ovl.hEvent);
59
+ return d;
60
+ }
61
+
62
+ int pipeHelperWriteChar(FD_TYPE fd, char c)
63
+ {
64
+ DWORD written;
65
+ return WriteFile(fd, &c, 1, &written, NULL) == 0 ? 0 : 1;
66
+ }
67
+
68
+ void pipeHelperClosePipe(FD_TYPE fd) {
69
+ CloseHandle(fd);
70
+ }
71
+
72
+ #endif
@@ -12,7 +12,7 @@ describe FFI::Function do
12
12
  attach_function :testFunctionAdd, [:int, :int, :pointer], :int
13
13
  end
14
14
  before do
15
- @libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
15
+ @libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
16
16
  FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
17
17
  end
18
18
 
@@ -22,7 +22,7 @@ describe FFI::Function do
22
22
  end
23
23
 
24
24
  it 'raises an error when passing a wrong signature' do
25
- expect { FFI::Function.new([], :int).new { } }.to raise_error TypeError
25
+ expect { FFI::Function.new([], :int).new { } }.to raise_error TypeError
26
26
  end
27
27
 
28
28
  it 'returns a native pointer' do
@@ -63,15 +63,20 @@ describe FFI::Function do
63
63
  end
64
64
 
65
65
  it 'can wrap a blocking function' do
66
- fp = FFI::Function.new(:void, [ :int ], @libtest.find_function('testBlocking'), :blocking => true)
67
- threads = 10.times.map do |x|
68
- Thread.new do
69
- time = Time.now
70
- fp.call(2)
71
- expect(Time.now - time).to be >= 2
72
- end
66
+ fpOpen = FFI::Function.new(:pointer, [ ], @libtest.find_function('testBlockingOpen'))
67
+ fpRW = FFI::Function.new(:char, [ :pointer, :char ], @libtest.find_function('testBlockingRW'), :blocking => true)
68
+ fpWR = FFI::Function.new(:char, [ :pointer, :char ], @libtest.find_function('testBlockingWR'), :blocking => true)
69
+ fpClose = FFI::Function.new(:void, [ :pointer ], @libtest.find_function('testBlockingClose'))
70
+ handle = fpOpen.call
71
+ expect(handle).not_to be_null
72
+ begin
73
+ thWR = Thread.new { fpWR.call(handle, 63) }
74
+ thRW = Thread.new { fpRW.call(handle, 64) }
75
+ expect(thWR.value).to eq(64)
76
+ expect(thRW.value).to eq(63)
77
+ ensure
78
+ fpClose.call(handle)
73
79
  end
74
- threads.each { |t| t.join }
75
80
  end
76
81
 
77
82
  it 'autorelease flag is set to true by default' do
@@ -5,29 +5,30 @@
5
5
 
6
6
  require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
7
 
8
- class Timeval < FFI::Struct
9
- layout :tv_sec, :ulong, 0, :tv_usec, :ulong, 4
10
- end
11
-
12
- module LibC
13
- extend FFI::Library
14
- ffi_lib FFI::Library::LIBC
8
+ unless FFI::Platform.windows?
9
+ class Timeval < FFI::Struct
10
+ layout :tv_sec, :ulong, 0, :tv_usec, :ulong, 4
11
+ end
15
12
 
16
- attach_function :gettimeofday, [:pointer, :pointer], :int
17
- end
13
+ module LibC
14
+ extend FFI::Library
15
+ ffi_lib FFI::Library::LIBC
18
16
 
19
- describe FFI::Library, "#attach_function" do
20
- it "correctly returns a value for gettimeofday" do
21
- t = Timeval.new
22
- time = LibC.gettimeofday(t.pointer, nil)
23
- expect(time).to be_kind_of(Integer)
17
+ attach_function :gettimeofday, [:pointer, :pointer], :int
24
18
  end
25
-
26
- it "correctly populates a struct for gettimeofday" do
27
- t = Timeval.new
28
- LibC.gettimeofday(t.pointer, nil)
29
- expect(t[:tv_sec]).to be_kind_of(Numeric)
30
- expect(t[:tv_usec]).to be_kind_of(Numeric)
19
+
20
+ describe FFI::Library, "#attach_function" do
21
+ it "correctly returns a value for gettimeofday" do
22
+ t = Timeval.new
23
+ time = LibC.gettimeofday(t.pointer, nil)
24
+ expect(time).to be_kind_of(Integer)
25
+ end
26
+
27
+ it "correctly populates a struct for gettimeofday" do
28
+ t = Timeval.new
29
+ LibC.gettimeofday(t.pointer, nil)
30
+ expect(t[:tv_sec]).to be_kind_of(Numeric)
31
+ expect(t[:tv_usec]).to be_kind_of(Numeric)
32
+ end
31
33
  end
32
34
  end
33
-
@@ -7,7 +7,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
7
 
8
8
  describe "Struct aligns fields correctly" do
9
9
  it "char, followed by an int" do
10
- pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
10
+ pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
11
11
  class CIStruct < FFI::Struct
12
12
  layout :c => :char, :i => :int
13
13
  end
@@ -15,7 +15,7 @@ describe "Struct aligns fields correctly" do
15
15
  end
16
16
 
17
17
  it "short, followed by an int" do
18
- pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
18
+ pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
19
19
  class SIStruct < FFI::Struct
20
20
  layout :s => :short, :i => :int
21
21
  end
@@ -23,7 +23,7 @@ describe "Struct aligns fields correctly" do
23
23
  end
24
24
 
25
25
  it "int, followed by an int" do
26
- pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
26
+ pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
27
27
  class IIStruct < FFI::Struct
28
28
  layout :i1 => :int, :i => :int
29
29
  end
@@ -31,7 +31,7 @@ describe "Struct aligns fields correctly" do
31
31
  end
32
32
 
33
33
  it "long long, followed by an int" do
34
- pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
34
+ pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
35
35
  class LLIStruct < FFI::Struct
36
36
  layout :l => :long_long, :i => :int
37
37
  end
@@ -13,6 +13,11 @@ describe "Function with variadic arguments" do
13
13
  enum :enum_type2, [:c3, 42, :c4]
14
14
  attach_function :pack_varargs, [ :buffer_out, :string, :varargs ], :void
15
15
  attach_function :pack_varargs2, [ :buffer_out, :enum_type1, :string, :varargs ], :enum_type1
16
+
17
+ attach_function :testBlockingOpen, [ ], :pointer
18
+ attach_function :testBlockingRWva, [ :pointer, :char, :varargs ], :char, :blocking => true
19
+ attach_function :testBlockingWRva, [ :pointer, :char, :varargs ], :char, :blocking => true
20
+ attach_function :testBlockingClose, [ :pointer ], :void
16
21
  end
17
22
 
18
23
  it "takes enum arguments" do
@@ -27,6 +32,20 @@ describe "Function with variadic arguments" do
27
32
  expect(LibTest.pack_varargs2(buf, :c1, "ii", :int, :c3, :int, :c4)).to eq(:c2)
28
33
  end
29
34
 
35
+ it 'can wrap a blocking function with varargs' do
36
+ pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
37
+ handle = LibTest.testBlockingOpen
38
+ expect(handle).not_to be_null
39
+ begin
40
+ thWR = Thread.new { LibTest.testBlockingWRva(handle, 63, :int, 40, :int, 23, :int, 0) }
41
+ thRW = Thread.new { LibTest.testBlockingRWva(handle, 64, :int, 40, :int, 24, :int, 0) }
42
+ expect(thWR.value).to eq(64)
43
+ expect(thRW.value).to eq(63)
44
+ ensure
45
+ LibTest.testBlockingClose(handle)
46
+ end
47
+ end
48
+
30
49
  [ 0, 127, -128, -1 ].each do |i|
31
50
  it "call variadic with (:char (#{i})) argument" do
32
51
  buf = FFI::Buffer.new :long_long
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.10
4
+ version: 1.9.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wayne Meissner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-01 00:00:00.000000000 Z
11
+ date: 2016-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.4.0
47
+ version: 0.5.2
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.4.0
54
+ version: 0.5.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -513,6 +513,9 @@ files:
513
513
  - spec/ffi/fixtures/GlobalVariable.c
514
514
  - spec/ffi/fixtures/LastErrorTest.c
515
515
  - spec/ffi/fixtures/NumberTest.c
516
+ - spec/ffi/fixtures/PipeHelper.h
517
+ - spec/ffi/fixtures/PipeHelperPosix.c
518
+ - spec/ffi/fixtures/PipeHelperWindows.c
516
519
  - spec/ffi/fixtures/PointerTest.c
517
520
  - spec/ffi/fixtures/ReferenceTest.c
518
521
  - spec/ffi/fixtures/StringTest.c
@@ -567,7 +570,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
567
570
  version: '0'
568
571
  requirements: []
569
572
  rubyforge_project:
570
- rubygems_version: 2.4.6
573
+ rubygems_version: 2.5.1
571
574
  signing_key:
572
575
  specification_version: 4
573
576
  summary: Ruby FFI