aboutsummaryrefslogtreecommitdiffstats
path: root/ext/fiddle/function.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-11-23 21:20:56 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-11-23 21:20:56 +0000
commit0f1073ca088f01a40e5c8c3f030760177d82a278 (patch)
tree732c1bbea1d729379b572b529fc464727ad02c88 /ext/fiddle/function.c
parentfebaecee921e7acc19b0cd726d3d72281c35f9b0 (diff)
downloadruby-0f1073ca088f01a40e5c8c3f030760177d82a278.tar.gz
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
Diffstat (limited to 'ext/fiddle/function.c')
-rw-r--r--ext/fiddle/function.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/ext/fiddle/function.c b/ext/fiddle/function.c
index 209c03f71e..164e5f3df6 100644
--- a/ext/fiddle/function.c
+++ b/ext/fiddle/function.c
@@ -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