Skip to content

Instantly share code, notes, and snippets.

@paddor
Created December 27, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paddor/10e4142a480eea36c57e to your computer and use it in GitHub Desktop.
Save paddor/10e4142a480eea36c57e to your computer and use it in GitHub Desktop.
JRuby/Rubinius: doesn't abort C function when FFI::Function breaks
#include <stdio.h>
typedef int (callback_fn) (void);
void
ten_times(callback_fn *callback)
{
for (int i = 1; i <= 10; i++) {
printf("libcallback: call #%i ...\n", i);
int rc = (* callback)();
if (rc == -1) {
printf("libcallback: early return because rc == -1\n");
return;
}
}
}
libcallback.dylib: callback.c
clang -dynamiclib -std=gnu99 callback.c -o $@
require 'minitest/autorun'
require 'ffi'
module LibCallback
extend ::FFI::Library
lib_name = 'libcallback'
ffi_lib "#{lib_name}.#{::FFI::Platform::LIBSUFFIX}"
attach_function :ten_times, [:pointer], :void, blocking: true
end
def mk_callback
FFI::Function.new(:void, [], blocking: true) do
yield
end
end
describe FFI::Function do
def foo
callback = mk_callback do
yield
end
LibCallback.ten_times(callback)
end
describe "with non-breaking block" do
it "calls block 10 times" do
called = 0
foo { called += 1 }
assert_equal 10, called
end
end
describe "with breaking block" do
it "doesn't call block anymore" do
called = 0
foo { called += 1; break }
assert_equal 1, called
end
end
end
describe "pure Ruby block" do
def foo
10.times { yield }
end
describe "with non-breaking block" do
it "calls block 10 times" do
called = 0
foo { called += 1 }
assert_equal 10, called
end
end
describe "with breaking block" do
it "doesn't call block anymore" do
called = 0
foo { called += 1; break }
assert_equal 1, called
end
end
end
__END__
##
# EXPECTED, as when run on Ruby 2.2.4
#
Run options: --seed 41083
# Running:
..libcallback: call #1 ...
libcallback: call #2 ...
libcallback: call #3 ...
libcallback: call #4 ...
libcallback: call #5 ...
libcallback: call #6 ...
libcallback: call #7 ...
libcallback: call #8 ...
libcallback: call #9 ...
libcallback: call #10 ...
.libcallback: call #1 ...
.
Finished in 0.002047s, 1954.3283 runs/s, 1954.3283 assertions/s.
4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
##
# ACTUAL, when run on JRuby 9.0.4.0
#
Run options: --seed 3230
# Running:
.libcallback: call #1 ...
libcallback: call #2 ...
libcallback: call #3 ...
libcallback: call #4 ...
libcallback: call #5 ...
libcallback: call #6 ...
libcallback: call #7 ...
libcallback: call #8 ...
libcallback: call #9 ...
libcallback: call #10 ...
.libcallback: call #1 ...
libcallback: call #2 ...
libcallback: call #3 ...
libcallback: call #4 ...
libcallback: call #5 ...
libcallback: call #6 ...
libcallback: call #7 ...
libcallback: call #8 ...
libcallback: call #9 ...
libcallback: call #10 ...
F.
Finished in 0.023067s, 173.4047 runs/s, 173.4047 assertions/s.
1) Failure:
FFI::Function::with breaking block#test_0001_doesn't call block anymore [test.rb:40]:
Expected: 1
Actual: 10
4 runs, 4 assertions, 1 failures, 0 errors, 0 skips
ruby test.rb 6.48s user 0.29s system 330% cpu 2.048 total
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment