mirror of
https://github.com/ruby/ruby.git
synced 2025-09-18 18:13:58 +02:00
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:
parent
3912b7f29d
commit
74bca55da9
5 changed files with 171 additions and 26 deletions
26
ChangeLog
26
ChangeLog
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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])
|
||||||
assert_nothing_raised {
|
begin
|
||||||
f.bind { |x, y| x + y }
|
assert_nothing_raised {
|
||||||
}
|
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,18 +153,22 @@ module DL
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_qsort1()
|
def test_qsort1()
|
||||||
cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
|
begin
|
||||||
[TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
|
cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
|
||||||
qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'),
|
[TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
|
||||||
[TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP])
|
qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'),
|
||||||
buff = "9341"
|
[TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP])
|
||||||
qsort.call(buff, buff.size, 1, cb)
|
buff = "9341"
|
||||||
assert_equal("1349", buff)
|
qsort.call(buff, buff.size, 1, cb)
|
||||||
|
assert_equal("1349", buff)
|
||||||
|
|
||||||
bug4929 = '[ruby-core:37395]'
|
bug4929 = '[ruby-core:37395]'
|
||||||
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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue