Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

143 lines (97 sloc) 4.992 kb
## 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
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
#### Strings
*Problem:* In order to support direct manipulaton 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
*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
Jump to Line
Something went wrong with that request. Please try again.