summaryrefslogtreecommitdiff
path: root/ext/dl/lib
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dl/lib')
-rw-r--r--ext/dl/lib/dl/callback.rb51
-rw-r--r--ext/dl/lib/dl/closure.rb19
-rw-r--r--ext/dl/lib/dl/func.rb64
-rw-r--r--ext/dl/lib/dl/import.rb9
-rw-r--r--ext/dl/lib/dl/value.rb11
5 files changed, 91 insertions, 63 deletions
diff --git a/ext/dl/lib/dl/callback.rb b/ext/dl/lib/dl/callback.rb
index 53da888d9d..c8daaf6322 100644
--- a/ext/dl/lib/dl/callback.rb
+++ b/ext/dl/lib/dl/callback.rb
@@ -1,21 +1,26 @@
require 'dl'
-require 'dl/closure'
require 'thread'
module DL
SEM = Mutex.new
- CdeclCallbackProcs = {}
- CdeclCallbackAddrs = {}
-
- def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = DL::Function::DEFAULT, &cbp)
+ def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
if( argc < 0 )
raise(ArgumentError, "arity should not be less than 0.")
end
-
- closure = DL::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp)
- proc_entry[closure.to_i] = closure
- closure.to_i
+ 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
end
def set_cdecl_callback(ty, argc, &cbp)
@@ -23,14 +28,32 @@ module DL
end
def set_stdcall_callback(ty, argc, &cbp)
- set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, DL::Function::STDCALL, &cbp)
+ set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
end
def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
- addr = addr.to_i
- return false unless proc_entry.key?(addr)
- proc_entry.delete(addr)
- true
+ 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
end
def remove_cdecl_callback(addr, ctype = nil)
diff --git a/ext/dl/lib/dl/closure.rb b/ext/dl/lib/dl/closure.rb
deleted file mode 100644
index eca941dfbc..0000000000
--- a/ext/dl/lib/dl/closure.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-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 c5a2dda355..7a8b62e325 100644
--- a/ext/dl/lib/dl/func.rb
+++ b/ext/dl/lib/dl/func.rb
@@ -1,26 +1,26 @@
require 'dl'
-require 'dl/closure'
require 'dl/callback'
require 'dl/stack'
require 'dl/value'
require 'thread'
module DL
- class Function < DL::Method
+ class Function
include DL
include ValueUtil
- def initialize cfunc, argtypes, abi = DEFAULT, &block
- if block_given?
- @cfunc = Class.new(DL::Closure) {
- define_method(:call, block)
- }.new(cfunc.ctype, argtypes)
+ 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
else
- @cfunc = cfunc
+ @unsigned = false
+ end
+ if( proc )
+ bind(&proc)
end
-
- @args = argtypes
- super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi)
end
def to_i()
@@ -32,10 +32,11 @@ module DL
end
def call(*args, &block)
- if block_given?
- args.find { |a| DL::Function === a }.bind_at_call(&block)
- end
- super
+ 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
def wrap_result(r)
@@ -51,16 +52,33 @@ module DL
end
def bind(&block)
- @cfunc = Class.new(DL::Closure) {
- def initialize ctype, args, block
- super(ctype, args)
- @block = 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}")
end
-
- def call *args
- @block.call(*args)
+ if( @cfunc.ptr == 0 )
+ raise(RuntimeException, "can't bind C function.")
end
- }.new(@cfunc.ctype, @args, block)
+ end
end
def unbind()
diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb
index 4c101d0f5c..199354c18e 100644
--- a/ext/dl/lib/dl/import.rb
+++ b/ext/dl/lib/dl/import.rb
@@ -1,5 +1,4 @@
require 'dl'
-require 'dl/closure'
require 'dl/func.rb'
require 'dl/struct.rb'
require 'dl/cparser.rb'
@@ -212,11 +211,9 @@ module DL
end
def bind_function(name, ctype, argtype, call_type = nil, &block)
- closure = Class.new(DL::Closure) {
- define_method(:call, block)
- }.new(ctype, argtype)
-
- Function.new(closure, argtype)
+ f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
+ f.bind(&block)
+ f
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 cc6da6a7fb..56dfcefa32 100644
--- a/ext/dl/lib/dl/value.rb
+++ b/ext/dl/lib/dl/value.rb
@@ -36,7 +36,16 @@ module DL
end
end
- def wrap_arg(arg, ty, funcs = [], &block)
+ 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
+ end
+
+ def wrap_arg(arg, ty, funcs, &block)
funcs ||= []
case arg
when nil