summaryrefslogtreecommitdiff
path: root/ext/dl
diff options
context:
space:
mode:
authortenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-05-06 06:59:24 +0000
committertenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-05-06 06:59:24 +0000
commit4bada8b864e445b6eebe1a341e30cad94dbcaf84 (patch)
treebb7e4ed991aa16eda953d536265c6f9e5dc03a5d /ext/dl
parentca3c007f058f17b2f0bf3c5ccc6701f3f6d49ca5 (diff)
* ext/fiddle/*: Adding fiddle library to wrap libffi
* test/fiddle/*: testing fiddle extension * ext/dl/lib/dl.rb: Requiring fiddle if it is available * ext/dl/lib/dl/callback.rb: using Fiddle if it is available * ext/dl/lib/dl/func.rb: ditto git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27640 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/dl')
-rw-r--r--ext/dl/lib/dl.rb12
-rw-r--r--ext/dl/lib/dl/callback.rb83
-rw-r--r--ext/dl/lib/dl/func.rb114
-rw-r--r--ext/dl/lib/dl/import.rb14
-rw-r--r--ext/dl/lib/dl/value.rb2
5 files changed, 154 insertions, 71 deletions
diff --git a/ext/dl/lib/dl.rb b/ext/dl/lib/dl.rb
new file mode 100644
index 0000000..168a18a
--- /dev/null
+++ b/ext/dl/lib/dl.rb
@@ -0,0 +1,12 @@
+require 'dl.so'
+
+begin
+ require 'fiddle'
+rescue LoadError
+end
+
+module DL
+ def self.fiddle?
+ Object.const_defined?(:Fiddle)
+ end
+end
diff --git a/ext/dl/lib/dl/callback.rb b/ext/dl/lib/dl/callback.rb
index c8daaf6..0863c70 100644
--- a/ext/dl/lib/dl/callback.rb
+++ b/ext/dl/lib/dl/callback.rb
@@ -4,22 +4,38 @@ require 'thread'
module DL
SEM = Mutex.new
- def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
+ if DL.fiddle?
+ CdeclCallbackProcs = {}
+ CdeclCallbackAddrs = {}
+ StdcallCallbackProcs = {}
+ StdcallCallbackAddrs = {}
+ end
+
+ def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &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
+
+ if DL.fiddle?
+ abi ||= Fiddle::Function::DEFAULT
+ closure = Fiddle::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp)
+ proc_entry[closure.to_i] = closure
+ addr = closure.to_i
+ else
+ 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
+ }
}
- }
+ end
+
addr
end
@@ -28,31 +44,42 @@ module DL
end
def set_stdcall_callback(ty, argc, &cbp)
- set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
+ if DL.fiddle?
+ set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, Fiddle::Function::STDCALL, &cbp)
+ else
+ set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
+ end
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
- }
+ if DL.fiddle?
+ addr = addr.to_i
+ return false unless proc_entry.key?(addr)
+ proc_entry.delete(addr)
+ true
else
- addr_entry.each{|ty,entry|
- entry.each_with_index{|xaddr, idx|
+ index = nil
+ if( ctype )
+ addr_entry[ctype].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
+ 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
end
end
diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb
index 7a8b62e..4d0db4e 100644
--- a/ext/dl/lib/dl/func.rb
+++ b/ext/dl/lib/dl/func.rb
@@ -5,21 +5,37 @@ require 'dl/value'
require 'thread'
module DL
- class Function
+ parent = DL.fiddle? ? Fiddle::Function : Object
+
+ class Function < parent
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 = nil, &block
+ if DL.fiddle?
+ abi ||= Fiddle::Function::DEFAULT
+ if block_given?
+ @cfunc = Class.new(Fiddle::Closure) {
+ define_method(:call, block)
+ }.new(cfunc.ctype, argtypes)
+ else
+ @cfunc = cfunc
+ end
+
+ @args = argtypes
+ super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi)
else
- @unsigned = false
- end
- if( proc )
- bind(&proc)
+ @cfunc = cfunc
+ @stack = Stack.new(argtypes.collect{|ty| ty.abs})
+ if( @cfunc.ctype < 0 )
+ @cfunc.ctype = @cfunc.ctype.abs
+ @unsigned = true
+ else
+ @unsigned = false
+ end
+ if block_given?
+ bind(&block)
+ end
end
end
@@ -32,11 +48,18 @@ 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 DL.fiddle?
+ if block_given?
+ args.find { |a| DL::Function === a }.bind_at_call(&block)
+ end
+ super
+ else
+ 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)
+ end
end
def wrap_result(r)
@@ -52,31 +75,44 @@ 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}")
+ if DL.fiddle?
+ @cfunc = Class.new(Fiddle::Closure) {
+ def initialize ctype, args, block
+ super(ctype, args)
+ @block = block
+ end
+
+ def call *args
+ @block.call(*args)
+ end
+ }.new(@cfunc.ctype, @args, block)
+ else
+ if( !block )
+ raise(RuntimeError, "block must be given.")
end
if( @cfunc.ptr == 0 )
- raise(RuntimeException, "can't bind C function.")
+ 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}")
+ end
+ if( @cfunc.ptr == 0 )
+ raise(RuntimeException, "can't bind C function.")
+ end
end
end
end
diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb
index 199354c..fd23bc9 100644
--- a/ext/dl/lib/dl/import.rb
+++ b/ext/dl/lib/dl/import.rb
@@ -211,9 +211,17 @@ 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
+ if DL.fiddle?
+ closure = Class.new(Fiddle::Closure) {
+ define_method(:call, block)
+ }.new(ctype, argtype)
+
+ Function.new(closure, argtype)
+ else
+ f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
+ f.bind(&block)
+ f
+ end
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 56dfcef..51f96b2 100644
--- a/ext/dl/lib/dl/value.rb
+++ b/ext/dl/lib/dl/value.rb
@@ -45,7 +45,7 @@ module DL
result
end
- def wrap_arg(arg, ty, funcs, &block)
+ def wrap_arg(arg, ty, funcs = [], &block)
funcs ||= []
case arg
when nil