Update to ARC 4.1.0
[gp-arc-client-c.git] / lib / arc_client_c_wrapper.rb
1 require 'ffi'
2 require 'ffi_libc'
3
4 #This is a monkey patching follows for dlopen with RTLD_GLOBAL flag.
5 #With the original RTLD_LOCAL dynamic_cast did not work in ARC as expected because of the 
6 #lack of rtti and returned NULL silently. 
7 module FFI
8   module Library
9     def ffi_global_lib(*names)
10
11       ffi_libs = names.map do |name|
12         if name == FFI::CURRENT_PROCESS
13           FFI::DynamicLibrary.open(nil, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
14         else
15           libnames = (name.is_a?(::Array) ? name : [ name ]).map { |n| [ n, FFI.map_library_name(n) ].uniq }.flatten.compact
16           lib = nil
17           errors = {}
18
19           libnames.each do |libname|
20             begin
21               lib = FFI::DynamicLibrary.open(libname, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
22               break if lib
23             rescue Exception => ex
24               errors[libname] = ex
25             end
26           end
27
28           if lib.nil?
29             raise LoadError.new(errors.values.join('. '))
30           end
31
32           # return the found lib
33           lib
34         end
35       end
36
37       @ffi_libs = ffi_libs
38     end
39   end
40 end
41
42
43 class ArcClientCWrapper
44   
45   class BaseStruct < FFI::Struct
46     
47     def get_str(name)
48       result = nil
49       val = self[name]
50       if(!val.null?)
51         result = val.read_string
52       end
53       result
54     end
55        
56     def free_pointer(name)
57       val = self[name]
58       if(val.is_a? FFI::Pointer)
59         LibC::free(val)
60       end
61     end
62     
63     def free_pointer_members
64       members.each do |member|
65         free_pointer member
66       end
67     end
68   end
69
70   
71   class GetResult < BaseStruct
72     layout  :message, :pointer, \
73             :get, :int
74
75   end
76
77
78   extend FFI::Library
79   
80   THIS_DIR = File.dirname(__FILE__)
81   ffi_global_lib ['arc_client_c.so', 'arc_client_c.bundle'].map {|file| File.join THIS_DIR, file}
82   
83   attach_function :initialize, [], :string
84   
85   attach_function :arc_submit, [:int, :pointer], :string
86   attach_function :arc_stat, [:int, :pointer], :string
87   attach_function :arc_get, [:int, :pointer], :int
88   attach_function :arc_kill, [:int, :pointer], :int
89   
90   def self.string_array_as_pointer(arr)
91     result = FFI::MemoryPointer.new(:pointer, arr.size)
92         result.write_array_of_pointer(arr.map {|item| FFI::MemoryPointer.from_string(item.to_s)})
93   end
94   
95   def self.free_array_of_pointer(arr, length)
96     pointers = arr.read_array_of_pointer length
97     
98     pointers.each do |i| 
99       LibC::free(i) 
100     end
101
102     LibC::free(arr)
103   end
104
105 end