<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/thread_pthread.h, branch v4.0.3</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>move th-&gt;event_serial to rb_thread_sched_item (#15500)</title>
<updated>2025-12-12T19:24:40+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-12-12T19:24:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=7909ce2a839ba1c3e134239189e6aa2de3b6b630'/>
<id>7909ce2a839ba1c3e134239189e6aa2de3b6b630</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix thread scheduler issue with thread_sched_wait_events (#15392)</title>
<updated>2025-12-04T21:51:11+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-12-04T21:51:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8d8159e7d87e4fd1594ce2fad3d2653e47fb1026'/>
<id>8d8159e7d87e4fd1594ce2fad3d2653e47fb1026</id>
<content type='text'>
Fix race between timer thread dequeuing waiting thread and thread
skipping sleeping due to being dequeued. We now use `th-&gt;event_serial` which
is protected by `thread_sched_lock`. When a thread is put on timer thread's waiting
list, the event serial is saved on the item. The timer thread checks
that the saved serial is the same as current thread's serial before
calling `thread_sched_to_ready`.

The following script (taken from a test in `test_thread.rb` used to crash on
scheduler debug assertions. It would likely crash in non-debug mode as well.

```ruby
def assert_nil(val)
  if val != nil
    raise "Expected #{val} to be nil"
  end
end

def assert_equal(expected, actual)
  if expected != actual
    raise "Expected #{expected} to be #{actual}"
  end
end

def test_join2
  ok = false
  t1 = Thread.new { ok = true; sleep }
  Thread.pass until ok
  Thread.pass until t1.stop?
  t2 = Thread.new do
    Thread.pass while ok
    t1.join(0.01)
  end
  t3 = Thread.new do
    ok = false
    t1.join
  end
  assert_nil(t2.value)
  t1.wakeup
  assert_equal(t1, t3.value)
ensure
  t1&amp;.kill&amp;.join
  t2&amp;.kill&amp;.join
  t3&amp;.kill&amp;.join
end

rs = 30.times.map do
  Ractor.new do
    test_join2
  end
end
rs.each(&amp;:join)
```</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Fix race between timer thread dequeuing waiting thread and thread
skipping sleeping due to being dequeued. We now use `th-&gt;event_serial` which
is protected by `thread_sched_lock`. When a thread is put on timer thread's waiting
list, the event serial is saved on the item. The timer thread checks
that the saved serial is the same as current thread's serial before
calling `thread_sched_to_ready`.

The following script (taken from a test in `test_thread.rb` used to crash on
scheduler debug assertions. It would likely crash in non-debug mode as well.

```ruby
def assert_nil(val)
  if val != nil
    raise "Expected #{val} to be nil"
  end
end

def assert_equal(expected, actual)
  if expected != actual
    raise "Expected #{expected} to be #{actual}"
  end
end

def test_join2
  ok = false
  t1 = Thread.new { ok = true; sleep }
  Thread.pass until ok
  Thread.pass until t1.stop?
  t2 = Thread.new do
    Thread.pass while ok
    t1.join(0.01)
  end
  t3 = Thread.new do
    ok = false
    t1.join
  end
  assert_nil(t2.value)
  t1.wakeup
  assert_equal(t1, t3.value)
ensure
  t1&amp;.kill&amp;.join
  t2&amp;.kill&amp;.join
  t3&amp;.kill&amp;.join
end

rs = 30.times.map do
  Ractor.new do
    test_join2
  end
end
rs.each(&amp;:join)
```</pre>
</div>
</content>
</entry>
<entry>
<title>Add a macro to manage the condition of no-inline version rb_current_ec</title>
<updated>2025-09-16T10:37:26+00:00</updated>
<author>
<name>Jun Aruga</name>
<email>jaruga@redhat.com</email>
</author>
<published>2025-09-04T17:59:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=971174054a26be0a4becbe7c67a7cc980158abf2'/>
<id>971174054a26be0a4becbe7c67a7cc980158abf2</id>
<content type='text'>
Add the macro `RB_THREAD_CURRENT_EC_NOINLINE` to manage the condition to use
no-inline version rb_current_ec for a better maintainability.

Note that the `vm_core.h` includes the `THREAD_IMPL_H` by the
`#include THREAD_IMPL_H`. The `THREAD_IMPL_H` can be `thread_none.h`,
`thread_pthread.h` or `thread_win32.h` according to the
`tool/m4/ruby_thread.m4` creating the `THREAD_IMPL_H`.

The change in this commit only defining the `RB_THREAD_CURRENT_EC_NOINLINE` in
the `thread_pthread.h` is okay in this situation. Because in the
`thread_none.h` case, the thread feature is not used at all, including
Thread-Local Storage (TLS), and in the `thread_win32.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is not defined. In the `thread_pthread.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is defined in the `configure.ac`. In the
`thread_none.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is defined in the
`thread_none.h`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add the macro `RB_THREAD_CURRENT_EC_NOINLINE` to manage the condition to use
no-inline version rb_current_ec for a better maintainability.

Note that the `vm_core.h` includes the `THREAD_IMPL_H` by the
`#include THREAD_IMPL_H`. The `THREAD_IMPL_H` can be `thread_none.h`,
`thread_pthread.h` or `thread_win32.h` according to the
`tool/m4/ruby_thread.m4` creating the `THREAD_IMPL_H`.

The change in this commit only defining the `RB_THREAD_CURRENT_EC_NOINLINE` in
the `thread_pthread.h` is okay in this situation. Because in the
`thread_none.h` case, the thread feature is not used at all, including
Thread-Local Storage (TLS), and in the `thread_win32.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is not defined. In the `thread_pthread.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is defined in the `configure.ac`. In the
`thread_none.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is defined in the
`thread_none.h`.
</pre>
</div>
</content>
</entry>
<entry>
<title>Use no-inline version rb_current_ec on ppc64le</title>
<updated>2025-09-04T14:55:27+00:00</updated>
<author>
<name>Jun Aruga</name>
<email>jaruga@redhat.com</email>
</author>
<published>2025-09-03T11:03:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=73854a4b65fcea8e409440b88d014d8fb18bbc68'/>
<id>73854a4b65fcea8e409440b88d014d8fb18bbc68</id>
<content type='text'>
This commit fixes the failures in bootstraptest/test_ractor.rb reported on
the issue ticket &lt;https://bugs.ruby-lang.org/issues/21534&gt;.

TLS (Thread-Local Storage) may not be accessed across .so on ppc64le too.
I am not sure about that.  The comment "// TLS can not be accessed across
.so on ..." in this commit comes from the following commit.

https://github.com/ruby/ruby/commit/319afed20fba8f9b44611d16e4930260f7b56b86#diff-408391c43b2372cfe1fefb3e1c2531df0184ed711f46d229b08964ec9e8fa8c7R118
&gt; // on Darwin, TLS can not be accessed across .so`

This failures only happened when configuring with cppflags=-DRUBY_DEBUG and -O3
on ppc64le.

The reproducing steps were below.

```
$ ./autogen.sh

$ ./configure -C --disable-install-doc cppflags=-DRUBY_DEBUG

$ make -j4

$ make btest BTESTS=bootstraptest/test_ractor.rb
...
FAIL 2/147 tests failed
make: *** [uncommon.mk:913: yes-btest] Error 1
```

The steps with a reproducing script based on the `bootstraptest/test_ractor.rb`
were below.

```
$ cat test_ractor_1.rb
counts = []
counts &lt;&lt; Ractor.count
p counts.inspect

ractors = (1..2).map { Ractor.new { Ractor.receive } }
counts &lt;&lt; Ractor.count
p counts.inspect

ractors[0].send('End 0').join
sleep 0.1 until ractors[0].inspect =~ /terminated/
counts &lt;&lt; Ractor.count
p counts.inspect

ractors[1].send('End 1').join
sleep 0.1 until ractors[1].inspect =~ /terminated/
counts &lt;&lt; Ractor.count
p counts.inspect

$ make run TESTRUN_SCRIPT=test_ractor_1.rb
...
vm_core.h:2017: Assertion Failed: rb_current_execution_context:ec == rb_current_ec_noinline()
...
```

The assertion failure happened at the following line.

https://github.com/ruby/ruby/blob/f3206cc79bec2fd852e81ec56de59f0a67ab32b7/vm_core.h#L2017

This fix is similar with the following commit for the arm64.

https://github.com/ruby/ruby/commit/f7059af50a31a4d27a04ace0beadb60616f3f971

Fixes [Bug #21534]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This commit fixes the failures in bootstraptest/test_ractor.rb reported on
the issue ticket &lt;https://bugs.ruby-lang.org/issues/21534&gt;.

TLS (Thread-Local Storage) may not be accessed across .so on ppc64le too.
I am not sure about that.  The comment "// TLS can not be accessed across
.so on ..." in this commit comes from the following commit.

https://github.com/ruby/ruby/commit/319afed20fba8f9b44611d16e4930260f7b56b86#diff-408391c43b2372cfe1fefb3e1c2531df0184ed711f46d229b08964ec9e8fa8c7R118
&gt; // on Darwin, TLS can not be accessed across .so`

This failures only happened when configuring with cppflags=-DRUBY_DEBUG and -O3
on ppc64le.

The reproducing steps were below.

```
$ ./autogen.sh

$ ./configure -C --disable-install-doc cppflags=-DRUBY_DEBUG

$ make -j4

$ make btest BTESTS=bootstraptest/test_ractor.rb
...
FAIL 2/147 tests failed
make: *** [uncommon.mk:913: yes-btest] Error 1
```

The steps with a reproducing script based on the `bootstraptest/test_ractor.rb`
were below.

```
$ cat test_ractor_1.rb
counts = []
counts &lt;&lt; Ractor.count
p counts.inspect

ractors = (1..2).map { Ractor.new { Ractor.receive } }
counts &lt;&lt; Ractor.count
p counts.inspect

ractors[0].send('End 0').join
sleep 0.1 until ractors[0].inspect =~ /terminated/
counts &lt;&lt; Ractor.count
p counts.inspect

ractors[1].send('End 1').join
sleep 0.1 until ractors[1].inspect =~ /terminated/
counts &lt;&lt; Ractor.count
p counts.inspect

$ make run TESTRUN_SCRIPT=test_ractor_1.rb
...
vm_core.h:2017: Assertion Failed: rb_current_execution_context:ec == rb_current_ec_noinline()
...
```

The assertion failure happened at the following line.

https://github.com/ruby/ruby/blob/f3206cc79bec2fd852e81ec56de59f0a67ab32b7/vm_core.h#L2017

This fix is similar with the following commit for the arm64.

https://github.com/ruby/ruby/commit/f7059af50a31a4d27a04ace0beadb60616f3f971

Fixes [Bug #21534]
</pre>
</div>
</content>
</entry>
<entry>
<title>`Ractor::Port`</title>
<updated>2025-05-30T19:01:33+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2025-05-26T18:58:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ef2bb61018cd9ccb5b61a3d91911e04a773da4a7'/>
<id>ef2bb61018cd9ccb5b61a3d91911e04a773da4a7</id>
<content type='text'>
* Added `Ractor::Port`
  * `Ractor::Port#receive` (support multi-threads)
  * `Rcator::Port#close`
  * `Ractor::Port#closed?`
* Added some methods
  * `Ractor#join`
  * `Ractor#value`
  * `Ractor#monitor`
  * `Ractor#unmonitor`
* Removed some methods
  * `Ractor#take`
  * `Ractor.yield`
* Change the spec
  * `Racotr.select`

You can wait for multiple sequences of messages with `Ractor::Port`.

```ruby
ports = 3.times.map{ Ractor::Port.new }
ports.map.with_index do |port, ri|
  Ractor.new port,ri do |port, ri|
    3.times{|i| port &lt;&lt; "r#{ri}-#{i}"}
  end
end

p ports.each{|port| pp 3.times.map{port.receive}}

```

In this example, we use 3 ports, and 3 Ractors send messages to them respectively.
We can receive a series of messages from each port.

You can use `Ractor#value` to get the last value of a Ractor's block:

```ruby
result = Ractor.new do
  heavy_task()
end.value
```

You can wait for the termination of a Ractor with `Ractor#join` like this:

```ruby
Ractor.new do
  some_task()
end.join
```

`#value` and `#join` are similar to `Thread#value` and `Thread#join`.

To implement `#join`, `Ractor#monitor` (and `Ractor#unmonitor`) is introduced.

This commit changes `Ractor.select()` method.
It now only accepts ports or Ractors, and returns when a port receives a message or a Ractor terminates.

We removes `Ractor.yield` and `Ractor#take` because:
* `Ractor::Port` supports most of similar use cases in a simpler manner.
* Removing them significantly simplifies the code.

We also change the internal thread scheduler code (thread_pthread.c):
* During barrier synchronization, we keep the `ractor_sched` lock to avoid deadlocks.
  This lock is released by `rb_ractor_sched_barrier_end()`
  which is called at the end of operations that require the barrier.
* fix potential deadlock issues by checking interrupts just before setting UBF.

https://bugs.ruby-lang.org/issues/21262
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* Added `Ractor::Port`
  * `Ractor::Port#receive` (support multi-threads)
  * `Rcator::Port#close`
  * `Ractor::Port#closed?`
* Added some methods
  * `Ractor#join`
  * `Ractor#value`
  * `Ractor#monitor`
  * `Ractor#unmonitor`
* Removed some methods
  * `Ractor#take`
  * `Ractor.yield`
* Change the spec
  * `Racotr.select`

You can wait for multiple sequences of messages with `Ractor::Port`.

```ruby
ports = 3.times.map{ Ractor::Port.new }
ports.map.with_index do |port, ri|
  Ractor.new port,ri do |port, ri|
    3.times{|i| port &lt;&lt; "r#{ri}-#{i}"}
  end
end

p ports.each{|port| pp 3.times.map{port.receive}}

```

In this example, we use 3 ports, and 3 Ractors send messages to them respectively.
We can receive a series of messages from each port.

You can use `Ractor#value` to get the last value of a Ractor's block:

```ruby
result = Ractor.new do
  heavy_task()
end.value
```

You can wait for the termination of a Ractor with `Ractor#join` like this:

```ruby
Ractor.new do
  some_task()
end.join
```

`#value` and `#join` are similar to `Thread#value` and `Thread#join`.

To implement `#join`, `Ractor#monitor` (and `Ractor#unmonitor`) is introduced.

This commit changes `Ractor.select()` method.
It now only accepts ports or Ractors, and returns when a port receives a message or a Ractor terminates.

We removes `Ractor.yield` and `Ractor#take` because:
* `Ractor::Port` supports most of similar use cases in a simpler manner.
* Removing them significantly simplifies the code.

We also change the internal thread scheduler code (thread_pthread.c):
* During barrier synchronization, we keep the `ractor_sched` lock to avoid deadlocks.
  This lock is released by `rb_ractor_sched_barrier_end()`
  which is called at the end of operations that require the barrier.
* fix potential deadlock issues by checking interrupts just before setting UBF.

https://bugs.ruby-lang.org/issues/21262
</pre>
</div>
</content>
</entry>
<entry>
<title>Use no-inline version `rb_current_ec` on Arm64</title>
<updated>2025-01-17T13:48:10+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2025-01-17T13:48:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f7059af50a31a4d27a04ace0beadb60616f3f971'/>
<id>f7059af50a31a4d27a04ace0beadb60616f3f971</id>
<content type='text'>
The TLS across .so issue seems related to Arm64, but not Darwin.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The TLS across .so issue seems related to Arm64, but not Darwin.
</pre>
</div>
</content>
</entry>
<entry>
<title>support `require` in non-main Ractors</title>
<updated>2024-11-08T09:02:46+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2024-11-04T19:54:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=aa63699d10e489bc6d9c13406fc47f581001568b'/>
<id>aa63699d10e489bc6d9c13406fc47f581001568b</id>
<content type='text'>
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]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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]
</pre>
</div>
</content>
</entry>
<entry>
<title>`struct rb_thread_sched_waiting`</title>
<updated>2024-07-08T20:57:03+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2024-04-27T22:19:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ffc69eec0a5746d48ef3cf649639c67631a6a609'/>
<id>ffc69eec0a5746d48ef3cf649639c67631a6a609</id>
<content type='text'>
Introduce `struct rb_thread_sched_waiting` and `timer_th.waiting`
can contain other than `rb_thread_t`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Introduce `struct rb_thread_sched_waiting` and `timer_th.waiting`
can contain other than `rb_thread_t`.
</pre>
</div>
</content>
</entry>
<entry>
<title>Use noinline version of accessing current ec</title>
<updated>2023-12-24T06:13:33+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2023-12-24T05:33:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=a87ae242bb460c7643d0f974b96489b5f73a2d45'/>
<id>a87ae242bb460c7643d0f974b96489b5f73a2d45</id>
<content type='text'>
On universal.arm64e-darwin22 with clang 15.0.0 (I didn't check
details yet) accessing `ruby_current_ec` directly causes
assertion violation `VM_ASSERT(ec == rb_current_ec_noinline())`
on `rb_current_execution_context()`, maybe because TLS accessing
issue.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
On universal.arm64e-darwin22 with clang 15.0.0 (I didn't check
details yet) accessing `ruby_current_ec` directly causes
assertion violation `VM_ASSERT(ec == rb_current_ec_noinline())`
on `rb_current_execution_context()`, maybe because TLS accessing
issue.
</pre>
</div>
</content>
</entry>
<entry>
<title>M:N thread scheduler for Ractors</title>
<updated>2023-10-12T05:47:01+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2023-04-10T01:53:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=be1bbd5b7d40ad863ab35097765d3754726bbd54'/>
<id>be1bbd5b7d40ad863ab35097765d3754726bbd54</id>
<content type='text'>
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]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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]
</pre>
</div>
</content>
</entry>
</feed>
