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 /test/fiddle | |
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 'test/fiddle')
-rw-r--r-- | test/fiddle/test_function.rb | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/test/fiddle/test_function.rb b/test/fiddle/test_function.rb index 2e3a432ec3..9351f961df 100644 --- a/test/fiddle/test_function.rb +++ b/test/fiddle/test_function.rb @@ -73,6 +73,25 @@ module Fiddle assert_equal("123", str.to_s) end + def test_nogvl_poll + begin + poll = @libc['poll'] + rescue Fiddle::DLError + skip 'poll(2) not available' + end + f = Function.new(poll, [TYPE_VOIDP, TYPE_INT, TYPE_INT], TYPE_INT) + + msec = 200 + t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + th = Thread.new { f.call(nil, 0, msec) } + n1 = f.call(nil, 0, msec) + n2 = th.value + t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + assert_in_delta(msec, t1 - t0, 100, 'slept correct amount of time') + assert_equal(0, n1, 'poll(2) called correctly main-thread') + assert_equal(0, n2, 'poll(2) called correctly in sub-thread') + end + def test_no_memory_leak prep = 'r = Fiddle::Function.new(Fiddle.dlopen(nil)["rb_obj_tainted"], [Fiddle::TYPE_UINTPTR_T], Fiddle::TYPE_UINTPTR_T); a = "a"' code = 'begin r.call(a); rescue TypeError; end' |