diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-23 21:20:56 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-23 21:20:56 +0000 |
commit | 0f1073ca088f01a40e5c8c3f030760177d82a278 (patch) | |
tree | 732c1bbea1d729379b572b529fc464727ad02c88 /ext/fiddle/function.c | |
parent | febaecee921e7acc19b0cd726d3d72281c35f9b0 (diff) | |
download | ruby-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.c | 36 |
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 |