1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

fiddle: release GVL for ffi_call

Some external functions I wish to call may take a long time
and unnecessarily block other threads.  This may lead to performance
regressions for fast functions as releasing/acquiring the GVL is not
cheap, but can improve performance for long-running functions
in multi-threaded applications.

This also means we must reacquire the GVL when calling Ruby-defined
callbacks for Fiddle::Closure, meaning we must detect whether the
current thread has the GVL by exporting ruby_thread_has_gvl_p
in internal.h

* ext/fiddle/function.c (struct nogvl_ffi_call_args):
  new struct for GVL release
  (nogvl_ffi_call): new function
  (function_call): adjust for GVL release
  [ruby-core:71642] [Feature #11607]
* ext/fiddle/closure.c (struct callback_args):
  new struct for GVL acquire
  (with_gvl_callback): adjusted original callback function
  (callback): wrapper for conditional GVL acquire
* ext/fiddle/depend: add dependencies
* ext/fiddle/extconf.rb: include top_srcdir for internal.h
* internal.h (ruby_thread_has_gvl_p): expose for fiddle
* vm_core.h (ruby_thread_has_gvl_p): moved to internal.h
* test/fiddle/test_function.rb (test_nogvl_poll): new test

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52723 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2015-11-23 21:20:56 +00:00
parent 6965964df6
commit 15476c695d
8 changed files with 124 additions and 36 deletions

View file

@ -1,4 +1,5 @@
#include <fiddle.h>
#include <ruby/thread.h>
#ifdef PRIsVALUE
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
@ -128,13 +129,28 @@ initialize(int argc, VALUE argv[], VALUE self)
return self;
}
struct nogvl_ffi_call_args {
ffi_cif *cif;
void (*fn)(void);
void **values;
fiddle_generic retval;
};
static void *
nogvl_ffi_call(void *ptr)
{
struct nogvl_ffi_call_args *args = ptr;
ffi_call(args->cif, args->fn, &args->retval, args->values);
return NULL;
}
static VALUE
function_call(int argc, VALUE argv[], VALUE self)
{
ffi_cif * cif;
fiddle_generic retval;
struct nogvl_ffi_call_args args = { 0 };
fiddle_generic *generic_args;
void **values;
VALUE cfunc, types, cPointer;
int i;
VALUE alloc_buffer = 0;
@ -148,7 +164,7 @@ function_call(int argc, VALUE argv[], VALUE self)
rb_error_arity(argc, i, i);
}
TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
TypedData_Get_Struct(self, ffi_cif, &function_data_type, args.cif);
if (rb_safe_level() >= 1) {
for (i = 0; i < argc; i++) {
@ -161,7 +177,8 @@ function_call(int argc, VALUE argv[], VALUE self)
generic_args = ALLOCV(alloc_buffer,
(size_t)(argc + 1) * sizeof(void *) + (size_t)argc * sizeof(fiddle_generic));
values = (void **)((char *)generic_args + (size_t)argc * sizeof(fiddle_generic));
args.values = (void **)((char *)generic_args +
(size_t)argc * sizeof(fiddle_generic));
for (i = 0; i < argc; i++) {
VALUE type = RARRAY_AREF(types, i);
@ -177,11 +194,12 @@ function_call(int argc, VALUE argv[], VALUE self)
}
VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
values[i] = (void *)&generic_args[i];
args.values[i] = (void *)&generic_args[i];
}
values[argc] = NULL;
args.values[argc] = NULL;
args.fn = NUM2PTR(rb_Integer(cfunc));
ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
#if defined(_WIN32)
@ -190,7 +208,7 @@ function_call(int argc, VALUE argv[], VALUE self)
ALLOCV_END(alloc_buffer);
return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
return GENERIC2VALUE(rb_iv_get(self, "@return_type"), args.retval);
}
void