summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2015-08-06 22:08:19 +0200
committerLars Kanis <lars@greiz-reinsdorf.de>2015-08-06 22:14:34 +0200
commitb035ca4e70dd696f4504622ea43eed0eb99fb5ba (patch)
tree8411522cac35b81ade508f3c3dddb0ac862fd3e5
parentfc00f561cb060aa4dd4e89cf2e548dfc629fc9fa (diff)
downloadffi-b035ca4e70dd696f4504622ea43eed0eb99fb5ba.tar.gz
Fix test for :blocking=>true with a sleep()-less version.
This tests for concurrency instead of timing. It however has a timeout, so that the test doesn't hang in a failure condition. This fixes: https://github.com/ffi/ffi/pull/406
-rw-r--r--spec/ffi/fixtures/FunctionTest.c58
-rw-r--r--spec/ffi/function_spec.rb24
2 files changed, 69 insertions, 13 deletions
diff --git a/spec/ffi/fixtures/FunctionTest.c b/spec/ffi/fixtures/FunctionTest.c
index 5310ab0..1c9a247 100644
--- a/spec/ffi/fixtures/FunctionTest.c
+++ b/spec/ffi/fixtures/FunctionTest.c
@@ -6,7 +6,6 @@
#ifdef _WIN32
#include <windows.h>
-#define sleep(x) Sleep((x)*1000)
#endif
#ifndef _WIN32
@@ -14,6 +13,9 @@
#include <pthread.h>
#endif
+#include <stdio.h>
+#include <stdlib.h>
+
int testAdd(int a, int b)
{
return a + b;
@@ -24,10 +26,60 @@ int testFunctionAdd(int a, int b, int (*f)(int, int))
return f(a, b);
};
-void testBlocking(int seconds) {
- sleep(seconds);
+struct testBlockingData {
+ int pipe1[2];
+ int pipe2[2];
};
+struct testBlockingData *testBlockingOpen()
+{
+ struct testBlockingData *self = malloc(sizeof(struct testBlockingData));
+
+ if( pipe(self->pipe1) == -1 ) return NULL;
+ if( pipe(self->pipe2) == -1 ) return NULL;
+ return self;
+}
+
+char testBlockingReadChar(int fd)
+{
+ char d;
+ struct timeval timeout;
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(fd, &read_fds);
+
+ timeout.tv_sec = 10; // timeout after x seconds
+ timeout.tv_usec = 0;
+
+ if(select(fd + 1, &read_fds, NULL, NULL, &timeout) <= 0)
+ return 0;
+
+ if( read(fd, &d, 1) != 1)
+ return 0;
+ return d;
+}
+
+char testBlockingWR(struct testBlockingData *self, char c) {
+ if( write(self->pipe1[1], &c, 1) != 1)
+ return 0;
+ return testBlockingReadChar(self->pipe2[0]);
+}
+
+char testBlockingRW(struct testBlockingData *self, char c) {
+ char d = testBlockingReadChar(self->pipe1[0]);
+ if( write(self->pipe2[1], &c, 1) != 1)
+ return 0;
+ return d;
+}
+
+void testBlockingClose(struct testBlockingData *self) {
+ close(self->pipe1[0]);
+ close(self->pipe1[1]);
+ close(self->pipe2[0]);
+ close(self->pipe2[1]);
+ free(self);
+}
+
struct async_data {
void (*fn)(int);
int value;
diff --git a/spec/ffi/function_spec.rb b/spec/ffi/function_spec.rb
index ab08f35..8dbbc72 100644
--- a/spec/ffi/function_spec.rb
+++ b/spec/ffi/function_spec.rb
@@ -12,7 +12,7 @@ describe FFI::Function do
attach_function :testFunctionAdd, [:int, :int, :pointer], :int
end
before do
- @libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
+ @libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
end
@@ -22,7 +22,7 @@ describe FFI::Function do
end
it 'raises an error when passing a wrong signature' do
- expect { FFI::Function.new([], :int).new { } }.to raise_error TypeError
+ expect { FFI::Function.new([], :int).new { } }.to raise_error TypeError
end
it 'returns a native pointer' do
@@ -63,15 +63,19 @@ describe FFI::Function do
end
it 'can wrap a blocking function' do
- fp = FFI::Function.new(:void, [ :int ], @libtest.find_function('testBlocking'), :blocking => true)
- threads = 10.times.map do |x|
- Thread.new do
- time = Time.now
- fp.call(2)
- expect(Time.now - time).to be >= 2
- end
+ fpOpen = FFI::Function.new(:pointer, [ ], @libtest.find_function('testBlockingOpen'))
+ fpRW = FFI::Function.new(:char, [ :pointer, :char ], @libtest.find_function('testBlockingRW'), :blocking => true)
+ fpWR = FFI::Function.new(:char, [ :pointer, :char ], @libtest.find_function('testBlockingWR'), :blocking => true)
+ fpClose = FFI::Function.new(:void, [ :pointer ], @libtest.find_function('testBlockingClose'))
+ handle = fpOpen.call
+ begin
+ thWR = Thread.new { fpWR.call(handle, 63) }
+ thRW = Thread.new { fpRW.call(handle, 64) }
+ expect(thWR.value).to eq(64)
+ expect(thRW.value).to eq(63)
+ ensure
+ fpClose.call(handle)
end
- threads.each { |t| t.join }
end
it 'autorelease flag is set to true by default' do