Fetching latest commit…
Cannot retrieve the latest commit at this time.
|Failed to load latest commit information.|
## JRuby implementation of Ruby C extensions API. This document explains the state of C extensions on JRuby. This is meant to become an exhaustive listing of the restrictions in the C API layer, their reasons, and how to work around them. We also provide code examples for some workarounds at the end of this document. If more restrictions are found, or you have code examples, please feel free to add them. ### Objectives Provide a highly compatible implementation of C extensions on JRuby. The goal here is not performance, but compatibility. We do not recommend running Ruby C extensions in production, at least not for a longer period of time, and we probably never will. The idea here is that if you're transitioning to JRuby, you can run your C extensions until you find something more suitable. The focus is also very clearly on Gems that have no JRuby specific version available. The C API is implemented as a JNI plugin to the JVM. ### Restrictions #### Runtime JRuby supports multiple "Runtimes" in a single process. Because you can only load a dynamic/shared library into the JVM once, and we cannot be sure whether a C extension is thread-safe, so we disallow loading C extensions in more than one runtime. To work around this, you may disable JRuby's in-process execution (default from 1.6.5 onwards). #### Strings * **RSTRING_PTR(VALUE)** *Problem:* In order to support direct manipulation of C array backed strings, whenever you call this macro, the object referenced by VALUE is added to a synchronization list, and whenever you transition between C and Java land, the contents of the Java and C string are copied back and forth, adding a potentially significant overhead. The lifetime of the C memory referenced by the result of RSTRING_PTR is the same as the garbage collection lifetime of the corresponding String object, so it will only go off the synchronization list if the associated object is collected. *Workaround:* To change bytes in a String object, use one of void rb_str_update(VALUE str, long beg, long len, VALUE val); VALUE rb_str_buf_append(VALUE str, VALUE val); VALUE rb_str_buf_cat(VALUE str, const char* bytes, long len); VALUE rb_str_buf_cat2(VALUE str, const char* cstring); VALUE rb_str_append(VALUE str, VALUE arg); #### Arrays * **RARRAY_PTR** *Problem:* The same runtime overhead implications as for RSTRING_PTR apply. *Workaround:* To access elements of an Array, use rb_ary_entry or rb_ary_store which are also available in MagLev and Rubinius. #### IO * **rb_io_wait_readable, rb_io_wait_writable, rb_io_check_readable, rb_io_check_writable, rb_io_check_closed, GetOpenFile** *Problem:* Mixing native file descriptors with JVM fds doesn't work very well. Sometimes, things will work just fine, but more often than not, these functions will simply fail. *Workaround:* Upcall to Ruby for dealing with IO and files. #### Hash * **rb_iterate_each_pair**, **rb_iterate**, **rb_each** *Problem:* Only supports iteration on Array arguments for now *Workaround:* You can coerce you're Hash into an array of pairs before iterating. * **RHASH**, **RHASH_TBL** *Problem:* Like on MagLev and Rubinius, these macros aren't supported. #### Threads * **thread_critical** *Problem:* Not supported, setting this to `true` is ignored #### Globals and GC * **Object lifetime** *Problem:* C-references aren't kept alive/valid after returning from C extension code. Each call from Ruby into a C extension initializes a list known to the garbage collector that is kept alive for the duration of that entry into a C extension. This list is dereferenced when returning from C back to Ruby. *Workaround:* For a newly created object to stay alive after returning from C to Ruby it must have been stored as the value of a Ruby global variable, Ruby constant, or stored into an instance variable of some other object reachable from top level Ruby state, or be reachable from the VALUE returned from C back to Ruby. #### Numerics * **rb_num2ulong** *Problem:* Java longs are of a different size than whatever the native long size may be on the machine. This can be observed in the spec failure "rb_num2ulong converts -1 to an unsigned number" in the Ruby specs. *Workaround:* None. ### Bugs and status of rubyspecs (as of 30 Sep 2011) For the rubyspecs in optional/capi/ , the following specs are skipped and are not supported * rb_define_hooked_variable * rb_define_variable * rb_protect_inspect * rb_inspecting_p * rb_exec_recursive The following functions have known bugs that we will try to fix * rb_class_new fails to throw an error when passed a singleton class as superclass * rb_rescue has some spec failures * rb_thread_select fails to detect an fd that's ready to read * rb_str_buf_* sometimes fails to synchronize the C buffer correctly