diff options
author | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-02-03 01:23:48 +0000 |
---|---|---|
committer | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-02-03 01:23:48 +0000 |
commit | b386fe21eca01e03a5ca447792354632e549c94e (patch) | |
tree | 30b480ee3ab580e28053d1ec3f31a5fd5285aa9c /ext/dl/lib | |
parent | b378bda47c3960acd983890efd01ac08794f6fd3 (diff) | |
download | ruby-b386fe21eca01e03a5ca447792354632e549c94e.tar.gz |
Wed Feb 3 10:12:09 2010 Aaron Patterson <tenderlove@ruby-lang.org>
* ext/dl/function.c: DL::Function now uses libffi
* ext/dl/cfunc.c (rb_dl_set_last_error): set to non static so errors
can be exposed.
* ext/dl/closure.c: DL::Closure will now be used in place of
ext/dl/callback/*.
* ext/dl/dl.c: legacy callbacks removed in favor of libffi
* ext/dl/dl_converions.(c,h): used for converting ruby types to FFI
types.
* ext/dl/callback/*: replaced by libffi callbacks.
* ext/dl/lib/dl/callback.rb: Converting internal callbacks to use
DL::Closure
* ext/dl/lib/dl/closure.rb: Ruby parts of the new DL::Closure object
* ext/dl/lib/dl/import.rb: More conversion to use DL::Closure object
* ext/dl/lib/dl/value.rb (ruby2ffi): adding private method for
DL::CPtr to ffi value conversion.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26545 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/dl/lib')
-rw-r--r-- | ext/dl/lib/dl/callback.rb | 51 | ||||
-rw-r--r-- | ext/dl/lib/dl/closure.rb | 19 | ||||
-rw-r--r-- | ext/dl/lib/dl/func.rb | 62 | ||||
-rw-r--r-- | ext/dl/lib/dl/import.rb | 9 | ||||
-rw-r--r-- | ext/dl/lib/dl/value.rb | 20 |
5 files changed, 73 insertions, 88 deletions
diff --git a/ext/dl/lib/dl/callback.rb b/ext/dl/lib/dl/callback.rb index c8daaf6322..53da888d9d 100644 --- a/ext/dl/lib/dl/callback.rb +++ b/ext/dl/lib/dl/callback.rb @@ -1,26 +1,21 @@ require 'dl' +require 'dl/closure' require 'thread' module DL SEM = Mutex.new - def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp) + CdeclCallbackProcs = {} + CdeclCallbackAddrs = {} + + def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = DL::Function::DEFAULT, &cbp) if( argc < 0 ) raise(ArgumentError, "arity should not be less than 0.") end - addr = nil - SEM.synchronize{ - ary = proc_entry[ty] - (0...MAX_CALLBACK).each{|n| - idx = (n * DLSTACK_SIZE) + argc - if( ary[idx].nil? ) - ary[idx] = cbp - addr = addr_entry[ty][idx] - break - end - } - } - addr + + closure = DL::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp) + proc_entry[closure.to_i] = closure + closure.to_i end def set_cdecl_callback(ty, argc, &cbp) @@ -28,32 +23,14 @@ module DL end def set_stdcall_callback(ty, argc, &cbp) - set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp) + set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, DL::Function::STDCALL, &cbp) end def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil) - index = nil - if( ctype ) - addr_entry[ctype].each_with_index{|xaddr, idx| - if( xaddr == addr ) - index = idx - end - } - else - addr_entry.each{|ty,entry| - entry.each_with_index{|xaddr, idx| - if( xaddr == addr ) - index = idx - end - } - } - end - if( index and proc_entry[ctype][index] ) - proc_entry[ctype][index] = nil - return true - else - return false - end + addr = addr.to_i + return false unless proc_entry.key?(addr) + proc_entry.delete(addr) + true end def remove_cdecl_callback(addr, ctype = nil) diff --git a/ext/dl/lib/dl/closure.rb b/ext/dl/lib/dl/closure.rb new file mode 100644 index 0000000000..eca941dfbc --- /dev/null +++ b/ext/dl/lib/dl/closure.rb @@ -0,0 +1,19 @@ +require 'dl' + +module DL + class Closure + attr_reader :ctype + attr_reader :args + + class BlockCaller < DL::Closure + def initialize ctype, args, abi = DL::Function::DEFAULT, &block + super(ctype, args, abi) + @block = block + end + + def call *args + @block.call(*args) + end + end + end +end diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb index 7a8b62e325..0ee2df1f23 100644 --- a/ext/dl/lib/dl/func.rb +++ b/ext/dl/lib/dl/func.rb @@ -1,4 +1,5 @@ require 'dl' +require 'dl/closure' require 'dl/callback' require 'dl/stack' require 'dl/value' @@ -9,18 +10,17 @@ module DL include DL include ValueUtil - def initialize(cfunc, argtypes, &proc) - @cfunc = cfunc - @stack = Stack.new(argtypes.collect{|ty| ty.abs}) - if( @cfunc.ctype < 0 ) - @cfunc.ctype = @cfunc.ctype.abs - @unsigned = true + def initialize cfunc, argtypes, abi = DEFAULT, &block + if block_given? + @cfunc = Class.new(DL::Closure) { + define_method(:call, block) + }.new(cfunc.ctype, argtypes) else - @unsigned = false - end - if( proc ) - bind(&proc) + @cfunc = cfunc end + + @args = argtypes + native_init(@args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi) end def to_i() @@ -32,11 +32,10 @@ module DL end def call(*args, &block) - funcs = [] - args = wrap_args(args, @stack.types, funcs, &block) - r = @cfunc.call(@stack.pack(args)) - funcs.each{|f| f.unbind_at_call()} - return wrap_result(r) + if block_given? + args.find { |a| DL::Function === a }.bind_at_call(&block) + end + native_call(*args) end def wrap_result(r) @@ -52,33 +51,16 @@ module DL end def bind(&block) - if( !block ) - raise(RuntimeError, "block must be given.") - end - if( @cfunc.ptr == 0 ) - cb = Proc.new{|*args| - ary = @stack.unpack(args) - @stack.types.each_with_index{|ty, idx| - case ty - when TYPE_VOIDP - ary[idx] = CPtr.new(ary[idx]) - end - } - r = block.call(*ary) - wrap_arg(r, @cfunc.ctype, []) - } - case @cfunc.calltype - when :cdecl - @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb) - when :stdcall - @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb) - else - raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}") + @cfunc = Class.new(DL::Closure) { + def initialize ctype, args, block + super(ctype, args) + @block = block end - if( @cfunc.ptr == 0 ) - raise(RuntimeException, "can't bind C function.") + + def call *args + @block.call(*args) end - end + }.new(@cfunc.ctype, @args, block) end def unbind() diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb index 199354c18e..4c101d0f5c 100644 --- a/ext/dl/lib/dl/import.rb +++ b/ext/dl/lib/dl/import.rb @@ -1,4 +1,5 @@ require 'dl' +require 'dl/closure' require 'dl/func.rb' require 'dl/struct.rb' require 'dl/cparser.rb' @@ -211,9 +212,11 @@ module DL end def bind_function(name, ctype, argtype, call_type = nil, &block) - f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype) - f.bind(&block) - f + closure = Class.new(DL::Closure) { + define_method(:call, block) + }.new(ctype, argtype) + + Function.new(closure, argtype) end def create_temp_function(name, ctype, argtype, call_type = nil) diff --git a/ext/dl/lib/dl/value.rb b/ext/dl/lib/dl/value.rb index 56dfcefa32..c613afe5cf 100644 --- a/ext/dl/lib/dl/value.rb +++ b/ext/dl/lib/dl/value.rb @@ -36,16 +36,20 @@ module DL end end - def wrap_args(args, tys, funcs, &block) - result = [] - tys ||= [] - args.each_with_index{|arg, idx| - result.push(wrap_arg(arg, tys[idx], funcs, &block)) - } - result + def ruby2ffi arg, type + return arg unless type == TYPE_VOIDP + case arg + when nil + 0 + when CPtr + arg.to_i + else + CPtr[arg].to_i + end end + private :ruby2ffi - def wrap_arg(arg, ty, funcs, &block) + def wrap_arg(arg, ty, funcs = [], &block) funcs ||= [] case arg when nil |