4 # A Foreign Function Interface used to bind C libraries to ruby.
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'}')")
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.
21 # Use this constant instead of nil directly.
23 USE_THIS_PROCESS_AS_LIBRARY = nil
25 TypeDefs = LookupTable.new
29 def add_typedef(current, add)
30 if current.kind_of? Fixnum
33 code = FFI::TypeDefs[current]
34 raise TypeError, "Unable to resolve type '#{current}'" unless code
37 FFI::TypeDefs[add] = code
41 code = FFI::TypeDefs[name]
42 raise TypeError, "Unable to resolve type '#{name}'" unless code
46 def create_backend(library, name, args, ret)
47 Ruby.primitive :nfunc_add
48 raise NotFoundError.new(name, library)
51 # Internal function, should not be used directly.
52 # See Module#attach_function.
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)
60 # We use this instead of map or each because it's really early, map
61 # isn't yet available.
63 args[i] = find_type(args[i])
68 if library.respond_to?(:each) and !library.kind_of? String
70 lib = setup_ld_library_path(lib) if lib
71 func = create_backend(lib, name, args, cret)
76 library = setup_ld_library_path(library) if library
77 create_backend(library, name, args, cret)
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
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(":")
97 # Converts a Rubinius Object
98 add_typedef TYPE_OBJECT, :object
101 add_typedef TYPE_CHAR, :char
103 # Converts an unsigned char
104 add_typedef TYPE_UCHAR, :uchar
107 add_typedef TYPE_SHORT, :short
109 # Converts an unsigned short
110 add_typedef TYPE_USHORT, :ushort
113 add_typedef TYPE_INT, :int
115 # Converts an unsigned int
116 add_typedef TYPE_UINT, :uint
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
131 add_typedef TYPE_FLOAT, :float
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
162 TypeSizes[8] = :long if Rubinius::L64
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)
173 def self.size_to_type(size)
174 if sz = TypeSizes[size]
178 # Be like C, use int as the default type size.
182 def self.config(name)
183 Rubinius::RUBY_CONFIG["rbx.platform.#{name}"]
186 def self.config_hash(name)
188 Rubinius::RUBY_CONFIG.each do |key,value|
189 if(key =~ /rbx\.platform\.#{name}\.(.+)/)
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.
206 def set_ffi_lib(*names)
210 # Attach C function +name+ to this module.
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.#
215 # After the +name+, the C function argument types are provided as an Array.
217 # The C function return type is provided last.
219 def attach_function(name, a3, a4, a5=nil)
230 func = FFI.create_function @ffi_lib, name, args, ret
232 # Error handling does not work properly so avoid it for now.
234 STDOUT.write "*** ERROR: Native function "
235 STDOUT.write name.to_s
236 STDOUT.write " from "
238 STDOUT.write @ffi_lib.to_s
240 STDOUT.write "this process"
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"
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"
255 metaclass.method_table[mname] = func
259 # Replaces the version above once Core has loaded.
260 def attach_function_cv(name, a3, a4, a5=nil)
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
279 # HACK: Unable to get EnvironmentVariables up at this point
281 Ruby.primitive :env_get
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.
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| ... }
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.
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
333 elsif type.kind_of? Symbol
334 size = FFI.type_size(type)
345 ptr = Platform::POSIX.malloc total
348 Platform::POSIX.memset ptr, 0, total if clear
359 ptr.autorelease = true
364 # Indicates how many bytes the chunk of memory that is pointed to takes up.
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.
376 # ptr = MemoryPointer.new(:int, 20)
380 # int *ptr = (int*)malloc(sizeof(int) * 20);
385 raise ArgumentError, "unknown type size" unless @type_size
386 self + (which * @type_size)
389 # Release the memory pointed to back to the OS.
391 self.autorelease = false
392 Platform::POSIX.free(self) unless null?
393 self.class.set_address self, nil
396 # Write +obj+ as a C int at the memory pointed to.
398 self.class.write_int self, Integer(obj)
401 # Read a C int from the memory pointed to.
403 self.class.read_int self
406 # Write +obj+ as a C long at the memory pointed to.
408 self.class.write_long self, Integer(obj)
411 # Read a C long from the memory pointed to.
413 self.class.read_long self
416 def read_string(len=nil)
418 self.class.read_string_length self, len
420 self.class.read_string self
424 def write_string(str, len=nil)
425 len = str.size unless len
427 self.class.write_string self, str, len
431 self.class.read_pointer self
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)
441 self.class.read_float self
444 def read_array_of_int(length)
445 read_array_of_type(:int, :read_int, length)
448 def write_array_of_int(ary)
449 write_array_of_type(:int, :write_int, ary)
452 def read_array_of_long(length)
453 read_array_of_type(:long, :read_long, length)
456 def write_array_of_long(ary)
457 write_array_of_type(:long, :write_long, ary)
460 def read_array_of_type(type, reader, length)
462 size = FFI.type_size(type)
465 ary << tmp.send(reader)
471 def write_array_of_type(type, writer, ary)
472 size = FFI.type_size(type)
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}>"
487 self.class.address self
495 self.class.add_ptr(self, value)
498 def autorelease=(val)
500 self.class.autorelease self, 1
502 self.class.autorelease self, 0
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
524 attach_function "ffi_type_size", :get_type_size, [:int], :int
526 def self.type_size(type)
527 get_type_size(find_type(type))
533 # Represents a C struct as ruby class.
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
555 code = FFI.find_type(f)
556 cspec[name] = [offset, code]
557 ending = offset + FFI.type_size(f)
558 @size = ending if @size < ending
563 @layout = cspec unless self == FFI::Struct
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
597 def initialize(pointer = nil, *spec)
598 @cspec = self.class.layout(*spec)
603 @pointer = MemoryPointer.new size
612 np = MemoryPointer.new size
613 Platform::POSIX.memcpy np, @pointer, size
614 return self.class.new(np)
617 alias_method :clone, :dup
620 offset, type = @cspec[field]
621 raise "Unknown field #{field}" unless offset
623 if type == FFI::TYPE_CHARARR
624 (@pointer + offset).read_string
626 self.class.ffi_get_field(@pointer, offset, type)
631 offset, type = @cspec[field]
632 raise "Unknown field #{field}" unless offset
634 self.class.ffi_set_field(@pointer, offset, type, val)
641 # A C function that can be executed. Similar to CompiledMethod.
645 # The *args means the primitive handles it own argument count checks.
647 Ruby.primitive :nfunc_call_object
651 # Static C variable like errno. (May not be used).
654 def initialize(library, name, a2, a3=nil)
665 @functions = LookupTable.new
668 def find_function(at)
670 at = @static_args + at
673 if func = @functions[at]
677 func = FFI.create_function @library, @name, at, @ret
678 @functions[at] = func
687 find_function(at).call(*args)
693 # Namespace for holding platform-specific C constants.