Advertisement
Guest User

Untitled

a guest
Jul 14th, 2015
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 36.60 KB | None | 0 0
  1. #
  2. #      thread.rb - thread support classes
  3. #         by Yukihiro Matsumoto <matz@netlab.co.jp>
  4. #
  5. # Copyright (C) 2001  Yukihiro Matsumoto
  6. # Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
  7. # Copyright (C) 2000  Information-technology Promotion Agency, Japan
  8. #
  9.  
  10. unless defined? Thread
  11.   raise "Thread not available for this ruby interpreter"
  12. end
  13.  
  14. unless defined? ThreadError
  15.   class ThreadError < StandardError
  16.   end
  17. end
  18.  
  19. if $DEBUG
  20.   Thread.abort_on_exception = true
  21. end
  22.  
  23. #
  24. # ConditionVariable objects augment class Mutex. Using condition variables,
  25. # it is possible to suspend while in the middle of a critical section until a
  26. # resource becomes available.
  27. #
  28. # Example:
  29. #
  30. #   require 'thread'
  31. #
  32. #   mutex = Mutex.new
  33. #   resource = ConditionVariable.new
  34. #  
  35. #   a = Thread.new {
  36. #     mutex.synchronize {
  37. #       # Thread 'a' now needs the resource
  38. #       resource.wait(mutex)
  39. #       # 'a' can now have the resource
  40. #     }
  41. #   }
  42. #  
  43. #   b = Thread.new {
  44. #     mutex.synchronize {
  45. #       # Thread 'b' has finished using the resource
  46. #       resource.signal
  47. #     }
  48. #   }
  49. #
  50. class ConditionVariable
  51.   #
  52.   # Creates a new ConditionVariable
  53.   #
  54.   def initialize
  55.     @waiters = []
  56.     @waiters_mutex = Mutex.new
  57.   end
  58.  
  59.   #
  60.   # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
  61.   #
  62.   def wait(mutex)
  63.     begin
  64.       # TODO: mutex should not be used
  65.       @waiters_mutex.synchronize do
  66.         @waiters.push(Thread.current)
  67.       end
  68.       mutex.sleep
  69.     end
  70.   end
  71.  
  72.   #
  73.   # Wakes up the first thread in line waiting for this lock.
  74.   #
  75.   def signal
  76.     begin
  77.       t = @waiters_mutex.synchronize { @waiters.shift }
  78.       t.run if t
  79.     rescue ThreadError
  80.       retry
  81.     end
  82.   end
  83.    
  84.   #
  85.   # Wakes up all threads waiting for this lock.
  86.   #
  87.   def broadcast
  88.     # TODO: imcomplete
  89.     waiters0 = nil
  90.     @waiters_mutex.synchronize do
  91.       waiters0 = @waiters.dup
  92.       @waiters.clear
  93.     end
  94.     for t in waiters0
  95.       begin
  96.    t.run
  97.       rescue ThreadError
  98.       end
  99.     end
  100.   end
  101. end
  102.  
  103. #
  104. # This class provides a way to synchronize communication between threads.
  105. #
  106. # Example:
  107. #
  108. #   require 'thread'
  109. #  
  110. #   queue = Queue.new
  111. #  
  112. #   producer = Thread.new do
  113. #     5.times do |i|
  114. #       sleep rand(i) # simulate expense
  115. #       queue << i
  116. #       puts "#{i} produced"
  117. #     end
  118. #   end
  119. #  
  120. #   consumer = Thread.new do
  121. #     5.times do |i|
  122. #       value = queue.pop
  123. #       sleep rand(i/2) # simulate expense
  124. #       puts "consumed #{value}"
  125. #     end
  126. #   end
  127. #  
  128. #   consumer.join
  129. #
  130. class Queue
  131.   #
  132.   # Creates a new queue.
  133.   #
  134.   def initialize
  135.     @que = []
  136.     @waiting = []
  137.     @que.taint      # enable tainted comunication
  138.     @waiting.taint
  139.     self.taint
  140.     @mutex = Mutex.new
  141.   end
  142.  
  143.   #
  144.   # Pushes +obj+ to the queue.
  145.   #
  146.   def push(obj)
  147.     t = nil
  148.     @mutex.synchronize{
  149.       @que.push obj
  150.       begin
  151.         t = @waiting.shift
  152.         t.wakeup if t
  153.       rescue ThreadError
  154.         retry
  155.       end
  156.     }
  157.     begin
  158.       t.run if t
  159.     rescue ThreadError
  160.     end
  161.   end
  162.  
  163.   #
  164.   # Alias of push
  165.   #
  166.   alias << push
  167.  
  168.   #
  169.   # Alias of push
  170.   #
  171.   alias enq push
  172.  
  173.   #
  174.   # Retrieves data from the queue.  If the queue is empty, the calling thread is
  175.   # suspended until data is pushed onto the queue.  If +non_block+ is true, the
  176.   # thread isn't suspended, and an exception is raised.
  177.   #
  178.   def pop(non_block=false)
  179.     while true
  180.       @mutex.synchronize{
  181.         if @que.empty?
  182.           raise ThreadError, "queue empty" if non_block
  183.           @waiting.push Thread.current
  184.           @mutex.sleep
  185.         else
  186.           return @que.shift
  187.         end
  188.       }
  189.     end
  190.   end
  191.  
  192.   #
  193.   # Alias of pop
  194.   #
  195.   alias shift pop
  196.  
  197.   #
  198.   # Alias of pop
  199.   #
  200.   alias deq pop
  201.  
  202.   #
  203.   # Returns +true+ if the queue is empty.
  204.   #
  205.   def empty?
  206.     @que.empty?
  207.   end
  208.  
  209.   #
  210.   # Removes all objects from the queue.
  211.   #
  212.   def clear
  213.     @que.clear
  214.   end
  215.  
  216.   #
  217.   # Returns the length of the queue.
  218.   #
  219.   def length
  220.     @que.length
  221.   end
  222.  
  223.   #
  224.   # Alias of length.
  225.   #
  226.   alias size length
  227.  
  228.   #
  229.   # Returns the number of threads waiting on the queue.
  230.   #
  231.   def num_waiting
  232.     @waiting.size
  233.   end
  234. end
  235.  
  236. #
  237. # This class represents queues of specified size capacity.  The push operation
  238. # may be blocked if the capacity is full.
  239. #
  240. # See Queue for an example of how a SizedQueue works.
  241. #
  242. class SizedQueue < Queue
  243.   #
  244.   # Creates a fixed-length queue with a maximum size of +max+.
  245.   #
  246.   def initialize(max)
  247.     raise ArgumentError, "queue size must be positive" unless max > 0
  248.     @max = max
  249.     @queue_wait = []
  250.     @queue_wait.taint      # enable tainted comunication
  251.     super()
  252.   end
  253.  
  254.   #
  255.   # Returns the maximum size of the queue.
  256.   #
  257.   def max
  258.     @max
  259.   end
  260.  
  261.   #
  262.   # Sets the maximum size of the queue.
  263.   #
  264.   def max=(max)
  265.     diff = nil
  266.     @mutex.synchronize {
  267.       if max <= @max
  268.         @max = max
  269.       else
  270.         diff = max - @max
  271.         @max = max
  272.       end
  273.     }
  274.     if diff
  275.       diff.times do
  276.    begin
  277.      t = @queue_wait.shift
  278.      t.run if t
  279.    rescue ThreadError
  280.      retry
  281.    end
  282.       end
  283.     end
  284.     max
  285.   end
  286.  
  287.   #
  288.   # Pushes +obj+ to the queue.  If there is no space left in the queue, waits
  289.   # until space becomes available.
  290.   #
  291.   def push(obj)
  292.     t = nil
  293.     @mutex.synchronize{
  294.       while true
  295.         break if @que.length < @max
  296.         @queue_wait.push Thread.current
  297.         @mutex.sleep
  298.       end
  299.    
  300.       @que.push obj
  301.       begin
  302.         t = @waiting.shift
  303.         t.wakeup if t
  304.       rescue ThreadError
  305.         retry
  306.       end
  307.     }
  308.    
  309.     begin
  310.       t.run if t
  311.     rescue ThreadError
  312.     end
  313.   end
  314.  
  315.   #
  316.   # Alias of push
  317.   #
  318.   alias << push
  319.  
  320.   #
  321.   # Alias of push
  322.   #
  323.   alias enq push
  324.  
  325.   #
  326.   # Retrieves data from the queue and runs a waiting thread, if any.
  327.   #
  328.   def pop(*args)
  329.     retval = super
  330.     t = nil
  331.     @mutex.synchronize {
  332.       if @que.length < @max
  333.         begin
  334.           t = @queue_wait.shift
  335.           t.wakeup if t
  336.         rescue ThreadError
  337.           retry
  338.         end
  339.       end
  340.     }
  341.     begin
  342.       t.run if t
  343.     rescue ThreadError
  344.     end
  345.     retval
  346.   end
  347.  
  348.   #
  349.   # Alias of pop
  350.   #
  351.   alias shift pop
  352.  
  353.   #
  354.   # Alias of pop
  355.   #
  356.   alias deq pop
  357.  
  358.   #
  359.   # Returns the number of threads waiting on the queue.
  360.   #
  361.   def num_waiting
  362.     @waiting.size + @queue_wait.size
  363.   end
  364. end
  365.  
  366. # Documentation comments:
  367. #  - How do you make RDoc inherit documentation from superclass?
  368. #require 'dl'
  369. #require 'thread'
  370.  
  371. module DL
  372.   SEM = Mutex.new
  373.  
  374.   def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
  375.     if( argc < 0 )
  376.       raise(ArgumentError, "arity should not be less than 0.")
  377.     end
  378.     addr = nil
  379.     SEM.synchronize{
  380.       ary = proc_entry[ty]
  381.       (0...MAX_CALLBACK).each{|n|
  382.         idx = (n * DLSTACK_SIZE) + argc
  383.         if( ary[idx].nil? )
  384.           ary[idx] = cbp
  385.           addr = addr_entry[ty][idx]
  386.           break
  387.         end
  388.       }
  389.     }
  390.     addr
  391.   end
  392.  
  393.   def set_cdecl_callback(ty, argc, &cbp)
  394.     set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
  395.   end
  396.  
  397.   def set_stdcall_callback(ty, argc, &cbp)
  398.     set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
  399.   end
  400.  
  401.   def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
  402.     index = nil
  403.     if( ctype )
  404.       addr_entry[ctype].each_with_index{|xaddr, idx|
  405.         if( xaddr == addr )
  406.           index = idx
  407.         end
  408.       }
  409.     else
  410.       addr_entry.each{|ty,entry|
  411.         entry.each_with_index{|xaddr, idx|
  412.           if( xaddr == addr )
  413.             index = idx
  414.           end
  415.         }
  416.       }
  417.     end
  418.     if( index and proc_entry[ctype][index] )
  419.       proc_entry[ctype][index] = nil
  420.       return true
  421.     else
  422.       return false
  423.     end
  424.   end
  425.  
  426.   def remove_cdecl_callback(addr, ctype = nil)
  427.     remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
  428.   end
  429.  
  430.   def remove_stdcall_callback(addr, ctype = nil)
  431.     remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
  432.   end
  433.  
  434.   alias set_callback set_cdecl_callback
  435.   alias remove_callback remove_cdecl_callback
  436. end
  437. module DL
  438.   module CParser
  439.     def parse_struct_signature(signature, tymap=nil)
  440.       if( signature.is_a?(String) )
  441.         signature = signature.split(/\s*,\s*/)
  442.       end
  443.       mems = []
  444.       tys  = []
  445.       signature.each{|msig|
  446.         tks = msig.split(/\s+(\*)?/)
  447.         ty = tks[0..-2].join(" ")
  448.         member = tks[-1]
  449.  
  450.         case ty
  451.         when /\[(\d+)\]/
  452.           n = $1.to_i
  453.           ty.gsub!(/\s*\[\d+\]/,"")
  454.           ty = [ty, n]
  455.         when /\[\]/
  456.           ty.gsub!(/\s*\[\]/, "*")
  457.         end
  458.  
  459.         case member
  460.         when /\[(\d+)\]/
  461.           ty = [ty, $1.to_i]
  462.           member.gsub!(/\s*\[\d+\]/,"")
  463.         when /\[\]/
  464.           ty = ty + "*"
  465.           member.gsub!(/\s*\[\]/, "")
  466.         end
  467.  
  468.         mems.push(member)
  469.         tys.push(parse_ctype(ty,tymap))
  470.       }
  471.       return tys, mems
  472.     end
  473.  
  474.     def parse_signature(signature, tymap=nil)
  475.       tymap ||= {}
  476.       signature = signature.gsub(/\s+/, " ").strip
  477.       case signature
  478.       when /^([\d\w@\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
  479.         ret = $1
  480.         (args = $2).strip!
  481.         ret = ret.split(/\s+/)
  482.         args = args.split(/\s*,\s*/)
  483.         func = ret.pop
  484.         if( func =~ /^\*/ )
  485.           func.gsub!(/^\*+/,"")
  486.           ret.push("*")
  487.         end
  488.         ret  = ret.join(" ")
  489.         return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}]
  490.       else
  491.         raise(RuntimeError,"can't parse the function prototype: #{proto}")
  492.       end
  493.     end
  494.  
  495.     def parse_ctype(ty, tymap=nil)
  496.       tymap ||= {}
  497.       case ty
  498.       when Array
  499.         return [parse_ctype(ty[0], tymap), ty[1]]
  500.       when "void"
  501.         return TYPE_VOID
  502.       when "char"
  503.         return TYPE_CHAR
  504.       when "unsigned char"
  505.         return  -TYPE_CHAR
  506.       when "short"
  507.         return TYPE_SHORT
  508.       when "unsigned short"
  509.         return -TYPE_SHORT
  510.       when "int"
  511.         return TYPE_INT
  512.       when "unsigned int"
  513.         return -TYPE_INT
  514.       when "long"
  515.         return TYPE_LONG
  516.       when "unsigned long"
  517.         return -TYPE_LONG
  518.       when "long long"
  519.         if( defined?(TYPE_LONG_LONG) )
  520.           return TYPE_LONG_LONG
  521.         else
  522.           raise(RuntimeError, "unsupported type: #{ty}")
  523.         end
  524.       when "unsigned long long"
  525.         if( defined?(TYPE_LONG_LONG) )
  526.           return -TYPE_LONG_LONG
  527.         else
  528.           raise(RuntimeError, "unsupported type: #{ty}")
  529.         end
  530.       when "float"
  531.         return TYPE_FLOAT
  532.       when "double"
  533.         return TYPE_DOUBLE
  534.       when /\*/, /\[\s*\]/
  535.         return TYPE_VOIDP
  536.       else
  537.         if( tymap[ty] )
  538.           return parse_ctype(tymap[ty], tymap)
  539.         else
  540.           raise(DLError, "unknown type: #{ty}", caller(1))
  541.         end
  542.       end
  543.     end
  544.   end
  545. end
  546. #require 'dl'
  547.  
  548. module DL
  549.   module PackInfo
  550.     if( defined?(TYPE_LONG_LONG) )
  551.     ALIGN_MAP = {
  552.       TYPE_VOIDP => ALIGN_VOIDP,
  553.       TYPE_CHAR  => ALIGN_CHAR,
  554.       TYPE_SHORT => ALIGN_SHORT,
  555.       TYPE_INT   => ALIGN_INT,
  556.       TYPE_LONG  => ALIGN_LONG,
  557.       TYPE_LONG_LONG => ALIGN_LONG_LONG,
  558.       TYPE_FLOAT => ALIGN_FLOAT,
  559.       TYPE_DOUBLE => ALIGN_DOUBLE,
  560.       -TYPE_CHAR  => ALIGN_CHAR,
  561.       -TYPE_SHORT => ALIGN_SHORT,
  562.       -TYPE_INT   => ALIGN_INT,
  563.       -TYPE_LONG  => ALIGN_LONG,
  564.       -TYPE_LONG_LONG => ALIGN_LONG_LONG,
  565.     }
  566.  
  567.     PACK_MAP = {
  568.       TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
  569.       TYPE_CHAR  => "c",
  570.       TYPE_SHORT => "s!",
  571.       TYPE_INT   => "i!",
  572.       TYPE_LONG  => "l!",
  573.       TYPE_LONG_LONG => "q",
  574.       TYPE_FLOAT => "f",
  575.       TYPE_DOUBLE => "d",
  576.       -TYPE_CHAR  => "c",
  577.       -TYPE_SHORT => "s!",
  578.       -TYPE_INT   => "i!",
  579.       -TYPE_LONG  => "l!",
  580.       -TYPE_LONG_LONG => "q",
  581.     }
  582.  
  583.     SIZE_MAP = {
  584.       TYPE_VOIDP => SIZEOF_VOIDP,
  585.       TYPE_CHAR  => SIZEOF_CHAR,
  586.       TYPE_SHORT => SIZEOF_SHORT,
  587.       TYPE_INT   => SIZEOF_INT,
  588.       TYPE_LONG  => SIZEOF_LONG,
  589.       TYPE_LONG_LONG => SIZEOF_LONG_LONG,
  590.       TYPE_FLOAT => SIZEOF_FLOAT,
  591.       TYPE_DOUBLE => SIZEOF_DOUBLE,
  592.       -TYPE_CHAR  => SIZEOF_CHAR,
  593.       -TYPE_SHORT => SIZEOF_SHORT,
  594.       -TYPE_INT   => SIZEOF_INT,
  595.       -TYPE_LONG  => SIZEOF_LONG,
  596.       -TYPE_LONG_LONG => SIZEOF_LONG_LONG,
  597.     }
  598.     else
  599.     ALIGN_MAP = {
  600.       TYPE_VOIDP => ALIGN_VOIDP,
  601.       TYPE_CHAR  => ALIGN_CHAR,
  602.       TYPE_SHORT => ALIGN_SHORT,
  603.       TYPE_INT   => ALIGN_INT,
  604.       TYPE_LONG  => ALIGN_LONG,
  605.       TYPE_FLOAT => ALIGN_FLOAT,
  606.       TYPE_DOUBLE => ALIGN_DOUBLE,
  607.       -TYPE_CHAR  => ALIGN_CHAR,
  608.       -TYPE_SHORT => ALIGN_SHORT,
  609.       -TYPE_INT   => ALIGN_INT,
  610.       -TYPE_LONG  => ALIGN_LONG,
  611.     }
  612.  
  613.     PACK_MAP = {
  614.       TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
  615.       TYPE_CHAR  => "c",
  616.       TYPE_SHORT => "s!",
  617.       TYPE_INT   => "i!",
  618.       TYPE_LONG  => "l!",
  619.       TYPE_FLOAT => "f",
  620.       TYPE_DOUBLE => "d",
  621.       -TYPE_CHAR  => "c",
  622.       -TYPE_SHORT => "s!",
  623.       -TYPE_INT   => "i!",
  624.       -TYPE_LONG  => "l!",
  625.     }
  626.  
  627.     SIZE_MAP = {
  628.       TYPE_VOIDP => SIZEOF_VOIDP,
  629.       TYPE_CHAR  => SIZEOF_CHAR,
  630.       TYPE_SHORT => SIZEOF_SHORT,
  631.       TYPE_INT   => SIZEOF_INT,
  632.       TYPE_LONG  => SIZEOF_LONG,
  633.       TYPE_FLOAT => SIZEOF_FLOAT,
  634.       TYPE_DOUBLE => SIZEOF_DOUBLE,
  635.       -TYPE_CHAR  => SIZEOF_CHAR,
  636.       -TYPE_SHORT => SIZEOF_SHORT,
  637.       -TYPE_INT   => SIZEOF_INT,
  638.       -TYPE_LONG  => SIZEOF_LONG,
  639.     }
  640.     end
  641.  
  642.     def align(addr, align)
  643.       d = addr % align
  644.       if( d == 0 )
  645.         addr
  646.       else
  647.         addr + (align - d)
  648.       end
  649.     end
  650.     module_function :align
  651.   end
  652.  
  653.   class Packer
  654.     include PackInfo
  655.  
  656.     def Packer.[](*types)
  657.       Packer.new(types)
  658.     end
  659.  
  660.     def initialize(types)
  661.       parse_types(types)
  662.     end
  663.  
  664.     def size()
  665.       @size
  666.     end
  667.    
  668.     def pack(ary)
  669.       case SIZEOF_VOIDP
  670.       when SIZEOF_LONG
  671.         ary.pack(@template)
  672.       when SIZEOF_LONG
  673.         ary.pack(@template)
  674.       else
  675.         raise(RuntimeError, "sizeof(void*)?")
  676.       end
  677.     end
  678.  
  679.     def unpack(ary)
  680.       case SIZEOF_VOIDP
  681.       when SIZEOF_LONG
  682.         ary.join().unpack(@template)
  683.       when SIZEOF_LONG_LONG
  684.         ary.join().unpack(@template)
  685.       else
  686.         raise(RuntimeError, "sizeof(void*)?")
  687.       end
  688.     end
  689.    
  690.     private
  691.    
  692.     def parse_types(types)
  693.       @template = ""
  694.       addr     = 0
  695.       types.each{|t|
  696.         orig_addr = addr
  697.         if( t.is_a?(Array) )
  698.           addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP])
  699.         else
  700.           addr = align(orig_addr, ALIGN_MAP[t])
  701.         end
  702.         d = addr - orig_addr
  703.         if( d > 0 )
  704.           @template << "x#{d}"
  705.         end
  706.         if( t.is_a?(Array) )
  707.           @template << (PACK_MAP[t[0]] * t[1])
  708.           addr += (SIZE_MAP[t[0]] * t[1])
  709.         else
  710.           @template << PACK_MAP[t]
  711.           addr += SIZE_MAP[t]
  712.         end
  713.       }
  714.       addr = align(addr, ALIGN_MAP[TYPE_VOIDP])
  715.       @size = addr
  716.     end
  717.   end
  718. end
  719. #require 'dl'
  720.  
  721. module DL
  722.   class Stack
  723.     def Stack.[](*types)
  724.       Stack.new(types)
  725.     end
  726.  
  727.     def initialize(types)
  728.       parse_types(types)
  729.     end
  730.  
  731.     def size()
  732.       @size
  733.     end
  734.  
  735.     def types()
  736.       @types
  737.     end
  738.  
  739.     def pack(ary)
  740.       case SIZEOF_VOIDP
  741.       when SIZEOF_LONG
  742.         ary.pack(@template).unpack('l!*')
  743.       when SIZEOF_LONG_LONG
  744.         ary.pack(@template).unpack('q*')
  745.       else
  746.         raise(RuntimeError, "sizeof(void*)?")
  747.       end
  748.     end
  749.  
  750.     def unpack(ary)
  751.       case SIZEOF_VOIDP
  752.       when SIZEOF_LONG
  753.         ary.pack('l!*').unpack(@template)
  754.       when SIZEOF_LONG_LONG
  755.         ary.pack('q*').unpack(@template)
  756.       else
  757.         raise(RuntimeError, "sizeof(void*)?")
  758.       end
  759.     end
  760.    
  761.     private
  762.    
  763.     def align(addr, align)
  764.       d = addr % align
  765.       if( d == 0 )
  766.         addr
  767.       else
  768.         addr + (align - d)
  769.       end
  770.     end
  771.  
  772. if( defined?(TYPE_LONG_LONG) )
  773.     ALIGN_MAP = {
  774.       TYPE_VOIDP => ALIGN_VOIDP,
  775.       TYPE_CHAR  => ALIGN_VOIDP,
  776.       TYPE_SHORT => ALIGN_VOIDP,
  777.       TYPE_INT   => ALIGN_VOIDP,
  778.       TYPE_LONG  => ALIGN_VOIDP,
  779.       TYPE_LONG_LONG => ALIGN_LONG_LONG,
  780.       TYPE_FLOAT => ALIGN_FLOAT,
  781.       TYPE_DOUBLE => ALIGN_DOUBLE,
  782.     }
  783.  
  784.     PACK_MAP = {
  785.       TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
  786.       TYPE_CHAR  => "c",
  787.       TYPE_SHORT => "s!",
  788.       TYPE_INT   => "i!",
  789.       TYPE_LONG  => "l!",
  790.       TYPE_LONG_LONG => "q",
  791.       TYPE_FLOAT => "f",
  792.       TYPE_DOUBLE => "d",
  793.     }
  794.  
  795.     SIZE_MAP = {
  796.       TYPE_VOIDP => SIZEOF_VOIDP,
  797.       TYPE_CHAR  => SIZEOF_CHAR,
  798.       TYPE_SHORT => SIZEOF_SHORT,
  799.       TYPE_INT   => SIZEOF_INT,
  800.       TYPE_LONG  => SIZEOF_LONG,
  801.       TYPE_LONG_LONG => SIZEOF_LONG_LONG,
  802.       TYPE_FLOAT => SIZEOF_FLOAT,
  803.       TYPE_DOUBLE => SIZEOF_DOUBLE,
  804.     }
  805. else
  806.     ALIGN_MAP = {
  807.       TYPE_VOIDP => ALIGN_VOIDP,
  808.       TYPE_CHAR  => ALIGN_VOIDP,
  809.       TYPE_SHORT => ALIGN_VOIDP,
  810.       TYPE_INT   => ALIGN_VOIDP,
  811.       TYPE_LONG  => ALIGN_VOIDP,
  812.       TYPE_FLOAT => ALIGN_FLOAT,
  813.       TYPE_DOUBLE => ALIGN_DOUBLE,
  814.     }
  815.  
  816.     PACK_MAP = {
  817.       TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
  818.       TYPE_CHAR  => "c",
  819.       TYPE_SHORT => "s!",
  820.       TYPE_INT   => "i!",
  821.       TYPE_LONG  => "l!",
  822.       TYPE_FLOAT => "f",
  823.       TYPE_DOUBLE => "d",
  824.     }
  825.  
  826.     SIZE_MAP = {
  827.       TYPE_VOIDP => SIZEOF_VOIDP,
  828.       TYPE_CHAR  => SIZEOF_CHAR,
  829.       TYPE_SHORT => SIZEOF_SHORT,
  830.       TYPE_INT   => SIZEOF_INT,
  831.       TYPE_LONG  => SIZEOF_LONG,
  832.       TYPE_FLOAT => SIZEOF_FLOAT,
  833.       TYPE_DOUBLE => SIZEOF_DOUBLE,
  834.     }
  835. end
  836.  
  837.     def parse_types(types)
  838.       @types = types
  839.       @template = ""
  840.       addr      = 0
  841.       types.each{|t|
  842.         addr = add_padding(addr, ALIGN_MAP[t])
  843.         @template << PACK_MAP[t]
  844.         addr += SIZE_MAP[t]
  845.       }
  846.       addr = add_padding(addr, ALIGN_MAP[SIZEOF_VOIDP])
  847.       if( addr % SIZEOF_VOIDP == 0 )
  848.         @size = addr / SIZEOF_VOIDP
  849.       else
  850.         @size = (addr / SIZEOF_VOIDP) + 1
  851.       end
  852.     end
  853.  
  854.     def add_padding(addr, align)
  855.       orig_addr = addr
  856.       addr = align(orig_addr, align)
  857.       d = addr - orig_addr
  858.       if( d > 0 )
  859.         @template << "x#{d}"
  860.       end
  861.       addr
  862.     end
  863.   end
  864. end
  865. #require 'dl'
  866.  
  867. module DL
  868.   module ValueUtil
  869.     def unsigned_value(val, ty)
  870.       case ty.abs
  871.       when TYPE_CHAR
  872.         [val].pack("c").unpack("C")[0]
  873.       when TYPE_SHORT
  874.         [val].pack("s!").unpack("S!")[0]
  875.       when TYPE_INT
  876.         [val].pack("i!").unpack("I!")[0]
  877.       when TYPE_LONG
  878.         [val].pack("l!").unpack("L!")[0]
  879.       when TYPE_LONG_LONG
  880.         [val].pack("q!").unpack("Q!")[0]
  881.       else
  882.         val
  883.       end
  884.     end
  885.  
  886.     def signed_value(val, ty)
  887.       case ty.abs
  888.       when TYPE_CHAR
  889.         [val].pack("C").unpack("c")[0]
  890.       when TYPE_SHORT
  891.         [val].pack("S!").unpack("s!")[0]
  892.       when TYPE_INT
  893.         [val].pack("I!").unpack("i!")[0]
  894.       when TYPE_LONG
  895.         [val].pack("L!").unpack("l!")[0]
  896.       when TYPE_LONG_LONG
  897.         [val].pack("Q!").unpack("q!")[0]
  898.       else
  899.         val
  900.       end
  901.     end
  902.  
  903.     def wrap_args(args, tys, funcs, &block)
  904.       result = []
  905.       tys ||= []
  906.       args.each_with_index{|arg, idx|
  907.         result.push(wrap_arg(arg, tys[idx], funcs, &block))
  908.       }
  909.       result
  910.     end
  911.  
  912.     def wrap_arg(arg, ty, funcs, &block)
  913.         funcs ||= []
  914.         case arg
  915.         when nil
  916.           return 0
  917.         when CPtr
  918.           return arg.to_i
  919.         when IO
  920.           case ty
  921.           when TYPE_VOIDP
  922.             return CPtr[arg].to_i
  923.           else
  924.             return arg.to_i
  925.           end
  926.         when Function
  927.           if( block )
  928.             arg.bind_at_call(&block)
  929.             funcs.push(arg)
  930.           elsif !arg.bound?
  931.             raise(RuntimeError, "block must be given.")
  932.           end
  933.           return arg.to_i
  934.         when String
  935.           if( ty.is_a?(Array) )
  936.             return arg.unpack('C*')
  937.           else
  938.             case SIZEOF_VOIDP
  939.             when SIZEOF_LONG
  940.               return [arg].pack("p").unpack("l!")[0]
  941.             when SIZEOF_LONG_LONG
  942.               return [arg].pack("p").unpack("q")[0]
  943.             else
  944.               raise(RuntimeError, "sizeof(void*)?")
  945.             end
  946.           end
  947.         when Float, Integer
  948.           return arg
  949.         when Array
  950.           if( ty.is_a?(Array) ) # used only by struct
  951.             case ty[0]
  952.             when TYPE_VOIDP
  953.               return arg.collect{|v| Integer(v)}
  954.             when TYPE_CHAR
  955.               if( arg.is_a?(String) )
  956.                 return val.unpack('C*')
  957.               end
  958.             end
  959.             return arg
  960.           else
  961.             return arg
  962.           end
  963.         else
  964.           if( arg.respond_to?(:to_ptr) )
  965.             return arg.to_ptr.to_i
  966.           else
  967.             begin
  968.               return Integer(arg)
  969.             rescue
  970.               raise(ArgumentError, "unknown argument type: #{arg.class}")
  971.             end
  972.           end
  973.         end
  974.     end
  975.   end
  976. end
  977. #require 'dl'
  978. #require 'dl/pack.rb'
  979.  
  980. module DL
  981.   class CStruct
  982.     def CStruct.entity_class()
  983.       CStructEntity
  984.     end
  985.   end
  986.  
  987.   class CUnion
  988.     def CUnion.entity_class()
  989.       CUnionEntity
  990.     end
  991.   end
  992.  
  993.   module CStructBuilder
  994.     def create(klass, types, members)
  995.       new_class = Class.new(klass){
  996.         define_method(:initialize){|addr|
  997.           @entity = klass.entity_class.new(addr, types)
  998.           @entity.assign_names(members)
  999.         }
  1000.         define_method(:to_ptr){ @entity }
  1001.         define_method(:to_i){ @entity.to_i }
  1002.         members.each{|name|
  1003.           define_method(name){ @entity[name] }
  1004.           define_method(name + "="){|val| @entity[name] = val }
  1005.         }
  1006.       }
  1007.       size = klass.entity_class.size(types)
  1008.       new_class.module_eval(<<-EOS)
  1009.         def new_class.size()
  1010.           #{size}
  1011.         end
  1012.         def new_class.malloc()
  1013.           addr = DL.malloc(#{size})
  1014.           new(addr)
  1015.         end
  1016.       EOS
  1017.       return new_class
  1018.     end
  1019.     module_function :create
  1020.   end
  1021.  
  1022.   class CStructEntity < CPtr
  1023.     include PackInfo
  1024.     include ValueUtil
  1025.  
  1026.     def CStructEntity.malloc(types, func = nil)
  1027.       addr = DL.malloc(CStructEntity.size(types))
  1028.       CStructEntity.new(addr, types, func)
  1029.     end
  1030.  
  1031.     def CStructEntity.size(types)
  1032.       offset = 0
  1033.       max_align = 0
  1034.       types.each_with_index{|t,i|
  1035.         orig_offset = offset
  1036.         if( t.is_a?(Array) )
  1037.           align = PackInfo::ALIGN_MAP[t[0]]
  1038.           offset = PackInfo.align(orig_offset, align)
  1039.           size = offset - orig_offset
  1040.           offset += (PackInfo::SIZE_MAP[t[0]] * t[1])
  1041.         else
  1042.           align = PackInfo::ALIGN_MAP[t]
  1043.           offset = PackInfo.align(orig_offset, align)
  1044.           size = offset - orig_offset
  1045.           offset += PackInfo::SIZE_MAP[t]
  1046.         end
  1047.         if (max_align < align)
  1048.           max_align = align
  1049.         end
  1050.       }
  1051.       offset = PackInfo.align(offset, max_align)
  1052.       offset
  1053.     end
  1054.  
  1055.     def initialize(addr, types, func = nil)
  1056.       set_ctypes(types)
  1057.       super(addr, @size, func)
  1058.     end
  1059.  
  1060.     def assign_names(members)
  1061.       @members = members
  1062.     end
  1063.  
  1064.     def set_ctypes(types)
  1065.       @ctypes = types
  1066.       @offset = []
  1067.       offset = 0
  1068.       max_align = 0
  1069.       types.each_with_index{|t,i|
  1070.         orig_offset = offset
  1071.         if( t.is_a?(Array) )
  1072.           align = ALIGN_MAP[t[0]]
  1073.         else
  1074.           align = ALIGN_MAP[t]
  1075.         end
  1076.         offset = PackInfo.align(orig_offset, align)
  1077.         size = offset - orig_offset
  1078.         @offset[i] = offset
  1079.         if( t.is_a?(Array) )
  1080.           offset += (SIZE_MAP[t[0]] * t[1])
  1081.         else
  1082.           offset += SIZE_MAP[t]
  1083.         end
  1084.         if (max_align < align)
  1085.           max_align = align
  1086.         end
  1087.       }
  1088.       offset = PackInfo.align(offset, max_align)
  1089.       @size = offset
  1090.     end
  1091.  
  1092.     def [](name)
  1093.       idx = @members.index(name)
  1094.       if( idx.nil? )
  1095.         raise(ArgumentError, "no such member: #{name}")
  1096.       end
  1097.       ty = @ctypes[idx]
  1098.       if( ty.is_a?(Array) )
  1099.         r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
  1100.       else
  1101.         r = super(@offset[idx], SIZE_MAP[ty.abs])
  1102.       end
  1103.       packer = Packer.new([ty])
  1104.       val = packer.unpack([r])
  1105.       case ty
  1106.       when Array
  1107.         case ty[0]
  1108.         when TYPE_VOIDP
  1109.           val = val.collect{|v| CPtr.new(v)}
  1110.         end
  1111.       when TYPE_VOIDP
  1112.         val = CPtr.new(val[0])
  1113.       else
  1114.         val = val[0]
  1115.       end
  1116.       if( ty.is_a?(Integer) && (ty < 0) )
  1117.         return unsigned_value(val, ty)
  1118.       elsif( ty.is_a?(Array) && (ty[0] < 0) )
  1119.         return val.collect{|v| unsigned_value(v,ty[0])}
  1120.       else
  1121.         return val
  1122.       end
  1123.     end
  1124.  
  1125.     def []=(name, val)
  1126.       idx = @members.index(name)
  1127.       if( idx.nil? )
  1128.         raise(ArgumentError, "no such member: #{name}")
  1129.       end
  1130.       ty  = @ctypes[idx]
  1131.       packer = Packer.new([ty])
  1132.       val = wrap_arg(val, ty, [])
  1133.       buff = packer.pack([val].flatten())
  1134.       super(@offset[idx], buff.size, buff)
  1135.       if( ty.is_a?(Integer) && (ty < 0) )
  1136.         return unsigned_value(val, ty)
  1137.       elsif( ty.is_a?(Array) && (ty[0] < 0) )
  1138.         return val.collect{|v| unsigned_value(v,ty[0])}
  1139.       else
  1140.         return val
  1141.       end
  1142.     end
  1143.  
  1144.     def to_s()
  1145.       super(@size)
  1146.     end
  1147.   end
  1148.  
  1149.   class CUnionEntity < CStructEntity
  1150.     include PackInfo
  1151.  
  1152.     def CUnionEntity.malloc(types, func=nil)
  1153.       addr = DL.malloc(CUnionEntity.size(types))
  1154.       CUnionEntity.new(addr, types, func)
  1155.     end
  1156.  
  1157.     def CUnionEntity.size(types)
  1158.       size   = 0
  1159.       types.each_with_index{|t,i|
  1160.         if( t.is_a?(Array) )
  1161.           tsize = PackInfo::SIZE_MAP[t[0]] * t[1]
  1162.         else
  1163.           tsize = PackInfo::SIZE_MAP[t]
  1164.         end
  1165.         if( tsize > size )
  1166.           size = tsize
  1167.         end
  1168.       }
  1169.     end
  1170.  
  1171.     def set_ctypes(types)
  1172.       @ctypes = types
  1173.       @offset = []
  1174.       @size   = 0
  1175.       types.each_with_index{|t,i|
  1176.         @offset[i] = 0
  1177.         if( t.is_a?(Array) )
  1178.           size = SIZE_MAP[t[0]] * t[1]
  1179.         else
  1180.           size = SIZE_MAP[t]
  1181.         end
  1182.         if( size > @size )
  1183.           @size = size
  1184.         end
  1185.       }
  1186.     end
  1187.   end
  1188. end
  1189.  
  1190. module DL
  1191.   module Win32Types
  1192.     def included(m)
  1193.       m.module_eval{
  1194.         typealias "DWORD", "unsigned long"
  1195.         typealias "PDWORD", "unsigned long *"
  1196.         typealias "WORD", "unsigned short"
  1197.         typealias "PWORD", "unsigned short *"
  1198.         typealias "BOOL", "int"
  1199.         typealias "ATOM", "int"
  1200.         typealias "BYTE", "unsigned char"
  1201.         typealias "PBYTE", "unsigned char *"
  1202.         typealias "UINT", "unsigned int"
  1203.         typealias "ULONG", "unsigned long"
  1204.         typealias "UCHAR", "unsigned char"
  1205.         typealias "HANDLE", "unsigned long"
  1206.         typealias "PHANDLE", "void*"
  1207.         typealias "PVOID", "void*"
  1208.         typealias "LPCSTR", "char*"
  1209.         typealias "LPSTR", "char*"
  1210.         typealias "HINSTANCE", "unsigned int"
  1211.         typealias "HDC", "unsigned int"
  1212.         typealias "HWND", "unsigned int"
  1213.       }
  1214.     end
  1215.     module_function :included
  1216.   end
  1217.  
  1218.   module BasicTypes
  1219.     def included(m)
  1220.       m.module_eval{
  1221.         typealias "uint", "unsigned int"
  1222.         typealias "u_int", "unsigned int"
  1223.         typealias "ulong", "unsigned long"
  1224.         typealias "u_long", "unsigned long"
  1225.       }
  1226.     end
  1227.     module_function :included
  1228.   end
  1229. end
  1230. #require 'dl'
  1231. #require 'dl/callback'
  1232. #require 'dl/stack'
  1233. #require 'dl/value'
  1234. #require 'thread'
  1235.  
  1236. module DL
  1237.   class Function
  1238.     include DL
  1239.     include ValueUtil
  1240.  
  1241.     def initialize(cfunc, argtypes, &proc)
  1242.       @cfunc = cfunc
  1243.       @stack = Stack.new(argtypes.collect{|ty| ty.abs})
  1244.       if( @cfunc.ctype < 0 )
  1245.         @cfunc.ctype = @cfunc.ctype.abs
  1246.         @unsigned = true
  1247.       end
  1248.       if( proc )
  1249.         bind(&proc)
  1250.       end
  1251.     end
  1252.  
  1253.     def to_i()
  1254.       @cfunc.to_i
  1255.     end
  1256.  
  1257.     def check_safe_obj(val)
  1258.       if $SAFE > 0 and val.tainted?
  1259.         raise SecurityError, 'Insecure operation'
  1260.       end
  1261.     end
  1262.  
  1263.     def call(*args, &block)
  1264.       funcs = []
  1265.       args.each{|e| check_safe_obj(e) }
  1266.       check_safe_obj(block)
  1267.       args = wrap_args(args, @stack.types, funcs, &block)
  1268.       r = @cfunc.call(@stack.pack(args))
  1269.       funcs.each{|f| f.unbind_at_call()}
  1270.       return wrap_result(r)
  1271.     end
  1272.  
  1273.     def wrap_result(r)
  1274.       case @cfunc.ctype
  1275.       when TYPE_VOIDP
  1276.         r = CPtr.new(r)
  1277.       else
  1278.         if( @unsigned )
  1279.           r = unsigned_value(r, @cfunc.ctype)
  1280.         end
  1281.       end
  1282.       r
  1283.     end
  1284.  
  1285.     def bind(&block)
  1286.       if( !block )
  1287.         raise(RuntimeError, "block must be given.")
  1288.       end
  1289.       if( @cfunc.ptr == 0 )
  1290.         cb = Proc.new{|*args|
  1291.           ary = @stack.unpack(args)
  1292.           @stack.types.each_with_index{|ty, idx|
  1293.             case ty
  1294.             when TYPE_VOIDP
  1295.               ary[idx] = CPtr.new(ary[idx])
  1296.             end
  1297.           }
  1298.           r = block.call(*ary)
  1299.           wrap_arg(r, @cfunc.ctype, [])
  1300.         }
  1301.         case @cfunc.calltype
  1302.         when :cdecl
  1303.           @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb)
  1304.         when :stdcall
  1305.           @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb)
  1306.         else
  1307.           raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
  1308.         end
  1309.         if( @cfunc.ptr == 0 )
  1310.           raise(RuntimeException, "can't bind C function.")
  1311.         end
  1312.       end
  1313.     end
  1314.  
  1315.     def unbind()
  1316.       if( @cfunc.ptr != 0 )
  1317.         case @cfunc.calltype
  1318.         when :cdecl
  1319.           remove_cdecl_callback(@cfunc.ptr, @cfunc.ctype)
  1320.         when :stdcall
  1321.           remove_stdcall_callback(@cfunc.ptr, @cfunc.ctype)
  1322.         else
  1323.           raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
  1324.         end
  1325.         @cfunc.ptr = 0
  1326.       end
  1327.     end
  1328.  
  1329.     def bound?()
  1330.       @cfunc.ptr != 0
  1331.     end
  1332.  
  1333.     def bind_at_call(&block)
  1334.       bind(&block)
  1335.     end
  1336.  
  1337.     def unbind_at_call()
  1338.     end
  1339.   end
  1340.  
  1341.   class TempFunction < Function
  1342.     def bind_at_call(&block)
  1343.       bind(&block)
  1344.     end
  1345.  
  1346.     def unbind_at_call()
  1347.       unbind()
  1348.     end
  1349.   end
  1350.  
  1351.   class CarriedFunction < Function
  1352.     def initialize(cfunc, argtypes, n)
  1353.       super(cfunc, argtypes)
  1354.       @carrier = []
  1355.       @index = n
  1356.       @mutex = Mutex.new
  1357.     end
  1358.  
  1359.     def create_carrier(data)
  1360.       ary = []
  1361.       userdata = [ary, data]
  1362.       @mutex.lock()
  1363.       @carrier.push(userdata)
  1364.       return dlwrap(userdata)
  1365.     end
  1366.  
  1367.     def bind_at_call(&block)
  1368.       userdata = @carrier[-1]
  1369.       userdata[0].push(block)
  1370.       bind{|*args|
  1371.         ptr = args[@index]
  1372.         if( !ptr )
  1373.           raise(RuntimeError, "The index of userdata should be lower than #{args.size}.")
  1374.         end
  1375.         userdata = dlunwrap(Integer(ptr))
  1376.         args[@index] = userdata[1]
  1377.         userdata[0][0].call(*args)
  1378.       }
  1379.       @mutex.unlock()
  1380.     end
  1381.   end
  1382. end
  1383. #require 'dl'
  1384. #require 'dl/func.rb'
  1385. #require 'dl/struct.rb'
  1386. #require 'dl/cparser.rb'
  1387.  
  1388. module DL
  1389.   class CompositeHandler
  1390.     def initialize(handlers)
  1391.       @handlers = handlers
  1392.     end
  1393.  
  1394.     def handlers()
  1395.       @handlers
  1396.     end
  1397.  
  1398.     def sym(symbol)
  1399.       @handlers.each{|handle|
  1400.         if( handle )
  1401.           begin
  1402.             addr = handle.sym(symbol)
  1403.             return addr
  1404.           rescue DLError
  1405.           end
  1406.         end
  1407.       }
  1408.       return nil
  1409.     end
  1410.  
  1411.     def [](symbol)
  1412.       sym(symbol)
  1413.     end
  1414.   end
  1415.  
  1416.   module Importer
  1417.     include DL
  1418.     include CParser
  1419.     extend Importer
  1420.  
  1421.     def dlload(*libs)
  1422.       handles = libs.collect{|lib|
  1423.         case lib
  1424.         when nil
  1425.           nil
  1426.         when Handle
  1427.           lib
  1428.         when Importer
  1429.           lib.handlers
  1430.         else
  1431.           begin
  1432.             DL.dlopen(lib)
  1433.           rescue DLError
  1434.             raise(DLError, "can't load #{lib}")
  1435.           end
  1436.         end
  1437.       }.flatten()
  1438.       @handler = CompositeHandler.new(handles)
  1439.       @func_map = {}
  1440.       @type_alias = {}
  1441.     end
  1442.  
  1443.     def typealias(alias_type, orig_type)
  1444.       @type_alias[alias_type] = orig_type
  1445.     end
  1446.  
  1447.     def sizeof(ty)
  1448.       case ty
  1449.       when String
  1450.         ty = parse_ctype(ty, @type_alias).abs()
  1451.         case ty
  1452.         when TYPE_CHAR
  1453.           return SIZEOF_CHAR
  1454.         when TYPE_SHORT
  1455.           return SIZEOF_SHORT
  1456.         when TYPE_INT
  1457.           return SIZEOF_INT
  1458.         when TYPE_LONG
  1459.           return SIZEOF_LONG
  1460.         when TYPE_LONG_LONG
  1461.           return SIZEOF_LONG_LON
  1462.         when TYPE_FLOAT
  1463.           return SIZEOF_FLOAT
  1464.         when TYPE_DOUBLE
  1465.           return SIZEOF_DOUBLE
  1466.         when TYPE_VOIDP
  1467.           return SIZEOF_VOIDP
  1468.         else
  1469.           raise(DLError, "unknown type: #{ty}")
  1470.         end
  1471.       when Class
  1472.         if( ty.instance_methods().include?(:to_ptr) )
  1473.           return ty.size()
  1474.         end
  1475.       end
  1476.       return CPtr[ty].size()
  1477.     end
  1478.  
  1479.     def parse_bind_options(opts)
  1480.       h = {}
  1481.       prekey = nil
  1482.       while( opt = opts.shift() )
  1483.         case opt
  1484.         when :stdcall, :cdecl
  1485.           h[:call_type] = opt
  1486.         when :carried, :temp, :temporal, :bind
  1487.           h[:callback_type] = opt
  1488.           h[:carrier] = opts.shift()
  1489.         else
  1490.           h[opt] = true
  1491.         end
  1492.       end
  1493.       h
  1494.     end
  1495.     private :parse_bind_options
  1496.  
  1497.     def extern(signature, *opts)
  1498.       symname, ctype, argtype = parse_signature(signature, @type_alias)
  1499.       opt = parse_bind_options(opts)
  1500.       f = import_function(symname, ctype, argtype, opt[:call_type])
  1501.       name = symname.gsub(/@.+/,'')
  1502.       @func_map[name] = f
  1503.       # define_method(name){|*args,&block| f.call(*args,&block)}
  1504.       module_eval(<<-EOS)
  1505.         def #{name}(*args, &block)
  1506.           @func_map['#{name}'].call(*args,&block)
  1507.         end
  1508.       EOS
  1509.       module_function(name)
  1510.       f
  1511.     end
  1512.  
  1513.     def bind(signature, *opts, &blk)
  1514.       name, ctype, argtype = parse_signature(signature, @type_alias)
  1515.       h = parse_bind_options(opts)
  1516.       case h[:callback_type]
  1517.       when :bind, nil
  1518.         f = bind_function(name, ctype, argtype, h[:call_type], &blk)
  1519.       when :temp, :temporal
  1520.         f = create_temp_function(name, ctype, argtype, h[:call_type])
  1521.       when :carried
  1522.         f = create_carried_function(name, ctype, argtype, h[:call_type], h[:carrier])
  1523.       else
  1524.         raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
  1525.       end
  1526.       @func_map[name] = f
  1527.       #define_method(name){|*args,&block| f.call(*args,&block)}
  1528.       module_eval(<<-EOS)
  1529.         def #{name}(*args,&block)
  1530.           @func_map['#{name}'].call(*args,&block)
  1531.         end
  1532.       EOS
  1533.       module_function(name)
  1534.       f
  1535.     end
  1536.  
  1537.     def struct(signature)
  1538.       tys, mems = parse_struct_signature(signature, @type_alias)
  1539.       DL::CStructBuilder.create(CStruct, tys, mems)
  1540.     end
  1541.  
  1542.     def union(signature)
  1543.       tys, mems = parse_struct_signature(signature, @type_alias)
  1544.       DL::CStructBuilder.create(CUnion, tys, mems)
  1545.     end
  1546.  
  1547.     def [](name)
  1548.       @func_map[name]
  1549.     end
  1550.  
  1551.     def create_value(ty, val=nil)
  1552.       s = struct([ty + " value"])
  1553.       ptr = s.malloc()
  1554.       if( val )
  1555.         ptr.value = val
  1556.       end
  1557.       return ptr
  1558.     end
  1559.     alias value create_value
  1560.  
  1561.     def import_value(ty, addr)
  1562.       s = struct([ty + " value"])
  1563.       ptr = s.new(addr)
  1564.       return ptr
  1565.     end
  1566.  
  1567.     def import_symbol(name)
  1568.       addr = @handler.sym(name)
  1569.       if( !addr )
  1570.         raise(DLError, "cannot find the symbol: #{name}")
  1571.       end
  1572.       CPtr.new(addr)
  1573.     end
  1574.  
  1575.     def import_function(name, ctype, argtype, call_type = nil)
  1576.       addr = @handler.sym(name)
  1577.       if( !addr )
  1578.         raise(DLError, "cannot find the function: #{name}()")
  1579.       end
  1580.       Function.new(CFunc.new(addr, ctype, name, call_type || :cdecl), argtype)
  1581.     end
  1582.  
  1583.     def bind_function(name, ctype, argtype, call_type = nil, &block)
  1584.       f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
  1585.       f.bind(&block)
  1586.       f
  1587.     end
  1588.  
  1589.     def create_temp_function(name, ctype, argtype, call_type = nil)
  1590.       TempFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
  1591.     end
  1592.  
  1593.     def create_carried_function(name, ctype, argtype, call_type = nil, n = 0)
  1594.       CarriedFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype, n)
  1595.     end
  1596.   end
  1597. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement