Skip to content

Commit

Permalink
Add tests for calls between Fiddle and FFI
Browse files Browse the repository at this point in the history
This is particular interesting because FFI stores thread local call info
on the stack, which is retrieved when a callback is received.
This is something that Fiddle doesn't do, but a callback should be handled
gracefully nevertheless.

The test "from fiddle to ffi" fails without the previous commit.

These tests succeed on MRI and on JRuby (provided
jruby/jruby#4518 will be merged).
  • Loading branch information
larskanis committed Jul 26, 2017
1 parent 743fae1 commit 047371b
Showing 1 changed file with 74 additions and 0 deletions.
74 changes: 74 additions & 0 deletions spec/ffi/callback_spec.rb
Expand Up @@ -771,3 +771,77 @@ module LibTestStdcall
end
end
end

describe "Callback interop" do
require 'fiddle'
require 'fiddle/import'

module LibTestFFI
extend FFI::Library
ffi_lib TestLibrary::PATH
attach_function :testCallbackVrV, :testClosureVrV, [ :pointer ], :void
attach_function :testCallbackVrV_blocking, :testClosureVrV, [ :pointer ], :void, blocking: true
end

module LibTestFiddle
extend Fiddle::Importer
dlload TestLibrary::PATH
extern 'void testClosureVrV(void *fp)'
end

def assert_callback_in_same_thread_called_once
called = 0
thread = nil
yield proc {
called += 1
thread = Thread.current
}
expect(called).to eq(1)
expect(thread).to eq(Thread.current)
end

it "from ffi to ffi" do
assert_callback_in_same_thread_called_once do |block|
func = FFI::Function.new(:void, [:pointer], &block)
LibTestFFI.testCallbackVrV(FFI::Pointer.new(func.to_i))
end
end

it "from ffi to ffi with blocking:true" do
assert_callback_in_same_thread_called_once do |block|
func = FFI::Function.new(:void, [:pointer], &block)
LibTestFFI.testCallbackVrV_blocking(FFI::Pointer.new(func.to_i))
end
end

# https://github.com/ffi/ffi/issues/527
if RUBY_VERSION.split('.').map(&:to_i).pack("C*") >= [2,3,0].pack("C*") || RUBY_PLATFORM =~ /java/
it "from fiddle to ffi" do
assert_callback_in_same_thread_called_once do |block|
func = FFI::Function.new(:void, [:pointer], &block)
LibTestFiddle.testClosureVrV(Fiddle::Pointer[func.to_i])
end
end
end

it "from ffi to fiddle" do
assert_callback_in_same_thread_called_once do |block|
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
LibTestFFI.testCallbackVrV(FFI::Pointer.new(func.to_i))
end
end

it "from ffi to fiddle with blocking:true" do
assert_callback_in_same_thread_called_once do |block|
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
LibTestFFI.testCallbackVrV_blocking(FFI::Pointer.new(func.to_i))
end
end

it "from fiddle to fiddle" do
assert_callback_in_same_thread_called_once do |block|
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
LibTestFiddle.testClosureVrV(Fiddle::Pointer[func.to_i])
end
end
end

0 comments on commit 047371b

Please sign in to comment.