Skip to content

Commit

Permalink
Share blocking code between Call.c and Variadic.c
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewdotn committed Jun 4, 2016
1 parent 61b7833 commit a00e9ce
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 25 deletions.
37 changes: 12 additions & 25 deletions ext/ffi_c/Call.c
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions ext/ffi_c/Call.h
Expand Up @@ -33,6 +33,8 @@
#ifndef RBFFI_CALL_H
#define RBFFI_CALL_H

#include "Thread.h"

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions ext/ffi_c/Variadic.c
Expand Up @@ -64,6 +64,7 @@ typedef struct VariadicInvoker_ {
ffi_abi abi;
void* function;
int paramCount;
bool blocking;
} VariadicInvoker;


Expand All @@ -84,6 +85,7 @@ variadic_allocate(VALUE klass)
invoker->rbAddress = Qnil;
invoker->rbEnums = Qnil;
invoker->rbReturnType = Qnil;
invoker->blocking = false;

return obj;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit a00e9ce

Please sign in to comment.