Change soft-fail to use the config, rather than env
[rbx.git] / kernel / platform / ffi.rb
blob356f8691e12777b38aa37e636816becc5f29f534
1 #depends on env.rb
3 ##
4 # A Foreign Function Interface used to bind C libraries to ruby.
6 module FFI
8   #  Specialised error classes
9   class TypeError < RuntimeError; end
11   class NotFoundError < RuntimeError
12     def initialize(function, library)
13       super("Function '#{function}' not found! (Looking in '#{library or 'this process'}')")
14     end
15   end
17   # Shorthand for the current process, i.e. all code that
18   # the process image itself contains. In addition to the
19   # Rubinius codebase, this also includes libc etc.
20   #
21   # Use this constant instead of nil directly.
22   #
23   USE_THIS_PROCESS_AS_LIBRARY = nil
25   TypeDefs = LookupTable.new
27   class << self
29     def add_typedef(current, add)
30       if current.kind_of? Fixnum
31         code = current
32       else
33         code = FFI::TypeDefs[current]
34         raise TypeError, "Unable to resolve type '#{current}'" unless code
35       end
37       FFI::TypeDefs[add] = code
38     end
40     def find_type(name)
41       code = FFI::TypeDefs[name]
42       raise TypeError, "Unable to resolve type '#{name}'" unless code
43       return code
44     end
46     def create_backend(library, name, args, ret)
47       Ruby.primitive :nfunc_add
48       raise NotFoundError.new(name, library) 
49     end
51     # Internal function, should not be used directly.
52     # See Module#attach_function.
53     #
54     # TODO: Is this necessary at all? When would we ever
55     #       create an unattached method (not a Method)?
56     def create_function(library, name, args, ret)
57       i = 0
58       tot = args.size
60       # We use this instead of map or each because it's really early, map
61       # isn't yet available.
62       while i < tot
63         args[i] = find_type(args[i])
64         i += 1
65       end
66       cret = find_type(ret)
67       
68       if library.respond_to?(:each) and !library.kind_of? String
69         library.each do |lib|
70           lib = setup_ld_library_path(lib) if lib
71           func = create_backend(lib, name, args, cret)
72           return func if func
73         end
74         return nil
75       else
76         library = setup_ld_library_path(library) if library
77         create_backend(library, name, args, cret)
78       end
79     end
81     # Setup the LD_LIBRARY_PATH 
82     def setup_ld_library_path(library)
83       # If we have a specific reference to the library, we load it here
84       specific_library = config("ld_library_path.#{library}")
85       library = specific_library if specific_library
86       
87       # This adds general paths to the search 
88       if path = config("ld_library_path.default")
89         ENV['LTDL_LIBRARY_PATH'] = [ENV['LTDL_LIBRARY_PATH'], path].compact.join(":")
90       end
91       
92       library
93     end
95   end
97   # Converts a Rubinius Object
98   add_typedef TYPE_OBJECT,  :object
100   # Converts a char
101   add_typedef TYPE_CHAR,    :char
103   # Converts an unsigned char
104   add_typedef TYPE_UCHAR,   :uchar
106   # Converts a short
107   add_typedef TYPE_SHORT,   :short
109   # Converts an unsigned short
110   add_typedef TYPE_USHORT,  :ushort
112   # Converts an int
113   add_typedef TYPE_INT,     :int
115   # Converts an unsigned int
116   add_typedef TYPE_UINT,    :uint
118   # Converts a long
119   add_typedef TYPE_LONG,    :long
121   # Converts an unsigned long
122   add_typedef TYPE_ULONG,   :ulong
124   # Converts a long long
125   add_typedef TYPE_LL,      :long_long
127   # Converts an unsigned long long
128   add_typedef TYPE_ULL,     :ulong_long
130   # Converts a float
131   add_typedef TYPE_FLOAT,   :float
133   # Converts a double
134   add_typedef TYPE_DOUBLE,  :double
136   # Converts a pointer to opaque data
137   add_typedef TYPE_PTR,     :pointer
139   # For when a function has no return value
140   add_typedef TYPE_VOID,    :void
142   # Converts NULL-terminated C strings
143   add_typedef TYPE_STRING,  :string
145   # Converts the current Rubinius state
146   add_typedef TYPE_STATE,   :state
148   # Use strptr when you need to free the result of some operation.
149   add_typedef TYPE_STRPTR,  :strptr
150   add_typedef TYPE_STRPTR,  :string_and_pointer
152   # Use for a C struct with a char [] embedded inside.
153   add_typedef TYPE_CHARARR, :char_array
155   TypeSizes = {
156     1 => :char,
157     2 => :short,
158     4 => :int,
159     8 => :long_long,
160   }
162   TypeSizes[8] = :long if Rubinius::L64
164   
165   # Load all the platform dependent types
167   Rubinius::RUBY_CONFIG.each do |key, value|
168     if key.substring(0, 20) == "rbx.platform.typedef"
169       add_typedef(find_type(value.to_sym), key.substring(21, key.length).to_sym)
170     end
171   end
173   def self.size_to_type(size)
174     if sz = TypeSizes[size]
175       return sz
176     end
178     # Be like C, use int as the default type size.
179     return :int
180   end
182   def self.config(name)
183     Rubinius::RUBY_CONFIG["rbx.platform.#{name}"]
184   end
186   def self.config_hash(name)
187     vals = { }
188     Rubinius::RUBY_CONFIG.each do |key,value|
189       if(key =~ /rbx\.platform\.#{name}\.(.+)/)
190         vals[$1] = value
191       end
192     end
193     vals
194   end
198 class Module
200   # Set which library or libraries +attach_function+ should
201   # look in. By default it only searches for the function in
202   # the current process. If you want to specify this as one
203   # of the locations, add FFI::USE_THIS_PROCESS_AS_LIBRARY.
204   # The libraries are tried in the order given.
205   #
206   def set_ffi_lib(*names)
207     @ffi_lib = names
208   end
210   # Attach C function +name+ to this module.
211   #
212   # If you want to provide an alternate name for the module function, supply
213   # it after the +name+, otherwise the C function name will be used.#
214   #
215   # After the +name+, the C function argument types are provided as an Array.
216   #
217   # The C function return type is provided last.
218   #
219   def attach_function(name, a3, a4, a5=nil)
220     if a5
221       mname = a3
222       args = a4
223       ret = a5
224     else
225       mname = name.to_sym
226       args = a3
227       ret = a4
228     end
230     func = FFI.create_function @ffi_lib, name, args, ret
232     # Error handling does not work properly so avoid it for now.
233     if !func
234       STDOUT.write "*** ERROR: Native function "
235       STDOUT.write name.to_s
236       STDOUT.write " from "
237       if @ffi_lib
238         STDOUT.write @ffi_lib.to_s
239       else
240         STDOUT.write "this process"
241       end
242       STDOUT.write " could not be found or linked.\n"
244       if Rubinius::RUBY_CONFIG["rbx.ffi.soft_fail"]
245         STDOUT.write "***        Proceeding because rbx.ffi.soft_fail is set. Program may fail later.\n"
246         return nil
247       else
248         STDOUT.write "***        If you want to try to work around this problem, you may set configuration\n"
249         STDOUT.write "***        variable rbx.ffi.soft_fail.\n"
250         STDOUT.write "***        Exiting.\n"
251         Process.exit 1
252       end
253     end
255     metaclass.method_table[mname] = func
256     return func
257   end
259   # Replaces the version above once Core has loaded.
260   def attach_function_cv(name, a3, a4, a5=nil)
261     if a5
262       mname = a3
263       args = a4
264       ret = a5
265     else
266       mname = name.to_sym
267       args = a3
268       ret = a4
269     end
271     func = FFI.create_function @ffi_lib, name, args, ret
273     raise FFI::NotFoundError.new(name, @ffi_lib) unless func
275     metaclass.method_table[mname] = func
276     return func
277   end
281 # MemoryPointer is Rubinius's "fat" pointer class. It represents an actual
282 # pointer, in C language terms, to an address in memory. They're called
283 # fat pointers because the MemoryPointer object is an wrapper around
284 # the actual pointer, the Rubinius runtime doesn't have direct access
285 # to the raw address.
287 # This class is used extensively in FFI usage to interface with various
288 # parts of the underlying system. It provides a number of operations
289 # for operating on the memory that is pointed to. These operations effectively
290 # give Rubinius the cast/read capabilities available in C, but using
291 # high level methods.
293 # MemoryPointer objects can be put in autorelease mode. In this mode, 
294 # when the GC cleans up a MemoryPointer object, the memory it points
295 # to is passed to free(3), releasing the memory back to the OS.
297 # NOTE: MemoryPointer exposes direct, unmanaged operations on any
298 # memory. It therefore MUST be used carefully. Reading or writing to
299 # invalid address will cause bus errors and segmentation faults.
301 class MemoryPointer
303   # call-seq:
304   #   MemoryPointer.new(num) => MemoryPointer instance of <i>num</i> bytes
305   #   MemoryPointer.new(sym) => MemoryPointer instance with number
306   #                             of bytes need by FFI type <i>sym</i>
307   #   MemoryPointer.new(obj) => MemoryPointer instance with number
308   #                             of <i>obj.size</i> bytes
309   #   MemoryPointer.new(sym, count) => MemoryPointer instance with number
310   #                             of bytes need by length-<i>count</i> array
311   #                             of FFI type <i>sym</i>
312   #   MemoryPointer.new(obj, count) => MemoryPointer instance with number
313   #                             of bytes need by length-<i>count</i> array
314   #                             of <i>obj.size</i> bytes
315   #   MemoryPointer.new(arg) { |p| ... }
316   #
317   # Both forms create a MemoryPointer instance. The number of bytes to
318   # allocate is either specified directly or by passing an FFI type, which
319   # specifies the number of bytes needed for that type.
320   #
321   # The form without a block returns the MemoryPointer instance. The form
322   # with a block yields the MemoryPointer instance and frees the memory
323   # when the block returns. The value returned is the value of the block.
325   def self.new(type, count=nil, clear=true)
326     if type.kind_of? Fixnum
327       size = type
328     elsif type.kind_of? Symbol
329       size = FFI.type_size(type)
330     else
331       size = type.size
332     end
334     if count
335       total = size * count
336     else
337       total = size
338     end
340     ptr = Platform::POSIX.malloc total
341     ptr.total = total
342     ptr.type_size = size
343     Platform::POSIX.memset ptr, 0, total if clear
345     if block_given?
346       begin
347         value = yield ptr
349         return value
350       ensure
351         ptr.free
352       end
353     else
354       ptr.autorelease = true
355       ptr
356     end
357   end
359   # Indicates how many bytes the chunk of memory that is pointed to takes up.
360   attr_accessor :total
362   # Indicates how many bytes the type that the pointer is cast as uses.
363   attr_accessor :type_size
365   # Access the MemoryPointer like a C array, accessing the +which+ number
366   # element in memory. The position of the element is calculate from
367   # +@type_size+ and +which+. A new MemoryPointer object is returned, which
368   # points to the address of the element.
369   # 
370   # Example:
371   #   ptr = MemoryPointer.new(:int, 20)
372   #   new_ptr = ptr[9]
373   #
374   # c-equiv: 
375   #   int *ptr = (int*)malloc(sizeof(int) * 20);
376   #   int *new_ptr; 
377   #   new_ptr = &ptr[9];
378   #
379   def [](which)
380     raise ArgumentError, "unknown type size" unless @type_size
381     self + (which * @type_size)
382   end
384   # Release the memory pointed to back to the OS.
385   def free
386     self.autorelease = false
387     Platform::POSIX.free(self) unless null?
388     self.class.set_address self, nil
389   end
391   # Write +obj+ as a C int at the memory pointed to.
392   def write_int(obj)
393     self.class.write_int self, Integer(obj)
394   end
396   # Read a C int from the memory pointed to.
397   def read_int
398     self.class.read_int self
399   end
401   # Write +obj+ as a C long at the memory pointed to.
402   def write_long(obj)
403     self.class.write_long self, Integer(obj)
404   end
406   # Read a C long from the memory pointed to.
407   def read_long
408     self.class.read_long self
409   end
411   def read_string(len=nil)
412     if len
413       self.class.read_string_length self, len
414     else
415       self.class.read_string self
416     end
417   end
419   def write_string(str, len=nil)
420     len = str.size unless len
422     self.class.write_string self, str, len
423   end
425   def read_pointer
426     self.class.read_pointer self
427   end
429   def write_float(obj)
430     # TODO: ffi needs to be fixed for passing [:pointer, double]
431     #       when :pointer is a (double *)
432     self.class.write_float self, Float(obj)
433   end
435   def read_float
436     self.class.read_float self
437   end
439   def read_array_of_int(length)
440     read_array_of_type(:int, :read_int, length)
441   end
443   def write_array_of_int(ary)
444     write_array_of_type(:int, :write_int, ary)
445   end
447   def read_array_of_long(length)
448     read_array_of_type(:long, :read_long, length)
449   end
451   def write_array_of_long(ary)
452     write_array_of_type(:long, :write_long, ary)
453   end
455   def read_array_of_type(type, reader, length)
456     ary = []
457     size = FFI.type_size(type)
458     tmp = self
459     length.times {
460       ary << tmp.send(reader)
461       tmp += size
462     }
463     ary
464   end
466   def write_array_of_type(type, writer, ary)
467     size = FFI.type_size(type)
468     tmp = self
469     ary.each {|i|
470       tmp.send(writer, i)
471       tmp += size
472     }
473     self
474   end
476   def inspect
477     # Don't have this print the data at the location. It can crash everything.
478     "#<MemoryPointer address=0x#{address.to_s(16)} size=#{total}>"
479   end
481   def address
482     self.class.address self
483   end
485   def null?
486     address == 0x0
487   end
489   def +(value)
490     self.class.add_ptr(self, value)
491   end
493   def autorelease=(val)
494     if val
495       self.class.autorelease self, 1
496     else
497       self.class.autorelease self, 0
498     end
499   end
501   attach_function "ffi_address", :address, [:pointer], :int
502   attach_function "ffi_write_int", :write_int, [:pointer, :int], :int
503   attach_function "ffi_read_int", :read_int, [:pointer], :int
504   attach_function "ffi_write_long", :write_long, [:pointer, :long], :long
505   attach_function "ffi_read_long", :read_long, [:pointer], :long
506   attach_function "ffi_write_float", :write_float, [:pointer, :double], :double
507   attach_function "ffi_read_float", :read_float, [:pointer], :double
508   attach_function "ffi_read_string", :read_string, [:pointer], :string
509   attach_function "ffi_read_string_length", :read_string_length, [:state, :pointer, :int], :object
510   attach_function "memcpy", :write_string, [:pointer, :string, :int], :void
511   attach_function "ffi_read_pointer", :read_pointer, [:pointer], :pointer
512   attach_function "ffi_add_ptr", :add_ptr, [:pointer, :int], :pointer
513   attach_function "ffi_autorelease", :autorelease, [:object, :int], :void
514   attach_function "ffi_set_address", :set_address, [:object, :pointer], :void
517 module FFI
519   attach_function "ffi_type_size", :get_type_size, [:int], :int
521   def self.type_size(type)
522     get_type_size(find_type(type))
523   end
528 # Represents a C struct as ruby class.
530 class FFI::Struct
532   attr_reader :pointer
534   attach_function "ffi_get_field", [:pointer, :int, :int], :object
535   attach_function "ffi_set_field", [:pointer, :int, :int, :object], :void
537   def self.layout(*spec)
538     return @layout if spec.size == 0
540     cspec = LookupTable.new
541     i = 0
543     @size = 0
545     while i < spec.size
546       name = spec[i]
547       f = spec[i + 1]
548       offset = spec[i + 2]
550       code = FFI.find_type(f)
551       cspec[name] = [offset, code]
552       ending = offset + FFI.type_size(f)
553       @size = ending if @size < ending
555       i += 3
556     end
558     @layout = cspec unless self == FFI::Struct
560     return cspec
561   end
563   def self.config(base, *fields)
564     @size = Rubinius::RUBY_CONFIG["#{base}.sizeof"]
565     cspec = LookupTable.new
567     fields.each do |field|
568       offset = Rubinius::RUBY_CONFIG["#{base}.#{field}.offset"]
569       size   = Rubinius::RUBY_CONFIG["#{base}.#{field}.size"]
570       type   = Rubinius::RUBY_CONFIG["#{base}.#{field}.type"]
571       type   = type ? type.to_sym : FFI.size_to_type(size)
573       code = FFI.find_type type
574       cspec[field] = [offset, code]
575       ending = offset + size
576       @size = ending if @size < ending
577     end
579     @layout = cspec
581     return cspec
582   end
584   def self.size
585     @size
586   end
588   def size
589     self.class.size
590   end
592   def initialize(pointer = nil, *spec)
593     @cspec = self.class.layout(*spec)
595     if pointer then
596       @pointer = pointer
597     else
598       @pointer = MemoryPointer.new size
599     end
600   end
602   def free
603     @pointer.free
604   end
606   def dup
607     np = MemoryPointer.new size
608     Platform::POSIX.memcpy np, @pointer, size
609     return self.class.new(np)
610   end
612   alias_method :clone, :dup
614   def [](field)
615     offset, type = @cspec[field]
616     raise "Unknown field #{field}" unless offset
618     if type == FFI::TYPE_CHARARR
619       (@pointer + offset).read_string
620     else
621       self.class.ffi_get_field(@pointer, offset, type)
622     end
623   end
625   def []=(field, val)
626     offset, type = @cspec[field]
627     raise "Unknown field #{field}" unless offset
629     self.class.ffi_set_field(@pointer, offset, type, val)
630     return val
631   end
636 # A C function that can be executed.  Similar to CompiledMethod.
638 class NativeFunction
640   # The *args means the primitive handles it own argument count checks.
641   def call(*args)
642     Ruby.primitive :nfunc_call_object
643   end
645   ##
646   # Static C variable like errno.  (May not be used).
648   class Variable
649     def initialize(library, name, a2, a3=nil)
650       if a3
651         @ret = a3
652         @static_args = a2
653       else
654         @ret = a2
655         @static_args = nil
656       end
658       @library = library
659       @name = name
660       @functions = LookupTable.new
661     end
663     def find_function(at)
664       if @static_args
665         at = @static_args + at
666       end
668       if func = @functions[at]
669         return func
670       end
672       func = FFI.create_function @library, @name, at, @ret
673       @functions[at] = func
674       return func
675     end
677     def [](*args)
678       find_function(args)
679     end
681     def call(at, *args)
682       find_function(at).call(*args)
683     end
684   end
688 # Namespace for holding platform-specific C constants.
690 module Platform