Skip to content

Commit 731b4e2

Browse files
committed
add (incomplete) documentation for the state of C ext support
1 parent 06d1602 commit 731b4e2

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

docs/README.cext

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
## JRuby implementation of Ruby C extensions API.
2+
3+
This document explains the state of C extensions on JRuby. This is
4+
meant to become an exhaustive listing of the restrictions in the C API
5+
layer, their reasons, and how to work around them.
6+
7+
We also provide code examples for some workarounds at the end of this
8+
document.
9+
10+
If more restrictions are found, or you have code examples, please feel
11+
free to add them.
12+
13+
### Objectives
14+
15+
Provide a highly compatible implementation of C extensions on
16+
JRuby. The goal here is not performance, but compatibility. We do not
17+
recommend running Ruby C extensions in production, at least not for a
18+
longer period of time, and we probably never will. The idea here is
19+
that if you're transitioning to JRuby, you can run your C extensions
20+
until you find something more suitable. The focus is also very clearly
21+
on Gems that have no JRuby specific version available. The C API is
22+
implemented as a JNI plugin to the JVM.
23+
24+
### Restrictions
25+
26+
#### Runtime
27+
28+
JRuby supports multiple "Runtimes" in a single process. Because you
29+
can only load a dynamic/shared library into the JVM once, and we
30+
cannot be sure whether a C extension is thread-safe, so we disallow
31+
loading C extensions in more than one runtime. To work around this,
32+
you may disable JRuby's in-process execution (default from 1.6.5
33+
onwards).
34+
35+
#### Strings
36+
37+
* **RSTRING_PTR(VALUE)**
38+
39+
*Problem:* In order to support direct manipulaton of C array
40+
backed strings, whenever you call this macro, the object
41+
referenced by VALUE is added to a synchronization list, and
42+
whenever you transition between C and Java land, the contents of
43+
the Java and C string are copied back and forth, adding a
44+
potentially significant overhead. The lifetime of the C memory
45+
referenced by the result of RSTRING_PTR is the same as the
46+
garbage collection lifetime of the corresponding String object,
47+
so it will only go off the synchronization list if the associated
48+
object is collected.
49+
50+
*Workaround:* To change bytes in a String object, use one of
51+
52+
void rb_str_update(VALUE str, long beg, long len, VALUE val);
53+
VALUE rb_str_buf_append(VALUE str, VALUE val);
54+
VALUE rb_str_buf_cat(VALUE str, const char* bytes, long len);
55+
VALUE rb_str_buf_cat2(VALUE str, const char* cstring);
56+
VALUE rb_str_append(VALUE str, VALUE arg);
57+
58+
#### Arrays
59+
60+
* **RARRAY_PTR**
61+
62+
*Problem:* The same runtime overhead implications as for RSTRING_PTR apply.
63+
64+
*Workaround:* To access elements of an Array, use rb_ary_entry or
65+
rb_ary_store which are also available in MagLev and Rubinius.
66+
67+
#### IO
68+
69+
* **rb_io_wait_readable, rb_io_wait_writable, rb_io_check_readable, rb_io_check_writable, rb_io_check_closed, GetOpenFile**
70+
71+
*Problem:* Mixing native file descriptors with JVM fds doesn't
72+
work very well. Sometimes, things will work just fine, but more
73+
often than not, these functions will simply fail.
74+
75+
*Workaround:* Upcall to Ruby for dealing with IO and files.
76+
77+
#### Hash
78+
79+
* **rb_iterate_each_pair**, **rb_iterate**, **rb_each**
80+
81+
*Problem:* Only supports iteration on Array arguments for now
82+
83+
*Workaround:* You can coerce you're Hash into an array of pairs
84+
before iterating.
85+
86+
* **RHASH**, **RHASH_TBL**
87+
88+
*Problem:* Like on MagLev and Rubinius, these macros aren't supported.
89+
90+
#### Threads
91+
92+
* **thread_critical**
93+
94+
*Problem:* Not supported, setting this to `true` is ignored
95+
96+
#### Globals and GC
97+
98+
* **Object lifetime**
99+
100+
*Problem:* C-references aren't kept alive/valid after returning
101+
from C extension code.
102+
103+
Each call from Ruby into a C extension initializes a list known to
104+
the garbage collector that is kept alive for the duration of that
105+
entry into a C extension. This list is dereferenced when returning
106+
from C back to Ruby.
107+
108+
*Workaround:* For a newly created object to stay alive after
109+
returning from C to Ruby it must have been stored as the value of
110+
a Ruby global variable, Ruby constant, or stored into an instance
111+
variable of some other object reachable from top level Ruby state,
112+
or be reachable from the VALUE returned from C back to Ruby.
113+
114+
#### Numerics
115+
116+
* **rb_num2ulong**
117+
118+
*Problem:* Java longs are of a different size than whatever the
119+
native long size may be on the machine. This can be observed in the
120+
spec failure "rb_num2ulong converts -1 to an unsigned number" in
121+
the Ruby specs.
122+
123+
*Workaround:* None.
124+
125+
### Bugs and status of rubyspecs (as of 30 Sep 2011)
126+
127+
For the rubyspecs in optional/capi/ , the following specs are skipped
128+
and are not supported
129+
130+
* rb_define_hooked_variable
131+
* rb_define_variable
132+
* rb_protect_inspect
133+
* rb_inspecting_p
134+
* rb_exec_recursive
135+
136+
The following functions have known bugs that we will try to fix
137+
138+
* rb_class_new fails to throw an error when passed a singleton class as superclass
139+
* rb_rescue has some spec failures
140+
* rb_thread_select fails to detect an fd that's ready to read
141+
* rb_str_buf_* sometimes fails to synchronize the C buffer correctly
142+

0 commit comments

Comments
 (0)