<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/ractor_sync.c, 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>Check for NULL fields in TYPEDDATA memsize functions (#15633)</title>
<updated>2025-12-18T20:42:49+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-12-18T20:42:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=aace29d485559e38ca06923a6af335dbb5fb28f1'/>
<id>aace29d485559e38ca06923a6af335dbb5fb28f1</id>
<content type='text'>
Some TYPEDDATA objects allocate struct fields using the GC right after
they get created, and in that case the VM can try to perform a GC and join
a barrier if another ractor started one. If we're dumping the heap in another
ractor, this acquires a barrier and it will call the `rb_obj_memsize` function on this
object. We can't assume these struct fields are non-null. This also goes for C extensions,
which may cause problems with heap dumping from a ractor if their memsize functions aren't
coded correctly to check for NULL fields. Because dumping the heap from a ractor is likely a
rare scenario and it has only recently been introduced, we'll have to see how this works in
practice and if it causes bugs.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Some TYPEDDATA objects allocate struct fields using the GC right after
they get created, and in that case the VM can try to perform a GC and join
a barrier if another ractor started one. If we're dumping the heap in another
ractor, this acquires a barrier and it will call the `rb_obj_memsize` function on this
object. We can't assume these struct fields are non-null. This also goes for C extensions,
which may cause problems with heap dumping from a ractor if their memsize functions aren't
coded correctly to check for NULL fields. Because dumping the heap from a ractor is likely a
rare scenario and it has only recently been introduced, we'll have to see how this works in
practice and if it causes bugs.</pre>
</div>
</content>
</entry>
<entry>
<title>Fix heap dump with ractor barrier</title>
<updated>2025-12-17T19:12:57+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-12-17T18:18:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=839410f0734cb3ed911d348855f69ff6d856f62b'/>
<id>839410f0734cb3ed911d348855f69ff6d856f62b</id>
<content type='text'>
When a ractor was being initialized and it would join the heap dump barrier when
allocating its queue or its ports, the heap dump code calls `rb_obj_memsize` on
the ractor and this function assumed `ports` was never NULL. We need to check for
the NULL case in case the ractor is still being initialized. Hopefully other T_DATA
objects don't suffer from the same issue, otherwise we could revert the ractor barrier
during heap dump or not use `rb_obj_memsize` on T_DATA during the heap dump.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When a ractor was being initialized and it would join the heap dump barrier when
allocating its queue or its ports, the heap dump code calls `rb_obj_memsize` on
the ractor and this function assumed `ports` was never NULL. We need to check for
the NULL case in case the ractor is still being initialized. Hopefully other T_DATA
objects don't suffer from the same issue, otherwise we could revert the ractor barrier
during heap dump or not use `rb_obj_memsize` on T_DATA during the heap dump.
</pre>
</div>
</content>
</entry>
<entry>
<title>allow Ractor::Port shareable</title>
<updated>2025-10-30T09:04:08+00:00</updated>
<author>
<name>Koichi Sasada</name>
<email>ko1@atdot.net</email>
</author>
<published>2025-10-27T09:14:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=b9188901c07649c3af3a5f925ec0dead444a4134'/>
<id>b9188901c07649c3af3a5f925ec0dead444a4134</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix deadlock when malloc in Ractor lock</title>
<updated>2025-08-25T19:43:01+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-08-25T15:21:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fca258f97f7b1d111f01250c1e0d97043b095954'/>
<id>fca258f97f7b1d111f01250c1e0d97043b095954</id>
<content type='text'>
If we malloc when the current Ractor is locked, we can deadlock because
GC requires VM lock and Ractor barrier. If another Ractor is waiting on
this Ractor lock, then it will deadlock because the other Ractor will
never join the barrier.

For example, this script deadlocks:

    r = Ractor.new do
      loop do
        Ractor::Port.new
      end
    end

    100000.times do |i|
      r.send(nil)
      puts i
    end

On debug builds, it fails with this assertion error:

    vm_sync.c:75: Assertion Failed: vm_lock_enter:cr-&gt;sync.locked_by != rb_ractor_self(cr)

On non-debug builds, we can see that it deadlocks in the debugger:

    Main Ractor:
    frame #3: 0x000000010021fdc4 miniruby`rb_native_mutex_lock(lock=&lt;unavailable&gt;) at thread_pthread.c:115:14
    frame #4: 0x0000000100193eb8 miniruby`ractor_send0 [inlined] ractor_lock(r=&lt;unavailable&gt;, file=&lt;unavailable&gt;, line=1180) at ractor.c:73:5
    frame #5: 0x0000000100193eb0 miniruby`ractor_send0 [inlined] ractor_send_basket(ec=&lt;unavailable&gt;, rp=0x0000000131092840, b=0x000000011c63de80, raise_on_error=true) at ractor_sync.c:1180:5
    frame #6: 0x0000000100193eac miniruby`ractor_send0(ec=&lt;unavailable&gt;, rp=0x0000000131092840, obj=4, move=&lt;unavailable&gt;, raise_on_error=true) at ractor_sync.c:1211:5

    Second Ractor:
    frame #2: 0x00000001002208d0 miniruby`rb_ractor_sched_barrier_start [inlined] rb_native_cond_wait(cond=&lt;unavailable&gt;, mutex=&lt;unavailable&gt;) at thread_pthread.c:221:13
    frame #3: 0x00000001002208cc miniruby`rb_ractor_sched_barrier_start(vm=0x000000013180d600, cr=0x0000000131093460) at thread_pthread.c:1438:13
    frame #4: 0x000000010028a328 miniruby`rb_vm_barrier at vm_sync.c:262:13 [artificial]
    frame #5: 0x00000001000dfa6c miniruby`gc_start [inlined] rb_gc_vm_barrier at gc.c:179:5
    frame #6: 0x00000001000dfa68 miniruby`gc_start [inlined] gc_enter(objspace=0x000000013180fc00, event=gc_enter_event_start, lock_lev=&lt;unavailable&gt;) at default.c:6636:9
    frame #7: 0x00000001000dfa48 miniruby`gc_start(objspace=0x000000013180fc00, reason=&lt;unavailable&gt;) at default.c:6361:5
    frame #8: 0x00000001000e3fd8 miniruby`objspace_malloc_increase_body [inlined] garbage_collect(objspace=0x000000013180fc00, reason=512) at default.c:6341:15
    frame #9: 0x00000001000e3fa4 miniruby`objspace_malloc_increase_body [inlined] garbage_collect_with_gvl(objspace=0x000000013180fc00, reason=512) at default.c:6741:16
    frame #10: 0x00000001000e3f88 miniruby`objspace_malloc_increase_body(objspace=0x000000013180fc00, mem=&lt;unavailable&gt;, new_size=&lt;unavailable&gt;, old_size=&lt;unavailable&gt;, type=&lt;unavailable&gt;) at default.c:8007:13
    frame #11: 0x00000001000e3c44 miniruby`rb_gc_impl_malloc [inlined] objspace_malloc_fixup(objspace=0x000000013180fc00, mem=0x000000011c700000, size=12582912) at default.c:8085:5
    frame #12: 0x00000001000e3c30 miniruby`rb_gc_impl_malloc(objspace_ptr=0x000000013180fc00, size=12582912) at default.c:8182:12
    frame #13: 0x00000001000d4584 miniruby`ruby_xmalloc [inlined] ruby_xmalloc_body(size=&lt;unavailable&gt;) at gc.c:5128:12
    frame #14: 0x00000001000d4568 miniruby`ruby_xmalloc(size=&lt;unavailable&gt;) at gc.c:5118:34
    frame #15: 0x00000001001eb184 miniruby`rb_st_init_existing_table_with_size(tab=0x000000011c2b4b40, type=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at st.c:559:39
    frame #16: 0x00000001001ebc74 miniruby`rebuild_table_if_necessary [inlined] rb_st_init_table_with_size(type=0x00000001004f4a78, size=524287) at st.c:585:5
    frame #17: 0x00000001001ebc5c miniruby`rebuild_table_if_necessary [inlined] rebuild_table(tab=0x000000013108e2f0) at st.c:753:19
    frame #18: 0x00000001001ebbfc miniruby`rebuild_table_if_necessary(tab=0x000000013108e2f0) at st.c:1125:9
    frame #19: 0x00000001001eba08 miniruby`rb_st_insert(tab=0x000000013108e2f0, key=262144, value=4767566624) at st.c:1143:5
    frame #20: 0x0000000100194b84 miniruby`ractor_port_initialzie [inlined] ractor_add_port(r=0x0000000131093460, id=262144) at ractor_sync.c:399:9
    frame #21: 0x0000000100194b58 miniruby`ractor_port_initialzie [inlined] ractor_port_init(rpv=4750065560, r=0x0000000131093460) at ractor_sync.c:87:5
    frame #22: 0x0000000100194b34 miniruby`ractor_port_initialzie(self=4750065560) at ractor_sync.c:103:12
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
If we malloc when the current Ractor is locked, we can deadlock because
GC requires VM lock and Ractor barrier. If another Ractor is waiting on
this Ractor lock, then it will deadlock because the other Ractor will
never join the barrier.

For example, this script deadlocks:

    r = Ractor.new do
      loop do
        Ractor::Port.new
      end
    end

    100000.times do |i|
      r.send(nil)
      puts i
    end

On debug builds, it fails with this assertion error:

    vm_sync.c:75: Assertion Failed: vm_lock_enter:cr-&gt;sync.locked_by != rb_ractor_self(cr)

On non-debug builds, we can see that it deadlocks in the debugger:

    Main Ractor:
    frame #3: 0x000000010021fdc4 miniruby`rb_native_mutex_lock(lock=&lt;unavailable&gt;) at thread_pthread.c:115:14
    frame #4: 0x0000000100193eb8 miniruby`ractor_send0 [inlined] ractor_lock(r=&lt;unavailable&gt;, file=&lt;unavailable&gt;, line=1180) at ractor.c:73:5
    frame #5: 0x0000000100193eb0 miniruby`ractor_send0 [inlined] ractor_send_basket(ec=&lt;unavailable&gt;, rp=0x0000000131092840, b=0x000000011c63de80, raise_on_error=true) at ractor_sync.c:1180:5
    frame #6: 0x0000000100193eac miniruby`ractor_send0(ec=&lt;unavailable&gt;, rp=0x0000000131092840, obj=4, move=&lt;unavailable&gt;, raise_on_error=true) at ractor_sync.c:1211:5

    Second Ractor:
    frame #2: 0x00000001002208d0 miniruby`rb_ractor_sched_barrier_start [inlined] rb_native_cond_wait(cond=&lt;unavailable&gt;, mutex=&lt;unavailable&gt;) at thread_pthread.c:221:13
    frame #3: 0x00000001002208cc miniruby`rb_ractor_sched_barrier_start(vm=0x000000013180d600, cr=0x0000000131093460) at thread_pthread.c:1438:13
    frame #4: 0x000000010028a328 miniruby`rb_vm_barrier at vm_sync.c:262:13 [artificial]
    frame #5: 0x00000001000dfa6c miniruby`gc_start [inlined] rb_gc_vm_barrier at gc.c:179:5
    frame #6: 0x00000001000dfa68 miniruby`gc_start [inlined] gc_enter(objspace=0x000000013180fc00, event=gc_enter_event_start, lock_lev=&lt;unavailable&gt;) at default.c:6636:9
    frame #7: 0x00000001000dfa48 miniruby`gc_start(objspace=0x000000013180fc00, reason=&lt;unavailable&gt;) at default.c:6361:5
    frame #8: 0x00000001000e3fd8 miniruby`objspace_malloc_increase_body [inlined] garbage_collect(objspace=0x000000013180fc00, reason=512) at default.c:6341:15
    frame #9: 0x00000001000e3fa4 miniruby`objspace_malloc_increase_body [inlined] garbage_collect_with_gvl(objspace=0x000000013180fc00, reason=512) at default.c:6741:16
    frame #10: 0x00000001000e3f88 miniruby`objspace_malloc_increase_body(objspace=0x000000013180fc00, mem=&lt;unavailable&gt;, new_size=&lt;unavailable&gt;, old_size=&lt;unavailable&gt;, type=&lt;unavailable&gt;) at default.c:8007:13
    frame #11: 0x00000001000e3c44 miniruby`rb_gc_impl_malloc [inlined] objspace_malloc_fixup(objspace=0x000000013180fc00, mem=0x000000011c700000, size=12582912) at default.c:8085:5
    frame #12: 0x00000001000e3c30 miniruby`rb_gc_impl_malloc(objspace_ptr=0x000000013180fc00, size=12582912) at default.c:8182:12
    frame #13: 0x00000001000d4584 miniruby`ruby_xmalloc [inlined] ruby_xmalloc_body(size=&lt;unavailable&gt;) at gc.c:5128:12
    frame #14: 0x00000001000d4568 miniruby`ruby_xmalloc(size=&lt;unavailable&gt;) at gc.c:5118:34
    frame #15: 0x00000001001eb184 miniruby`rb_st_init_existing_table_with_size(tab=0x000000011c2b4b40, type=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at st.c:559:39
    frame #16: 0x00000001001ebc74 miniruby`rebuild_table_if_necessary [inlined] rb_st_init_table_with_size(type=0x00000001004f4a78, size=524287) at st.c:585:5
    frame #17: 0x00000001001ebc5c miniruby`rebuild_table_if_necessary [inlined] rebuild_table(tab=0x000000013108e2f0) at st.c:753:19
    frame #18: 0x00000001001ebbfc miniruby`rebuild_table_if_necessary(tab=0x000000013108e2f0) at st.c:1125:9
    frame #19: 0x00000001001eba08 miniruby`rb_st_insert(tab=0x000000013108e2f0, key=262144, value=4767566624) at st.c:1143:5
    frame #20: 0x0000000100194b84 miniruby`ractor_port_initialzie [inlined] ractor_add_port(r=0x0000000131093460, id=262144) at ractor_sync.c:399:9
    frame #21: 0x0000000100194b58 miniruby`ractor_port_initialzie [inlined] ractor_port_init(rpv=4750065560, r=0x0000000131093460) at ractor_sync.c:87:5
    frame #22: 0x0000000100194b34 miniruby`ractor_port_initialzie(self=4750065560) at ractor_sync.c:103:12
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix typo in function name ractor_port_initialize</title>
<updated>2025-08-22T18:21:30+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-08-22T14:24:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=1e3fcc28b99cf689c42d78fb412aab9690879ab9'/>
<id>1e3fcc28b99cf689c42d78fb412aab9690879ab9</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Make Ractor::Selector write-barrier protected</title>
<updated>2025-08-06T13:02:30+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-07-31T18:38:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=06312377adc62ea1c82b5574749ee3704a1e4e9f'/>
<id>06312377adc62ea1c82b5574749ee3704a1e4e9f</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>[DOC] Fill undocumented documents</title>
<updated>2025-08-03T17:23:43+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2025-08-03T17:23:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=6179cc011829b9e4c7b253ac2d2a3f47d8fd6890'/>
<id>6179cc011829b9e4c7b253ac2d2a3f47d8fd6890</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Remove dead rb_ractor_t in ractor_selector</title>
<updated>2025-08-01T13:43:24+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-07-31T16:47:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=bf2c8ad3833d194ff5d95274569b911fbf350ffa'/>
<id>bf2c8ad3833d194ff5d95274569b911fbf350ffa</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>ractor_sync.c: Optimize `ractor_set_successor_once` to be lock free</title>
<updated>2025-07-04T06:23:20+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-07-03T09:46:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=856962fa38bfe071baa22870aaa2bd8c1ce9f8f3'/>
<id>856962fa38bfe071baa22870aaa2bd8c1ce9f8f3</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Suppress warnings</title>
<updated>2025-06-21T16:08:38+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2025-06-21T16:08:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ec20f7feb64d9cd8989ada24315ac4af0bb4158c'/>
<id>ec20f7feb64d9cd8989ada24315ac4af0bb4158c</id>
<content type='text'>
- `ractor_sync_terminate_atfork` is unused unless fork is working
- `cr` in `vm_lock_leave` is only for debugging
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- `ractor_sync_terminate_atfork` is unused unless fork is working
- `cr` in `vm_lock_leave` is only for debugging
</pre>
</div>
</content>
</entry>
</feed>
