diff options
author | tduehr <td@matasano.com> | 2015-08-07 17:25:56 -0500 |
---|---|---|
committer | tduehr <td@matasano.com> | 2015-08-07 17:25:56 -0500 |
commit | eb120500a5045e27f1f3b4129349df0190fc4d3a (patch) | |
tree | 7f067a3d999c5f4f99f76275c0a866a640cb35cd | |
parent | fc00f561cb060aa4dd4e89cf2e548dfc629fc9fa (diff) | |
parent | 97e518404c2cdb20b3b3a13c64677da50215c519 (diff) | |
download | ffi-eb120500a5045e27f1f3b4129349df0190fc4d3a.tar.gz |
Merge pull request #451 from larskanis/blocking-test
Fix test for :blocking=>true with a sleep()-less version.
-rw-r--r-- | spec/ffi/fixtures/FunctionTest.c | 39 | ||||
-rw-r--r-- | spec/ffi/fixtures/PipeHelper.h | 21 | ||||
-rw-r--r-- | spec/ffi/fixtures/PipeHelperPosix.c | 41 | ||||
-rw-r--r-- | spec/ffi/fixtures/PipeHelperWindows.c | 72 | ||||
-rw-r--r-- | spec/ffi/function_spec.rb | 25 |
5 files changed, 185 insertions, 13 deletions
diff --git a/spec/ffi/fixtures/FunctionTest.c b/spec/ffi/fixtures/FunctionTest.c index 5310ab0..a37373a 100644 --- a/spec/ffi/fixtures/FunctionTest.c +++ b/spec/ffi/fixtures/FunctionTest.c @@ -6,14 +6,16 @@ #ifdef _WIN32 #include <windows.h> -#define sleep(x) Sleep((x)*1000) #endif #ifndef _WIN32 #include <unistd.h> #include <pthread.h> +#include <stdlib.h> #endif +#include "PipeHelper.h" + int testAdd(int a, int b) { return a + b; @@ -24,10 +26,41 @@ int testFunctionAdd(int a, int b, int (*f)(int, int)) return f(a, b); }; -void testBlocking(int seconds) { - sleep(seconds); +struct testBlockingData { + FD_TYPE pipe1[2]; + FD_TYPE pipe2[2]; }; +struct testBlockingData *testBlockingOpen() +{ + struct testBlockingData *self = malloc(sizeof(struct testBlockingData)); + + if( pipeHelperCreatePipe(self->pipe1) == -1 ) return NULL; + if( pipeHelperCreatePipe(self->pipe2) == -1 ) return NULL; + return self; +} + +char testBlockingWR(struct testBlockingData *self, char c) { + if( pipeHelperWriteChar(self->pipe1[1], c) != 1) + return 0; + return pipeHelperReadChar(self->pipe2[0], 10); +} + +char testBlockingRW(struct testBlockingData *self, char c) { + char d = pipeHelperReadChar(self->pipe1[0], 10); + if( pipeHelperWriteChar(self->pipe2[1], c) != 1) + return 0; + return d; +} + +void testBlockingClose(struct testBlockingData *self) { + pipeHelperClosePipe(self->pipe1[0]); + pipeHelperClosePipe(self->pipe1[1]); + pipeHelperClosePipe(self->pipe2[0]); + pipeHelperClosePipe(self->pipe2[1]); + free(self); +} + struct async_data { void (*fn)(int); int value; diff --git a/spec/ffi/fixtures/PipeHelper.h b/spec/ffi/fixtures/PipeHelper.h new file mode 100644 index 0000000..4a02111 --- /dev/null +++ b/spec/ffi/fixtures/PipeHelper.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 Lars Kanis. All rights reserved. + * + * For licensing, see LICENSE.SPECS + */ + +#ifndef PIPEHELPER_H +#define PIPEHELPER_H + +#ifdef _WIN32 +#define FD_TYPE HANDLE +#else +#define FD_TYPE int +#endif + +int pipeHelperCreatePipe(FD_TYPE pipefd[2]); +char pipeHelperReadChar(FD_TYPE fd, int timeout); +int pipeHelperWriteChar(FD_TYPE fd, char c); +void pipeHelperClosePipe(FD_TYPE fd); + +#endif diff --git a/spec/ffi/fixtures/PipeHelperPosix.c b/spec/ffi/fixtures/PipeHelperPosix.c new file mode 100644 index 0000000..c1252b4 --- /dev/null +++ b/spec/ffi/fixtures/PipeHelperPosix.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Lars Kanis. All rights reserved. + * + * For licensing, see LICENSE.SPECS + */ + +#ifndef _WIN32 +#include <unistd.h> +#include <sys/time.h> +#include "PipeHelper.h" + +int pipeHelperCreatePipe(FD_TYPE pipefd[2]) +{ + return pipe(pipefd); +} + +char pipeHelperReadChar(FD_TYPE fd, int timeout) +{ + char d; + struct timeval time = {timeout, 0}; // timeout after x seconds + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + if(select(fd + 1, &read_fds, NULL, NULL, &time) <= 0) + return 0; + + if( read(fd, &d, 1) != 1) + return 0; + return d; +} + +int pipeHelperWriteChar(FD_TYPE fd, char c) +{ + return write(fd, &c, 1); +} + +void pipeHelperClosePipe(FD_TYPE fd) { + close(fd); +} +#endif diff --git a/spec/ffi/fixtures/PipeHelperWindows.c b/spec/ffi/fixtures/PipeHelperWindows.c new file mode 100644 index 0000000..470bacc --- /dev/null +++ b/spec/ffi/fixtures/PipeHelperWindows.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 Wayne Meissner. All rights reserved. + * + * For licensing, see LICENSE.SPECS + */ + +#ifdef _WIN32 +#include <windows.h> +#include "PipeHelper.h" + +int pipeHelperCreatePipe(FD_TYPE pipefd[2]) +{ + char name[ MAX_PATH ]; + static int pipe_idx = 0; + sprintf( name, "\\\\.\\Pipe\\pipeHelper-%u-%i", + (unsigned int)GetCurrentProcessId(), pipe_idx++ ); + + pipefd[0] = CreateNamedPipe( name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT, + 1, // Number of pipes + 5, // Out buffer size + 5, // In buffer size + 60 * 1000, // Timeout in ms + NULL ); + if(pipefd[0] == INVALID_HANDLE_VALUE) + return -1; + + pipefd[1] = CreateFile( name, GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(pipefd[1] == INVALID_HANDLE_VALUE) { + CloseHandle( pipefd[0] ); + return -1; + } + return 0; +} + +char pipeHelperReadChar(FD_TYPE fd, int timeout) +{ + char d; + OVERLAPPED ovl; + ZeroMemory(&ovl, sizeof(ovl)); + ovl.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if( ReadFile(fd, &d, 1, NULL, &ovl) == 0) { + DWORD recvd = 0;; + DWORD res = WaitForSingleObject(ovl.hEvent, timeout * 1000); + if( res != WAIT_OBJECT_0 ) { + CloseHandle(ovl.hEvent); + return 0; + } + if( GetOverlappedResult(fd, &ovl, &recvd, FALSE) == 0 ) { + CloseHandle(ovl.hEvent); + return 0; + } + } + CloseHandle(ovl.hEvent); + return d; +} + +int pipeHelperWriteChar(FD_TYPE fd, char c) +{ + DWORD written; + return WriteFile(fd, &c, 1, &written, NULL) == 0 ? 0 : 1; +} + +void pipeHelperClosePipe(FD_TYPE fd) { + CloseHandle(fd); +} + +#endif diff --git a/spec/ffi/function_spec.rb b/spec/ffi/function_spec.rb index ab08f35..dd4d2ea 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,20 @@ 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 + expect(handle).not_to be_null + 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 |