diff options
author | Lars Kanis <lars@greiz-reinsdorf.de> | 2015-08-06 22:08:19 +0200 |
---|---|---|
committer | Lars Kanis <lars@greiz-reinsdorf.de> | 2015-08-06 22:14:34 +0200 |
commit | b035ca4e70dd696f4504622ea43eed0eb99fb5ba (patch) | |
tree | 8411522cac35b81ade508f3c3dddb0ac862fd3e5 | |
parent | fc00f561cb060aa4dd4e89cf2e548dfc629fc9fa (diff) | |
download | ffi-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.c | 58 | ||||
-rw-r--r-- | spec/ffi/function_spec.rb | 24 |
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 |