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
