From 41cd3d868de66ff407dd6f3c9a4126ac1692575f Mon Sep 17 00:00:00 2001 From: ttate Date: Fri, 4 Feb 2005 14:01:22 +0000 Subject: added missing files. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7884 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/dl/lib/dl/callback.rb | 69 ++++++++++++++++++ ext/dl/lib/dl/cparser.rb | 109 +++++++++++++++++++++++++++++ ext/dl/lib/dl/func.rb | 141 +++++++++++++++++++++++++++++++++++++ ext/dl/lib/dl/pack.rb | 173 ++++++++++++++++++++++++++++++++++++++++++++++ ext/dl/lib/dl/stack.rb | 140 +++++++++++++++++++++++++++++++++++++ ext/dl/lib/dl/value.rb | 101 +++++++++++++++++++++++++++ 6 files changed, 733 insertions(+) create mode 100644 ext/dl/lib/dl/callback.rb create mode 100644 ext/dl/lib/dl/cparser.rb create mode 100644 ext/dl/lib/dl/func.rb create mode 100644 ext/dl/lib/dl/pack.rb create mode 100644 ext/dl/lib/dl/stack.rb create mode 100644 ext/dl/lib/dl/value.rb (limited to 'ext/dl') diff --git a/ext/dl/lib/dl/callback.rb b/ext/dl/lib/dl/callback.rb new file mode 100644 index 0000000000..d0b2c7a819 --- /dev/null +++ b/ext/dl/lib/dl/callback.rb @@ -0,0 +1,69 @@ +require 'dl' +require 'thread' + +module DL + SEM = Mutex.new + + def set_callback_internal(proc_entry, addr_entry, argc, ty, &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 + end + + def set_cdecl_callback(ty, argc, &cbp) + set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp) + end + + def set_stdcall_callback(ty, argc, &cbp) + set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &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( proc_entry[ctype][index] ) + proc_entry[ctype][index] = nil + return true + else + return false + end + end + + def remove_cdecl_callback(addr, ctype = nil) + remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype) + end + + def remove_stdcall_callback(addr, ctype = nil) + remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype) + end + + alias set_callback set_cdecl_callback + alias remove_callback remove_cdecl_callback +end diff --git a/ext/dl/lib/dl/cparser.rb b/ext/dl/lib/dl/cparser.rb new file mode 100644 index 0000000000..5b5dd5f478 --- /dev/null +++ b/ext/dl/lib/dl/cparser.rb @@ -0,0 +1,109 @@ +module DL + module CParser + def parse_struct_signature(signature, tymap=nil) + if( signature.is_a?(String) ) + signature = signature.split("\s*,\s*") + end + mems = [] + tys = [] + signature.each{|msig| + tks = msig.split(/\s+(\*)?/) + ty = tks[0..-2].join(" ") + member = tks[-1] + + case ty + when /\[(\d+)\]/ + n = $1.to_i + ty.gsub!(/\s*\[\d+\]/,"") + ty = [ty, n] + when /\[\]/ + ty.gsub!(/\s*\[\]/, "*") + end + + case member + when /\[(\d+)\]/ + ty = [ty, $1.to_i] + member.gsub!(/\s*\[\d+\]/,"") + when /\[\]/ + ty = ty + "*" + member.gsub!(/\s*\[\]/, "") + end + + mems.push(member) + tys.push(parse_ctype(ty,tymap)) + } + return tys, mems + end + + def parse_signature(signature, tymap=nil) + tymap ||= {} + signature = signature.gsub(/\s+/, " ").strip + case signature + when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/ + ret = $1 + args = $2 + ret = ret.split(/\s+/) + args = args.split(/\s*,\s*/) + func = ret.pop + if( func =~ /^\*/ ) + func.gsub!(/^\*+/,"") + ret.push("*") + end + ret = ret.join(" ") + return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}] + else + raise(RuntimeError,"can't parse the function prototype: #{proto}") + end + end + + def parse_ctype(ty, tymap=nil) + tymap ||= {} + case ty + when Array + return [parse_ctype(ty[0], tymap), ty[1]] + when "void" + return TYPE_VOID + when "char" + return TYPE_CHAR + when "unsigned char" + return -TYPE_CHAR + when "short" + return TYPE_SHORT + when "unsigned short" + return -TYPE_SHORT + when "int" + return TYPE_INT + when "unsigned int" + return -TYPE_INT + when "long" + return TYPE_LONG + when "unsigned long" + return -TYPE_LONG + when "long long" + if( defined?(TYPE_LONG_LONG) ) + return TYPE_LONG_LONG + else + raise(RuntimeError, "unsupported type: #{ty}") + end + when "unsigned long long" + if( defined?(TYPE_LONG_LONG) ) + return -TYPE_LONG_LONG + else + raise(RuntimeError, "unsupported type: #{ty}") + end + when "float" + return TYPE_FLOAT + when "double" + return TYPE_DOUBLE + when /\*/, /\[\s*\]/ + return TYPE_VOIDP + else + if( tymap[ty] ) + return parse_ctype(tymap[ty], tymap) + else + raise(DLError, "unknown type: #{ty}") + end + end + end + end +end diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb new file mode 100644 index 0000000000..121f2efcc0 --- /dev/null +++ b/ext/dl/lib/dl/func.rb @@ -0,0 +1,141 @@ +require 'dl' +require 'dl/callback' +require 'dl/stack' +require 'dl/value' +require 'thread' + +module DL + class Function + 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 + end + if( proc ) + bind(&proc) + end + end + + def to_i() + @cfunc.to_i + end + + def call(*args, &block) + funcs = [] + args = wrap_args(args, nil, funcs, &block) + r = @cfunc.call(@stack.pack(args)) + funcs.each{|f| f.unbind_at_call()} + return wrap_result(r) + end + + def wrap_result(r) + case @cfunc.ctype + when TYPE_VOIDP + r = CPtr.new(r) + else + if( @unsigned ) + r = unsigned_value(r, @cfunc.ctype) + end + end + r + 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, nil, []) + } + 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 + + def unbind() + if( @cfunc.ptr != 0 ) + case @cfunc.calltype + when :cdecl + remove_cdecl_callback(@cfunc.ptr, @cfunc.ctype) + when :stdcall + remove_stdcall_callback(@cfunc.ptr, @cfunc.ctype) + else + raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}") + end + @cfunc.ptr = 0 + end + end + + def bind_at_call(&block) + bind(&block) + end + + def unbind_at_call() + end + end + + class TempFunction < Function + def bind_at_call(&block) + bind(&block) + end + + def unbind_at_call() + unbind() + end + end + + class CarriedFunction < Function + def initialize(cfunc, argtypes, n) + super(cfunc, argtypes) + @carrier = [] + @index = n + @mutex = Mutex.new + end + + def create_carrier(data) + ary = [] + userdata = [ary, data] + @mutex.lock() + @carrier.push(userdata) + return dlwrap(userdata) + end + + def bind_at_call(&block) + userdata = @carrier[-1] + userdata[0].push(block) + bind{|*args| + ptr = args[@index] + if( !ptr ) + raise(RuntimeError, "The index of userdata should be lower than #{args.size}.") + end + userdata = dlunwrap(Integer(ptr)) + args[@index] = userdata[1] + userdata[0][0].call(*args) + } + @mutex.unlock() + end + end +end diff --git a/ext/dl/lib/dl/pack.rb b/ext/dl/lib/dl/pack.rb new file mode 100644 index 0000000000..ad91833b3a --- /dev/null +++ b/ext/dl/lib/dl/pack.rb @@ -0,0 +1,173 @@ +require 'dl' + +module DL + module PackInfo + if( defined?(TYPE_LONG_LONG) ) + ALIGN_MAP = { + TYPE_VOIDP => ALIGN_VOIDP, + TYPE_CHAR => ALIGN_CHAR, + TYPE_SHORT => ALIGN_SHORT, + TYPE_INT => ALIGN_INT, + TYPE_LONG => ALIGN_LONG, + TYPE_LONG_LONG => ALIGN_LONG_LONG, + TYPE_FLOAT => ALIGN_FLOAT, + TYPE_DOUBLE => ALIGN_DOUBLE, + -TYPE_CHAR => ALIGN_CHAR, + -TYPE_SHORT => ALIGN_SHORT, + -TYPE_INT => ALIGN_INT, + -TYPE_LONG => ALIGN_LONG, + -TYPE_LONG_LONG => ALIGN_LONG_LONG, + } + + PACK_MAP = { + TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"), + TYPE_CHAR => "c", + TYPE_SHORT => "s!", + TYPE_INT => "i!", + TYPE_LONG => "l!", + TYPE_LONG_LONG => "q", + TYPE_FLOAT => "f", + TYPE_DOUBLE => "d", + -TYPE_CHAR => "c", + -TYPE_SHORT => "s!", + -TYPE_INT => "i!", + -TYPE_LONG => "l!", + -TYPE_LONG_LONG => "q", + } + + SIZE_MAP = { + TYPE_VOIDP => SIZEOF_VOIDP, + TYPE_CHAR => SIZEOF_CHAR, + TYPE_SHORT => SIZEOF_SHORT, + TYPE_INT => SIZEOF_INT, + TYPE_LONG => SIZEOF_LONG, + TYPE_LONG_LONG => SIZEOF_LONG_LONG, + TYPE_FLOAT => SIZEOF_FLOAT, + TYPE_DOUBLE => SIZEOF_DOUBLE, + -TYPE_CHAR => SIZEOF_CHAR, + -TYPE_SHORT => SIZEOF_SHORT, + -TYPE_INT => SIZEOF_INT, + -TYPE_LONG => SIZEOF_LONG, + -TYPE_LONG_LONG => SIZEOF_LONG_LONG, + } + else + ALIGN_MAP = { + TYPE_VOIDP => ALIGN_VOIDP, + TYPE_CHAR => ALIGN_CHAR, + TYPE_SHORT => ALIGN_SHORT, + TYPE_INT => ALIGN_INT, + TYPE_LONG => ALIGN_LONG, + TYPE_FLOAT => ALIGN_FLOAT, + TYPE_DOUBLE => ALIGN_DOUBLE, + -TYPE_CHAR => ALIGN_CHAR, + -TYPE_SHORT => ALIGN_SHORT, + -TYPE_INT => ALIGN_INT, + -TYPE_LONG => ALIGN_LONG, + } + + PACK_MAP = { + TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"), + TYPE_CHAR => "c", + TYPE_SHORT => "s!", + TYPE_INT => "i!", + TYPE_LONG => "l!", + TYPE_FLOAT => "f", + TYPE_DOUBLE => "d", + -TYPE_CHAR => "c", + -TYPE_SHORT => "s!", + -TYPE_INT => "i!", + -TYPE_LONG => "l!", + } + + SIZE_MAP = { + TYPE_VOIDP => SIZEOF_VOIDP, + TYPE_CHAR => SIZEOF_CHAR, + TYPE_SHORT => SIZEOF_SHORT, + TYPE_INT => SIZEOF_INT, + TYPE_LONG => SIZEOF_LONG, + TYPE_FLOAT => SIZEOF_FLOAT, + TYPE_DOUBLE => SIZEOF_DOUBLE, + -TYPE_CHAR => SIZEOF_CHAR, + -TYPE_SHORT => SIZEOF_SHORT, + -TYPE_INT => SIZEOF_INT, + -TYPE_LONG => SIZEOF_LONG, + } + end + + def align(addr, align) + d = addr % align + if( d == 0 ) + addr + else + addr + (align - d) + end + end + module_function :align + end + + class Packer + include PackInfo + + def Packer.[](*types) + Packer.new(types) + end + + def initialize(types) + parse_types(types) + end + + def size() + @size + end + + def pack(ary) + case SIZEOF_VOIDP + when SIZEOF_LONG + ary.pack(@template) + when SIZEOF_LONG + ary.pack(@template) + else + raise(RuntimeError, "sizeof(void*)?") + end + end + + def unpack(ary) + case SIZEOF_VOIDP + when SIZEOF_LONG + ary.join().unpack(@template) + when SIZEOF_LONG_LONG + ary.join().unpack(@template) + else + raise(RuntimeError, "sizeof(void*)?") + end + end + + private + + def parse_types(types) + @template = "" + addr = 0 + types.each{|t| + orig_addr = addr + if( t.is_a?(Array) ) + addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP]) + else + addr = align(orig_addr, ALIGN_MAP[t]) + end + d = addr - orig_addr + if( d > 0 ) + @template << "x#{d}" + end + if( t.is_a?(Array) ) + @template << (PACK_MAP[t[0]] * t[1]) + addr += (SIZE_MAP[t[0]] * t[1]) + else + @template << PACK_MAP[t] + addr += SIZE_MAP[t] + end + } + addr = align(addr, ALIGN_MAP[TYPE_VOIDP]) + @size = addr + end + end +end diff --git a/ext/dl/lib/dl/stack.rb b/ext/dl/lib/dl/stack.rb new file mode 100644 index 0000000000..93c2d3bbed --- /dev/null +++ b/ext/dl/lib/dl/stack.rb @@ -0,0 +1,140 @@ +require 'dl' + +module DL + class Stack + def Stack.[](*types) + Stack.new(types) + end + + def initialize(types) + parse_types(types) + end + + def size() + @size + end + + def types() + @types + end + + def pack(ary) + case SIZEOF_VOIDP + when SIZEOF_LONG + ary.pack(@template).unpack('l!*') + when SIZEOF_LONG + ary.pack(@template).unpack('q*') + else + raise(RuntimeError, "sizeof(void*)?") + end + end + + def unpack(ary) + case SIZEOF_VOIDP + when SIZEOF_LONG + ary.pack('l!*').unpack(@template) + when SIZEOF_LONG_LONG + ary.pack('q*').unpack(@template) + else + raise(RuntimeError, "sizeof(void*)?") + end + end + + private + + def align(addr, align) + d = addr % align + if( d == 0 ) + addr + else + addr + (align - d) + end + end + +if( defined?(TYPE_LONG_LONG) ) + ALIGN_MAP = { + TYPE_VOIDP => ALIGN_VOIDP, + TYPE_CHAR => ALIGN_VOIDP, + TYPE_SHORT => ALIGN_VOIDP, + TYPE_INT => ALIGN_VOIDP, + TYPE_LONG => ALIGN_VOIDP, + TYPE_LONG_LONG => ALIGN_LONG_LONG, + TYPE_FLOAT => ALIGN_FLOAT, + TYPE_DOUBLE => ALIGN_DOUBLE, + } + + PACK_MAP = { + TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"), + TYPE_CHAR => "c", + TYPE_SHORT => "s!", + TYPE_INT => "i!", + TYPE_LONG => "l!", + TYPE_LONG_LONG => "q", + TYPE_FLOAT => "f", + TYPE_DOUBLE => "d", + } + + SIZE_MAP = { + TYPE_VOIDP => SIZEOF_VOIDP, + TYPE_CHAR => SIZEOF_CHAR, + TYPE_SHORT => SIZEOF_SHORT, + TYPE_INT => SIZEOF_INT, + TYPE_LONG => SIZEOF_LONG, + TYPE_LONG_LONG => SIZEOF_LONG_LONG, + TYPE_FLOAT => SIZEOF_FLOAT, + TYPE_DOUBLE => SIZEOF_DOUBLE, + } +else + ALIGN_MAP = { + TYPE_VOIDP => ALIGN_VOIDP, + TYPE_CHAR => ALIGN_VOIDP, + TYPE_SHORT => ALIGN_VOIDP, + TYPE_INT => ALIGN_VOIDP, + TYPE_LONG => ALIGN_VOIDP, + TYPE_FLOAT => ALIGN_FLOAT, + TYPE_DOUBLE => ALIGN_DOUBLE, + } + + PACK_MAP = { + TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"), + TYPE_CHAR => "c", + TYPE_SHORT => "s!", + TYPE_INT => "i!", + TYPE_LONG => "l!", + TYPE_FLOAT => "f", + TYPE_DOUBLE => "d", + } + + SIZE_MAP = { + TYPE_VOIDP => SIZEOF_VOIDP, + TYPE_CHAR => SIZEOF_CHAR, + TYPE_SHORT => SIZEOF_SHORT, + TYPE_INT => SIZEOF_INT, + TYPE_LONG => SIZEOF_LONG, + TYPE_FLOAT => SIZEOF_FLOAT, + TYPE_DOUBLE => SIZEOF_DOUBLE, + } +end + + def parse_types(types) + @types = types + @template = "" + addr = 0 + types.each{|t| + orig_addr = addr + addr = align(orig_addr, ALIGN_MAP[t]) + d = addr - orig_addr + if( d > 0 ) + @template << "x#{d}" + end + @template << PACK_MAP[t] + addr += SIZE_MAP[t] + } + if( addr % SIZEOF_VOIDP == 0 ) + @size = addr / SIZEOF_VOIDP + else + @size = (addr / SIZEOF_VOIDP) + 1 + end + end + end +end diff --git a/ext/dl/lib/dl/value.rb b/ext/dl/lib/dl/value.rb new file mode 100644 index 0000000000..1357106a42 --- /dev/null +++ b/ext/dl/lib/dl/value.rb @@ -0,0 +1,101 @@ +require 'dl' + +module DL + module ValueUtil + def unsigned_value(val, ty) + case ty.abs + when TYPE_CHAR + [val].pack("c").unpack("C")[0] + when TYPE_SHORT + [val].pack("s!").unpack("S!")[0] + when TYPE_INT + [val].pack("i!").unpack("I!")[0] + when TYPE_LONG + [val].pack("l!").unpack("L!")[0] + when TYPE_LONG_LONG + [val].pack("q!").unpack("Q!")[0] + else + val + end + end + + def signed_value(val, ty) + case ty.abs + when TYPE_CHAR + [val].pack("C").unpack("c")[0] + when TYPE_SHORT + [val].pack("S!").unpack("s!")[0] + when TYPE_INT + [val].pack("I!").unpack("i!")[0] + when TYPE_LONG + [val].pack("L!").unpack("l!")[0] + when TYPE_LONG_LONG + [val].pack("Q!").unpack("q!")[0] + else + val + 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 + end + + def wrap_arg(arg, ty, funcs, &block) + funcs ||= [] + case arg + when CPtr + return arg.to_i + when Function + if( block ) + arg.bind_at_call(&block) + funcs.push(arg) + end + return arg.to_i + when String + if( ty.is_a?(Array) ) + return arg.unpack('C*') + else + case SIZEOF_VOIDP + when SIZEOF_LONG + return [arg].pack("p").unpack("l!")[0] + when SIZEOF_LONG_LONG + return [arg].pack("p").unpack("q")[0] + else + raise(RuntimeError, "sizeof(void*)?") + end + end + when Float, Integer + return arg + when Array + if( ty.is_a?(Array) ) # used only by struct + case ty[0] + when TYPE_VOIDP + return arg.collect{|v| Integer(v)} + when TYPE_CHAR + if( arg.is_a?(String) ) + return val.unpack('C*') + end + end + return arg + else + return arg + end + else + if( arg.respond_to?(:to_ptr) ) + return arg.to_ptr.to_i + else + begin + return Integer(arg) + rescue + raise(ArgumentError, "unknown argument type: #{arg.class}") + end + end + end + end + end +end -- cgit v1.2.3