ffi 1.0.2-x86-mingw32 → 1.0.3-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ffi might be problematic. Click here for more details.
- data/History.txt +3 -0
- data/Rakefile +7 -7
- data/ext/ffi_c/AbstractMemory.c +5 -6
- data/ext/ffi_c/Call.c +69 -24
- data/ext/ffi_c/ClosurePool.c +13 -55
- data/ext/ffi_c/Function.c +79 -20
- data/ext/ffi_c/MethodHandle.c +12 -24
- data/ext/ffi_c/Pointer.c +9 -3
- data/ext/ffi_c/Thread.c +169 -0
- data/ext/ffi_c/Thread.h +64 -0
- data/ext/ffi_c/Type.c +8 -2
- data/ext/ffi_c/Types.c +3 -4
- data/ext/ffi_c/Types.h +1 -1
- data/ext/ffi_c/Variadic.c +25 -22
- data/ext/ffi_c/extconf.rb +5 -5
- data/lib/ffi_c.so +0 -0
- data/spec/ffi/async_callback_spec.rb +2 -2
- data/spec/ffi/function_spec.rb +22 -8
- data/spec/ffi/pointer_spec.rb +33 -29
- data/spec/ffi/spec_helper.rb +16 -2
- data/spec/ffi/string_spec.rb +29 -13
- data/spec/ffi/struct_initialize_spec.rb +16 -1
- metadata +7 -7
    
        data/History.txt
    CHANGED
    
    
    
        data/Rakefile
    CHANGED
    
    | @@ -75,7 +75,7 @@ PROJ.name = 'ffi' | |
| 75 75 | 
             
            PROJ.authors = 'Wayne Meissner'
         | 
| 76 76 | 
             
            PROJ.email = 'wmeissner@gmail.com'
         | 
| 77 77 | 
             
            PROJ.url = 'http://wiki.github.com/ffi/ffi'
         | 
| 78 | 
            -
            PROJ.version = '1.0. | 
| 78 | 
            +
            PROJ.version = '1.0.3'
         | 
| 79 79 | 
             
            PROJ.rubyforge.name = 'ffi'
         | 
| 80 80 | 
             
            PROJ.readme_file = 'README.rdoc'
         | 
| 81 81 |  | 
| @@ -90,11 +90,11 @@ PROJ.ann.email[:server] = 'smtp.gmail.com' | |
| 90 90 | 
             
            PROJ.gem.need_tar = false
         | 
| 91 91 | 
             
            PROJ.gem.files = %w(History.txt LICENSE README.rdoc Rakefile) + Dir.glob("{ext,gen,lib,spec,tasks}/**/*")
         | 
| 92 92 | 
             
            PROJ.gem.platform = Gem::Platform::RUBY
         | 
| 93 | 
            -
            PROJ.gem.required_ruby_version = ">= 1.9.2"
         | 
| 93 | 
            +
            #PROJ.gem.required_ruby_version = ">= 1.9.2"
         | 
| 94 94 |  | 
| 95 95 | 
             
            # Override Mr. Bones autogenerated extensions and force ours in
         | 
| 96 96 | 
             
            PROJ.gem.extras['extensions'] = %w(ext/ffi_c/extconf.rb gen/Rakefile)
         | 
| 97 | 
            -
            PROJ.gem.extras['required_ruby_version'] = ">= 1.9.2"
         | 
| 97 | 
            +
            #PROJ.gem.extras['required_ruby_version'] = ">= 1.9.2"
         | 
| 98 98 |  | 
| 99 99 | 
             
            # RDoc
         | 
| 100 100 | 
             
            PROJ.rdoc.exclude << '^ext\/'
         | 
| @@ -116,23 +116,23 @@ TEST_DEPS = [ LIBTEST ] | |
| 116 116 | 
             
            if RUBY_PLATFORM == "java"
         | 
| 117 117 | 
             
              desc "Run all specs"
         | 
| 118 118 | 
             
              task :specs => TEST_DEPS do
         | 
| 119 | 
            -
                sh %{#{Gem.ruby} -S  | 
| 119 | 
            +
                sh %{#{Gem.ruby} -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
         | 
| 120 120 | 
             
              end
         | 
| 121 121 | 
             
              desc "Run rubinius specs"
         | 
| 122 122 | 
             
              task :rbxspecs => TEST_DEPS do
         | 
| 123 | 
            -
                sh %{#{Gem.ruby} -S  | 
| 123 | 
            +
                sh %{#{Gem.ruby} -S rspec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
         | 
| 124 124 | 
             
              end
         | 
| 125 125 | 
             
            else
         | 
| 126 126 | 
             
              TEST_DEPS.unshift :compile
         | 
| 127 127 | 
             
              desc "Run all specs"
         | 
| 128 128 | 
             
              task :specs => TEST_DEPS do
         | 
| 129 129 | 
             
                ENV["MRI_FFI"] = "1"
         | 
| 130 | 
            -
                sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S  | 
| 130 | 
            +
                sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
         | 
| 131 131 | 
             
              end
         | 
| 132 132 | 
             
              desc "Run rubinius specs"
         | 
| 133 133 | 
             
              task :rbxspecs => TEST_DEPS do
         | 
| 134 134 | 
             
                ENV["MRI_FFI"] = "1"
         | 
| 135 | 
            -
                sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S  | 
| 135 | 
            +
                sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S rspec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
         | 
| 136 136 | 
             
              end
         | 
| 137 137 | 
             
            end
         | 
| 138 138 |  | 
    
        data/ext/ffi_c/AbstractMemory.c
    CHANGED
    
    | @@ -133,10 +133,10 @@ memory_get_array_of_##name(VALUE self, VALUE offset, VALUE length) \ | |
| 133 133 | 
             
                long count = NUM2LONG(length); \
         | 
| 134 134 | 
             
                long off = NUM2LONG(offset); \
         | 
| 135 135 | 
             
                AbstractMemory* memory = MEMORY(self); \
         | 
| 136 | 
            +
                VALUE retVal = rb_ary_new2(count); \
         | 
| 136 137 | 
             
                long i; \
         | 
| 137 138 | 
             
                checkRead(memory); \
         | 
| 138 139 | 
             
                checkBounds(memory, off, count * sizeof(type)); \
         | 
| 139 | 
            -
                VALUE retVal = rb_ary_new2(count); \
         | 
| 140 140 | 
             
                for (i = 0; i < count; ++i) { \
         | 
| 141 141 | 
             
                    type tmp; \
         | 
| 142 142 | 
             
                    memcpy(&tmp, memory->address + off + (i * sizeof(type)), sizeof(tmp)); \
         | 
| @@ -165,7 +165,6 @@ SWAPU16(uint16_t x) | |
| 165 165 | 
             
                return bswap16(x);
         | 
| 166 166 | 
             
            }
         | 
| 167 167 |  | 
| 168 | 
            -
            #define SWAP16(x) (x)
         | 
| 169 168 | 
             
            #if __GNUC__ < 4
         | 
| 170 169 | 
             
            #define bswap32(x) \
         | 
| 171 170 | 
             
                   (((x << 24) & 0xff000000) | \
         | 
| @@ -208,10 +207,10 @@ SWAPU64(uint64_t x) | |
| 208 207 | 
             
            }
         | 
| 209 208 |  | 
| 210 209 | 
             
            #else
         | 
| 211 | 
            -
            # define  | 
| 212 | 
            -
            # define  | 
| 213 | 
            -
            # define SWAPS64(x) __builtin_bswap64(x)
         | 
| 214 | 
            -
            # define SWAPU64(x) __builtin_bswap64(x)
         | 
| 210 | 
            +
            # define SWAPS32(x) ((int32_t) __builtin_bswap32(x))
         | 
| 211 | 
            +
            # define SWAPU32(x) ((uint32_t) __builtin_bswap32(x))
         | 
| 212 | 
            +
            # define SWAPS64(x) ((int64_t) __builtin_bswap64(x))
         | 
| 213 | 
            +
            # define SWAPU64(x) ((uint64_t) __builtin_bswap64(x))
         | 
| 215 214 | 
             
            #endif
         | 
| 216 215 |  | 
| 217 216 | 
             
            #if LONG_MAX > INT_MAX
         | 
    
        data/ext/ffi_c/Call.c
    CHANGED
    
    | @@ -43,6 +43,7 @@ | |
| 43 43 | 
             
            #include "LastError.h"
         | 
| 44 44 | 
             
            #include "Call.h"
         | 
| 45 45 | 
             
            #include "MappedType.h"
         | 
| 46 | 
            +
            #include "Thread.h"
         | 
| 46 47 |  | 
| 47 48 | 
             
            #ifdef USE_RAW
         | 
| 48 49 | 
             
            #  ifndef __i386__
         | 
| @@ -239,13 +240,13 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes, | |
| 239 240 | 
             
            }
         | 
| 240 241 |  | 
| 241 242 |  | 
| 242 | 
            -
            #if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION)
         | 
| 243 | 
            -
             | 
| 244 243 | 
             
            typedef struct BlockingCall_ {
         | 
| 245 244 | 
             
                void* function;
         | 
| 246 245 | 
             
                FunctionType* info;
         | 
| 247 246 | 
             
                void **ffiValues;
         | 
| 248 | 
            -
                 | 
| 247 | 
            +
                void* retval;
         | 
| 248 | 
            +
                void* stkretval;
         | 
| 249 | 
            +
                void* params;
         | 
| 249 250 | 
             
            } BlockingCall;
         | 
| 250 251 |  | 
| 251 252 | 
             
            static VALUE
         | 
| @@ -257,7 +258,28 @@ call_blocking_function(void* data) | |
| 257 258 |  | 
| 258 259 | 
             
                return Qnil;
         | 
| 259 260 | 
             
            }
         | 
| 260 | 
            -
             | 
| 261 | 
            +
             | 
| 262 | 
            +
            static VALUE
         | 
| 263 | 
            +
            do_blocking_call(void *data)
         | 
| 264 | 
            +
            {
         | 
| 265 | 
            +
                rbffi_thread_blocking_region(call_blocking_function, data, (void *) -1, NULL);
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                return Qnil;
         | 
| 268 | 
            +
            }
         | 
| 269 | 
            +
             | 
| 270 | 
            +
            static VALUE
         | 
| 271 | 
            +
            cleanup_blocking_call(void *data)
         | 
| 272 | 
            +
            {
         | 
| 273 | 
            +
                BlockingCall* bc = (BlockingCall *) data;
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                memcpy(bc->stkretval, bc->retval, MAX(bc->info->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
         | 
| 276 | 
            +
                xfree(bc->params);
         | 
| 277 | 
            +
                xfree(bc->ffiValues);
         | 
| 278 | 
            +
                xfree(bc->retval);
         | 
| 279 | 
            +
                xfree(bc);
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                return Qnil;
         | 
| 282 | 
            +
            }
         | 
| 261 283 |  | 
| 262 284 | 
             
            VALUE
         | 
| 263 285 | 
             
            rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
         | 
| @@ -265,38 +287,61 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo) | |
| 265 287 | 
             
                void* retval;
         | 
| 266 288 | 
             
                void** ffiValues;
         | 
| 267 289 | 
             
                FFIStorage* params;
         | 
| 290 | 
            +
                VALUE rbReturnValue;
         | 
| 268 291 |  | 
| 269 | 
            -
             | 
| 270 | 
            -
                 | 
| 271 | 
            -
             | 
| 272 | 
            -
             | 
| 273 | 
            -
                rbffi_SetupCallParams(argc, argv,
         | 
| 274 | 
            -
                    fnInfo->parameterCount, fnInfo->parameterTypes, params, ffiValues,
         | 
| 275 | 
            -
                    fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
         | 
| 292 | 
            +
            #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
         | 
| 293 | 
            +
                rbffi_thread_t oldThread;
         | 
| 294 | 
            +
            #endif
         | 
| 276 295 |  | 
| 277 | 
            -
             | 
| 296 | 
            +
                retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
         | 
| 297 | 
            +
                
         | 
| 278 298 | 
             
                if (unlikely(fnInfo->blocking)) {
         | 
| 279 | 
            -
                    BlockingCall bc;
         | 
| 299 | 
            +
                    BlockingCall* bc;
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                    // due to the way thread switching works on older ruby variants, we
         | 
| 302 | 
            +
                    // cannot allocate anything passed to the blocking function on the stack
         | 
| 303 | 
            +
                    ffiValues = ALLOC_N(void *, fnInfo->parameterCount);
         | 
| 304 | 
            +
                    params = ALLOC_N(FFIStorage, fnInfo->parameterCount);
         | 
| 305 | 
            +
                    bc = ALLOC_N(BlockingCall, 1);
         | 
| 306 | 
            +
                    bc->info = fnInfo;
         | 
| 307 | 
            +
                    bc->function = function;
         | 
| 308 | 
            +
                    bc->ffiValues = ffiValues;
         | 
| 309 | 
            +
                    bc->params = params;
         | 
| 310 | 
            +
                    bc->retval = xmalloc(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
         | 
| 311 | 
            +
                    bc->stkretval = retval;
         | 
| 312 | 
            +
             | 
| 313 | 
            +
                    rbffi_SetupCallParams(argc, argv,
         | 
| 314 | 
            +
                        fnInfo->parameterCount, fnInfo->parameterTypes, params, ffiValues,
         | 
| 315 | 
            +
                        fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
         | 
| 316 | 
            +
                    
         | 
| 317 | 
            +
                    rb_ensure(do_blocking_call, (VALUE) bc, cleanup_blocking_call, (VALUE) bc);
         | 
| 318 | 
            +
                    
         | 
| 319 | 
            +
                } else {
         | 
| 280 320 |  | 
| 281 | 
            -
                     | 
| 282 | 
            -
                     | 
| 283 | 
            -
                    bc.ffiValues = ffiValues;
         | 
| 284 | 
            -
                    bc.retval = retval;
         | 
| 321 | 
            +
                    ffiValues = ALLOCA_N(void *, fnInfo->parameterCount);
         | 
| 322 | 
            +
                    params = ALLOCA_N(FFIStorage, fnInfo->parameterCount);
         | 
| 285 323 |  | 
| 286 | 
            -
                     | 
| 287 | 
            -
             | 
| 324 | 
            +
                    rbffi_SetupCallParams(argc, argv,
         | 
| 325 | 
            +
                        fnInfo->parameterCount, fnInfo->parameterTypes, params, ffiValues,
         | 
| 326 | 
            +
                        fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
         | 
| 327 | 
            +
             | 
| 328 | 
            +
            #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
         | 
| 329 | 
            +
                    oldThread = rbffi_active_thread;
         | 
| 330 | 
            +
                    rbffi_active_thread = rbffi_thread_self();
         | 
| 331 | 
            +
            #endif
         | 
| 332 | 
            +
                    retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
         | 
| 288 333 | 
             
                    ffi_call(&fnInfo->ffi_cif, FFI_FN(function), retval, ffiValues);
         | 
| 289 | 
            -
             | 
| 290 | 
            -
            # | 
| 291 | 
            -
             | 
| 334 | 
            +
             | 
| 335 | 
            +
            #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
         | 
| 336 | 
            +
                    rbffi_active_thread = oldThread;
         | 
| 292 337 | 
             
            #endif
         | 
| 338 | 
            +
                }
         | 
| 293 339 |  | 
| 294 340 | 
             
                if (unlikely(!fnInfo->ignoreErrno)) {
         | 
| 295 341 | 
             
                    rbffi_save_errno();
         | 
| 296 342 | 
             
                }
         | 
| 297 343 |  | 
| 298 | 
            -
                return rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval | 
| 299 | 
            -
                    fnInfo->rbEnums);
         | 
| 344 | 
            +
                return rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval);
         | 
| 300 345 | 
             
            }
         | 
| 301 346 |  | 
| 302 347 | 
             
            static inline void*
         | 
    
        data/ext/ffi_c/ClosurePool.c
    CHANGED
    
    | @@ -1,28 +1,20 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 | 
            -
             * Copyright (c) 2009, Wayne Meissner
         | 
| 2 | 
            +
             * Copyright (c) 2009, 2010 Wayne Meissner
         | 
| 3 3 | 
             
             * All rights reserved.
         | 
| 4 4 | 
             
             *
         | 
| 5 | 
            -
             *  | 
| 6 | 
            -
             * modification, are permitted provided that the following conditions are met:
         | 
| 5 | 
            +
             * This file is part of ruby-ffi.
         | 
| 7 6 | 
             
             *
         | 
| 8 | 
            -
             *  | 
| 9 | 
            -
             * | 
| 10 | 
            -
             *  | 
| 11 | 
            -
             *   this list of conditions and the following disclaimer in the documentation
         | 
| 12 | 
            -
             *   and/or other materials provided with the distribution.
         | 
| 13 | 
            -
             * * The name of the author or authors may not be used to endorse or promote
         | 
| 14 | 
            -
             *   products derived from this software without specific prior written permission.
         | 
| 7 | 
            +
             * This code is free software: you can redistribute it and/or modify it under
         | 
| 8 | 
            +
             * the terms of the GNU Lesser General Public License version 3 only, as
         | 
| 9 | 
            +
             * published by the Free Software Foundation.
         | 
| 15 10 | 
             
             *
         | 
| 16 | 
            -
             *  | 
| 17 | 
            -
             *  | 
| 18 | 
            -
             *  | 
| 19 | 
            -
             *  | 
| 20 | 
            -
             * | 
| 21 | 
            -
             *  | 
| 22 | 
            -
             *  | 
| 23 | 
            -
             * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
         | 
| 24 | 
            -
             * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         | 
| 25 | 
            -
             * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
| 11 | 
            +
             * This code is distributed in the hope that it will be useful, but WITHOUT
         | 
| 12 | 
            +
             * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
         | 
| 13 | 
            +
             * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
         | 
| 14 | 
            +
             * version 3 for more details.
         | 
| 15 | 
            +
             *
         | 
| 16 | 
            +
             * You should have received a copy of the GNU Lesser General Public License
         | 
| 17 | 
            +
             * version 3 along with this work.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 26 18 | 
             
             */
         | 
| 27 19 |  | 
| 28 20 | 
             
            #include <sys/param.h>
         | 
| @@ -40,9 +32,6 @@ | |
| 40 32 | 
             
            #endif
         | 
| 41 33 | 
             
            #include <errno.h>
         | 
| 42 34 | 
             
            #include <ruby.h>
         | 
| 43 | 
            -
            #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
         | 
| 44 | 
            -
            # include <pthread.h>
         | 
| 45 | 
            -
            #endif
         | 
| 46 35 |  | 
| 47 36 | 
             
            #include <ffi.h>
         | 
| 48 37 | 
             
            #include "rbffi.h"
         | 
| @@ -57,10 +46,6 @@ | |
| 57 46 | 
             
            #include "ClosurePool.h"
         | 
| 58 47 |  | 
| 59 48 |  | 
| 60 | 
            -
            #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
         | 
| 61 | 
            -
            #  define USE_PTHREAD_LOCAL
         | 
| 62 | 
            -
            #endif
         | 
| 63 | 
            -
             | 
| 64 49 | 
             
            #ifndef roundup
         | 
| 65 50 | 
             
            #  define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
         | 
| 66 51 | 
             
            #endif
         | 
| @@ -78,22 +63,11 @@ struct ClosurePool_ { | |
| 78 63 | 
             
                void* ctx;
         | 
| 79 64 | 
             
                int closureSize;
         | 
| 80 65 | 
             
                bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize);
         | 
| 81 | 
            -
            #if defined (HAVE_NATIVETHREAD) && !defined(_WIN32)
         | 
| 82 | 
            -
                pthread_mutex_t mutex;
         | 
| 83 | 
            -
            #endif
         | 
| 84 66 | 
             
                struct Memory* blocks; /* Keeps track of all the allocated memory for this pool */
         | 
| 85 67 | 
             
                Closure* list;
         | 
| 86 68 | 
             
                long refcnt;
         | 
| 87 69 | 
             
            };
         | 
| 88 70 |  | 
| 89 | 
            -
            #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
         | 
| 90 | 
            -
            #  define pool_lock(p) pthread_mutex_lock(&(p)->mutex)
         | 
| 91 | 
            -
            #  define pool_unlock(p)  pthread_mutex_unlock(&(p)->mutex)
         | 
| 92 | 
            -
            #else
         | 
| 93 | 
            -
            #  define pool_lock(p)
         | 
| 94 | 
            -
            #  define pool_unlock(p)
         | 
| 95 | 
            -
            #endif
         | 
| 96 | 
            -
             | 
| 97 71 | 
             
            static int pageSize;
         | 
| 98 72 |  | 
| 99 73 | 
             
            static void* allocatePage(void);
         | 
| @@ -113,10 +87,6 @@ rbffi_ClosurePool_New(int closureSize, | |
| 113 87 | 
             
                pool->prep = prep;
         | 
| 114 88 | 
             
                pool->refcnt = 1;
         | 
| 115 89 |  | 
| 116 | 
            -
            #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
         | 
| 117 | 
            -
                pthread_mutex_init(&pool->mutex, NULL);
         | 
| 118 | 
            -
            #endif
         | 
| 119 | 
            -
             | 
| 120 90 | 
             
                return pool;
         | 
| 121 91 | 
             
            }
         | 
| 122 92 |  | 
| @@ -140,10 +110,7 @@ rbffi_ClosurePool_Free(ClosurePool* pool) | |
| 140 110 | 
             
            {
         | 
| 141 111 | 
             
                if (pool != NULL) {
         | 
| 142 112 | 
             
                    int refcnt;
         | 
| 143 | 
            -
                    pool_lock(pool);
         | 
| 144 113 | 
             
                    refcnt = --(pool->refcnt);
         | 
| 145 | 
            -
                    pool_unlock(pool);
         | 
| 146 | 
            -
             | 
| 147 114 | 
             
                    if (refcnt == 0) {
         | 
| 148 115 | 
             
                        cleanup_closure_pool(pool);
         | 
| 149 116 | 
             
                    }
         | 
| @@ -160,13 +127,11 @@ rbffi_Closure_Alloc(ClosurePool* pool) | |
| 160 127 | 
             
                int nclosures, trampolineSize;
         | 
| 161 128 | 
             
                int i;
         | 
| 162 129 |  | 
| 163 | 
            -
                pool_lock(pool);
         | 
| 164 130 | 
             
                if (pool->list != NULL) {
         | 
| 165 131 | 
             
                    Closure* closure = pool->list;
         | 
| 166 132 | 
             
                    pool->list = pool->list->next;
         | 
| 167 133 | 
             
                    pool->refcnt++;
         | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 134 | 
            +
                
         | 
| 170 135 | 
             
                    return closure;
         | 
| 171 136 | 
             
                }
         | 
| 172 137 |  | 
| @@ -177,7 +142,6 @@ rbffi_Closure_Alloc(ClosurePool* pool) | |
| 177 142 | 
             
                code = allocatePage();
         | 
| 178 143 |  | 
| 179 144 | 
             
                if (block == NULL || list == NULL || code == NULL) {
         | 
| 180 | 
            -
                    pool_unlock(pool);
         | 
| 181 145 | 
             
                    snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno));
         | 
| 182 146 | 
             
                    goto error;
         | 
| 183 147 | 
             
                }
         | 
| @@ -208,13 +172,10 @@ rbffi_Closure_Alloc(ClosurePool* pool) | |
| 208 172 | 
             
                pool->list = list->next;
         | 
| 209 173 | 
             
                pool->refcnt++;
         | 
| 210 174 |  | 
| 211 | 
            -
                pool_unlock(pool);
         | 
| 212 | 
            -
             | 
| 213 175 | 
             
                /* Use the first one as the new handle */
         | 
| 214 176 | 
             
                return list;
         | 
| 215 177 |  | 
| 216 178 | 
             
            error:
         | 
| 217 | 
            -
                pool_unlock(pool);
         | 
| 218 179 | 
             
                free(block);
         | 
| 219 180 | 
             
                free(list);
         | 
| 220 181 | 
             
                if (code != NULL) {
         | 
| @@ -232,13 +193,10 @@ rbffi_Closure_Free(Closure* closure) | |
| 232 193 | 
             
                if (closure != NULL) {
         | 
| 233 194 | 
             
                    ClosurePool* pool = closure->pool;
         | 
| 234 195 | 
             
                    int refcnt;
         | 
| 235 | 
            -
                    pool_lock(pool);
         | 
| 236 196 | 
             
                    // Just push it on the front of the free list
         | 
| 237 197 | 
             
                    closure->next = pool->list;
         | 
| 238 198 | 
             
                    pool->list = closure;
         | 
| 239 199 | 
             
                    refcnt = --(pool->refcnt);
         | 
| 240 | 
            -
                    pool_unlock(pool);
         | 
| 241 | 
            -
             | 
| 242 200 | 
             
                    if (refcnt == 0) {
         | 
| 243 201 | 
             
                        cleanup_closure_pool(pool);
         | 
| 244 202 | 
             
                    }
         | 
    
        data/ext/ffi_c/Function.c
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 | 
            -
             * Copyright (c) 2009, Wayne Meissner
         | 
| 2 | 
            +
             * Copyright (c) 2009, 2010 Wayne Meissner
         | 
| 3 3 |  | 
| 4 4 | 
             
             * All rights reserved.
         | 
| 5 5 | 
             
             *
         | 
| @@ -35,6 +35,7 @@ | |
| 35 35 | 
             
            #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
         | 
| 36 36 | 
             
            #include <pthread.h>
         | 
| 37 37 | 
             
            #endif
         | 
| 38 | 
            +
            #include <fcntl.h>
         | 
| 38 39 |  | 
| 39 40 | 
             
            #include "rbffi.h"
         | 
| 40 41 | 
             
            #include "compat.h"
         | 
| @@ -49,6 +50,7 @@ | |
| 49 50 | 
             
            #include "ClosurePool.h"
         | 
| 50 51 | 
             
            #include "Function.h"
         | 
| 51 52 | 
             
            #include "MappedType.h"
         | 
| 53 | 
            +
            #include "Thread.h"
         | 
| 52 54 |  | 
| 53 55 | 
             
            typedef struct Function_ {
         | 
| 54 56 | 
             
                AbstractMemory memory;
         | 
| @@ -67,12 +69,10 @@ static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* | |
| 67 69 | 
             
            static bool callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
         | 
| 68 70 | 
             
            static void* callback_with_gvl(void* data);
         | 
| 69 71 |  | 
| 70 | 
            -
            # | 
| 71 | 
            -
            # define DEFER_ASYNC_CALLBACK 1
         | 
| 72 | 
            -
            #endif
         | 
| 72 | 
            +
            #define DEFER_ASYNC_CALLBACK 1
         | 
| 73 73 |  | 
| 74 74 | 
             
            #if defined(DEFER_ASYNC_CALLBACK)
         | 
| 75 | 
            -
            static VALUE async_cb_event(void);
         | 
| 75 | 
            +
            static VALUE async_cb_event(void *);
         | 
| 76 76 | 
             
            static VALUE async_cb_call(void *);
         | 
| 77 77 | 
             
            #endif
         | 
| 78 78 |  | 
| @@ -96,7 +96,7 @@ struct gvl_callback { | |
| 96 96 | 
             
                Closure* closure;
         | 
| 97 97 | 
             
                void*    retval;
         | 
| 98 98 | 
             
                void**   parameters;
         | 
| 99 | 
            -
             | 
| 99 | 
            +
                bool done;
         | 
| 100 100 | 
             
            #if defined(DEFER_ASYNC_CALLBACK)
         | 
| 101 101 | 
             
                struct gvl_callback* next;
         | 
| 102 102 | 
             
            # ifndef _WIN32
         | 
| @@ -112,8 +112,11 @@ struct gvl_callback { | |
| 112 112 | 
             
            #if defined(DEFER_ASYNC_CALLBACK)
         | 
| 113 113 | 
             
            static struct gvl_callback* async_cb_list = NULL;
         | 
| 114 114 | 
             
            # ifndef _WIN32
         | 
| 115 | 
            -
            static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
         | 
| 116 | 
            -
            static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
         | 
| 115 | 
            +
                static pthread_mutex_t async_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
         | 
| 116 | 
            +
                static pthread_cond_t async_cb_cond = PTHREAD_COND_INITIALIZER;
         | 
| 117 | 
            +
            #  if !defined(HAVE_RB_THREAD_BLOCKING_REGION)
         | 
| 118 | 
            +
                static int async_cb_pipe[2];
         | 
| 119 | 
            +
            #  endif
         | 
| 117 120 | 
             
            # else
         | 
| 118 121 | 
             
            static HANDLE async_cb_cond;
         | 
| 119 122 | 
             
            static CRITICAL_SECTION async_cb_lock;
         | 
| @@ -265,9 +268,15 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) | |
| 265 268 | 
             
                    }
         | 
| 266 269 |  | 
| 267 270 | 
             
            #if defined(DEFER_ASYNC_CALLBACK)
         | 
| 271 | 
            +
            # if !defined(HAVE_RB_THREAD_BLOCKING_REGION)
         | 
| 272 | 
            +
                    pipe(async_cb_pipe);
         | 
| 273 | 
            +
                    fcntl(async_cb_pipe[0], F_SETFL, fcntl(async_cb_pipe[0], F_GETFL) | O_NONBLOCK);
         | 
| 274 | 
            +
                    fcntl(async_cb_pipe[1], F_SETFL, fcntl(async_cb_pipe[1], F_GETFL) | O_NONBLOCK);
         | 
| 275 | 
            +
            # endif
         | 
| 268 276 | 
             
                    if (async_cb_thread == Qnil) {
         | 
| 269 277 | 
             
                        async_cb_thread = rb_thread_create(async_cb_event, NULL);
         | 
| 270 278 | 
             
                    }
         | 
| 279 | 
            +
             | 
| 271 280 | 
             
            #endif
         | 
| 272 281 |  | 
| 273 282 | 
             
                    fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
         | 
| @@ -380,12 +389,9 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) | |
| 380 389 | 
             
                cb.closure = (Closure *) user_data;
         | 
| 381 390 | 
             
                cb.retval = retval;
         | 
| 382 391 | 
             
                cb.parameters = parameters;
         | 
| 392 | 
            +
                cb.done = false;
         | 
| 383 393 |  | 
| 384 | 
            -
             | 
| 385 | 
            -
                if (ruby_thread_has_gvl_p()) {
         | 
| 386 | 
            -
            #else
         | 
| 387 | 
            -
                if (1) {
         | 
| 388 | 
            -
            #endif
         | 
| 394 | 
            +
                if (rbffi_thread_has_gvl_p()) {
         | 
| 389 395 | 
             
                    callback_with_gvl(&cb);
         | 
| 390 396 |  | 
| 391 397 | 
             
            #if defined(HAVE_RUBY_NATIVE_THREAD_P) && defined (HAVE_RB_THREAD_CALL_WITH_GVL)
         | 
| @@ -394,21 +400,38 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) | |
| 394 400 | 
             
            #endif
         | 
| 395 401 | 
             
            #if defined(DEFER_ASYNC_CALLBACK) && !defined(_WIN32)
         | 
| 396 402 | 
             
                } else {
         | 
| 403 | 
            +
                    bool empty = false;
         | 
| 404 | 
            +
             | 
| 397 405 | 
             
                    pthread_mutex_init(&cb.async_mutex, NULL);
         | 
| 398 406 | 
             
                    pthread_cond_init(&cb.async_cond, NULL);
         | 
| 399 407 |  | 
| 400 | 
            -
                    pthread_mutex_lock(&cb.async_mutex);
         | 
| 401 | 
            -
             | 
| 402 408 | 
             
                    // Now signal the async callback thread
         | 
| 403 409 | 
             
                    pthread_mutex_lock(&async_cb_mutex);
         | 
| 410 | 
            +
                    empty = async_cb_list == NULL;
         | 
| 404 411 | 
             
                    cb.next = async_cb_list;
         | 
| 405 412 | 
             
                    async_cb_list = &cb;
         | 
| 406 | 
            -
                    pthread_cond_signal(&async_cb_cond);
         | 
| 407 413 | 
             
                    pthread_mutex_unlock(&async_cb_mutex);
         | 
| 408 414 |  | 
| 415 | 
            +
            #if !defined(HAVE_RB_THREAD_BLOCKING_REGION)
         | 
| 416 | 
            +
                    // Only signal if the list was empty
         | 
| 417 | 
            +
                    if (empty) {
         | 
| 418 | 
            +
                        char c;
         | 
| 419 | 
            +
                        write(async_cb_pipe[1], &c, 1);
         | 
| 420 | 
            +
                    }
         | 
| 421 | 
            +
            #else
         | 
| 422 | 
            +
                    pthread_cond_signal(&async_cb_cond);
         | 
| 423 | 
            +
            #endif
         | 
| 424 | 
            +
             | 
| 409 425 | 
             
                    // Wait for the thread executing the ruby callback to signal it is done
         | 
| 410 | 
            -
                     | 
| 411 | 
            -
             | 
| 426 | 
            +
                    pthread_mutex_lock(&cb.async_mutex);
         | 
| 427 | 
            +
                    while (!cb.done) {
         | 
| 428 | 
            +
                        pthread_cond_wait(&cb.async_cond, &cb.async_mutex);
         | 
| 429 | 
            +
                    }
         | 
| 430 | 
            +
                    pthread_mutex_unlock(&cb.async_mutex);
         | 
| 431 | 
            +
                    pthread_cond_destroy(&cb.async_cond);
         | 
| 432 | 
            +
                    pthread_mutex_destroy(&cb.async_mutex);
         | 
| 433 | 
            +
             | 
| 434 | 
            +
            #elif defined(DEFER_ASYNC_CALLBACK) && defined(_WIN32)
         | 
| 412 435 | 
             
                } else {
         | 
| 413 436 | 
             
                    cb.async_event = CreateEvent(NULL, FALSE, FALSE, NULL);
         | 
| 414 437 |  | 
| @@ -436,8 +459,9 @@ struct async_wait { | |
| 436 459 | 
             
            static VALUE async_cb_wait(void *);
         | 
| 437 460 | 
             
            static void async_cb_stop(void *);
         | 
| 438 461 |  | 
| 462 | 
            +
            #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
         | 
| 439 463 | 
             
            static VALUE
         | 
| 440 | 
            -
            async_cb_event(void)
         | 
| 464 | 
            +
            async_cb_event(void* unused)
         | 
| 441 465 | 
             
            {
         | 
| 442 466 | 
             
                struct async_wait w = { 0 };
         | 
| 443 467 |  | 
| @@ -453,6 +477,40 @@ async_cb_event(void) | |
| 453 477 | 
             
                return Qnil;
         | 
| 454 478 | 
             
            }
         | 
| 455 479 |  | 
| 480 | 
            +
            #else
         | 
| 481 | 
            +
            static VALUE
         | 
| 482 | 
            +
            async_cb_event(void* unused)
         | 
| 483 | 
            +
            {
         | 
| 484 | 
            +
                while (true) {
         | 
| 485 | 
            +
                    struct gvl_callback* cb;
         | 
| 486 | 
            +
                    char buf[64];
         | 
| 487 | 
            +
             | 
| 488 | 
            +
                    if (read(async_cb_pipe[0], buf, sizeof(buf)) < 0) {
         | 
| 489 | 
            +
                        rb_thread_wait_fd(async_cb_pipe[0]);
         | 
| 490 | 
            +
                        while (read(async_cb_pipe[0], buf, sizeof (buf)) < 0) {
         | 
| 491 | 
            +
                            if (rb_io_wait_readable(async_cb_pipe[0]) != Qtrue) {
         | 
| 492 | 
            +
                                return Qfalse;
         | 
| 493 | 
            +
                            }
         | 
| 494 | 
            +
                        }
         | 
| 495 | 
            +
                    }
         | 
| 496 | 
            +
             | 
| 497 | 
            +
                    pthread_mutex_lock(&async_cb_mutex);
         | 
| 498 | 
            +
                    cb = async_cb_list;
         | 
| 499 | 
            +
                    async_cb_list = NULL;
         | 
| 500 | 
            +
                    pthread_mutex_unlock(&async_cb_mutex);
         | 
| 501 | 
            +
             | 
| 502 | 
            +
                    while (cb != NULL) {
         | 
| 503 | 
            +
                        struct gvl_callback* next = cb->next;
         | 
| 504 | 
            +
                        // Start up a new ruby thread to run the ruby callback
         | 
| 505 | 
            +
                        rb_thread_create(async_cb_call, cb);
         | 
| 506 | 
            +
                        cb = next;
         | 
| 507 | 
            +
                    }
         | 
| 508 | 
            +
                }
         | 
| 509 | 
            +
             | 
| 510 | 
            +
                return Qnil;
         | 
| 511 | 
            +
            }
         | 
| 512 | 
            +
            #endif
         | 
| 513 | 
            +
             | 
| 456 514 | 
             
            #ifdef _WIN32
         | 
| 457 515 | 
             
            static VALUE
         | 
| 458 516 | 
             
            async_cb_wait(void *data)
         | 
| @@ -538,6 +596,7 @@ async_cb_call(void *data) | |
| 538 596 | 
             
                SetEvent(cb->async_event);
         | 
| 539 597 | 
             
            #else
         | 
| 540 598 | 
             
                pthread_mutex_lock(&cb->async_mutex);
         | 
| 599 | 
            +
                cb->done = true;
         | 
| 541 600 | 
             
                pthread_cond_signal(&cb->async_cond);
         | 
| 542 601 | 
             
                pthread_mutex_unlock(&cb->async_mutex);
         | 
| 543 602 | 
             
            #endif
         | 
| @@ -624,7 +683,7 @@ callback_with_gvl(void* data) | |
| 624 683 | 
             
                        case NATIVE_FUNCTION:
         | 
| 625 684 | 
             
                        case NATIVE_CALLBACK:
         | 
| 626 685 | 
             
                        case NATIVE_STRUCT:
         | 
| 627 | 
            -
                            param = rbffi_NativeValue_ToRuby(paramType, rbParamType, parameters[i] | 
| 686 | 
            +
                            param = rbffi_NativeValue_ToRuby(paramType, rbParamType, parameters[i]);
         | 
| 628 687 | 
             
                            break;
         | 
| 629 688 |  | 
| 630 689 | 
             
                        default:
         |