RubyCall
Хелперы низкого уровня. ВСЁ здесь исполняется на воркер-треде (инвариант RubyCall.ruby); локальные переменные обычных методов живут на машинном стеке воркера → консервативный GC MRI их видит. VALUE в замыканиях/куче Crystal — запрещены (см. keep-слоты).
Constants
Блоки Crystal → ruby-блоки (rb_block_call). Доступ только с воркера (под глобальным MUTEX) — обычный Hash без доп. блокировок.
Глобальная блокировка на ВЕСЬ доступ к Ruby из Crystal (как PyCall::MUTEX в pycall.cr). Составные операции (funcall→convert→wrap) атомарны, interleaving фибер на разных тредах исключён.
Class methods
Трамплин rb_block_call: вызывается Ruby-ом (GIL/GVL уже на воркере). data2 = fixnum(id реестра). Исключение кристалла → rb_exc_raise — longjmp поймается внешним rb_protect драйвера.
Константа/модуль верхнего уровня: Math, Object, GC...
Идемпотентна; VM поднимается ВНУТРИ воркер-треда: он же становится main-Ruby-тредом (один стек → консервативный GC MRI корректен, GVL никогда не переходит между тредами).
Снятие keep-слота из финалайзера (GC-тред Crystal): на воркере — сразу; иначе заявкой (MUTEX; тред просто ждёт — дедлока нет, цикла ожиданий не возникает). При мёртвом воркере — утечка лучше краша.
Единая точка входа для ЛЮБОГО обращения к Ruby.
- не на воркере: под глобальным MUTEX заявка уходит воркеру;
- на воркере (вложенный вызов): исполнить напрямую — мьютекс нереентерабелен, быстрый путь обязателен (аналог PyGILState_Check).