diff options
author | Andrew Neitsch <andrew@neitsch.ca> | 2016-06-04 13:55:06 -0600 |
---|---|---|
committer | Andrew Neitsch <andrew@neitsch.ca> | 2016-06-04 13:55:06 -0600 |
commit | a00e9ce868deee260d210ca4cd9da193d13a3ff6 (patch) | |
tree | 8be233b5ddda661b89d75162b2b72cb74e988ce3 | |
parent | 61b7833df75a5144de7207eb149c8691a5110d1b (diff) | |
download | ffi-a00e9ce868deee260d210ca4cd9da193d13a3ff6.tar.gz |
Share blocking code between Call.c and Variadic.c
-rw-r--r-- | ext/ffi_c/Call.c | 37 | ||||
-rw-r--r-- | ext/ffi_c/Call.h | 17 | ||||
-rw-r--r-- | ext/ffi_c/Variadic.c | 24 |
3 files changed, 53 insertions, 25 deletions
diff --git a/ext/ffi_c/Call.c b/ext/ffi_c/Call.c index b028811..a738cb5 100644 --- a/ext/ffi_c/Call.c +++ b/ext/ffi_c/Call.c @@ -338,40 +338,27 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes, } } - -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 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo) 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 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo) #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 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo) 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 --git a/ext/ffi_c/Call.h b/ext/ffi_c/Call.h index 0b971f2..56bdd61 100644 --- a/ext/ffi_c/Call.h +++ b/ext/ffi_c/Call.h @@ -33,6 +33,8 @@ #ifndef RBFFI_CALL_H #define RBFFI_CALL_H +#include "Thread.h" + #ifdef __cplusplus extern "C" { #endif @@ -85,6 +87,21 @@ Invoker rbffi_GetInvoker(struct FunctionType_* fnInfo); 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 --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c index 0027be2..877ffab 100644 --- a/ext/ffi_c/Variadic.c +++ b/ext/ffi_c/Variadic.c @@ -64,6 +64,7 @@ typedef struct VariadicInvoker_ { ffi_abi abi; void* function; int paramCount; + bool blocking; } VariadicInvoker; @@ -84,6 +85,7 @@ variadic_allocate(VALUE klass) invoker->rbAddress = Qnil; invoker->rbEnums = Qnil; invoker->rbReturnType = Qnil; + invoker->blocking = false; return obj; } @@ -115,6 +117,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE 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 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues) 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(); |