Re-enable spec/library for full CI runs.
[rbx.git] / kernel / platform / ffi.rb
blobc09fee5185301704d1279bd14aaad623b32eff3d
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 env "RBX_FFI_SOFTFAIL"
245         STDOUT.write "***        Proceeding because RBX_FFI_SOFTFAIL 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 environment\n"
249         STDOUT.write "***        variable RBX_FFI_SOFTFAIL.\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
279   # HACK: Unable to get EnvironmentVariables up at this point
280   def env(str)
281     Ruby.primitive :env_get
282   end
286 # MemoryPointer is Rubinius's "fat" pointer class. It represents an actual
287 # pointer, in C language terms, to an address in memory. They're called
288 # fat pointers because the MemoryPointer object is an wrapper around
289 # the actual pointer, the Rubinius runtime doesn't have direct access
290 # to the raw address.
292 # This class is used extensively in FFI usage to interface with various
293 # parts of the underlying system. It provides a number of operations
294 # for operating on the memory that is pointed to. These operations effectively
295 # give Rubinius the cast/read capabilities available in C, but using
296 # high level methods.
298 # MemoryPointer objects can be put in autorelease mode. In this mode, 
299 # when the GC cleans up a MemoryPointer object, the memory it points
300 # to is passed to free(3), releasing the memory back to the OS.
302 # NOTE: MemoryPointer exposes direct, unmanaged operations on any
303 # memory. It therefore MUST be used carefully. Reading or writing to
304 # invalid address will cause bus errors and segmentation faults.
306 class MemoryPointer
308   # call-seq:
309   #   MemoryPointer.new(num) => MemoryPointer instance of <i>num</i> bytes
310   #   MemoryPointer.new(sym) => MemoryPointer instance with number
311   #                             of bytes need by FFI type <i>sym</i>
312   #   MemoryPointer.new(obj) => MemoryPointer instance with number
313   #                             of <i>obj.size</i> bytes
314   #   MemoryPointer.new(sym, count) => MemoryPointer instance with number
315   #                             of bytes need by length-<i>count</i> array
316   #                             of FFI type <i>sym</i>
317   #   MemoryPointer.new(obj, count) => MemoryPointer instance with number
318   #                             of bytes need by length-<i>count</i> array
319   #                             of <i>obj.size</i> bytes
320   #   MemoryPointer.new(arg) { |p| ... }
321   #
322   # Both forms create a MemoryPointer instance. The number of bytes to
323   # allocate is either specified directly or by passing an FFI type, which
324   # specifies the number of bytes needed for that type.
325   #
326   # The form without a block returns the MemoryPointer instance. The form
327   # with a block yields the MemoryPointer instance and frees the memory
328   # when the block returns. The value returned is the value of the block.
330   def self.new(type, count=nil, clear=true)
331     if type.kind_of? Fixnum
332       size = type
333     elsif type.kind_of? Symbol
334       size = FFI.type_size(type)
335     else
336       size = type.size
337     end
339     if count
340       total = size * count
341     else
342       total = size
343     end
345     ptr = Platform::POSIX.malloc total
346     ptr.total = total
347     ptr.type_size = size
348     Platform::POSIX.memset ptr, 0, total if clear
350     if block_given?
351       begin
352         value = yield ptr
354         return value
355       ensure
356         ptr.free
357       end
358     else
359       ptr.autorelease = true
360       ptr
361     end
362   end
364   # Indicates how many bytes the chunk of memory that is pointed to takes up.
365   attr_accessor :total
367   # Indicates how many bytes the type that the pointer is cast as uses.
368   attr_accessor :type_size
370   # Access the MemoryPointer like a C array, accessing the +which+ number
371   # element in memory. The position of the element is calculate from
372   # +@type_size+ and +which+. A new MemoryPointer object is returned, which
373   # points to the address of the element.
374   # 
375   # Example:
376   #   ptr = MemoryPointer.new(:int, 20)
377   #   new_ptr = ptr[9]
378   #
379   # c-equiv: 
380   #   int *ptr = (int*)malloc(sizeof(int) * 20);
381   #   int *new_ptr; 
382   #   new_ptr = &ptr[9];
383   #
384   def [](which)
385     raise ArgumentError, "unknown type size" unless @type_size
386     self + (which * @type_size)
387   end
389   # Release the memory pointed to back to the OS.
390   def free
391     self.autorelease = false
392     Platform::POSIX.free(self) unless null?
393     self.class.set_address self, nil
394   end
396   # Write +obj+ as a C int at the memory pointed to.
397   def write_int(obj)
398     self.class.write_int self, Integer(obj)
399   end
401   # Read a C int from the memory pointed to.
402   def read_int
403     self.class.read_int self
404   end
406   # Write +obj+ as a C long at the memory pointed to.
407   def write_long(obj)
408     self.class.write_long self, Integer(obj)
409   end
411   # Read a C long from the memory pointed to.
412   def read_long
413     self.class.read_long self
414   end
416   def read_string(len=nil)
417     if len
418       self.class.read_string_length self, len
419     else
420       self.class.read_string self
421     end
422   end
424   def write_string(str, len=nil)
425     len = str.size unless len
427     self.class.write_string self, str, len
428   end
430   def read_pointer
431     self.class.read_pointer self
432   end
434   def write_float(obj)
435     # TODO: ffi needs to be fixed for passing [:pointer, double]
436     #       when :pointer is a (double *)
437     self.class.write_float self, Float(obj)
438   end
440   def read_float
441     self.class.read_float self
442   end
444   def read_array_of_int(length)
445     read_array_of_type(:int, :read_int, length)
446   end
448   def write_array_of_int(ary)
449     write_array_of_type(:int, :write_int, ary)
450   end
452   def read_array_of_long(length)
453     read_array_of_type(:long, :read_long, length)
454   end
456   def write_array_of_long(ary)
457     write_array_of_type(:long, :write_long, ary)
458   end
460   def read_array_of_type(type, reader, length)
461     ary = []
462     size = FFI.type_size(type)
463     tmp = self
464     length.times {
465       ary << tmp.send(reader)
466       tmp += size
467     }
468     ary
469   end
471   def write_array_of_type(type, writer, ary)
472     size = FFI.type_size(type)
473     tmp = self
474     ary.each {|i|
475       tmp.send(writer, i)
476       tmp += size
477     }
478     self
479   end
481   def inspect
482     # Don't have this print the data at the location. It can crash everything.
483     "#<MemoryPointer address=0x#{address.to_s(16)} size=#{total}>"
484   end
486   def address
487     self.class.address self
488   end
490   def null?
491     address == 0x0
492   end
494   def +(value)
495     self.class.add_ptr(self, value)
496   end
498   def autorelease=(val)
499     if val
500       self.class.autorelease self, 1
501     else
502       self.class.autorelease self, 0
503     end
504   end
506   attach_function "ffi_address", :address, [:pointer], :int
507   attach_function "ffi_write_int", :write_int, [:pointer, :int], :int
508   attach_function "ffi_read_int", :read_int, [:pointer], :int
509   attach_function "ffi_write_long", :write_long, [:pointer, :long], :long
510   attach_function "ffi_read_long", :read_long, [:pointer], :long
511   attach_function "ffi_write_float", :write_float, [:pointer, :double], :double
512   attach_function "ffi_read_float", :read_float, [:pointer], :double
513   attach_function "ffi_read_string", :read_string, [:pointer], :string
514   attach_function "ffi_read_string_length", :read_string_length, [:state, :pointer, :int], :object
515   attach_function "memcpy", :write_string, [:pointer, :string, :int], :void
516   attach_function "ffi_read_pointer", :read_pointer, [:pointer], :pointer
517   attach_function "ffi_add_ptr", :add_ptr, [:pointer, :int], :pointer
518   attach_function "ffi_autorelease", :autorelease, [:object, :int], :void
519   attach_function "ffi_set_address", :set_address, [:object, :pointer], :void
522 module FFI
524   attach_function "ffi_type_size", :get_type_size, [:int], :int
526   def self.type_size(type)
527     get_type_size(find_type(type))
528   end
533 # Represents a C struct as ruby class.
535 class FFI::Struct
537   attr_reader :pointer
539   attach_function "ffi_get_field", [:pointer, :int, :int], :object
540   attach_function "ffi_set_field", [:pointer, :int, :int, :object], :void
542   def self.layout(*spec)
543     return @layout if spec.size == 0
545     cspec = LookupTable.new
546     i = 0
548     @size = 0
550     while i < spec.size
551       name = spec[i]
552       f = spec[i + 1]
553       offset = spec[i + 2]
555       code = FFI.find_type(f)
556       cspec[name] = [offset, code]
557       ending = offset + FFI.type_size(f)
558       @size = ending if @size < ending
560       i += 3
561     end
563     @layout = cspec unless self == FFI::Struct
565     return cspec
566   end
568   def self.config(base, *fields)
569     @size = Rubinius::RUBY_CONFIG["#{base}.sizeof"]
570     cspec = LookupTable.new
572     fields.each do |field|
573       offset = Rubinius::RUBY_CONFIG["#{base}.#{field}.offset"]
574       size   = Rubinius::RUBY_CONFIG["#{base}.#{field}.size"]
575       type   = Rubinius::RUBY_CONFIG["#{base}.#{field}.type"]
576       type   = type ? type.to_sym : FFI.size_to_type(size)
578       code = FFI.find_type type
579       cspec[field] = [offset, code]
580       ending = offset + size
581       @size = ending if @size < ending
582     end
584     @layout = cspec
586     return cspec
587   end
589   def self.size
590     @size
591   end
593   def size
594     self.class.size
595   end
597   def initialize(pointer = nil, *spec)
598     @cspec = self.class.layout(*spec)
600     if pointer then
601       @pointer = pointer
602     else
603       @pointer = MemoryPointer.new size
604     end
605   end
607   def free
608     @pointer.free
609   end
611   def dup
612     np = MemoryPointer.new size
613     Platform::POSIX.memcpy np, @pointer, size
614     return self.class.new(np)
615   end
617   alias_method :clone, :dup
619   def [](field)
620     offset, type = @cspec[field]
621     raise "Unknown field #{field}" unless offset
623     if type == FFI::TYPE_CHARARR
624       (@pointer + offset).read_string
625     else
626       self.class.ffi_get_field(@pointer, offset, type)
627     end
628   end
630   def []=(field, val)
631     offset, type = @cspec[field]
632     raise "Unknown field #{field}" unless offset
634     self.class.ffi_set_field(@pointer, offset, type, val)
635     return val
636   end
641 # A C function that can be executed.  Similar to CompiledMethod.
643 class NativeFunction
645   # The *args means the primitive handles it own argument count checks.
646   def call(*args)
647     Ruby.primitive :nfunc_call_object
648   end
650   ##
651   # Static C variable like errno.  (May not be used).
653   class Variable
654     def initialize(library, name, a2, a3=nil)
655       if a3
656         @ret = a3
657         @static_args = a2
658       else
659         @ret = a2
660         @static_args = nil
661       end
663       @library = library
664       @name = name
665       @functions = LookupTable.new
666     end
668     def find_function(at)
669       if @static_args
670         at = @static_args + at
671       end
673       if func = @functions[at]
674         return func
675       end
677       func = FFI.create_function @library, @name, at, @ret
678       @functions[at] = func
679       return func
680     end
682     def [](*args)
683       find_function(args)
684     end
686     def call(at, *args)
687       find_function(at).call(*args)
688     end
689   end
693 # Namespace for holding platform-specific C constants.
695 module Platform