From: eregontp@... Date: 2020-11-20T12:29:52+00:00 Subject: [ruby-core:100974] [Ruby master Feature#17307] A way to mark C extensions as thread-safe, Ractor-safe, or unsafe Issue #17307 has been updated by Eregon (Benoit Daloze). By marking as thread-safe, I mean that the C extension would manipulate its own state in a thread-safe manner. I think the various APIs mentioned above all make that clear. The thread safety of the interpreter is not considered here. It's up to the interpreter to make use or not of these flags on the C extension. We should indeed define better what thread-safe for a C extension means in practice, i.e. some docs on how making a C extension thread-safe. I or Duncan will prototype something in TruffleRuby and with a couple C exts, and write some documentation about that. It would be useful if @ko1 can write some documentation about how to make a C extension Ractor-safe, as I think he knows best. --- In short, all `rb_*` functions are expected to be thread-safe on TruffleRuby. I think CRuby never really had the concept of thread safety for the interpreter, because it never had shared memory parallelism. The GVL/GIL basically avoids any thread-safety issue by not allowing Ruby Threads to run in parallel (inside a Ractor, different Ractors have almost isolated heaps, so there is no actual shared memory at the Ruby level). (there is `rb_thread_call_without_gvl()` but basically calling any `rb_*()` function inside is unsafe). So, "thread-safe C extensions" would probably not be directly useful to CRuby as long as the GVL exists. So CRuby can ignore the thread-safe flag basically, and instead the Ractor-safe flag is the interesting part for CRuby. I think we'd want to avoid having "truffleruby" in the name for the thread-safe flag, because there could be other Ruby implementations in the future with C extension support and parallel threads (Rubinius is an example, although it's inactive recently). If a Ruby implementation supports parallel threads, it needs most things in the interpreter to be thread-safe. C extension APIs too. ---------------------------------------- Feature #17307: A way to mark C extensions as thread-safe, Ractor-safe, or unsafe https://bugs.ruby-lang.org/issues/17307#change-88637 * Author: Eregon (Benoit Daloze) * Status: Open * Priority: Normal ---------------------------------------- I would like to design a way to mark C extensions as thread-safe, Ractor-safe, or unsafe (= needs process-global lock). By default, if not marked, C extensions would be treated as unsafe for compatibility. Specifically, TruffleRuby supports C extensions, but for scalability it is important to run at least some of them in parallel (e.g., HTTP parsing in Puma). This was notably mentioned in my [RubyKaigi talk](https://speakerdeck.com/eregon/running-rack-and-rails-faster-with-truffleruby?slide=17). TruffleRuby defaults to acquire a global lock when executing C extension code for maximum compatibility (Ruby code OTOH can always run in parallel). There is a command-line option for that lock and it can be disabled, but then it is disabled for all C extensions. The important property for TruffleRuby is that the C extension does not need a global lock, i.e., that it synchronizes any mutable state in C that could be accessed by multiple threads, such as global C variables. I believe many C extensions are already thread-safe, or can easily become thread-safe, because they do not rely on global state and do not share the RData objects between threads. Ractor also needs a way to mark C extensions, to know if it's OK to use the C extension in multiple Ractors in parallel, and that the C extension will not leak non-shareable objects from one Ractor to another, which would lead to bugs & segfaults. Otherwise, C extensions could only be used on the main/initial Ractor (or need to acquire a process-global lock whenever executing C extension code and ensure no non-shareable objects leak between Ractors), which would be a very big limitation (almost every non-trivial application depends on a C extension transitively). In both cases, global state in the C extension needs synchronization. In the thread-safe case, mutable state in C that could be accessed by multiple Ruby threads needs to be synchronized too (there might be no such state, e.g., if C extension objects are created per Thread). In the Ractor case, the C extension must never pass an object from a Ractor to another, unless it is a shareable object. What do you think would be a good way to "mark" C extensions? Maybe defining a symbol in the C extension, similar to the `Init_foo` we have, like say `foo_is_thread_safe`/`foo_is_ractor_safe`? A symbol including the C extension name seems best, to avoid any possible confusion when looking it up. Maybe there are other ways to mark C extensions than defining symbols, that could still be read by the Ruby implementation reliably? I used the term `C extensions` but of course it would apply to native extensions too (including C++/Rust/...). cc @ko1 -- https://bugs.ruby-lang.org/ Unsubscribe: