<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Segment7: Rubinius' Foreign Function Interface</title>
    <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>The Blog</description>
    <item>
      <title>Rubinius' Foreign Function Interface</title>
      <description>&lt;p&gt;I really, really, really love Rubinius&amp;#8217; Foreign Function Interface (FFI) since it allows you to replace C code with Ruby code.  Earlier today I wrote &lt;code&gt;Socket::getaddrinfo&lt;/code&gt; in C for Rubinius, and just now I finished a rewrite using &lt;span class="caps"&gt;FFI&lt;/span&gt; and Ruby.  I&amp;#8217;ve commented the code for clarity.

&lt;pre&gt;&lt;code&gt;def self.getaddrinfo(host, service, family = nil, socktype = nil,
                     protocol = nil, flags = nil)
  service = service.to_s

  # MemoryPointer.new is kind-of like malloc(3), but understands what's inside
  hints_p = MemoryPointer.new Socket::Foreign::AddrInfo.size

  # Socket::Foreign::AddrInfo is a struct addrinfo wrapper with friendly accessors
  hints = Socket::Foreign::AddrInfo.new hints_p
  hints[:ai_family] = family || 0
  hints[:ai_socktype] = socktype || 0
  hints[:ai_protocol] = protocol || 0
  hints[:ai_flags] = flags || 0

  # getaddrinfo(3) asks for a struct addrinfo **.
  # This creates a pointer to a pointer
  res_p = MemoryPointer.new :pointer

  # call out to C
  err = Socket::Foreign.getaddrinfo host, service, hints_p, res_p

  # check for errors
  raise SocketError, Socket::Foreign.gai_strerror(err) unless err == 0

  # now we read out the pointer that getaddrinfo() passed us, and cast it
  # to a struct addrinfo *
  res = Socket::Foreign::AddrInfo.new res_p.read_pointer

  addrinfos = []

  loop do
    addrinfo = []

    # Extract data
    addrinfo &amp;lt;&amp;lt; Socket::Constants::AF_TO_FAMILY[res[:ai_family]]

    ai_sockaddr = res[:ai_addr].read_string res[:ai_addrlen]

    sockaddr = Socket::Foreign::unpack_sa_ip ai_sockaddr, true

    addrinfo &amp;lt;&amp;lt; sockaddr.pop # port
    addrinfo.concat sockaddr # hosts
    addrinfo &amp;lt;&amp;lt; res[:ai_family]
    addrinfo &amp;lt;&amp;lt; res[:ai_socktype]
    addrinfo &amp;lt;&amp;lt; res[:ai_protocol]

    addrinfos &amp;lt;&amp;lt; addrinfo

    # struct addrinfo is a linked list, so if we've hit the end, stop
    break unless res[:ai_next]

    # otherwise, down the linked-list
    res = Socket::Foreign::AddrInfo.new res[:ai_next]
  end

  return addrinfos
ensure
  # like a C code, we have to free our MemoryPointer objects
  hints_p.free if hints_p

  if res_p then
    # also, we have to do any C-side cleanup
    Socket::Foreign.freeaddrinfo res_p.read_pointer
    res_p.free
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;getaddrinfo(3), freeaddrinfo(3) and gai_strerror(3) are wrapped up by &lt;span class="caps"&gt;FFI&lt;/span&gt; like this:

&lt;pre&gt;&lt;code&gt;attach_function "gai_strerror", :gai_strerror, [:int], :string

attach_function "getaddrinfo", :getaddrinfo,
                [:string, :string, :pointer, :pointer], :int

attach_function "freeaddrinfo", :freeaddrinfo, [:pointer], :void&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first argument is the C function name, the second is the Ruby name, the third is the input arguments, and the fourth is the return type.  Currently, &lt;span class="caps"&gt;FFI&lt;/span&gt; can only wrap up C functions with six or fewer args.

&lt;p&gt;The &lt;code&gt;AddrInfo&lt;/code&gt; struct is wrapped up like this:

&lt;pre&gt;&lt;code&gt;class AddrInfo &amp;lt; FFI::Struct
  config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
         :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The config method pulls pre-generated struct information out of a Rubinius config file and hooks up accessors to each of the struct&amp;#8217;s fields.  The accessors know which offset into the struct the data lives at and what type to convert data from and to when working with the struct.  The information is collected at Rubinius build time by a small bit of C code.

&lt;p&gt;I still have some confusion between passing an &lt;code&gt;FFI::Struct&lt;/code&gt; like &lt;code&gt;Socket::Foreign::AddrInfo&lt;/code&gt; vs. passing a &lt;code&gt;MemoryPointer&lt;/code&gt; instance (which is what an &lt;span class="caps"&gt;FFI&lt;/span&gt; wrapped function understands) to an &lt;span class="caps"&gt;FFI&lt;/span&gt;-wrapped function, so we&amp;#8217;re going to clean up that part of the &lt;span class="caps"&gt;API&lt;/span&gt; to make it more natural.  Instead you&amp;#8217;ll be able to initialize an &lt;code&gt;FFI::Struct&lt;/code&gt; directly and pass it to the &lt;span class="caps"&gt;FFI&lt;/span&gt;-wrapped function.  This will make the code quite a bit cleaner.
</description>
      <pubDate>Tue, 15 Jan 2008 01:22:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:461529cf-df98-485f-8967-88ee13166e0e</guid>
      <author>drbrain@segment7.net (Eric Hodel)</author>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface</link>
      <category>Rubinius</category>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Kevin Clark</title>
      <description>&lt;p&gt;@Dan: Callbacks aren&amp;#8217;t currently supported in the FFI layer, but they &lt;em&gt;are&lt;/em&gt; supported through subtend, the C extension compatability layer. This is because Rubinius is&amp;#169; stackless, and so requires a whole new C stack (woo getcontext) in order for C to be able to call back into Ruby land (when it switches back to the original context). This is exactly what happens in subtend, but complicates FFI a bit. In the future, if we&amp;#8217;re going to support callbacks from FFI, we&amp;#8217;ll need to have a way to hint that some function uses callbacks and so will need a new context. In the meantime, it&amp;#8217;s a simplicity and performance optimization, as we&amp;#8217;ve made a fairly clear distinction up to this point that FFI calls are one way.&lt;/p&gt;</description>
      <pubDate>Thu, 17 Jan 2008 11:48:23 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:f5781e4a-d923-4376-b660-62e3635e80ed</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-879</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Daniel Berger</title>
      <description>&lt;p&gt;Interesting. Do you have an example of how callbacks would work?&lt;/p&gt;


	&lt;p&gt;Dan&lt;/p&gt;</description>
      <pubDate>Thu, 17 Jan 2008 08:40:14 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:ba469daf-9189-433c-96aa-509eeb575bfe</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-878</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Eric Hodel</title>
      <description>&lt;p&gt;Justin: You&amp;#8217;ll have to instantiate the inner struct from it&amp;#8217;s outer struct pointer, but that&amp;#8217;s just an extra line, just like how I walk down the linked-list for each struct addrinfo.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 17:03:03 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:3cc16adc-77de-43ee-92a4-41022d07d8ff</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-877</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Eero Saynatkari</title>
      <description>&lt;p&gt;Just to add a bit to Wilson&amp;#8217;s explanation, each #attach_function call directly generates a thin intermediary function or &amp;#8220;shim&amp;#8221; in native machine code (so no compilation is necessary) and this is wrapped in a Ruby object. When the Ruby-side method is actually called, it unwraps the shim and executes it. The shim handles calling the type conversion functions for parameters and the return value and it of course calls the actual function we are bridging to. The performance should be roughly equivalent to a compiled extension written in C (one additional function call.) This can certainly be further optimized, but right now it just works.&lt;/p&gt;


	&lt;p&gt;@Ryan: The best thing to do at this time would be to write the C that you need and have it built along with rest of Rubinius. You also already have access to all functions in a Rubinius process such as those from libc and support for allowing linking against arbitrary libraries through dynamic loading is already in but disabled until the API is more refined&amp;#8212;so eventually you can just ask for a particular symbol to be loaded from libpcre, for example.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 16:32:50 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d9a01dfc-ffef-4061-ba71-70261bd85cda</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-876</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Justin Bailey</title>
      <description>&lt;p&gt;Are nested pointers supported? Those were really painful with ruby&amp;#8217;s Array#pack, String#unpack methods.&lt;/p&gt;


	&lt;p&gt;Justin&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 14:13:25 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:47a07adb-56dd-47a2-beec-d23b8ef5eb5b</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-874</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Eric Hodel</title>
      <description>&lt;p&gt;@Ryan: Before hooking in to a C library, it must be loaded into the process.  The easiest way to do that is with subtend, Rubinius&amp;#8217; implementation of the Ruby/C interface.  That way you can just require the library, and use FFI to do the rest.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ll write up a post on that in the future.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 13:57:04 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:51e5a7fd-b13d-4f72-9264-923a5c1ae4db</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-873</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Eric Hodel</title>
      <description>&lt;p&gt;@Shin: I have no idea how fast it is.  Making things work is more important than making things fast right now.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 13:49:58 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d880fc8a-48fa-4e86-9584-f93a118f7c1c</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-872</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Eric Hodel</title>
      <description>&lt;p&gt;@Bil: The C version is a bit shorter because it&amp;#8217;s less verbose, and things like traversing a linked-list are more natural.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 13:45:20 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d3d9bf95-550f-4239-8687-c4aaf4f547d0</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-871</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Wilson Bilkovich</title>
      <description>&lt;p&gt;The Rubinius FFI system ends up generating native functions, so other than the time spent executing the Ruby code you see in the post there, it shouldn&amp;#8217;t be slower than writing it in C.&lt;/p&gt;


	&lt;p&gt;Either way you end up invoking C from Ruby, it&amp;#8217;s just a matter of where the Ruby stops and the C starts.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 12:10:57 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:a72a8083-cde2-476e-a828-d0bcb2ef048b</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-870</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by she</title>
      <description>&lt;p&gt;The speed question interests me as well&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 11:49:07 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d9f3cef7-b384-4888-ae6c-4a38dfdf5d60</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-869</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Laurel Fan</title>
      <description>&lt;p&gt;Aagh, you just reminded me about addrinfo and struct sockaddr and friends&amp;#8230;&lt;/p&gt;


	&lt;p&gt;As long as you never mention strtok.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 09:35:51 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:31e58d87-bf42-4e76-beba-a601bb9ecc4c</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-868</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Ryan</title>
      <description>&lt;p&gt;The part I don&amp;#8217;t fully understand about the Rubinius FFI is how to set up the C files so they can actually be hosted by it properly. A week ago I tried to hook up to the SHA1 implementation in the shotgun/lib directory but I couldn&amp;#8217;t figure out how to do it. After the behind-the-scenes pipes are hooked up, then the FFI works great&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 08:16:57 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:8c1990f9-42e5-4e8a-ac9f-8c57918ed320</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-867</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Shin Guey</title>
      <description>&lt;p&gt;What is the speed of execution compare to C code with the ruby code with FFI?&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 04:22:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:54f6bf6e-9d0a-4a96-b058-7384b34167a4</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-866</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Dee Zsombor</title>
      <description>&lt;p&gt;So basically there is no need to write C code while implementing ruby wrappers over low level libraries &amp;#8230; great!&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 03:31:15 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:a8e8fe8a-9667-466b-a4af-c882cdbecd2d</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-865</link>
    </item>
    <item>
      <title>"Rubinius' Foreign Function Interface" by Bil Kleb</title>
      <description>&lt;p&gt;Is the C version too long to show?&lt;/p&gt;</description>
      <pubDate>Tue, 15 Jan 2008 03:05:06 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:55ceecb6-c55c-4b9a-a21b-131b1765490c</guid>
      <link>http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface#comment-864</link>
    </item>
  </channel>
</rss>
