summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortduehr <td@matasano.com>2015-08-07 17:25:56 -0500
committertduehr <td@matasano.com>2015-08-07 17:25:56 -0500
commiteb120500a5045e27f1f3b4129349df0190fc4d3a (patch)
tree7f067a3d999c5f4f99f76275c0a866a640cb35cd
parentfc00f561cb060aa4dd4e89cf2e548dfc629fc9fa (diff)
parent97e518404c2cdb20b3b3a13c64677da50215c519 (diff)
downloadffi-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.c39
-rw-r--r--spec/ffi/fixtures/PipeHelper.h21
-rw-r--r--spec/ffi/fixtures/PipeHelperPosix.c41
-rw-r--r--spec/ffi/fixtures/PipeHelperWindows.c72
-rw-r--r--spec/ffi/function_spec.rb25
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