Skip to content

[pull] master from ruby:master - #1340

Merged
pull[bot] merged 4 commits into
turkdevops:masterfrom
ruby:master
Aug 23, 2026
Merged

[pull] master from ruby:master#1340
pull[bot] merged 4 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull

@pull pull Bot commented Aug 23, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

byroot and others added 4 commits August 23, 2026 15:26
`st_replace` assumes that the `st_table` hasn't been
initialized, so when duping a hash, we shouldn't pre-allocate
the `st_table` otherwise we'll leak memory.
thread_sched_setup_running_threads runs on every context switch (park,
resume, and both ends of every blocking region) and took the global
ractor.sched.lock to maintain the running_threads and timeslice lists
and running_cnt.  With many ractors switching concurrently this lock is
the scaling ceiling.

Replace all three with ntlist, a per-location registration of who runs
where, and no shared counter:

- a thread on a shared nt registers in that nt's running_th, under the
  nt's own lock -- uncontended, no cross-core traffic
- a dedicated nt goes on ntlist.running_dnts while its thread runs (the
  switch rate of dedicated threads is what it always was; only the lock
  shrank), so the fast path writes no shared cache line at all

The consumers walk the registrations: the barrier's interrupt walk also
counts them into a snapshot (barrier_running_cnt) and stamps each nt
with the barrier serial; a stamped nt deregistering during that barrier
decrements the snapshot under sched.lock, so the completion check stays
O(1) however many runners there are.

The timeslice list becomes timeslice.scheds, the scheds whose readyq
holds waiters.  The enq that fills an empty readyq (and the add path
taking a turn with waiters already queued) links the sched; the timer
thread interrupts each listed sched's running thread and prunes entries
whose readyq drained.  A steadily contended sched stays linked, so the
switch path never touches the list, and idle scheds are not walked at
all.  The timer takes each sched's lock by trylock, because the
switchers nest sched.lock -> timeslice.lock; pruning is lazy, so
ractor_free delists the dying ractor's sched.

Barrier pairing needs no fences: the barrier sets barrier_is_waiting
and then walks the registrations under their locks; a switch moves its
registration under the same lock and then reads the flag.  A walk that
missed a registration ran before that registration's critical section,
so its flag store is visible to that switcher.  Nothing may start
running while the flag stands -- an interrupt flag alone would let a
resuming thread run, and allocate, inside the stop-the-world section --
so the add path takes its registration back and waits for
rb_ractor_sched_barrier_end's broadcast.  While a scan holds a
running_th lock the registered thread cannot finish parking, so it
cannot die under the scan.  An snt turned dedicated under
rb_thread_lock_native_thread has no creation-time running_thread, so
the running_dnts registration writes nt->running_thread itself.

R ractor pairs ping-ponging via ports (msgs/sec) and R ractors doing
pipe write/read round-trips (rt/sec), 16-HT machine (Ryzen 9 5900HX),
mean of 2 alternating same-tree runs:

                     before    after
    port pairs  8      503k     815k   +62%
    port pairs 32      453k     799k   +76%
    pipe self   4R     837k     940k   +12%
    pipe self  16R     820k     898k   +10%

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Aug 23, 2026
@pull pull Bot added the ⤵️ pull label Aug 23, 2026
@pull
pull Bot merged commit 8d46d62 into turkdevops:master Aug 23, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants