Hello community,

here is the log from the commit of package rubygem-ffi for openSUSE:Factory 
checked in at 2016-07-15 12:50:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-ffi (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-ffi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-ffi"

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-ffi/rubygem-ffi.changes  2015-07-03 
00:19:57.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.rubygem-ffi.new/rubygem-ffi.changes     
2016-07-15 12:50:59.000000000 +0200
@@ -1,0 +2,12 @@
+Thu Jul  7 04:29:55 UTC 2016 - [email protected]
+
+- updated to version 1.9.13
+ see installed ChangeLog
+
+-------------------------------------------------------------------
+Wed Jul  6 04:30:36 UTC 2016 - [email protected]
+
+- updated to version 1.9.12
+ see installed ChangeLog
+
+-------------------------------------------------------------------

Old:
----
  ffi-1.9.10.gem

New:
----
  ffi-1.9.13.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-ffi.spec ++++++
--- /var/tmp/diff_new_pack.uTG4he/_old  2016-07-15 12:51:01.000000000 +0200
+++ /var/tmp/diff_new_pack.uTG4he/_new  2016-07-15 12:51:01.000000000 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-ffi
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-ffi
-Version:        1.9.10
+Version:        1.9.13
 Release:        0
 %define mod_name ffi
 %define mod_full_name %{mod_name}-%{version}

++++++ ffi-1.9.10.gem -> ffi-1.9.13.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Rakefile new/Rakefile
--- old/Rakefile        2015-07-01 04:49:44.000000000 +0200
+++ new/Rakefile        2016-07-07 00:26:27.000000000 +0200
@@ -93,13 +93,13 @@
 
 CLOBBER.include 'lib/ffi/types.conf'
 CLOBBER.include 'pkg'
+CLOBBER.include 'log'
 
 CLEAN.include 'build'
 CLEAN.include 'conftest.dSYM'
 CLEAN.include 'spec/ffi/fixtures/libtest.{dylib,so,dll}'
 CLEAN.include 'spec/ffi/fixtures/*.o'
-CLEAN.include "pkg/ffi-#{FFI::VERSION}-*-mingw32"
-CLEAN.include "pkg/ffi-#{FFI::VERSION}-java"
+CLEAN.include "pkg/ffi-*-{mingw32,java}"
 CLEAN.include 'lib/1.*'
 CLEAN.include 'lib/2.*'
 CLEAN.include 'bin'
@@ -138,7 +138,7 @@
 task 'spec:run' => TEST_DEPS
 task 'spec:specdoc' => TEST_DEPS
 
-task :default => :specs
+task :default => :spec
 
 namespace 'java' do
 
@@ -175,15 +175,16 @@
     ext.cross_platform = %w[i386-mingw32 x64-mingw32]                     # 
forces the Windows platform instead of the default one
   end
 
-  ENV['RUBY_CC_VERSION'] ||= '1.8.7:1.9.3:2.0.0:2.1.5:2.2.1'
+  ENV['RUBY_CC_VERSION'] ||= '1.8.7:1.9.3:2.0.0:2.1.6:2.2.2:2.3.0'
 
+  # To reduce the gem file size strip mingw32 dlls before packaging
   ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version|
-    task "copy:ffi_c:i386-mingw32:#{ruby_version}" do |t|
-      sh "i686-w64-mingw32-strip -S 
#{BUILD_DIR}/i386-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so"
+    task "build/i386-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so" 
do |t|
+      sh "i686-w64-mingw32-strip -S 
build/i386-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so"
     end
 
-    task "copy:ffi_c:x64-mingw32:#{ruby_version}" do |t|
-      sh "x86_64-w64-mingw32-strip -S 
#{BUILD_DIR}/x64-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so"
+    task "build/x64-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so" 
do |t|
+      sh "x86_64-w64-mingw32-strip -S 
build/x64-mingw32/stage/lib/#{ruby_version[/^\d+\.\d+/]}/ffi_c.so"
     end
   end
 
@@ -194,6 +195,27 @@
   end
 end
 
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
+require 'ffi/platform'
+types_conf = File.expand_path(File.join(FFI::Platform::CONF_DIR, 'types.conf'))
+logfile = File.join(File.dirname(__FILE__), 'types_log')
+
+file types_conf => File.join("lib", "ffi", "version.rb") do |task|
+  require 'fileutils'
+  require 'ffi/tools/types_generator'
+  options = {}
+  FileUtils.mkdir_p(File.dirname(task.name), { :mode => 0755 })
+  File.open(task.name, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f|
+    f.puts FFI::TypesGenerator.generate(options)
+  end
+  File.open(logfile, 'w') do |log|
+    log.puts(types_conf)
+  end
+end
+
+task :types_conf => types_conf do
+end
+
 Gem::Tasks.new do |t|
   t.scm.tag.format = '%s'
 end
Files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/AbstractMemory.c 
new/ext/ffi_c/AbstractMemory.c
--- old/ext/ffi_c/AbstractMemory.c      2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/AbstractMemory.c      2016-07-07 00:26:27.000000000 +0200
@@ -497,7 +497,7 @@
     off = NUM2LONG(offset);
     idx = nargs > 2 ? NUM2LONG(rbIndex) : 0;
     if (idx < 0) {
-        rb_raise(rb_eRangeError, "index canot be less than zero");
+        rb_raise(rb_eRangeError, "index cannot be less than zero");
         return Qnil;
     }
     len = nargs > 3 ? NUM2LONG(rbLength) : (RSTRING_LEN(str) - idx);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Buffer.c new/ext/ffi_c/Buffer.c
--- old/ext/ffi_c/Buffer.c      2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Buffer.c      2016-07-07 00:26:27.000000000 +0200
@@ -253,7 +253,7 @@
  * @overload order(order)
  *  @param [:big, :little, :network] order
  *  @return [self]
- *  Set endinaness of Buffer (+:network+ is an alias for +:big+).
+ *  Set endianness of Buffer (+:network+ is an alias for +:big+).
  */
 static VALUE
 buffer_order(int argc, VALUE* argv, VALUE self)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Call.c new/ext/ffi_c/Call.c
--- old/ext/ffi_c/Call.c        2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Call.c        2016-07-07 00:26:27.000000000 +0200
@@ -338,40 +338,27 @@
     }
 }
 
-
-typedef struct BlockingCall_ {
-    rbffi_frame_t* frame;
-    void* function;
-    FunctionType* info;
-    void **ffiValues;
-    void* retval;
-    void* params;
-#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || 
defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
-    void* stkretval;
-#endif
-} BlockingCall;
-
 static VALUE
 call_blocking_function(void* data)
 {
-    BlockingCall* b = (BlockingCall *) data;
+    rbffi_blocking_call_t* b = (rbffi_blocking_call_t *) data;
     b->frame->has_gvl = false;
-    ffi_call(&b->info->ffi_cif, FFI_FN(b->function), b->retval, b->ffiValues);
+    ffi_call(&b->cif, FFI_FN(b->function), b->retval, b->ffiValues);
     b->frame->has_gvl = true;
 
     return Qnil;
 }
 
-static VALUE
-do_blocking_call(void *data)
+VALUE
+rbffi_do_blocking_call(void *data)
 {
     rbffi_thread_blocking_region(call_blocking_function, data, (void *) -1, 
NULL);
 
     return Qnil;
 }
 
-static VALUE
-save_frame_exception(void *data, VALUE exc)
+VALUE
+rbffi_save_frame_exception(void *data, VALUE exc)
 {
     rbffi_frame_t* frame = (rbffi_frame_t *) data;
     frame->exc = exc;
@@ -390,7 +377,7 @@
     retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
     
     if (unlikely(fnInfo->blocking)) {
-        BlockingCall* bc;
+        rbffi_blocking_call_t* bc;
 
         /*
          * due to the way thread switching works on older ruby variants, we
@@ -399,16 +386,16 @@
 #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || 
defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
         ffiValues = ALLOCA_N(void *, fnInfo->parameterCount);
         params = ALLOCA_N(FFIStorage, fnInfo->parameterCount);
-        bc = ALLOCA_N(BlockingCall, 1);
+        bc = ALLOCA_N(rbffi_blocking_call_t, 1);
         bc->retval = retval;
 #else
         ffiValues = ALLOC_N(void *, fnInfo->parameterCount);
         params = ALLOC_N(FFIStorage, fnInfo->parameterCount);
-        bc = ALLOC_N(BlockingCall, 1);
+        bc = ALLOC_N(rbffi_blocking_call_t, 1);
         bc->retval = xmalloc(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
         bc->stkretval = retval;
 #endif
-        bc->info = fnInfo;
+        bc->cif = fnInfo->ffi_cif;
         bc->function = function;
         bc->ffiValues = ffiValues;
         bc->params = params;
@@ -419,11 +406,11 @@
             fnInfo->callbackParameters, fnInfo->callbackCount, 
fnInfo->rbEnums);
 
         rbffi_frame_push(&frame); 
-        rb_rescue2(do_blocking_call, (VALUE) bc, save_frame_exception, (VALUE) 
&frame, rb_eException, (VALUE) 0);
+        rb_rescue2(rbffi_do_blocking_call, (VALUE) bc, 
rbffi_save_frame_exception, (VALUE) &frame, rb_eException, (VALUE) 0);
         rbffi_frame_pop(&frame);
 
 #if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || 
defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
-        memcpy(bc->stkretval, bc->retval, MAX(bc->info->ffi_cif.rtype->size, 
FFI_SIZEOF_ARG));
+        memcpy(bc->stkretval, bc->retval, MAX(bc->cif.rtype->size, 
FFI_SIZEOF_ARG));
         xfree(bc->params);
         xfree(bc->ffiValues);
         xfree(bc->retval);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Call.h new/ext/ffi_c/Call.h
--- old/ext/ffi_c/Call.h        2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Call.h        2016-07-07 00:26:27.000000000 +0200
@@ -33,6 +33,8 @@
 #ifndef RBFFI_CALL_H
 #define        RBFFI_CALL_H
 
+#include "Thread.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -85,6 +87,21 @@
 extern VALUE rbffi_GetEnumValue(VALUE enums, VALUE value);
 extern int rbffi_GetSignedIntValue(VALUE value, int type, int minValue, int 
maxValue, const char* typeName, VALUE enums);
 
+typedef struct rbffi_blocking_call {
+    rbffi_frame_t* frame;
+    void* function;
+    ffi_cif cif;
+    void **ffiValues;
+    void* retval;
+    void* params;
+#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || 
defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL))
+    void* stkretval;
+#endif
+} rbffi_blocking_call_t;
+
+VALUE rbffi_do_blocking_call(void* data);
+VALUE rbffi_save_frame_exception(void *data, VALUE exc);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Function.c new/ext/ffi_c/Function.c
--- old/ext/ffi_c/Function.c    2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Function.c    2016-07-07 00:26:27.000000000 +0200
@@ -202,7 +202,7 @@
 static VALUE
 function_initialize(int argc, VALUE* argv, VALUE self)
 {
-    
+
     VALUE rbReturnType = Qnil, rbParamTypes = Qnil, rbProc = Qnil, rbOptions = 
Qnil;
     VALUE rbFunctionInfo = Qnil;
     VALUE infoArgv[3];
@@ -229,14 +229,14 @@
          *      Function.new(:int, [ :int ], addr, { :convention => :stdcall })
          */
     }
-    
+
     infoArgv[0] = rbReturnType;
     infoArgv[1] = rbParamTypes;
     infoArgv[2] = rbOptions;
     rbFunctionInfo = rb_class_new_instance(rbOptions != Qnil ? 3 : 2, 
infoArgv, rbffi_FunctionTypeClass);
 
     function_init(self, rbFunctionInfo, rbProc);
-    
+
     return self;
 }
 
@@ -272,12 +272,12 @@
             return cbref;
         }
     }
-    
+
     cbTable = RTEST(rb_ivar_defined(proc, id_cbtable)) ? rb_ivar_get(proc, 
id_cbtable) : Qnil;
     if (cbTable != Qnil && (callback = rb_hash_aref(cbTable, rbFunctionInfo)) 
!= Qnil) {
         return callback;
     }
-    
+
     /* No existing function for the proc with that signature, create a new one 
and cache it */
     callback = rbffi_Function_NewInstance(rbFunctionInfo, proc);
     if (cbref == Qnil) {
@@ -297,7 +297,7 @@
 function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
 {
     Function* fn = NULL;
-    
+
     Data_Get_Struct(self, Function, fn);
 
     fn->rbFunctionInfo = rbFunctionInfo;
@@ -342,7 +342,7 @@
         rb_raise(rb_eTypeError, "wrong argument type %s, expected pointer or 
proc",
                 rb_obj_classname(rbProc));
     }
-    
+
     fn->rbProc = rbProc;
 
     return self;
@@ -402,7 +402,7 @@
     rb_define_singleton_method(module, StringValueCStr(name),
             rbffi_MethodHandle_CodeAddress(fn->methodHandle), -1);
 
-    
+
     rb_define_method(module, StringValueCStr(name),
             rbffi_MethodHandle_CodeAddress(fn->methodHandle), -1);
 
@@ -452,10 +452,10 @@
     if (fn->closure == NULL) {
         rb_raise(rb_eRuntimeError, "cannot free function which was not 
allocated");
     }
-    
+
     rbffi_Closure_Free(fn->closure);
     fn->closure = NULL;
-    
+
     return self;
 }
 
@@ -463,13 +463,13 @@
 callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
 {
     struct gvl_callback cb = { 0 };
-    
+
     cb.closure = (Closure *) user_data;
     cb.retval = retval;
     cb.parameters = parameters;
     cb.done = false;
     cb.frame = rbffi_frame_current();
-    
+
     if (cb.frame != NULL) cb.frame->exc = Qnil;
     if (cb.frame != NULL && cb.frame->has_gvl) {
         callback_with_gvl(&cb);
@@ -651,14 +651,14 @@
         WaitForSingleObject(async_cb_cond, INFINITE);
         EnterCriticalSection(&async_cb_lock);
     }
-    
+
     if (async_cb_list != NULL) {
         w->cb = async_cb_list;
         async_cb_list = async_cb_list->next;
     }
 
     LeaveCriticalSection(&async_cb_lock);
-    
+
     return Qnil;
 }
 
@@ -686,14 +686,14 @@
     while (!w->stop && async_cb_list == NULL) {
         pthread_cond_wait(&async_cb_cond, &async_cb_mutex);
     }
-    
+
     if (async_cb_list != NULL) {
         w->cb = async_cb_list;
         async_cb_list = async_cb_list->next;
     }
 
     pthread_mutex_unlock(&async_cb_mutex);
-    
+
     return Qnil;
 }
 
@@ -713,9 +713,9 @@
 async_cb_call(void *data)
 {
     struct gvl_callback* cb = (struct gvl_callback *) data;
-    
+
     callback_with_gvl(data);
-        
+
     /* Signal the original native thread that the ruby code has completed */
 #ifdef _WIN32
     SetEvent(cb->async_event);
@@ -835,8 +835,7 @@
     }
 
     rbReturnValue = rb_funcall2(fn->rbProc, id_call, cbInfo->parameterCount, 
rbParams);
-    RB_GC_GUARD_PTR(rbParams);
-    
+
     if (unlikely(returnType->nativeType == NATIVE_MAPPED)) {
         VALUE values[] = { rbReturnValue, Qnil };
         rbReturnValue = rb_funcall2(((MappedType *) returnType)->rbConverter, 
id_to_native, 2, values);
@@ -915,7 +914,7 @@
                 } else {
                     memset(retval, 0, returnType->ffiType->size);
                 }
-                
+
             } else {
                 memset(retval, 0, returnType->ffiType->size);
             }
@@ -929,14 +928,14 @@
     return Qnil;
 }
 
-static VALUE 
+static VALUE
 save_callback_exception(void* data, VALUE exc)
 {
     struct gvl_callback* cb = (struct gvl_callback *) data;
-    
+
     memset(cb->retval, 0, ((Function *) 
cb->closure->info)->info->returnType->ffiType->size);
     if (cb->frame != NULL) cb->frame->exc = exc;
-    
+
     return Qnil;
 }
 
@@ -963,7 +962,7 @@
      * Document-class: FFI::Function < FFI::Pointer
      */
     rbffi_FunctionClass = rb_define_class_under(moduleFFI, "Function", 
rbffi_PointerClass);
-    
+
     rb_global_variable(&rbffi_FunctionClass);
     rb_define_alloc_func(rbffi_FunctionClass, function_allocate);
 
@@ -997,4 +996,3 @@
     async_cb_cond = CreateEvent(NULL, FALSE, FALSE, NULL);
 #endif
 }
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/MethodHandle.c new/ext/ffi_c/MethodHandle.c
--- old/ext/ffi_c/MethodHandle.c        2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/MethodHandle.c        2016-07-07 00:26:27.000000000 +0200
@@ -228,9 +228,8 @@
 {
     FunctionType* fnInfo = (FunctionType *) handle->info;
     VALUE rbReturnValue;
-    
+
     RB_GC_GUARD(rbReturnValue) = (*fnInfo->invoke)(argc, argv, 
handle->function, fnInfo);
-    RB_GC_GUARD_PTR(argv);
     RB_GC_GUARD(self);
 
     return rbReturnValue;
@@ -243,10 +242,10 @@
 #define TRAMPOLINE_FUN_MAGIC (0xbeefcafe)
 
 /*
- * This is a hand-coded trampoline to speedup entry from ruby to the FFI 
translation
+ * This is a hand-coded trampoline to speed-up entry from ruby to the FFI 
translation
  * layer for i386 arches.
  *
- * This does not make a discernable difference vs a raw closure, so for now,
+ * This does not make a discernible difference vs a raw closure, so for now,
  * it is not enabled.
  */
 __asm__(
@@ -357,4 +356,3 @@
 
 #endif
 }
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Pointer.c new/ext/ffi_c/Pointer.c
--- old/ext/ffi_c/Pointer.c     2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Pointer.c     2016-07-07 00:26:27.000000000 +0200
@@ -89,7 +89,7 @@
  * @overload initialize(type, address)
  *  @param [Type] type type for pointer
  *  @param [Integer] address base address for pointer
- *  Create a new pointer from a {Type} and a base adresse
+ *  Create a new pointer from a {Type} and a base address
  * @return [self]
  * A new instance of Pointer.
  */
@@ -146,11 +146,11 @@
  * call-seq: ptr.initialize_copy(other)
  * @param [Pointer] other source for cloning or dupping
  * @return [self]
- * @raise {RuntimeError} if +other+ is an unbounded memory area, or is 
unreable/unwritable
+ * @raise {RuntimeError} if +other+ is an unbounded memory area, or is 
unreadable/unwritable
  * @raise {NoMemError} if failed to allocate memory for new object
  * DO NOT CALL THIS METHOD.
  *
- * This method is internally used by #dup and #clone. Memory contents is 
copied from +other+.
+ * This method is internally used by #dup and #clone. Memory content is copied 
from +other+.
  */
 static VALUE
 ptr_initialize_copy(VALUE self, VALUE other)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/Variadic.c new/ext/ffi_c/Variadic.c
--- old/ext/ffi_c/Variadic.c    2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/Variadic.c    2016-07-07 00:26:27.000000000 +0200
@@ -64,6 +64,7 @@
     ffi_abi abi;
     void* function;
     int paramCount;
+    bool blocking;
 } VariadicInvoker;
 
 
@@ -84,6 +85,7 @@
     invoker->rbAddress = Qnil;
     invoker->rbEnums = Qnil;
     invoker->rbReturnType = Qnil;
+    invoker->blocking = false;
 
     return obj;
 }
@@ -115,6 +117,7 @@
     invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums")));
     invoker->rbAddress = rbFunction;
     invoker->function = rbffi_AbstractMemory_Cast(rbFunction, 
rbffi_PointerClass)->address;
+    invoker->blocking = RTEST(rb_hash_aref(options, 
ID2SYM(rb_intern("blocking"))));
 
 #if defined(X86_WIN32)
     rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL);
@@ -253,7 +256,28 @@
         ffiValues, NULL, 0, invoker->rbEnums);
     
     rbffi_frame_push(&frame);
+#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
+    /* In Call.c, blocking: true is supported on older ruby variants
+     * without rb_thread_call_without_gvl by allocating on the heap instead
+     * of the stack. Since this functionality is being added later,
+     * we’re skipping support for old rubies here. */
+    if(unlikely(invoker->blocking)) {
+        rbffi_blocking_call_t* bc;
+        bc = ALLOCA_N(rbffi_blocking_call_t, 1);
+        bc->retval = retval;
+        bc->function = invoker->function;
+        bc->ffiValues = ffiValues;
+        bc->params = params;
+        bc->frame = &frame;
+        bc->cif = cif;
+
+        rb_rescue2(rbffi_do_blocking_call, (VALUE) bc, 
rbffi_save_frame_exception, (VALUE) &frame, rb_eException, (VALUE) 0);
+    } else {
+        ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues);
+    }
+#else
     ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues);
+#endif
     rbffi_frame_pop(&frame);
     
     rbffi_save_errno();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/compat.h new/ext/ffi_c/compat.h
--- old/ext/ffi_c/compat.h      2015-07-01 04:49:44.000000000 +0200
+++ new/ext/ffi_c/compat.h      2016-07-07 00:26:27.000000000 +0200
@@ -75,9 +75,4 @@
 #  define RB_GC_GUARD(x) (x)
 #endif
 
-#ifndef RB_GC_GUARD_PTR
-#  define RB_GC_GUARD_PTR(x) (x)
-#endif
-
 #endif /* RBFFI_COMPAT_H */
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/libffi/src/mips/ffi.c 
new/ext/ffi_c/libffi/src/mips/ffi.c
--- old/ext/ffi_c/libffi/src/mips/ffi.c 2015-07-01 04:49:45.000000000 +0200
+++ new/ext/ffi_c/libffi/src/mips/ffi.c 2016-07-07 00:26:27.000000000 +0200
@@ -76,6 +76,7 @@
   void **p_argv;
   char *argp;
   ffi_type **p_arg;
+  int ecif_test;
 
 #ifdef FFI_MIPS_N32
   /* If more than 8 double words are used, the remainder go
@@ -92,10 +93,11 @@
   memset(stack, 0, bytes);
 
 #ifdef FFI_MIPS_N32
-  if ( ecif->cif->rstruct_flag != 0 )
+  ecif_test = ecif->cif->rstruct_flag != 0;
 #else
-  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
+  ecif_test = ecif->cif->rtype->type == FFI_TYPE_STRUCT;
 #endif  
+    if (ecif_test)
     {
       *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
       argp += sizeof(ffi_arg);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/ffi_c/rbffi_endian.h new/ext/ffi_c/rbffi_endian.h
--- old/ext/ffi_c/rbffi_endian.h        2015-07-01 04:49:45.000000000 +0200
+++ new/ext/ffi_c/rbffi_endian.h        2016-07-07 00:26:27.000000000 +0200
@@ -7,7 +7,7 @@
 
 #include <sys/types.h>
 
-#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || 
defined(__GLIBC__)
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || 
defined(__GLIBC__) || defined(__HAIKU__)
 # include <endian.h>
 # if !defined(LITTLE_ENDIAN) && defined(__LITTLE_ENDIAN)
 #  define LITTLE_ENDIAN __LITTLE_ENDIAN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ffi.gemspec new/ffi.gemspec
--- old/ffi.gemspec     2015-07-01 04:49:45.000000000 +0200
+++ new/ffi.gemspec     2016-07-07 00:26:27.000000000 +0200
@@ -17,7 +17,7 @@
   s.required_ruby_version = '>= 1.8.7'
   s.add_development_dependency 'rake', '~> 10.1'
   s.add_development_dependency 'rake-compiler', '~> 0.9'
-  s.add_development_dependency 'rake-compiler-dock', '~> 0.4.0'
+  s.add_development_dependency 'rake-compiler-dock', '~> 0.5.2'
   s.add_development_dependency 'rspec', '~> 2.14.1'
   s.add_development_dependency 'rubygems-tasks', "~> 0.2.4"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/autopointer.rb new/lib/ffi/autopointer.rb
--- old/lib/ffi/autopointer.rb  2015-07-01 04:49:45.000000000 +0200
+++ new/lib/ffi/autopointer.rb  2016-07-07 00:26:27.000000000 +0200
@@ -34,27 +34,29 @@
     extend DataConverter
 
     # @overload initialize(pointer, method)
-    #  @param [Pointer] pointer
-    #  @param [Method] method
-    #  @return [self]
-    #  The passed Method will be invoked at GC time.
+    #   @param pointer [Pointer]
+    #   @param method [Method]
+    #   @return [self]
+    #   The passed Method will be invoked at GC time.
     # @overload initialize(pointer, proc)
-    #  @param [Pointer] pointer
-    #  @return [self]
-    #  The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
-    #  @note WARNING: passing a proc _may_ cause your pointer to never be 
GC'd, unless you're 
-    #   careful to avoid trapping a reference to the pointer in the proc. See 
the test 
-    #   specs for examples.
+    #   @param pointer [Pointer]
+    #   @return [self]
+    #   The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
+    #   @note WARNING: passing a proc _may_ cause your pointer to never be
+    #     GC'd, unless you're careful to avoid trapping a reference to the
+    #     pointer in the proc. See the test specs for examples.
     # @overload initialize(pointer) { |p| ... }
-    #  @param [Pointer] pointer
-    #  @yieldparam [Pointer] p +pointer+ passed to the block
-    #  @return [self]
-    #  The passed block will be invoked at GC time.
-    #  @note WARNING: passing a block will cause your pointer to never be 
GC'd. This is bad.
+    #   @param pointer [Pointer]
+    #   @yieldparam [Pointer] p +pointer+ passed to the block
+    #   @return [self]
+    #   The passed block will be invoked at GC time.
+    #   @note
+    #     WARNING: passing a block will cause your pointer to never be GC'd.
+    #     This is bad.
     # @overload initialize(pointer)
-    #  @param [Pointer] pointer
-    #  @return [self]
-    #  The pointer's release() class method will be invoked at GC time.
+    #   @param pointer [Pointer]
+    #   @return [self]
+    #   The pointer's release() class method will be invoked at GC time.
     #
     # @note The safest, and therefore preferred, calling
     #  idiom is to pass a Method as the second parameter. Example usage:
@@ -79,11 +81,15 @@
         || ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
 
       @releaser = if proc
-                    raise RuntimeError.new("proc must be callable") unless 
proc.respond_to?(:call)
+                    if not proc.respond_to?(:call)
+                      raise RuntimeError.new("proc must be callable")
+                    end
                     CallableReleaser.new(ptr, proc)
 
                   else
-                    raise RuntimeError.new("no release method defined") unless 
self.class.respond_to?(:release)
+                    if not self.class.respond_to?(:release)
+                      raise RuntimeError.new("no release method defined")
+                    end
                     DefaultReleaser.new(ptr, self.class)
                   end
 
@@ -143,16 +149,15 @@
       def call(*args)
         release(@ptr) if @autorelease && @ptr
       end
-      
     end
 
-    # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined 
without Proc
-    # or Method. In this case, the pointer to release must be of a class 
derived from 
-    # AutoPointer with a +#release+ class method.
+    # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined
+    # without Proc or Method. In this case, the pointer to release must be of
+    # a class derived from AutoPointer with a {release} class method.
     class DefaultReleaser < Releaser
       # @param [Pointer] ptr
       # @return [nil]
-      # Release +ptr+ by using his #release class method.
+      # Release +ptr+ using the {release} class method of its class.
       def release(ptr)
         @proc.release(ptr)
       end
@@ -161,7 +166,9 @@
     # CallableReleaser is a {Releaser} used when an {AutoPointer} is defined 
with a
     # Proc or a Method.
     class CallableReleaser < Releaser
-      # Release +ptr+ by using Proc or Method defined at +ptr+ 
{AutoPointer#initialize initialization}.
+      # Release +ptr+ by using Proc or Method defined at +ptr+
+      # {AutoPointer#initialize initialization}.
+      #
       # @param [Pointer] ptr
       # @return [nil]
       def release(ptr)
@@ -175,7 +182,9 @@
     # @return [Type::POINTER]
     # @raise {RuntimeError} if class does not implement a +#release+ method
     def self.native_type
-      raise RuntimeError.new("no release method defined for #{self.inspect}") 
unless self.respond_to?(:release)
+      if not self.respond_to?(:release)
+        raise RuntimeError.new("no release method defined for #{self.inspect}")
+      end
       Type::POINTER
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/enum.rb new/lib/ffi/enum.rb
--- old/lib/ffi/enum.rb 2015-07-01 04:49:45.000000000 +0200
+++ new/lib/ffi/enum.rb 2016-07-07 00:26:27.000000000 +0200
@@ -146,7 +146,7 @@
     def symbol_map
       @kv_map
     end
-    
+
     alias to_h symbol_map
     alias to_hash symbol_map
 
@@ -168,7 +168,5 @@
     def from_native(val, ctx)
       @vk_map[val] || val
     end
-
   end
-
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/library.rb new/lib/ffi/library.rb
--- old/lib/ffi/library.rb      2015-07-01 04:49:45.000000000 +0200
+++ new/lib/ffi/library.rb      2016-07-07 00:26:27.000000000 +0200
@@ -109,6 +109,7 @@
 
           libnames.each do |libname|
             begin
+              orig = libname
               lib = FFI::DynamicLibrary.open(libname, lib_flags)
               break if lib
 
@@ -124,7 +125,20 @@
               if ldscript
                 retry
               else
-                errors[libname] = ex
+                # TODO better library lookup logic
+                libname = libname.to_s
+                unless libname.start_with?("/")
+                  path = ['/usr/lib/','/usr/local/lib/'].find do |pth|
+                    File.exist?(pth + libname)
+                  end
+                  if path
+                    libname = path + libname
+                    retry
+                  end
+                end
+
+                libr = (orig == libname ? orig : "#{orig} #{libname}")
+                errors[libr] = ex
               end
             end
           end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/pointer.rb new/lib/ffi/pointer.rb
--- old/lib/ffi/pointer.rb      2015-07-01 04:49:46.000000000 +0200
+++ new/lib/ffi/pointer.rb      2016-07-07 00:26:27.000000000 +0200
@@ -33,7 +33,7 @@
 require 'ffi/platform'
 module FFI
   class Pointer
-    
+
     # Pointer size
     SIZE = Platform::ADDRESS_SIZE / 8
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/struct.rb new/lib/ffi/struct.rb
--- old/lib/ffi/struct.rb       2015-07-01 04:49:46.000000000 +0200
+++ new/lib/ffi/struct.rb       2016-07-07 00:26:27.000000000 +0200
@@ -341,7 +341,7 @@
       # @raise if Ruby 1.8
       # Add hash +spec+ to +builder+.
       def hash_layout(builder, spec)
-        raise "Ruby version not supported" if RUBY_VERSION =~ /1\.8\.*/
+        raise "Ruby version not supported" if RUBY_VERSION =~ /^1\.8\..*/
         spec[0].each do |name, type|
           builder.add name, find_field_type(type), nil
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/tools/types_generator.rb 
new/lib/ffi/tools/types_generator.rb
--- old/lib/ffi/tools/types_generator.rb        2015-07-01 04:49:46.000000000 
+0200
+++ new/lib/ffi/tools/types_generator.rb        2016-07-07 00:26:27.000000000 
+0200
@@ -1,7 +1,7 @@
 require 'tempfile'
 
 module FFI
-  
+
   # @private
   class TypesGenerator
 
@@ -65,7 +65,7 @@
           typedefs = `#{cmd} #{io.path}`
         end
       end
-      
+
       code = ""
 
       typedefs.each_line do |type|
@@ -73,11 +73,11 @@
         next unless type =~ /typedef/
         # Ignore unions or structs
         next if type =~ /union|struct/
-        
+
         # strip off the starting typedef and ending ;
         type.gsub!(/^(.*typedef\s*)/, "")
         type.gsub!(/\s*;\s*$/, "")
-    
+
         parts = type.split(/\s+/)
         def_type   = parts.join(" ")
 
@@ -99,7 +99,7 @@
           else
             final_type = parts.pop
           end
-          
+
           def_type = case type
                      when /__QI__/   then "char"
                      when /__HI__/   then "short"
@@ -114,7 +114,7 @@
           final_type = parts.pop
           def_type   = parts.join(" ")
         end
-        
+
         if type = TYPE_MAP[def_type]
           code << "rbx.platform.typedef.#{final_type} = #{type}\n"
           TYPE_MAP[final_type] = TYPE_MAP[def_type]
@@ -129,7 +129,6 @@
 
       code
     end
-
   end
 end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/types.rb new/lib/ffi/types.rb
--- old/lib/ffi/types.rb        2015-07-01 04:49:46.000000000 +0200
+++ new/lib/ffi/types.rb        2016-07-07 00:26:27.000000000 +0200
@@ -65,7 +65,6 @@
 
     elsif name.is_a?(DataConverter)
       (type_map || TypeDefs)[name] = Type::Mapped.new(name)
-    
     else
       raise TypeError, "unable to resolve type '#{name}'"
     end
@@ -149,19 +148,24 @@
       :varargs => Type::VARARGS,
   })
 
-  
+  # This will convert a pointer to a Ruby string (just like `:string`), but
+  # also allow to work with the pointer itself. This is useful when you want
+  # a Ruby string already containing a copy of the data, but also the pointer
+  # to the data for you to do something with it, like freeing it, in case the
+  # library handed the memory to off to the caller (Ruby-FFI).
+  #
+  # It's {typedef}'d as +:strptr+.
   class StrPtrConverter
     extend DataConverter
     native_type Type::POINTER
 
     # @param [Pointer] val
-    # @param ctx
+    # @param ctx not used
     # @return [Array(String, Pointer)]
     # Returns a [ String, Pointer ] tuple so the C memory for the string can 
be freed
     def self.from_native(val, ctx)
       [ val.null? ? nil : val.get_string(0), val ]
     end
-
   end
 
   typedef(StrPtrConverter, :strptr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/ffi/version.rb new/lib/ffi/version.rb
--- old/lib/ffi/version.rb      2015-07-01 04:49:46.000000000 +0200
+++ new/lib/ffi/version.rb      2016-07-07 00:26:27.000000000 +0200
@@ -1,4 +1,4 @@
 module FFI
-  VERSION = '1.9.10'
+  VERSION = '1.9.13'
 end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtest/FunctionTest.c new/libtest/FunctionTest.c
--- old/libtest/FunctionTest.c  2015-07-01 04:49:46.000000000 +0200
+++ new/libtest/FunctionTest.c  2016-07-07 00:26:27.000000000 +0200
@@ -6,7 +6,7 @@
 
 #ifdef _WIN32
 #include <windows.h>
-#define sleep(x) Sleep(x)
+#define sleep(x) Sleep((x)*1000)
 #endif
 
 #ifndef _WIN32
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtest/VariadicTest.c new/libtest/VariadicTest.c
--- old/libtest/VariadicTest.c  2015-07-01 04:49:46.000000000 +0200
+++ new/libtest/VariadicTest.c  2016-07-07 00:26:27.000000000 +0200
@@ -60,3 +60,40 @@
     va_end(ap);
 }
 
+int pack_varargs2(s64* buf, int retval, const char* fmt, ...)
+{
+    va_list ap;
+    int c;
+    double d;
+    va_start(ap, fmt);
+    while ((c = *fmt++)) {
+        switch (c) {
+            case 'c':
+            case 's':
+            case 'i':
+                *buf++ = va_arg(ap, s32);
+                break;
+            case 'l':
+                *buf++ = va_arg(ap, long);
+                break;
+            case 'j':
+                *buf++ = va_arg(ap, s64);
+                break;
+            case 'f':
+            case 'd':
+                d = va_arg(ap, double);
+                memcpy(buf++, &d, sizeof(d));
+                break;
+            case 'C':
+            case 'S':
+            case 'I':
+                *buf++ = va_arg(ap, u32);
+                break;
+            case 'L':
+                *buf++ = va_arg(ap, unsigned long);
+                break;
+        }
+    }
+    va_end(ap);
+    return retval + 1;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2015-07-01 04:49:44.000000000 +0200
+++ new/metadata        2016-07-07 00:26:27.000000000 +0200
@@ -1,14 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: ffi
 version: !ruby/object:Gem::Version
-  version: 1.9.10
+  version: 1.9.13
 platform: ruby
 authors:
 - Wayne Meissner
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2015-07-01 00:00:00.000000000 Z
+date: 2016-07-06 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: rake
@@ -44,14 +44,14 @@
     requirements:
     - - "~>"
       - !ruby/object:Gem::Version
-        version: 0.4.0
+        version: 0.5.2
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - "~>"
       - !ruby/object:Gem::Version
-        version: 0.4.0
+        version: 0.5.2
 - !ruby/object:Gem::Dependency
   name: rspec
   requirement: !ruby/object:Gem::Requirement
@@ -513,6 +513,9 @@
 - spec/ffi/fixtures/GlobalVariable.c
 - spec/ffi/fixtures/LastErrorTest.c
 - spec/ffi/fixtures/NumberTest.c
+- spec/ffi/fixtures/PipeHelper.h
+- spec/ffi/fixtures/PipeHelperPosix.c
+- spec/ffi/fixtures/PipeHelperWindows.c
 - spec/ffi/fixtures/PointerTest.c
 - spec/ffi/fixtures/ReferenceTest.c
 - spec/ffi/fixtures/StringTest.c
@@ -567,7 +570,7 @@
       version: '0'
 requirements: []
 rubyforge_project: 
-rubygems_version: 2.4.6
+rubygems_version: 2.5.1
 signing_key: 
 specification_version: 4
 summary: Ruby FFI
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/fixtures/ClosureTest.c 
new/spec/ffi/fixtures/ClosureTest.c
--- old/spec/ffi/fixtures/ClosureTest.c 2015-07-01 04:49:46.000000000 +0200
+++ new/spec/ffi/fixtures/ClosureTest.c 2016-07-07 00:26:28.000000000 +0200
@@ -50,6 +50,21 @@
 P(P, const void*);
 P(UL, unsigned long);
 
+#if defined(_WIN32) && !defined(_WIN64)
+bool __stdcall testClosureStdcall(long *a1, void __stdcall(*closure)(void *, 
long), long a2) { \
+    void* sp_pre;
+    void* sp_post;
+
+    asm volatile (" movl %%esp,%0" : "=g" (sp_pre));
+    (*closure)(a1, a2);
+    asm volatile (" movl %%esp,%0" : "=g" (sp_post));
+
+    /* %esp before pushing parameters on the stack and after the call returns
+     * should be equal, if both sides respects the stdcall convention */
+    return sp_pre == sp_post;
+}
+#endif
+
 void testOptionalClosureBrV(void (*closure)(char), char a1)
 {
     if (closure) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/fixtures/FunctionTest.c 
new/spec/ffi/fixtures/FunctionTest.c
--- old/spec/ffi/fixtures/FunctionTest.c        2015-07-01 04:49:46.000000000 
+0200
+++ new/spec/ffi/fixtures/FunctionTest.c        2016-07-07 00:26:28.000000000 
+0200
@@ -6,14 +6,17 @@
 
 #ifdef _WIN32
 #include <windows.h>
-#define sleep(x) Sleep(x)
 #endif
 
 #ifndef _WIN32
 #include <unistd.h>
 #include <pthread.h>
+#include <stdarg.h>
+#include <stdlib.h>
 #endif
 
+#include "PipeHelper.h"
+
 int testAdd(int a, int b)
 {
     return a + b;
@@ -24,10 +27,79 @@
     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);
+}
+
+static int sum_varargs(va_list args) {
+    char sum = 0;
+    int arg;
+    while ((arg = va_arg(args, int)) != 0) {
+        sum += arg;
+    }
+    va_end(args);
+    return sum;
+}
+
+/* Write c to pipe1 and return the value read from pipe2, or 0 if there’s
+ * an error such as a timeout, or if c does not equal the sum of the
+ * zero-terminated list of char arguments. */
+char testBlockingWRva(struct testBlockingData *self, char c, ...) {
+    va_list args;
+    va_start(args, c);
+    if (sum_varargs(args) != c) {
+        return 0;
+    }
+
+    if( pipeHelperWriteChar(self->pipe1[1], c) != 1)
+        return 0;
+    return pipeHelperReadChar(self->pipe2[0], 10);
+}
+
+char testBlockingRWva(struct testBlockingData *self, char c, ...) {
+    va_list args;
+    va_start(args, c);
+    if (sum_varargs(args) != c) {
+        return 0;
+    }
+
+    char d = pipeHelperReadChar(self->pipe1[0], 10);
+    if( pipeHelperWriteChar(self->pipe2[1], c) != 1)
+        return 0;
+    return d;
+}
+
 struct async_data {
     void (*fn)(int);
     int value;
@@ -55,4 +127,16 @@
 #else
     (*fn)(value);
 #endif
-} 
+}
+
+#if defined(_WIN32) && !defined(_WIN64)
+struct StructUCDP {
+  unsigned char a1;
+  double a2;
+  void *a3;
+};
+
+void __stdcall testStdcallManyParams(long *a1, char a2, short int a3, int a4, 
__int64 a5,
+            struct StructUCDP a6, struct StructUCDP *a7, float a8, double a9) {
+}
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/fixtures/PipeHelper.h 
new/spec/ffi/fixtures/PipeHelper.h
--- old/spec/ffi/fixtures/PipeHelper.h  1970-01-01 01:00:00.000000000 +0100
+++ new/spec/ffi/fixtures/PipeHelper.h  2016-07-07 00:26:28.000000000 +0200
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/fixtures/PipeHelperPosix.c 
new/spec/ffi/fixtures/PipeHelperPosix.c
--- old/spec/ffi/fixtures/PipeHelperPosix.c     1970-01-01 01:00:00.000000000 
+0100
+++ new/spec/ffi/fixtures/PipeHelperPosix.c     2016-07-07 00:26:28.000000000 
+0200
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/fixtures/PipeHelperWindows.c 
new/spec/ffi/fixtures/PipeHelperWindows.c
--- old/spec/ffi/fixtures/PipeHelperWindows.c   1970-01-01 01:00:00.000000000 
+0100
+++ new/spec/ffi/fixtures/PipeHelperWindows.c   2016-07-07 00:26:28.000000000 
+0200
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/function_spec.rb 
new/spec/ffi/function_spec.rb
--- old/spec/ffi/function_spec.rb       2015-07-01 04:49:46.000000000 +0200
+++ new/spec/ffi/function_spec.rb       2016-07-07 00:26:28.000000000 +0200
@@ -12,7 +12,7 @@
     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 @@
   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 @@
   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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/library_spec.rb new/spec/ffi/library_spec.rb
--- old/spec/ffi/library_spec.rb        2015-07-01 04:49:46.000000000 +0200
+++ new/spec/ffi/library_spec.rb        2016-07-07 00:26:28.000000000 +0200
@@ -96,6 +96,16 @@
       }.not_to raise_error
     end
 
+    it "loads library using symbol" do
+      expect {
+        expect(Module.new do |m|
+          m.extend FFI::Library
+          ffi_lib :c
+          attach_function :getpid, [ ], :uint
+        end.getpid).to eq(Process.pid)
+      }.not_to raise_error
+    end
+
     it "attach_function :getpid from [ 'c', 'libc.so.6'] " do
       expect {
         expect(Module.new do |m|
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/rbx/attach_function_spec.rb 
new/spec/ffi/rbx/attach_function_spec.rb
--- old/spec/ffi/rbx/attach_function_spec.rb    2015-07-01 04:49:46.000000000 
+0200
+++ new/spec/ffi/rbx/attach_function_spec.rb    2016-07-07 00:26:28.000000000 
+0200
@@ -5,29 +5,30 @@
 
 require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
 
-class Timeval < FFI::Struct
-  layout :tv_sec, :ulong, 0, :tv_usec, :ulong, 4  
-end
-
-module LibC
-  extend FFI::Library
-  ffi_lib FFI::Library::LIBC
+unless FFI::Platform.windows?
+  class Timeval < FFI::Struct
+    layout :tv_sec, :ulong, 0, :tv_usec, :ulong, 4
+  end
 
-  attach_function :gettimeofday, [:pointer, :pointer], :int
-end
+  module LibC
+    extend FFI::Library
+    ffi_lib FFI::Library::LIBC
 
-describe FFI::Library, "#attach_function" do
-  it "correctly returns a value for gettimeofday" do
-    t = Timeval.new
-    time = LibC.gettimeofday(t.pointer, nil)
-    expect(time).to be_kind_of(Integer)
+    attach_function :gettimeofday, [:pointer, :pointer], :int
   end
-  
-  it "correctly populates a struct for gettimeofday" do
-    t = Timeval.new
-    LibC.gettimeofday(t.pointer, nil)
-    expect(t[:tv_sec]).to be_kind_of(Numeric)
-    expect(t[:tv_usec]).to be_kind_of(Numeric)
+
+  describe FFI::Library, "#attach_function" do
+    it "correctly returns a value for gettimeofday" do
+      t = Timeval.new
+      time = LibC.gettimeofday(t.pointer, nil)
+      expect(time).to be_kind_of(Integer)
+    end
+
+    it "correctly populates a struct for gettimeofday" do
+      t = Timeval.new
+      LibC.gettimeofday(t.pointer, nil)
+      expect(t[:tv_sec]).to be_kind_of(Numeric)
+      expect(t[:tv_usec]).to be_kind_of(Numeric)
+    end
   end
 end
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/struct_spec.rb new/spec/ffi/struct_spec.rb
--- old/spec/ffi/struct_spec.rb 2015-07-01 04:49:46.000000000 +0200
+++ new/spec/ffi/struct_spec.rb 2016-07-07 00:26:28.000000000 +0200
@@ -7,7 +7,7 @@
 
 describe "Struct aligns fields correctly" do
   it "char, followed by an int" do
-    pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
+    pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
     class CIStruct < FFI::Struct
       layout :c => :char, :i => :int
     end
@@ -15,7 +15,7 @@
   end
 
   it "short, followed by an int" do
-    pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
+    pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
     class SIStruct < FFI::Struct
       layout :s => :short, :i => :int
     end
@@ -23,7 +23,7 @@
   end
 
   it "int, followed by an int" do
-    pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
+    pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
     class IIStruct < FFI::Struct
       layout :i1 => :int, :i => :int
     end
@@ -31,7 +31,7 @@
   end
 
   it "long long, followed by an int" do
-    pending("not supported in 1.8") if RUBY_VERSION =~ /1.8.*/
+    pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
     class LLIStruct < FFI::Struct
       layout :l => :long_long, :i => :int
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/ffi/variadic_spec.rb 
new/spec/ffi/variadic_spec.rb
--- old/spec/ffi/variadic_spec.rb       2015-07-01 04:49:46.000000000 +0200
+++ new/spec/ffi/variadic_spec.rb       2016-07-07 00:26:28.000000000 +0200
@@ -13,6 +13,11 @@
     enum :enum_type2, [:c3, 42, :c4]
     attach_function :pack_varargs, [ :buffer_out, :string, :varargs ], :void
     attach_function :pack_varargs2, [ :buffer_out, :enum_type1, :string, 
:varargs ], :enum_type1
+
+    attach_function :testBlockingOpen, [ ], :pointer
+    attach_function :testBlockingRWva, [ :pointer, :char, :varargs ], :char, 
:blocking => true
+    attach_function :testBlockingWRva, [ :pointer, :char, :varargs ], :char, 
:blocking => true
+    attach_function :testBlockingClose, [ :pointer ], :void
   end
 
   it "takes enum arguments" do
@@ -27,6 +32,20 @@
     expect(LibTest.pack_varargs2(buf, :c1, "ii", :int, :c3, :int, :c4)).to 
eq(:c2)
   end
 
+  it 'can wrap a blocking function with varargs' do
+    pending("not supported in 1.8") if RUBY_VERSION =~ /^1\.8\..*/
+    handle = LibTest.testBlockingOpen
+    expect(handle).not_to be_null
+    begin
+      thWR = Thread.new { LibTest.testBlockingWRva(handle, 63, :int, 40, :int, 
23, :int, 0) }
+      thRW = Thread.new { LibTest.testBlockingRWva(handle, 64, :int, 40, :int, 
24, :int, 0) }
+      expect(thWR.value).to eq(64)
+      expect(thRW.value).to eq(63)
+    ensure
+      LibTest.testBlockingClose(handle)
+    end
+  end
+
   [ 0, 127, -128, -1 ].each do |i|
     it "call variadic with (:char (#{i})) argument" do
       buf = FFI::Buffer.new :long_long


Reply via email to