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 Rubinius::RUBY_CONFIG["rbx.ffi.soft_fail"]
245 STDOUT.write "*** Proceeding because rbx.ffi.soft_fail is set. Program may fail later.\n"
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"
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
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.
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| ... }
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.
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
328 elsif type.kind_of? Symbol
329 size = FFI.type_size(type)
340 ptr = Platform::POSIX.malloc total
343 Platform::POSIX.memset ptr, 0, total if clear
354 ptr.autorelease = true
359 # Indicates how many bytes the chunk of memory that is pointed to takes up.
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.
371 # ptr = MemoryPointer.new(:int, 20)
375 # int *ptr = (int*)malloc(sizeof(int) * 20);
380 raise ArgumentError, "unknown type size" unless @type_size
381 self + (which * @type_size)
384 # Release the memory pointed to back to the OS.
386 self.autorelease = false
387 Platform::POSIX.free(self) unless null?
388 self.class.set_address self, nil
391 # Write +obj+ as a C int at the memory pointed to.
393 self.class.write_int self, Integer(obj)
396 # Read a C int from the memory pointed to.
398 self.class.read_int self
401 # Write +obj+ as a C long at the memory pointed to.
403 self.class.write_long self, Integer(obj)
406 # Read a C long from the memory pointed to.
408 self.class.read_long self
411 def read_string(len=nil)
413 self.class.read_string_length self, len
415 self.class.read_string self
419 def write_string(str, len=nil)
420 len = str.size unless len
422 self.class.write_string self, str, len
426 self.class.read_pointer self
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)
436 self.class.read_float self
439 def read_array_of_int(length)
440 read_array_of_type(:int, :read_int, length)
443 def write_array_of_int(ary)
444 write_array_of_type(:int, :write_int, ary)
447 def read_array_of_long(length)
448 read_array_of_type(:long, :read_long, length)
451 def write_array_of_long(ary)
452 write_array_of_type(:long, :write_long, ary)
455 def read_array_of_type(type, reader, length)
457 size = FFI.type_size(type)
460 ary << tmp.send(reader)
466 def write_array_of_type(type, writer, ary)
467 size = FFI.type_size(type)
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}>"
482 self.class.address self
490 self.class.add_ptr(self, value)
493 def autorelease=(val)
495 self.class.autorelease self, 1
497 self.class.autorelease self, 0
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
519 attach_function "ffi_type_size", :get_type_size, [:int], :int
521 def self.type_size(type)
522 get_type_size(find_type(type))
528 # Represents a C struct as ruby class.
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
550 code = FFI.find_type(f)
551 cspec[name] = [offset, code]
552 ending = offset + FFI.type_size(f)
553 @size = ending if @size < ending
558 @layout = cspec unless self == FFI::Struct
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
592 def initialize(pointer = nil, *spec)
593 @cspec = self.class.layout(*spec)
598 @pointer = MemoryPointer.new size
607 np = MemoryPointer.new size
608 Platform::POSIX.memcpy np, @pointer, size
609 return self.class.new(np)
612 alias_method :clone, :dup
615 offset, type = @cspec[field]
616 raise "Unknown field #{field}" unless offset
618 if type == FFI::TYPE_CHARARR
619 (@pointer + offset).read_string
621 self.class.ffi_get_field(@pointer, offset, type)
626 offset, type = @cspec[field]
627 raise "Unknown field #{field}" unless offset
629 self.class.ffi_set_field(@pointer, offset, type, val)
636 # A C function that can be executed. Similar to CompiledMethod.
640 # The *args means the primitive handles it own argument count checks.
642 Ruby.primitive :nfunc_call_object
646 # Static C variable like errno. (May not be used).
649 def initialize(library, name, a2, a3=nil)
660 @functions = LookupTable.new
663 def find_function(at)
665 at = @static_args + at
668 if func = @functions[at]
672 func = FFI.create_function @library, @name, at, @ret
673 @functions[at] = func
682 find_function(at).call(*args)
688 # Namespace for holding platform-specific C constants.