1require 'dl' 2require 'thread' 3 4module DL 5 # The mutual exclusion (Mutex) semaphore for the DL module 6 SEM = Mutex.new # :nodoc: 7 8 if DL.fiddle? 9 # A Hash of callback Procs 10 # 11 # Uses Fiddle 12 CdeclCallbackProcs = {} # :nodoc: 13 14 # A Hash of the addresses of callback Proc 15 # 16 # Uses Fiddle 17 CdeclCallbackAddrs = {} # :nodoc: 18 19 # A Hash of Stdcall callback Procs 20 # 21 # Uses Fiddle on win32 22 StdcallCallbackProcs = {} # :nodoc: 23 24 # A Hash of the addresses of Stdcall callback Procs 25 # 26 # Uses Fiddle on win32 27 StdcallCallbackAddrs = {} # :nodoc: 28 end 29 30 def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &cbp) 31 if( argc < 0 ) 32 raise(ArgumentError, "arity should not be less than 0.") 33 end 34 addr = nil 35 36 if DL.fiddle? 37 abi ||= Fiddle::Function::DEFAULT 38 closure = Fiddle::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp) 39 proc_entry[closure.to_i] = closure 40 addr = closure.to_i 41 else 42 SEM.synchronize{ 43 ary = proc_entry[ty] 44 (0...MAX_CALLBACK).each{|n| 45 idx = (n * DLSTACK_SIZE) + argc 46 if( ary[idx].nil? ) 47 ary[idx] = cbp 48 addr = addr_entry[ty][idx] 49 break 50 end 51 } 52 } 53 end 54 55 addr 56 end 57 58 def set_cdecl_callback(ty, argc, &cbp) 59 set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp) 60 end 61 62 def set_stdcall_callback(ty, argc, &cbp) 63 if DL.fiddle? 64 set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, Fiddle::Function::STDCALL, &cbp) 65 else 66 set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp) 67 end 68 end 69 70 def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil) 71 if DL.fiddle? 72 addr = addr.to_i 73 return false unless proc_entry.key?(addr) 74 proc_entry.delete(addr) 75 true 76 else 77 index = nil 78 if( ctype ) 79 addr_entry[ctype].each_with_index{|xaddr, idx| 80 if( xaddr == addr ) 81 index = idx 82 end 83 } 84 else 85 addr_entry.each{|ty,entry| 86 entry.each_with_index{|xaddr, idx| 87 if( xaddr == addr ) 88 index = idx 89 end 90 } 91 } 92 end 93 if( index and proc_entry[ctype][index] ) 94 proc_entry[ctype][index] = nil 95 return true 96 else 97 return false 98 end 99 end 100 end 101 102 def remove_cdecl_callback(addr, ctype = nil) 103 remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype) 104 end 105 106 def remove_stdcall_callback(addr, ctype = nil) 107 remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype) 108 end 109 110 alias set_callback set_cdecl_callback 111 alias remove_callback remove_cdecl_callback 112end 113