177 Commits

Author SHA1 Message Date
Peter Zhu
386f874816 Don't copy FL_PROMOTED to new object in Ractor move
We should not copy the FL_PROMOTED flag when we move an object in Ractor#send(move: true)
because the newly created object may not be old.
2025-05-26 15:04:00 -04:00
John Hawthorn
f483befd90 Add shape_id to RBasic under 32 bit
This makes `RBobject` `4B` larger on 32 bit systems
but simplifies the implementation a lot.

[Feature #21353]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2025-05-26 10:31:54 +02:00
Nobuyoshi Nakada
aad9fa2853
Use RB_VM_LOCKING 2025-05-25 15:22:43 +09:00
Luke Gruber
2b5a674440 ractor_wakeup was broken when compiled with USE_RUBY_DEBUG_LOG
The `ractor_wakeup` function takes an optional `th` argument, so it can be NULL.
There is a macro call to RUBY_DEBUG_LOG that dereferences `th` without checking
if it's NULL first. To fix this, we never dereference `th` in this macro call.
2025-05-23 16:02:48 -07:00
Luke Gruber
f64c89f18d Fix 'require' from a ractor when the required file raises an error
If you catch an error that was raised from a file you required in
a ractor, that error did not have its belonging reset from the main
ractor to the current ractor, so you hit assertion errors in debug
mode.
2025-05-23 21:13:23 +02:00
Peter Zhu
746d7fef92 Fix moving old objects between Ractors
The FL_PROMOTED flag was not copied when moving objects, causing assertions
to fail when an old object is moved:

    gc/default/default.c:834: Assertion Failed: RVALUE_AGE_SET:age <= RVALUE_OLD_AGE

Co-Authored-By: Luke Gruber <luke.gruber@shopify.com>
2025-05-23 11:06:53 -04:00
John Hawthorn
7b10660974 Use rb_inspect for Ractor error
Previously the object was used directly, which calls `to_s` if defined.
We should use rb_inspect to get a value suitable for display to the
programmer.
2025-05-21 12:23:14 -07:00
Nobuyoshi Nakada
2e3f81838c
Align styles [ci skip] 2025-05-15 17:48:40 +09:00
Luke Gruber
1d4822a175 Get ractor message passing working with > 1 thread sending/receiving values in same ractor
Rework ractors so that any ractor action (Ractor.receive, Ractor#send, Ractor.yield, Ractor#take,
Ractor.select) will operate on the thread that called the action. It will put that thread to sleep if
it's a blocking function and it needs to put it to sleep, and the awakening action (Ractor.yield,
Ractor#send) will wake up the blocked thread.

Before this change every blocking ractor action was associated with the ractor struct and its fields.
If a ractor called Ractor.receive, its wait status was wait_receiving, and when another ractor calls
r.send on it, it will look for that status in the ractor struct fields and wake it up. The problem was that
what if 2 threads call blocking ractor actions in the same ractor. Imagine if 1 thread has called Ractor.receive
and another r.take. Then, when a different ractor calls r.send on it, it doesn't know which ruby thread is associated
to which ractor action, so what ruby thread should it schedule? This change moves some fields onto the ruby thread
itself so that ruby threads are the ones that have ractor blocking statuses, and threads are then specifically scheduled
when unblocked.

Fixes [#17624]
Fixes [#21037]
2025-05-13 13:23:57 -07:00
Jean Boussier
5974841d11 Remove outdated references to FL_SEEN_OBJ_ID 2025-05-13 12:02:19 +02:00
Jean Boussier
3f7c0af051 Rename rb_shape_obj_too_complex -> rb_shape_obj_too_complex_p 2025-05-09 10:22:51 +02:00
Aaron Patterson
e3452cfad2 Raise error on take/send for Ractors in child processes
Ractor objects that are available in a child process should raise a
`Ractor::ClosedError` exception when called with `send` or `take`

Co-authored-by: John Hawthorn <john@hawthorn.email>
2025-05-08 10:53:28 -07:00
Aaron Patterson
f7ff380998 Clean up Ractor cache after fork
Ractors created in a parent process should be properly shut down in the
child process.  They need their cache cleared and status set to
"terminated"

Co-authored-by: John Hawthorn <john@hawthorn.email>
2025-05-08 10:53:28 -07:00
Jean Boussier
f48e45d1e9 Move object_id in object fields.
And get rid of the `obj_to_id_tbl`

It's no longer needed, the `object_id` is now stored inline
in the object alongside instance variables.

We still need the inverse table in case `_id2ref` is invoked, but
we lazily build it by walking the heap if that happens.

The `object_id` concern is also no longer a GC implementation
concern, but a generic implementation.

Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
2025-05-08 07:58:05 +02:00
Jean Boussier
0ea210d1ea Rename ivptr -> fields, next_iv_index -> next_field_index
Ivars will longer be the only thing stored inline
via shapes, so keeping the `iv_index` and `ivptr` names
would be confusing.

Instance variables won't be the only thing stored inline
via shapes, so keeping the `ivptr` name would be confusing.

`field` encompass anything that can be stored in a VALUE array.

Similarly, `gen_ivtbl` becomes `gen_fields_tbl`.
2025-05-08 07:58:05 +02:00
John Hawthorn
7866e124a8 Use rb_current_ec_noinline in assertions
When doing a coroutine transfer from one thread to another, there's a
risk that the compiler will reuse an address from TLS before the
transfer to the new thread.

These VM assertions are all in places we would not otherwise be reading
from TLS, but using the value of `ec` or `cr` passed in. Switching these
to test against rb_current_ec_noinline() instead ensures there isn't an
optimization applied to how we read ruby_current_ec.

Currently it seems we were hitting this on LLVM 18 specifically, but I
don't know of any reason other versions wouldn't have the same issue.
2025-04-30 15:36:58 -07:00
Jean Boussier
085cc6e434 Ractor: revert to moving object bytes, but size pool aware
Using `rb_obj_clone` introduce other problems, such as `initialize_*`
callbacks invocation in the context of the parent ractor.

So we can revert back to copy the content of the object slots,
but in a way that is aware of size pools.
2025-04-04 16:26:29 +02:00
John Hawthorn
137b51e4d3 Remove rb_gc_start from cancel_single_ractor_mode
In 307732ccee7f9f28f8422bab2f839da021d8cdec Ractors were changed to
explicitly run GC when the first non-main one was activated in order to
disable the transient heap. Theap no longer exists so I don't think we
need to do this.
2025-04-03 10:39:47 -07:00
Jean Boussier
0350290262 Ractor: Fix moving embedded objects
[Bug #20271]
[Bug #20267]
[Bug #20255]

`rb_obj_alloc(RBASIC_CLASS(obj))` will always allocate from the basic
40B pool, so if `obj` is larger than `40B`, we'll create a corrupted
object when we later copy the shape_id.

Instead we can use the same logic than ractor copy, which is
to use `rb_obj_clone`, and later ask the GC to free the original
object.

We then must turn it into a `T_OBJECT`, because otherwise
just changing its class to `RactorMoved` leaves a lot of
ways to keep using the object, e.g.:

```
a = [1, 2, 3]
Ractor.new{}.send(a, move: true)
[].concat(a) # Should raise, but wasn't.
```

If it turns out that `rb_obj_clone` isn't performant enough
for some uses, we can always have carefully crafted specialized
paths for the types that would benefit from it.
2025-03-31 12:01:55 +02:00
lukeg
d80f3a287c Ractor.make_shareable(proc_obj) makes inner structure shareable
Proc objects are now traversed like other objects when making them
shareable.

Fixes [Bug #19372]
Fixes [Bug #19374]
2025-03-26 16:05:02 -07:00
Nobuyoshi Nakada
4a67ef09cc
[Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
Nobuyoshi Nakada
92f850ae84
[DOC] Hide Ractor::Selector
It is not enabled by default currently.
2024-12-25 11:13:07 +09:00
lukeg
0d81177c20 Fix calls to require_internal in multi-ractor mode
After a ractor is started (multi-ractor mode), any calls to
require_internal will hang the process due to deadlock. For example,
loading a new encoding will deadlock after a ractor starts.

Fixes [Bug #19562]
2024-12-24 11:40:00 +09:00
Luke Gruber
38af38edcb Fix ractor move of unshareable frozen objects
These objects didn't retain their frozen status after the move

Bug [#19408]
2024-12-24 11:38:44 +09:00
Yudai Takada
b0d40d3d03
[DOC] Fix typos in comments in ractor.c 2024-12-22 18:08:39 +09:00
Koichi Sasada
e09c23433e followup 0bdb38ba6be208064a514c12a9b80328645689f8
(forgot to amend...)
2024-12-13 17:05:58 +09:00
Koichi Sasada
0bdb38ba6b Ractor.set_if_absent(key)
to initialize ractor local storage in thread-safety.
[Feature #20875]
2024-12-13 06:22:13 +09:00
Matt Valentine-House
551be8219e Place all non-default GC API behind USE_SHARED_GC
So that it doesn't get included in the generated binaries for builds
that don't support loading shared GC modules

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2024-11-25 13:05:23 +00:00
Koichi Sasada
97aaf6f760 introduce rb_ec_check_ints()
to avoid TLS issue with N:M threads.
2024-11-08 18:02:46 +09:00
Koichi Sasada
0d63b9b4a4 check closing flag
`Ractor.receive` and `Ractor.yield` should stop when the
incoming/outgoing port is closed.
2024-11-08 18:02:46 +09:00
Koichi Sasada
aa63699d10 support require in non-main Ractors
Many libraries should be loaded on the main ractor because of
setting constants with unshareable objects and so on.

This patch allows to call `requore` on non-main Ractors by
asking the main ractor to call `require` on it. The calling ractor
waits for the result of `require` from the main ractor.

If the `require` call failed with some reasons, an exception
objects will be deliverred from the main ractor to the calling ractor
if it is copy-able.

Same on `require_relative` and `require` by `autoload`.

Now `Ractor.new{pp obj}` works well (the first call of `pp` requires
`pp` library implicitly).

[Feature #20627]
2024-11-08 18:02:46 +09:00
Matt Valentine-House
1634280e1c Fix shared GC with -DRUBY_DEBUG
RUBY_DEBUG enables ractor assertions, which sets up some space at the
end of each RVALUE to store the associated ractor ID. We need to make
sure the function that does this is visible to shared GC libraries.
2024-10-24 16:08:46 +01:00
Peter Zhu
fbabe13b7e Use rb_id_table_foreach_values for marking Ractor local storage
Since we only mark the values, we can use rb_id_table_foreach_values to
avoid the overhead of converting the key to an ID.
2024-10-18 13:06:56 -04:00
Peter Zhu
c083a3ffcd Fix memory leak reported in main ractor when RUBY_FREE_AT_EXIT
STACK OF 1 INSTANCE OF 'ROOT LEAK: <calloc in rb_ractor_main_alloc>':
6   dyld                                  0x1840e20e0 start + 2360
5   miniruby                              0x1006796c8 main + 88  main.c:62
4   miniruby                              0x10072f4a4 ruby_init + 16  eval.c:99
3   miniruby                              0x10072f328 ruby_setup + 104  eval.c:81
2   miniruby                              0x1008d08c0 Init_BareVM + 508  vm.c:4276
1   miniruby                              0x1007f8944 rb_ractor_main_alloc + 76  ractor.c:2034
0   libsystem_malloc.dylib                0x1842a4cac _malloc_zone_calloc_instrumented_or_legacy + 128
====
    1 (96 bytes) ROOT LEAK: <calloc in rb_ractor_main_alloc 0x1347075d0> [96]
2024-07-16 15:50:00 -04:00
Peter Zhu
51bd816517 [Feature #20470] Split GC into gc_impl.c
This commit splits gc.c into two files:

- gc.c now only contains code not specific to Ruby GC. This includes
  code to mark objects (which the GC implementation may choose not to
  use) and wrappers for internal APIs that the implementation may need
  to use (e.g. locking the VM).

- gc_impl.c now contains the implementation of Ruby's GC. This includes
  marking, sweeping, compaction, and statistics. Most importantly,
  gc_impl.c only uses public APIs in Ruby and a limited set of functions
  exposed in gc.c. This allows us to build gc_impl.c independently of
  Ruby and plug Ruby's GC into itself.
2024-07-03 09:03:40 -04:00
Étienne Barrié
1376881e9a Stop marking chilled strings as frozen
They were initially made frozen to avoid false positives for cases such
as:

    str = str.dup if str.frozen?

But this may cause bugs and is generally confusing for users.

[Feature #20205]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-05-28 07:32:33 +02:00
Luke Gruber
6747fbe77d
Fix interrupts during Ractor.select
Fixes [Bug #20168]
2024-05-05 15:14:53 +00:00
Peter Zhu
214811974b Add ruby_mimcalloc
Many places call ruby_mimmalloc then MEMZERO. This can be reduced by
using ruby_mimcalloc instead.
2024-04-24 15:30:43 -04:00
Étienne Barrié
12be40ae6b Implement chilled strings
[Feature #20205]

As a path toward enabling frozen string literals by default in the future,
this commit introduce "chilled strings". From a user perspective chilled
strings pretend to be frozen, but on the first attempt to mutate them,
they lose their frozen status and emit a warning rather than to raise a
`FrozenError`.

Implementation wise, `rb_compile_option_struct.frozen_string_literal` is
no longer a boolean but a tri-state of `enabled/disabled/unset`.

When code is compiled with frozen string literals neither explictly enabled
or disabled, string literals are compiled with a new `putchilledstring`
instruction. This instruction is identical to `putstring` except it marks
the String with the `STR_CHILLED (FL_USER3)` and `FL_FREEZE` flags.

Chilled strings have the `FL_FREEZE` flag as to minimize the need to check
for chilled strings across the codebase, and to improve compatibility with
C extensions.

Notes:
  - `String#freeze`: clears the chilled flag.
  - `String#-@`: acts as if the string was mutable.
  - `String#+@`: acts as if the string was mutable.
  - `String#clone`: copies the chilled flag.

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-03-19 09:26:49 +01:00
Nobuyoshi Nakada
28a2105a55
Prefer enum ruby_tag_type over int 2024-03-17 15:57:19 +09:00
Nobuyoshi Nakada
361b3efe16
Use UNDEF_P 2024-01-30 14:48:59 +09:00
KJ Tsanaktsidis
ef276858d9 Trigger postponed jobs on running_ec if that is available
Currently, any postponed job triggered from a non-ruby thread gets sent
to the main thread, but if the main thread is sleeping it won't be
checking ints. Instead, we should try and interrupt running_ec if that's
possible, and only fall back to the main thread if it's not.

[Bug #20197]
2024-01-25 13:10:35 +11:00
Luke Gruber
32c4b0125f Set Ractor moved object's shape to original object's shape
Fixes [Bug #19409]
2024-01-02 08:10:59 +09:00
John Hawthorn
1f0304218c Use main_thread->ec from rb_vm_main_ractor_ec
rb_vm_main_ractor_ec was introduced to allow rb_postponed_job_* to work
when fired on non-Ruby threads, which have no EC set, and that is its
only use.

When RUBY_MN_THREADS=1 is set ractor->threads.running_ec is NULL when
the shared thread is sleeping. This instead grabs the EC directly from
the main thread which seems to always be set.

Fixes [Bug #20016]

Co-authored-by: Dustin Brown <dbrown9@gmail.com>
2023-12-21 09:17:22 -08:00
Koichi Sasada
054f56fd3e moved object should not have a shape ID
fix [Bug #19917]
2023-12-20 07:04:32 +09:00
Koichi Sasada
c9a9b8036c remove Ractor::Selector from Ruby level
`Ractor::Selector` is not approved by Matz so remove it from
Ruby-level.

The implementation is used by `Ractor.select` so most of implementation
was remaind and calling `rb_init_ractor_selector()`, `Ractor::Selector`
will be defined. I will provide `ractor-selector` gem to try it.
2023-12-16 01:00:01 +09:00
Peter Zhu
10f44dfeff Fix Ractor sharing for too complex Objects 2023-11-28 17:43:22 -05:00
Peter Zhu
6eb5a9cf8f Fix Ractor sharing for too complex generic ivars 2023-11-28 17:43:22 -05:00
Peter Zhu
e2d950733e Add ST table to gen_ivtbl for complex shapes
On 32-bit systems, we must store the shape ID in the gen_ivtbl to not
lose the shape. If we directly store the ST table into the generic
ivar table, then we lose the shape. This makes it impossible to
determine the shape of the object and whether it is too complex or not.
2023-10-31 12:07:54 -04:00
Koichi Sasada
be1bbd5b7d M:N thread scheduler for Ractors
This patch introduce M:N thread scheduler for Ractor system.

In general, M:N thread scheduler employs N native threads (OS threads)
to manage M user-level threads (Ruby threads in this case).
On the Ruby interpreter, 1 native thread is provided for 1 Ractor
and all Ruby threads are managed by the native thread.

From Ruby 1.9, the interpreter uses 1:1 thread scheduler which means
1 Ruby thread has 1 native thread. M:N scheduler change this strategy.

Because of compatibility issue (and stableness issue of the implementation)
main Ractor doesn't use M:N scheduler on default. On the other words,
threads on the main Ractor will be managed with 1:1 thread scheduler.

There are additional settings by environment variables:

`RUBY_MN_THREADS=1` enables M:N thread scheduler on the main ractor.
Note that non-main ractors use the M:N scheduler without this
configuration. With this configuration, single ractor applications
run threads on M:1 thread scheduler (green threads, user-level threads).

`RUBY_MAX_CPU=n` specifies maximum number of native threads for
M:N scheduler (default: 8).

This patch will be reverted soon if non-easy issues are found.

[Bug #19842]
2023-10-12 14:47:01 +09:00