merge revision(s) 38202,38238,38324,38326: [Backport #7527]

* test/dl/test_func.rb (test_name_with_block, test_bind, test_qsort1):
  call unbind to release the callback closure because maximum number
  of callbacks is limited to DL::MAX_CALLBACK (== 5) with pure DL
  without Fiddle.

* ext/dl/lib/dl/func.rb (DL::Function#unbind, #bound?): suppress
  NoMethodError when Fiddle is available. [ruby-core:50756] [Bug #7543]
* test/dl/test_func.rb (test_bound*, test_unbind*): tests for the above.

* ext/dl/lib/dl/func.rb (DL::Function#initialize, DL::Function#bind):
  ABI should be set by using CFunc#calltype even when Fiddle is used.
  When Fiddle is used and a block is given, name shoud not be ignored.
  [ruby-core:50562] [Bug #7514]

* ext/dl/lib/dl/import.rb (DL::Importer#bind_function): should respect
  abi and name when Fiddle is used.

* test/dl/test_func.rb (test_name_with_block): test for "name" method
  with giving a block.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@38506 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
usa 2012-12-20 09:52:46 +00:00
parent 3912b7f29d
commit 74bca55da9
5 changed files with 171 additions and 26 deletions

View file

@ -1,3 +1,29 @@
Thu Dec 20 18:46:17 2012 Naohisa Goto <ngotogenome@gmail.com>
* test/dl/test_func.rb (test_name_with_block, test_bind, test_qsort1):
call unbind to release the callback closure because maximum number
of callbacks is limited to DL::MAX_CALLBACK (== 5) with pure DL
without Fiddle.
Thu Dec 20 18:46:17 2012 Naohisa Goto <ngotogenome@gmail.com>
* ext/dl/lib/dl/func.rb (DL::Function#unbind, #bound?): suppress
NoMethodError when Fiddle is available. [ruby-core:50756] [Bug #7543]
* test/dl/test_func.rb (test_bound*, test_unbind*): tests for the above.
Thu Dec 20 18:46:17 2012 Naohisa Goto <ngotogenome@gmail.com>
* ext/dl/lib/dl/func.rb (DL::Function#initialize, DL::Function#bind):
ABI should be set by using CFunc#calltype even when Fiddle is used.
When Fiddle is used and a block is given, name shoud not be ignored.
[ruby-core:50562] [Bug #7514]
* ext/dl/lib/dl/import.rb (DL::Importer#bind_function): should respect
abi and name when Fiddle is used.
* test/dl/test_func.rb (test_name_with_block): test for "name" method
with giving a block.
Thu Dec 20 18:43:00 2012 Naohisa Goto <ngotogenome@gmail.com> Thu Dec 20 18:43:00 2012 Naohisa Goto <ngotogenome@gmail.com>
* ext/fiddle/extconf.rb, ext/fiddle/function.c * ext/fiddle/extconf.rb, ext/fiddle/function.c

View file

@ -11,13 +11,50 @@ module DL
include DL include DL
include ValueUtil include ValueUtil
if DL.fiddle?
# :stopdoc:
CALL_TYPE_TO_ABI = Hash.new { |h, k|
raise RuntimeError, "unsupported call type: #{k}"
}.merge({ :stdcall =>
(Fiddle::Function::STDCALL rescue Fiddle::Function::DEFAULT),
:cdecl => Fiddle::Function::DEFAULT,
nil => Fiddle::Function::DEFAULT
}).freeze
private_constant :CALL_TYPE_TO_ABI
# :startdoc:
def self.call_type_to_abi(call_type) # :nodoc:
CALL_TYPE_TO_ABI[call_type]
end
private_class_method :call_type_to_abi
class FiddleClosureCFunc < Fiddle::Closure # :nodoc: all
def initialize ctype, arg, abi, name
@name = name
super(ctype, arg, abi)
end
def name
@name
end
def ptr
to_i
end
end
private_constant :FiddleClosureCFunc
def self.class_fiddle_closure_cfunc # :nodoc:
FiddleClosureCFunc
end
private_class_method :class_fiddle_closure_cfunc
end
def initialize cfunc, argtypes, abi = nil, &block def initialize cfunc, argtypes, abi = nil, &block
if DL.fiddle? if DL.fiddle?
abi ||= Fiddle::Function::DEFAULT abi ||= CALL_TYPE_TO_ABI[(cfunc.calltype rescue nil)]
if block_given? if block_given?
@cfunc = Class.new(Fiddle::Closure) { @cfunc = Class.new(FiddleClosureCFunc) {
define_method(:call, block) define_method(:call, block)
}.new(cfunc.ctype, argtypes) }.new(cfunc.ctype, argtypes, abi, cfunc.name)
else else
@cfunc = cfunc @cfunc = cfunc
end end
@ -76,16 +113,16 @@ module DL
def bind(&block) def bind(&block)
if DL.fiddle? if DL.fiddle?
@cfunc = Class.new(Fiddle::Closure) { @cfunc = Class.new(FiddleClosureCFunc) {
def initialize ctype, args, block def initialize ctype, args, abi, name, block
super(ctype, args) super(ctype, args, abi, name)
@block = block @block = block
end end
def call *args def call *args
@block.call(*args) @block.call(*args)
end end
}.new(@cfunc.ctype, @args, block) }.new(@cfunc.ctype, @args, abi, name, block)
@ptr = @cfunc @ptr = @cfunc
return nil return nil
else else
@ -120,6 +157,25 @@ module DL
end end
def unbind() def unbind()
if DL.fiddle? then
if @cfunc.kind_of?(Fiddle::Closure) and @cfunc.ptr != 0 then
call_type = case abi
when CALL_TYPE_TO_ABI[nil]
nil
when CALL_TYPE_TO_ABI[:stdcall]
:stdcall
else
raise(RuntimeError, "unsupported abi: #{abi}")
end
@cfunc = CFunc.new(0, @cfunc.ctype, name, call_type)
return 0
elsif @cfunc.ptr != 0 then
@cfunc.ptr = 0
return 0
else
return nil
end
end
if( @cfunc.ptr != 0 ) if( @cfunc.ptr != 0 )
case @cfunc.calltype case @cfunc.calltype
when :cdecl when :cdecl

View file

@ -231,11 +231,13 @@ module DL
def bind_function(name, ctype, argtype, call_type = nil, &block) def bind_function(name, ctype, argtype, call_type = nil, &block)
if DL.fiddle? if DL.fiddle?
closure = Class.new(Fiddle::Closure) { klass = Function.instance_eval { class_fiddle_closure_cfunc }
abi = Function.instance_eval { call_type_to_abi(call_type) }
closure = Class.new(klass) {
define_method(:call, block) define_method(:call, block)
}.new(ctype, argtype) }.new(ctype, argtype, abi, name)
Function.new(closure, argtype) Function.new(closure, argtype, abi)
else else
f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype) f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
f.bind(&block) f.bind(&block)

View file

@ -9,12 +9,69 @@ module DL
assert_equal 'strcpy', f.name assert_equal 'strcpy', f.name
end end
def test_name_with_block
begin
cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
[TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
assert_equal('<callback>qsort', cb.name)
ensure
cb.unbind if cb # max number of callbacks is limited to MAX_CALLBACK
end
end
def test_bound
f = Function.new(CFunc.new(0, TYPE_INT, 'test'), [TYPE_INT, TYPE_INT])
assert_equal false, f.bound?
begin
f.bind { |x,y| x + y }
assert_equal true, f.bound?
ensure
f.unbind # max number of callbacks is limited to MAX_CALLBACK
end
end
def test_bound_for_callback_closure
begin
f = Function.new(CFunc.new(0, TYPE_INT, 'test'),
[TYPE_INT, TYPE_INT]) { |x,y| x + y }
assert_equal true, f.bound?
ensure
f.unbind if f # max number of callbacks is limited to MAX_CALLBACK
end
end
def test_unbind
f = Function.new(CFunc.new(0, TYPE_INT, 'test'), [TYPE_INT, TYPE_INT])
begin
f.bind { |x, y| x + y }
assert_nothing_raised { f.unbind }
assert_equal false, f.bound?
# unbind() after unbind() should not raise error
assert_nothing_raised { f.unbind }
ensure
f.unbind # max number of callbacks is limited to MAX_CALLBACK
end
end
def test_unbind_normal_function
f = Function.new(CFunc.new(@libc['strcpy'], TYPE_VOIDP, 'strcpy'),
[TYPE_VOIDP, TYPE_VOIDP])
assert_nothing_raised { f.unbind }
assert_equal false, f.bound?
# unbind() after unbind() should not raise error
assert_nothing_raised { f.unbind }
end
def test_bind def test_bind
f = Function.new(CFunc.new(0, TYPE_INT, 'test'), [TYPE_INT, TYPE_INT]) f = Function.new(CFunc.new(0, TYPE_INT, 'test'), [TYPE_INT, TYPE_INT])
begin
assert_nothing_raised { assert_nothing_raised {
f.bind { |x, y| x + y } f.bind { |x, y| x + y }
} }
assert_equal 579, f.call(123, 456) assert_equal 579, f.call(123, 456)
ensure
f.unbind # max number of callbacks is limited to MAX_CALLBACK
end
end end
def test_to_i def test_to_i
@ -96,6 +153,7 @@ module DL
end end
def test_qsort1() def test_qsort1()
begin
cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'), cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
[TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]} [TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'), qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'),
@ -108,6 +166,9 @@ module DL
buff = "9341" buff = "9341"
EnvUtil.under_gc_stress {qsort.call(buff, buff.size, 1, cb)} EnvUtil.under_gc_stress {qsort.call(buff, buff.size, 1, cb)}
assert_equal("1349", buff, bug4929) assert_equal("1349", buff, bug4929)
ensure
cb.unbind if cb # max number of callbacks is limited to MAX_CALLBACK
end
end end
def test_qsort2() def test_qsort2()

View file

@ -1,5 +1,5 @@
#define RUBY_VERSION "1.9.3" #define RUBY_VERSION "1.9.3"
#define RUBY_PATCHLEVEL 352 #define RUBY_PATCHLEVEL 353
#define RUBY_RELEASE_DATE "2012-12-20" #define RUBY_RELEASE_DATE "2012-12-20"
#define RUBY_RELEASE_YEAR 2012 #define RUBY_RELEASE_YEAR 2012