10#include "ractor_core.h"
11#include "internal/array.h"
12#include "internal/class.h"
13#include "internal/complex.h"
14#include "internal/cont.h"
15#include "internal/error.h"
16#include "internal/gc.h"
17#include "internal/hash.h"
18#include "internal/object.h"
19#include "internal/array.h"
20#include "internal/string.h"
21#include "internal/variable.h"
22#include "eval_intern.h"
23#include "internal/io.h"
24#include "internal/marshal.h"
25#include "internal/ractor.h"
26#include "internal/rational.h"
27#include "internal/re.h"
28#include "internal/struct.h"
29#include "internal/st.h"
30#include "internal/thread.h"
31#include "internal/vm.h"
39static VALUE rb_cRactorSelector;
41VALUE rb_eRactorUnsafeError;
42VALUE rb_eRactorIsolationError;
43static VALUE rb_eRactorError;
44static VALUE rb_eRactorRemoteError;
45static VALUE rb_eRactorMovedError;
46static VALUE rb_eRactorClosedError;
47static VALUE rb_cRactorMovedObject;
49static ID id_marshal_dump, id_marshal_load;
50static ID id_dump, id_load, id_dump_data, id_load_data;
52static void vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *r,
const char *file,
int line);
55#if RACTOR_CHECK_MODE > 0
56bool rb_ractor_ignore_belonging_flag =
false;
64#if RACTOR_CHECK_MODE > 0
66 if (ec != NULL && r->sync.locked_by == rb_ractor_self(rb_ec_ractor_ptr(ec))) {
67 rb_bug(
"recursive ractor locking");
75#if RACTOR_CHECK_MODE > 0
77 if (ec != NULL && r->sync.locked_by != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
78 rp(r->sync.locked_by);
79 rb_bug(
"ractor lock is not acquired.");
85ractor_lock(
rb_ractor_t *r,
const char *file,
int line)
87 RUBY_DEBUG_LOG2(file, line,
"locking r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
89 ASSERT_ractor_unlocking(r);
95 VM_ASSERT(!cr->malloc_gc_disabled);
96 cr->malloc_gc_disabled =
true;
99#if RACTOR_CHECK_MODE > 0
102 r->sync.locked_by = rb_ractor_self(cr);
106 RUBY_DEBUG_LOG2(file, line,
"locked r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
110ractor_lock_self(
rb_ractor_t *cr,
const char *file,
int line)
112 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
113#if RACTOR_CHECK_MODE > 0
114 VM_ASSERT(cr->sync.locked_by != cr->pub.self);
116 ractor_lock(cr, file, line);
120ractor_unlock(
rb_ractor_t *r,
const char *file,
int line)
122 ASSERT_ractor_locking(r);
123#if RACTOR_CHECK_MODE > 0
124 r->sync.locked_by =
Qnil;
130 VM_ASSERT(cr->malloc_gc_disabled);
131 cr->malloc_gc_disabled =
false;
136 RUBY_DEBUG_LOG2(file, line,
"r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
140ractor_unlock_self(
rb_ractor_t *cr,
const char *file,
int line)
142 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
143#if RACTOR_CHECK_MODE > 0
144 VM_ASSERT(cr->sync.locked_by == cr->pub.self);
146 ractor_unlock(cr, file, line);
149#define RACTOR_LOCK(r) ractor_lock(r, __FILE__, __LINE__)
150#define RACTOR_UNLOCK(r) ractor_unlock(r, __FILE__, __LINE__)
151#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
152#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
163 RACTOR_UNLOCK_SELF(r);
169ractor_status_str(
enum ractor_status status)
172 case ractor_created:
return "created";
173 case ractor_running:
return "running";
174 case ractor_blocking:
return "blocking";
175 case ractor_terminated:
return "terminated";
177 rb_bug(
"unreachable");
181ractor_status_set(
rb_ractor_t *r,
enum ractor_status status)
183 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u [%s]->[%s]", r->pub.id, ractor_status_str(r->status_), ractor_status_str(status));
186 if (r->status_ != ractor_created) {
187 VM_ASSERT(r == GET_RACTOR());
192 switch (r->status_) {
194 VM_ASSERT(status == ractor_blocking);
197 VM_ASSERT(status == ractor_blocking||
198 status == ractor_terminated);
200 case ractor_blocking:
201 VM_ASSERT(status == ractor_running);
203 case ractor_terminated:
204 rb_bug(
"unreachable");
212ractor_status_p(
rb_ractor_t *r,
enum ractor_status status)
214 return rb_ractor_status_p(r, status);
219static void ractor_local_storage_mark(
rb_ractor_t *r);
220static void ractor_local_storage_free(
rb_ractor_t *r);
224static size_t ractor_sync_memsize(
const rb_ractor_t *r);
228mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
232 if (hook_list->type == hook_list_type_targeted_iseq) {
233 rb_gc_mark((
VALUE)key);
237 RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
238 rb_gc_mark(def->body.bmethod.proc);
240 rb_hook_list_mark(hook_list);
248 rb_gc_mark(th->self);
252 if (th->root_fiber) {
253 VALUE root_fiber_self = rb_fiberptr_self(th->root_fiber);
254 if (root_fiber_self) rb_gc_mark(root_fiber_self);
259 VALUE ec_fiber_self = (th->ec && th->ec->fiber_ptr) ? rb_fiberptr_self(th->ec->fiber_ptr) : 0;
261 rb_gc_mark(ec_fiber_self);
264 rb_execution_context_mark(th->ec);
269 rb_thread_mark_owned_roots(th);
285 ractor_sync_mark(ctx, r);
289 rb_hook_list_mark(&r->pub.hooks);
290 if (r->pub.targeted_hooks.num_entries) {
291 st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
294 if (r->threads.cnt > 0) {
296 ccan_list_for_each(&r->threads.set, th, lt_node) {
297 VM_ASSERT(th != NULL);
298 ractor_mark_thread(th);
309 if (dying_th) ractor_mark_thread(dying_th);
311 ractor_local_storage_mark(r);
315ractor_mark(
void *ptr)
332 if (!rb_gc_multi_objspace_p()) {
333 ractor_mark_unshareable_parts(&ctx, r);
334 rb_ractor_mark_terminated_join_value(r);
336 else if (rb_gc_during_global_gc_p()) {
341 rb_ractor_mark_terminated_join_value(r);
358 rb_ractor_mark_terminated_join_value(r);
359 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
360 rb_gc_mark_registered_addrs(r,
true);
369 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
370 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
371 ractor_mark_unshareable_parts(ctx, r);
376 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
383rb_ractor_mark_terminated_join_value(
rb_ractor_t *r)
388 rb_gc_mark_vm_stack_values((
long)numberof(slots), slots);
397 if (src->registered_marks_cnt == 0)
return;
398 size_t need = dst->registered_marks_cnt + src->registered_marks_cnt;
399 if (need > dst->registered_marks_capa) {
400 size_t nc = dst->registered_marks_capa ? dst->registered_marks_capa : 64;
401 while (nc < need) nc *= 2;
402 VALUE *p = realloc(dst->registered_marks, nc *
sizeof(
VALUE));
403 if (!p) rb_bug(
"rb_ractor_absorb_registered_marks: out of memory");
404 dst->registered_marks = p;
405 dst->registered_marks_capa = nc;
407 MEMCPY(dst->registered_marks + dst->registered_marks_cnt,
408 src->registered_marks,
VALUE, src->registered_marks_cnt);
409 dst->registered_marks_cnt = need;
410 src->registered_marks_cnt = 0;
419 if (src->registered_addrs_cnt > 0) {
420 size_t need = dst->registered_addrs_cnt + src->registered_addrs_cnt;
421 if (need > dst->registered_addrs_capa) {
422 size_t nc = dst->registered_addrs_capa ? dst->registered_addrs_capa : 64;
423 while (nc < need) nc *= 2;
426 if (!p) rb_bug(
"rb_ractor_absorb_registered_addrs_without_gc: out of memory");
427 dst->registered_addrs = p;
428 dst->registered_addrs_capa = nc;
430 MEMCPY(dst->registered_addrs + dst->registered_addrs_cnt,
432 dst->registered_addrs_cnt = need;
433 src->registered_addrs_cnt = 0;
434 rb_gc_registered_addrs_enroll_without_gc(vm, dst);
436 rb_gc_registered_addrs_unenroll_without_gc(vm, src);
441free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
444 rb_hook_list_free(hook_list);
449free_targeted_hooks(
st_table *hooks_tbl)
451 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
457ractor_free(
void *ptr)
460 RUBY_DEBUG_LOG(
"free r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
462 free_targeted_hooks(&r->pub.targeted_hooks);
463 rb_thread_sched_destroy(&r->threads.sched);
465 ractor_local_storage_free(r);
466 rb_hook_list_free(&r->pub.hooks);
467 rb_st_free_embedded_table(&r->pub.targeted_hooks);
469 if (r->newobj_cache) {
472 rb_gc_ractor_cache_free(r->newobj_cache);
473 r->newobj_cache = NULL;
480 if (r->objspace && !r->main_ractor) {
481 rb_gc_objspace_disown(r->objspace);
487 if (r->in_terminated_set) {
489 ccan_list_del(&r->vmlr_node);
490 r->in_terminated_set =
false;
497 if (!r->main_ractor) {
498 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
499 rb_ractor_absorb_registered_addrs_without_gc(GET_VM()->ractor.main_ractor, r);
503 rb_gc_registered_addrs_unenroll_without_gc(GET_VM(), r);
506 free(r->registered_marks);
507 r->registered_marks = NULL;
508 r->registered_marks_cnt = r->registered_marks_capa = 0;
510 free(r->registered_addrs);
511 r->registered_addrs = NULL;
512 r->registered_addrs_cnt = r->registered_addrs_capa = 0;
514 if (!r->main_ractor) {
520targeted_hook_list_memsize_i(st_data_t key, st_data_t val, st_data_t arg)
522 size_t *size = (
size_t *)arg;
525 *size +=
sizeof(
rb_hook_list_t) + rb_hook_list_memsize(hook_list);
531ractor_memsize(
const void *ptr)
536 size += ractor_sync_memsize(r);
538 size += rb_st_memsize(&r->pub.targeted_hooks) -
sizeof(
struct st_table);
539 st_foreach(&r->pub.targeted_hooks, targeted_hook_list_memsize_i, (st_data_t)&size);
540 size += rb_hook_list_memsize(&r->pub.hooks);
542 if (r->local_storage) {
543 size += st_memsize(r->local_storage);
545 if (r->idkey_local_storage) {
546 size += rb_id_table_memsize(r->idkey_local_storage);
549 size += r->registered_marks_capa *
sizeof(
VALUE);
556ractor_update_references(
void *ptr)
568 ractor_update_references,
576 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
585RACTOR_PTR(
VALUE self)
587 VM_ASSERT(rb_ractor_p(self));
592#define MAIN_RACTOR_ID 1
593static rb_serial_t ractor_last_id = MAIN_RACTOR_ID;
595#include "ractor_sync.c"
606 VM_ASSERT(RB_VM_LOCKED_P() || !rb_multi_ractor_p());
607 return ++ractor_last_id;
613 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
614 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
619 if (vm->ractor.cnt == 1) {
623 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
626 if (r->newobj_cache) {
627 VM_ASSERT(r == ruby_single_main_ractor);
630 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
635cancel_single_ractor_mode(
void)
638 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
640 ruby_single_main_ractor = NULL;
641 rb_yjit_invalidate_single_ractor();
642 rb_zjit_invalidate_single_ractor();
644 ASSERT_vm_unlocking();
651 VM_ASSERT(ractor_status_p(r, ractor_created));
653 if (rb_multi_ractor_p()) {
656 vm_insert_ractor0(vm, r,
false);
657 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
662 if (cur && cur->creating_child_objspace == r->objspace) {
663 cur->creating_child_objspace = NULL;
669 if (vm->ractor.cnt == 0) {
671 vm_insert_ractor0(vm, r,
true);
672 ractor_status_set(r, ractor_blocking);
673 ractor_status_set(r, ractor_running);
676 cancel_single_ractor_mode();
677 vm_insert_ractor0(vm, r,
true);
678 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
683 if (cur && cur->creating_child_objspace == r->objspace) {
684 cur->creating_child_objspace = NULL;
693 VM_ASSERT(ractor_status_p(cr, ractor_running));
694 VM_ASSERT(vm->ractor.cnt > 1);
695 VM_ASSERT(cr->threads.cnt == 1);
699 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
700 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
702 VM_ASSERT(vm->ractor.cnt > 0);
703 ccan_list_del(&cr->vmlr_node);
708 if (!rb_gc_multi_objspace_p()) {
710 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
711 cr->in_terminated_set =
true;
715 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
719 rb_gc_ractor_cache_free(cr->newobj_cache);
720 cr->newobj_cache = NULL;
730 rb_gc_objspace_retire(&cr->objspace);
734 ractor_status_set(cr, ractor_terminated);
746 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
747 VM_ASSERT(th->ec != NULL);
750 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
755 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
756 rb_gc_objspace_postmortem_self();
760 pf->th = (th->self == 0) ? th : NULL;
761 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
767 if (pf->fiber == NULL && pf->th == NULL)
return;
772#ifdef RB_THREAD_LOCAL_SPECIFIER
773 rb_current_ec_set(NULL);
775 native_tls_set(ruby_current_ec_key, NULL);
779 if (pf->fiber) rb_fiber_free_body(pf->fiber);
780 if (pf->th) rb_thread_free_body(pf->th);
784ractor_alloc(
VALUE klass)
790 r->next_ec_serial = 1;
791 VM_ASSERT(ractor_status_p(r, ractor_created));
798 .pub.id = MAIN_RACTOR_ID,
805rb_ractor_main_alloc(
void)
810 ruby_single_main_ractor = r;
815#if defined(HAVE_WORKING_FORK)
823 vm->ractor.blocking_cnt = 0;
826 rb_gc_disable_holders_atfork();
830 th->ractor->creating_child_objspace = NULL;
831 ruby_single_main_ractor = th->ractor;
832 th->ractor->status_ = ractor_created;
834 rb_ractor_living_threads_init(th->ractor);
835 rb_ractor_living_threads_insert(th->ractor, th);
837 VM_ASSERT(vm->ractor.blocking_cnt == 0);
838 VM_ASSERT(vm->ractor.cnt == 1);
844 rb_gc_ractor_cache_free(r->newobj_cache);
845 r->newobj_cache = NULL;
846 r->status_ = ractor_terminated;
848 r->threads.dying_th = NULL;
849 if (!rb_gc_multi_objspace_p()) {
850 ccan_list_del(&r->vmlr_node);
851 ccan_list_add(&vm->ractor.terminated_set, &r->vmlr_node);
852 r->in_terminated_set =
true;
858 rb_gc_objspace_retire(&r->objspace);
860 ractor_sync_terminate_atfork(vm, r);
869 ccan_list_head_init(&r->threads.set);
871 r->threads.blocking_cnt = 0;
872 r->threads.terminating =
false;
874 r->threads.dying_th = NULL;
881 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
882 r->pub.hooks.type = hook_list_type_ractor_local;
885 rb_thread_sched_init(&r->threads.sched,
false);
886 rb_ractor_living_threads_init(r);
892 enc = rb_enc_get(name);
893 if (!rb_enc_asciicompat(enc)) {
894 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
911 r->threads.main = th;
912 rb_ractor_living_threads_insert(r, th);
913 rb_ractor_setup_default_port(r);
921 VALUE rv = ractor_alloc(self);
923 ractor_init(r, name, loc);
926 r->pub.id = ractor_next_id();
928 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", r->pub.id);
931 r->verbose = cr->verbose;
932 r->debug = cr->debug;
936 r->objspace = rb_gc_objspace_alloc();
938 rb_thread_create_ractor(r, args, block);
949 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
956 ractor_notify_exit(ec, cr, result, exc);
964 ractor_postmortem_collect(th, pf);
965 ractor_send_exit_tokens(th->ec, th->ractor);
972 ractor_atexit(ec, cr, result,
false);
979 ractor_atexit(ec, cr, ec->errinfo,
true);
989 VM_ASSERT(cr->threads.main != NULL);
990 cr->threads.main = NULL;
997 for (
int i=0; i<
len; i++) {
998 ptr[i] = ractor_receive(ec, ractor_default_port(r), NULL);
1006 for (
int i=0; i<
len; i++) {
1007 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
1012rb_ractor_main_p_(
void)
1014 VM_ASSERT(rb_multi_ractor_p());
1016 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
1022 return r->threads.cnt;
1027rb_ractor_thread_list(
void)
1033 ccan_list_for_each(&r->threads.set, th, lt_node) {
1034 switch (th->status) {
1035 case THREAD_RUNNABLE:
1036 case THREAD_STOPPED:
1037 case THREAD_STOPPED_FOREVER:
1050 VM_ASSERT(th != NULL);
1054 RUBY_DEBUG_LOG(
"r(%"PRI_SERIALT_PREFIX
"u)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
1055 ccan_list_add_tail(&r->threads.set, &th->lt_node);
1061 if (r->threads.cnt == 1) {
1062 VM_ASSERT(ractor_status_p(r, ractor_created));
1063 vm_insert_ractor(th->vm, r);
1070 ractor_status_set(r, ractor_blocking);
1072 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
1073 vm->ractor.blocking_cnt++;
1074 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
1078rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1080 ASSERT_vm_locking();
1081 VM_ASSERT(GET_RACTOR() == cr);
1082 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
1086rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1088 ASSERT_vm_locking();
1089 VM_ASSERT(GET_RACTOR() == cr);
1091 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
1092 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1093 vm->ractor.blocking_cnt--;
1095 ractor_status_set(cr, ractor_running);
1106 ccan_list_del(&th->lt_node);
1114 VM_ASSERT(vm->ractor.cnt > 1);
1115 ccan_list_del(&r->vmlr_node);
1120 VM_ASSERT(r->status_ == ractor_blocking);
1121 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1122 vm->ractor.blocking_cnt--;
1124 rb_gc_ractor_cache_free(r->newobj_cache);
1125 r->newobj_cache = NULL;
1128 rb_gc_objspace_disown(r->objspace);
1131 r->status_ = ractor_terminated;
1139 VM_ASSERT(cr == GET_RACTOR());
1140 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
1142 if (cr->threads.cnt == 1) {
1143 vm_remove_ractor(th->vm, cr);
1148 ccan_list_del(&th->lt_node);
1156rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1158 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1160 VM_ASSERT(cr->threads.cnt > 0);
1161 VM_ASSERT(cr == GET_RACTOR());
1163 cr->threads.blocking_cnt++;
1167rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1169 RUBY_DEBUG_LOG2(file, line,
1170 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1171 cr->threads.blocking_cnt, cr->threads.cnt);
1173 VM_ASSERT(cr == GET_RACTOR());
1175 cr->threads.blocking_cnt--;
1179rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1181 VM_ASSERT(r != GET_RACTOR());
1182 ASSERT_ractor_unlocking(r);
1183 ASSERT_vm_locking();
1187 if (ractor_status_p(r, ractor_running)) {
1190 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1198rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1200 VM_ASSERT(r != GET_RACTOR());
1201 ASSERT_ractor_unlocking(r);
1202 ASSERT_vm_locking();
1206 if (main_th->status != THREAD_KILLED) {
1207 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1208 rb_threadptr_interrupt(main_th);
1211 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1219ractor_terminal_interrupt_all(
rb_vm_t *vm)
1221 if (vm->ractor.cnt > 1) {
1224 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1225 if (r != vm->ractor.main_ractor) {
1226 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
1227 rb_ractor_terminate_interrupt_main_thread(r);
1237rb_ractor_terminate_all(
void)
1242 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1244 VM_ASSERT(cr == GET_RACTOR());
1248 ractor_terminal_interrupt_all(vm);
1251 rb_thread_terminate_all(GET_THREAD());
1255 while (vm->ractor.cnt > 1) {
1256 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1257 vm->ractor.sync.terminate_waiting =
true;
1260 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1261 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1262 rb_ractor_sched_wait_terminate(vm, &vm->ractor.sync.terminate_cond, 1000 );
1263 while (vm->ractor.sched.barrier_is_waiting) {
1270 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1272 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1273 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1275 ractor_terminal_interrupt_all(vm);
1282 rb_gc_objspace_absorb_all_zombies();
1286rb_vm_main_ractor_ec(
rb_vm_t *vm)
1303 if (running_ec) {
return running_ec; }
1304 return vm->ractor.main_thread->ec;
1308ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1310 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1412 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1413 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1414 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1416 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1420 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1423 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1427 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1428 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1429 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1430 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1448 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1449 if (r != vm->ractor.main_ractor) {
1450 fprintf(stderr,
"r:%"PRI_SERIALT_PREFIX
"u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1458 if (rb_ractor_main_p()) {
1463 if (UNLIKELY(cr->r_stdin == 0)) {
1464 cr->r_stdin = rb_io_prep_stdin();
1471rb_ractor_stdout(
void)
1473 if (rb_ractor_main_p()) {
1478 if (UNLIKELY(cr->r_stdout == 0)) {
1479 cr->r_stdout = rb_io_prep_stdout();
1481 return cr->r_stdout;
1486rb_ractor_stderr(
void)
1488 if (rb_ractor_main_p()) {
1493 if (UNLIKELY(cr->r_stderr == 0)) {
1494 cr->r_stderr = rb_io_prep_stderr();
1496 return cr->r_stderr;
1503 if (rb_ractor_main_p()) {
1515 if (rb_ractor_main_p()) {
1527 if (rb_ractor_main_p()) {
1540 return &cr->pub.targeted_hooks;
1544rb_obj_set_shareable_no_assert(
VALUE obj)
1551 rb_gc_obj_became_shareable(obj);
1555 bool froze_ivars =
false;
1559 RBASIC_SET_SHAPE_ID(obj, rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj)));
1570 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1571 if (imemo_type_p(fields, imemo_fields)) {
1574 rb_gc_obj_became_shareable(fields);
1576 if (froze_ivars) RBASIC_SET_SHAPE_ID(fields, RBASIC_SHAPE_ID(obj));
1580 rb_imemo_fields_record_shrefs(fields);
1585#ifndef STRICT_VERIFY_SHAREABLE
1586#define STRICT_VERIFY_SHAREABLE 0
1590rb_ractor_verify_shareable(
VALUE obj)
1592#if STRICT_VERIFY_SHAREABLE
1593 rb_gc_verify_shareable(obj);
1603 rb_obj_set_shareable_no_assert(obj);
1615enum obj_traverse_iterator_result {
1621typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1622typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1623typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1625static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1628 rb_obj_traverse_enter_func enter_func;
1629 rb_obj_traverse_leave_func leave_func;
1648 if (obj_traverse_i(key, d->data)) {
1653 if (obj_traverse_i(val, d->data)) {
1662obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1669 if (!rb_objspace_live_object_p(obj)) {
1675 if (obj_traverse_i(obj, d->data)) {
1688 rb_objspace_reachable_objects_from_local(obj, obj_traverse_reachable_i, &d);
1695 if (UNLIKELY(!data->rec)) {
1696 data->rec_hash = rb_ident_hash_new();
1698 data->rec = RHASH_ST_TABLE(data->rec_hash);
1704obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1708 if (obj_traverse_i(val, d->data)) {
1721 switch (data->enter_func(obj)) {
1722 case traverse_cont:
break;
1723 case traverse_skip:
return 0;
1724 case traverse_stop:
return 1;
1727 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1733 if (rb_obj_shape_has_ivars(obj)) {
1739 if (d.stop)
return 1;
1757 rb_ary_cancel_sharing(obj);
1761 if (obj_traverse_i(e, data))
return 1;
1775 if (d.stop)
return 1;
1782 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1785 if (obj_traverse_i(ptr[i], data))
return 1;
1791 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1795 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1796 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1799 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1800 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1805 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1808 if (!ptr || !
type->function.dmark) {
1811 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1812 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1813 for (; *offsets != RUBY_REF_END; offsets++) {
1814 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1815 if (obj_traverse_i(ref, data))
return 1;
1819 if (obj_traverse_reachable(obj, data))
return 1;
1826 if (obj_traverse_reachable(obj, data))
return 1;
1835 rb_bug(
"unreachable");
1838 if (data->leave_func(obj) == traverse_stop) {
1847 rb_obj_traverse_final_func final_func;
1852obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1855 if (data->final_func(key)) {
1865rb_obj_traverse(
VALUE obj,
1866 rb_obj_traverse_enter_func enter_func,
1867 rb_obj_traverse_leave_func leave_func,
1868 rb_obj_traverse_final_func final_func)
1871 .enter_func = enter_func,
1872 .leave_func = leave_func,
1876 if (obj_traverse_i(obj, &data))
return 1;
1877 if (final_func && data.rec) {
1879 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1886allow_frozen_shareable_p(
VALUE obj)
1896 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1905make_shareable_freeze(
VALUE obj)
1908 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1911 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1914 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1915 rb_hash_freeze(obj);
1922static enum obj_traverse_iterator_result
1923make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1926 make_shareable_freeze(obj);
1929 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1933 return traverse_skip;
1940static int obj_refer_only_shareables_p(
VALUE obj);
1942static enum obj_traverse_iterator_result
1943make_shareable_check_shareable(
VALUE obj)
1948 return traverse_skip;
1950 else if (!allow_frozen_shareable_p(obj)) {
1952 rb_raise(rb_eRactorError,
1953 "can not make shareable object for %+"PRIsVALUE, obj);
1955 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1956 if (obj_refer_only_shareables_p(obj)) {
1957 make_shareable_check_shareable_freeze(obj, traverse_skip);
1959 return traverse_skip;
1962 rb_raise(rb_eRactorError,
1963 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1967 rb_proc_ractor_make_shareable(obj,
Qundef);
1968 return traverse_cont;
1971 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1975 switch (
TYPE(obj)) {
1977 return traverse_skip;
1984 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1985 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1986 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1987 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1996 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1999static enum obj_traverse_iterator_result
2000mark_shareable(
VALUE obj)
2003 rb_str_make_independent(obj);
2006 rb_obj_set_shareable_no_assert(obj);
2007 return traverse_cont;
2013 rb_obj_traverse(obj,
2014 make_shareable_check_shareable,
2015 null_leave, mark_shareable);
2024 VALUE copy = ractor_copy(obj);
2029rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
2032 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
2040rb_ractor_ensure_main_ractor(
const char *msg)
2042 if (!rb_ractor_main_p()) {
2043 rb_raise(rb_eRactorIsolationError,
"%s", msg);
2047static enum obj_traverse_iterator_result
2048shareable_p_enter(
VALUE obj)
2051 return traverse_skip;
2057 mark_shareable(obj);
2058 return traverse_skip;
2061 allow_frozen_shareable_p(obj)) {
2062 return traverse_cont;
2070 if (obj_refer_only_shareables_p(obj)) {
2071 mark_shareable(obj);
2072 return traverse_skip;
2076 return traverse_stop;
2080rb_ractor_shareable_p_continue(
VALUE obj)
2082 if (rb_obj_traverse(obj,
2083 shareable_p_enter, null_leave,
2092static enum obj_traverse_iterator_result
2093null_leave(
VALUE obj)
2095 return traverse_cont;
2111 rb_obj_traverse_replace_enter_func enter_func;
2112 rb_obj_traverse_replace_leave_func leave_func;
2118 VALUE rec_keepalive;
2131obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2137obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2142 if (obj_traverse_replace_i(*key, data)) {
2146 else if (*key != data->replacement) {
2147 VALUE v = *key = data->replacement;
2151 if (obj_traverse_replace_i(*val, data)) {
2155 else if (*val != data->replacement) {
2156 VALUE v = *val = data->replacement;
2164obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2170obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2175 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2179 else if (*(
VALUE *)val != data->replacement) {
2190 if (UNLIKELY(!data->rec)) {
2191 data->rec = st_init_numtable();
2198obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2200 int *pcnt = (
int *)ptr;
2202 if (!rb_objspace_live_object_p(obj)) {
2212obj_refer_only_shareables_p(
VALUE obj)
2215 rb_objspace_reachable_objects_from_local(obj, obj_refer_only_shareables_p_i, &cnt);
2222 st_data_t replacement;
2225 data->replacement = obj;
2232 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2233 data->replacement = (
VALUE)replacement;
2237 switch (data->enter_func(obj, data)) {
2238 case traverse_cont:
break;
2239 case traverse_skip:
return 0;
2240 case traverse_stop:
return 1;
2243 replacement = (st_data_t)data->replacement;
2244 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2253#define CHECK_AND_REPLACE(parent_obj, v) do { \
2255 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2256 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2259 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2260 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2262 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2268 rb_st_foreach_with_replace(
2269 rb_imemo_fields_complex_tbl(fields_obj),
2270 obj_iv_hash_traverse_replace_foreach_i,
2271 obj_iv_hash_traverse_replace_i,
2274 if (d.stop)
return 1;
2277 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2278 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2279 for (uint32_t i = 0; i < fields_count; i++) {
2280 CHECK_AND_REPLACE(fields_obj, fields[i]);
2294 rb_str_make_independent(obj);
2299 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2300 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2301 if (rb_shape_complex_p(shape_id)) {
2307 rb_st_foreach_with_replace(
2308 rb_imemo_fields_complex_tbl(fields_obj),
2309 obj_iv_hash_traverse_replace_foreach_i,
2310 obj_iv_hash_traverse_replace_i,
2313 if (d.stop)
return 1;
2316 attr_index_t
len = RSHAPE_LEN(shape_id);
2317 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2319 for (attr_index_t i = 0; i <
len; i++) {
2320 CHECK_AND_REPLACE(obj, ptr[i]);
2328 rb_ary_cancel_sharing(obj);
2333 if (obj_traverse_replace_i(e, data)) {
2336 else if (e != data->replacement) {
2350 rb_hash_stlike_foreach_with_replace(obj,
2351 obj_hash_traverse_replace_foreach_i,
2352 obj_hash_traverse_replace_i,
2354 if (d.stop)
return 1;
2358 if (obj_traverse_replace_i(ifnone, data)) {
2361 else if (ifnone != data->replacement) {
2370 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2373 CHECK_AND_REPLACE(obj, ptr[i]);
2379 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2383 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2384 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2387 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2388 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2392 if (!data->move && obj_refer_only_shareables_p(obj)) {
2396 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2410 rb_bug(
"unreachable");
2413 data->replacement = (
VALUE)replacement;
2415 if (data->leave_func(obj, data) == traverse_stop) {
2426rb_obj_traverse_replace(
VALUE obj,
2427 rb_obj_traverse_replace_enter_func enter_func,
2428 rb_obj_traverse_replace_leave_func leave_func,
2432 .enter_func = enter_func,
2433 .leave_func = leave_func,
2440 int stopped = obj_traverse_replace_i(obj, &data);
2444 if (data.rec) st_free_table(data.rec);
2451 return data.replacement;
2461enum courier_node_kind {
2463 COURIER_KIND_BACKTRACE,
2464 COURIER_KIND_STRING,
2467 COURIER_KIND_OBJECT,
2468 COURIER_KIND_STRUCT,
2471 COURIER_KIND_REGEXP,
2472 COURIER_KIND_HOOKED,
2479 COURIER_HOOK_MARSHAL_DUMP,
2481 COURIER_HOOK_COMPAT,
2482 COURIER_HOOK_DUMP_DATA,
2486static enum courier_hook
2487courier_hook_of(
VALUE obj)
2489 if (
rb_obj_respond_to(obj, id_marshal_dump, TRUE))
return COURIER_HOOK_MARSHAL_DUMP;
2491 if (rb_marshal_compat_lookup(
CLASS_OF(obj), NULL, NULL))
return COURIER_HOOK_COMPAT;
2493 return COURIER_HOOK_NONE;
2497 enum courier_node_kind kind;
2508 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2509 struct {
VALUE klass; } obj;
2511 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2512 struct {
void *blob;
int size; } bt;
2513 struct {
VALUE src;
int options;
VALUE klass; } re;
2514 struct {
VALUE klass; uint32_t payload_id;
enum courier_hook hook; } hooked;
2521 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2529#define COURIER_ID_REF_BIT 0x80000000u
2537 uint32_t refs_count;
2565 uint32_t
capa = c->capa ? c->capa * 2 : 8;
2571 ruby_xfree(old_nodes);
2578 uint32_t
capa = c->refs_capa ? c->refs_capa * 2 : 8;
2580 if (c->refs_count > 0)
MEMCPY(refs, c->refs,
VALUE, c->refs_count);
2581 VALUE *old_refs = c->refs;
2583 c->refs_capa =
capa;
2584 ruby_xfree(old_refs);
2590 if (RB_UNLIKELY(c->count == c->capa)) courier_grow_nodes(c);
2595 n->kind = COURIER_KIND_REF;
2611 c->order =
ALLOC_N(uint32_t, nodes);
2616 c->refs_capa = refs;
2628 if (RB_UNLIKELY(c->refs_count == c->refs_capa)) courier_grow_refs(c);
2629 c->refs[c->refs_count] = v;
2630 return COURIER_ID_REF_BIT | c->refs_count++;
2637 if (
id & COURIER_ID_REF_BIT)
return c->refs[
id & ~COURIER_ID_REF_BIT];
2644move_neutralize_source(
VALUE obj)
2649 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2650 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2660 bool wipe_body =
true;
2663 if (!STR_EMBED_P(obj) && !rb_str_reembeddable_p(obj)) {
2668 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2670 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2674 wipe_body = !rb_str_embedded_shared_root_p(obj);
2677 if (!ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && (ARY_SHARED_ROOT_P(obj) ||
OBJ_FROZEN(obj))) {
2682 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2684 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2685 if (!ARY_SHARED_ROOT_P(obj)) {
2688 RARRAY(obj)->as.heap.len = 0;
2692 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2704 size_t slot_size = rb_gc_obj_slot_size(obj);
2705 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2706 RBASIC(obj)->flags = flags;
2707 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2725courier_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2728 uint32_t kid = courier_capture(hc->b, (
VALUE)key);
2729 uint32_t vid = courier_capture(hc->b, (
VALUE)val);
2730 hc->kv[hc->i++] = kid;
2731 hc->kv[hc->i++] = vid;
2744courier_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2747 if (oc->n == oc->capa) {
2748 oc->capa = oc->capa ? oc->capa * 2 : 4;
2750 REALLOC_N(oc->vals, uint32_t, oc->capa);
2752 uint32_t vid = courier_capture(oc->b, val);
2753 oc->ids[oc->n] = name;
2754 oc->vals[oc->n] = vid;
2766 rb_ivar_foreach_buffered(obj, courier_capture_ivar_i, (st_data_t)&oc);
2767 b->c->nodes[id].niv = (uint32_t)oc.n;
2768 b->c->nodes[id].iv_ids = oc.ids;
2769 b->c->nodes[id].iv_vals = oc.vals;
2777courier_capture_hooked(
struct courier_build *b,
VALUE obj, uint32_t
id,
enum courier_hook hook)
2783 case COURIER_HOOK_DUMP: {
2792 case COURIER_HOOK_MARSHAL_DUMP:
2793 payload =
rb_funcallv(obj, id_marshal_dump, 0, 0);
2795 case COURIER_HOOK_DUMP_DATA:
2798 case COURIER_HOOK_COMPAT: {
2800 rb_marshal_compat_lookup(klass, &dumper, NULL);
2801 payload = dumper(obj);
2805 rb_bug(
"courier_capture_hooked: no dump protocol");
2808 uint32_t payload_id = courier_capture(b, payload);
2810 b->c->nodes[id].kind = COURIER_KIND_HOOKED;
2811 b->c->nodes[id].u.hooked.klass = klass;
2812 b->c->nodes[id].u.hooked.hook = hook;
2813 b->c->nodes[id].u.hooked.payload_id = payload_id;
2833 return courier_alloc_ref(b->c, obj);
2841 if (st_lookup(b->c->seen, (st_data_t)obj, &existing)) {
2842 return (uint32_t)existing - 1;
2846 return courier_alloc_ref(b->c, obj);
2849 uint32_t
id = courier_alloc_node(b->c);
2850 st_insert(b->c->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2854 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2858 b->c->nodes[id].frozen = frozen;
2859 courier_capture_ivars(b, obj,
id);
2866 if (!b->copy) rb_str_make_independent(obj);
2871 const int termlen = rb_enc_mbminlen(rb_enc_from_index(encidx));
2874 if (!b->copy && !STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2877 ptr =
RSTRING(obj)->as.heap.ptr;
2885 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2886 memset(ptr +
len, 0, termlen);
2889 b->c->nodes[id].kind = COURIER_KIND_STRING;
2890 b->c->nodes[id].u.str.klass = courier_klass(b, obj);
2891 b->c->nodes[id].u.str.ptr = ptr;
2892 b->c->nodes[id].u.str.len =
len;
2893 b->c->nodes[id].u.str.capa =
capa;
2894 b->c->nodes[id].u.str.encidx = encidx;
2902 elems[i] = courier_capture(b,
RARRAY_AREF(obj, i));
2904 b->c->nodes[id].kind = COURIER_KIND_ARRAY;
2905 b->c->nodes[id].u.ary.klass = courier_klass(b, obj);
2906 b->c->nodes[id].u.ary.len =
len;
2907 b->c->nodes[id].u.ary.elems = elems;
2911 if (!b->copy && !ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2918 uint32_t ifnone_id = courier_capture(b,
RHASH_IFNONE(obj));
2921 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2923 rb_hash_stlike_foreach(obj, courier_capture_hash_i, (st_data_t)&hc);
2924 b->c->nodes[id].kind = COURIER_KIND_HASH;
2925 b->c->nodes[id].u.hash.klass = courier_klass(b, obj);
2926 b->c->nodes[id].u.hash.size = size;
2927 b->c->nodes[id].u.hash.kv = kv;
2928 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2929 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2930 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2932 if (!b->copy) rb_hash_free(obj);
2937 b->c->nodes[id].kind = COURIER_KIND_OBJECT;
2938 b->c->nodes[id].u.obj.klass = courier_klass(b, obj);
2945 elems[i] = courier_capture(b,
RSTRUCT_GET(obj, (
int)i));
2947 b->c->nodes[id].kind = COURIER_KIND_STRUCT;
2948 b->c->nodes[id].u.strct.len =
len;
2949 b->c->nodes[id].u.strct.elems = elems;
2950 b->c->nodes[id].u.strct.klass = courier_klass(b, obj);
2952 if (!b->copy && RSTRUCT_EMBED_LEN(obj) == 0) {
2953 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2963 void *regs = rb_match_blob_dump(obj, &re, &st, &nregs, !b->copy);
2964 uint32_t rid = courier_capture(b, re);
2965 uint32_t sid = courier_capture(b, st);
2966 b->c->nodes[id].kind = COURIER_KIND_MATCH;
2967 b->c->nodes[id].u.match.regexp_id = rid;
2968 b->c->nodes[id].u.match.str_id = sid;
2969 b->c->nodes[id].u.match.num_regs = nregs;
2970 b->c->nodes[id].u.match.regs = regs;
2971 b->c->nodes[id].u.match.klass = courier_klass(b, obj);
2977 VM_ASSERT(!b->copy);
2983 uint32_t pathv_id = courier_capture(b, fptr->
pathv);
2984 uint32_t ecopts_id = courier_capture(b, fptr->
encs.
ecopts);
2987 uint32_t timeout_id = courier_capture(b, fptr->
timeout);
2995 fptr->wakeup_mutex =
Qnil;
2997 b->c->nodes[id].kind = COURIER_KIND_IO;
2998 b->c->nodes[id].u.io.fptr = fptr;
2999 b->c->nodes[id].u.io.klass = courier_klass(b, obj);
3000 b->c->nodes[id].u.io.pathv_id = pathv_id;
3001 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
3002 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
3003 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
3004 b->c->nodes[id].u.io.timeout_id = timeout_id;
3015 b->c->nodes[id].kind = COURIER_KIND_REGEXP;
3016 b->c->nodes[id].u.re.klass = courier_klass(b, obj);
3017 b->c->nodes[id].u.re.src = src;
3025 if (b->copy && rb_backtrace_p(obj)) {
3027 void *blob = rb_backtrace_blob_dump(obj, &size);
3028 b->c->nodes[id].kind = COURIER_KIND_BACKTRACE;
3029 b->c->nodes[id].u.bt.blob = blob;
3030 b->c->nodes[id].u.bt.size = size;
3037 enum courier_hook hook = b->copy ? courier_hook_of(obj) : COURIER_HOOK_NONE;
3038 if (hook == COURIER_HOOK_NONE) {
3039 rb_raise(rb_eRactorError,
"can not %s a %"PRIsVALUE
" object",
3042 courier_capture_hooked(b, obj,
id, hook);
3047 if (!b->copy) move_neutralize_source(obj);
3049 b->c->order[b->ordered++] = id;
3056 uint32_t nodes, refs;
3062move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
3069move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3088 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
3089 st_insert(seen, (st_data_t)obj, 0);
3096 rb_class_check_singleton_movable(klass);
3105 move_preflight(rm->
regexp, ctx);
3106 move_preflight(rm->
str, ctx);
3115 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)ctx);
3126 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
3131 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
3133 if (
RTEST(fptr->wakeup_mutex)) {
3135 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
3137 move_preflight(fptr->
pathv, ctx);
3141 move_preflight(fptr->
timeout, ctx);
3145 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
3157 uint32_t nodes, refs;
3164copy_support_val_i(st_data_t val, st_data_t arg)
3167 if (!copy_courier_supported_p((
VALUE)val, ctx)) {
3175copy_support_ivar_i(
ID name,
VALUE val, st_data_t arg)
3177 return copy_support_val_i((st_data_t)val, arg);
3181copy_support_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3183 if (copy_support_val_i(key, arg) == ST_STOP)
return ST_STOP;
3184 return copy_support_val_i(val, arg);
3197 if (st_lookup(seen, (st_data_t)obj, NULL))
return true;
3198 st_insert(seen, (st_data_t)obj, 0);
3210 if (!copy_courier_supported_p(rm->
regexp, ctx))
return false;
3211 if (!copy_courier_supported_p(rm->
str, ctx))
return false;
3216 if (!rb_backtrace_p(obj) && courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3220 if (!copy_courier_supported_p(
RARRAY_AREF(obj, i), ctx))
return false;
3224 rb_hash_stlike_foreach(obj, copy_support_hash_i, (st_data_t)ctx);
3225 if (!ctx->ok)
return false;
3226 if (!copy_courier_supported_p(
RHASH_IFNONE(obj), ctx))
return false;
3230 if (!copy_courier_supported_p(
RSTRUCT_GET(obj, (
int)i), ctx))
return false;
3237 if (courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3252 bool ok = copy_courier_supported_p(obj, &scan);
3253 st_free_table(scan.seen);
3254 if (!ok)
return NULL;
3258 courier_reserve(c, scan.nodes, scan.refs);
3259 c->seen = st_init_numtable();
3266 enum ruby_tag_type state;
3269 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3270 c->root = courier_capture(&b, obj);
3273 st_free_table(c->seen);
3276 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3289 enum ruby_tag_type state;
3292 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3293 move_preflight(obj, &scan);
3296 st_free_table(scan.seen);
3297 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3301 courier_reserve(c, scan.nodes, scan.refs);
3302 c->seen = st_init_numtable();
3310 enum ruby_tag_type state;
3313 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3314 c->root = courier_capture(&b, obj);
3317 st_free_table(c->seen);
3319 if (state != TAG_NONE) {
3323 EC_JUMP_TAG(ec, state);
3335 RBASIC_SET_CLASS(shell, klass);
3340 rb_class_take_ownership(klass);
3353 for (uint32_t i = 0; i < c->count; i++) {
3357 case COURIER_KIND_REF:
3360 case COURIER_KIND_STRING:
3364 shell = rb_str_new_owned(n->u.str.ptr, n->u.str.len, n->u.str.capa, n->u.str.encidx);
3365 n->u.str.ptr = NULL;
3366 courier_apply_klass(shell, n->u.str.klass);
3368 case COURIER_KIND_ARRAY:
3370 courier_apply_klass(shell, n->u.ary.klass);
3372 case COURIER_KIND_HASH:
3373 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
3374 courier_apply_klass(shell, n->u.hash.klass);
3376 case COURIER_KIND_OBJECT:
3380 courier_apply_klass(shell, n->u.obj.klass);
3382 case COURIER_KIND_STRUCT:
3384 courier_apply_klass(shell, n->u.strct.klass);
3386 case COURIER_KIND_MATCH:
3387 shell = rb_match_blob_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
3388 courier_apply_klass(shell, n->u.match.klass);
3390 case COURIER_KIND_BACKTRACE:
3391 shell = rb_backtrace_blob_load(n->u.bt.blob, n->u.bt.size);
3393 case COURIER_KIND_REGEXP:
3396 shell = rb_reg_init_str(rb_reg_s_alloc(
rb_class_real(n->u.re.klass)), n->u.re.src, n->u.re.options);
3397 courier_apply_klass(shell, n->u.re.klass);
3399 case COURIER_KIND_HOOKED:
3400 if (n->u.hooked.hook == COURIER_HOOK_DUMP) {
3407 courier_apply_klass(shell, n->u.hooked.klass);
3409 case COURIER_KIND_IO:
3411 courier_apply_klass(shell, n->u.io.klass);
3412 RFILE(shell)->fptr = n->u.io.fptr;
3413 n->u.io.fptr->
self = shell;
3414 n->u.io.fptr = NULL;
3417 rb_bug(
"rb_ractor_courier_materialize: bad node kind");
3428 for (uint32_t k = 0; k < c->count; k++) {
3429 uint32_t i = c->order[k];
3433 case COURIER_KIND_ARRAY: {
3440 RARRAY_ASET(shell, j, courier_child(c, shells, n->u.ary.elems[j]));
3445 case COURIER_KIND_HASH:
3446 for (
long j = 0; j < n->u.hash.size; j++) {
3447 rb_hash_aset(shell, courier_child(c, shells, n->u.hash.kv[2 * j]),
3448 courier_child(c, shells, n->u.hash.kv[2 * j + 1]));
3451 VALUE ifnone = courier_child(c, shells, n->u.hash.ifnone_id);
3452 if (n->u.hash.proc_default) {
3453 rb_hash_set_default_proc(shell, ifnone);
3455 else if (ifnone !=
Qnil) {
3456 rb_hash_set_default(shell, ifnone);
3459 case COURIER_KIND_HOOKED: {
3460 VALUE payload = courier_child(c, shells, n->u.hooked.payload_id);
3461 VALUE klass = n->u.hooked.klass;
3463 switch (n->u.hooked.hook) {
3464 case COURIER_HOOK_DUMP:
3466 rb_raise(
rb_eTypeError,
"class %"PRIsVALUE
" needs to have method '_load'", klass);
3474 case COURIER_HOOK_MARSHAL_DUMP:
3475 case COURIER_HOOK_DUMP_DATA:
3476 mid = n->u.hooked.hook == COURIER_HOOK_MARSHAL_DUMP ? id_marshal_load : id_load_data;
3478 rb_raise(
rb_eTypeError,
"instance of %"PRIsVALUE
" needs to have method '%"PRIsVALUE
"'",
3479 klass, rb_id2str(mid));
3483 case COURIER_HOOK_COMPAT: {
3485 rb_marshal_compat_lookup(klass, NULL, &loader);
3486 loader(shell, payload);
3490 rb_bug(
"rb_ractor_courier_materialize: no dump protocol");
3494 case COURIER_KIND_STRUCT:
3495 for (
rb_len_t j = 0; j < n->u.strct.len; j++) {
3496 RSTRUCT_SET(shell, (
int)j, courier_child(c, shells, n->u.strct.elems[j]));
3499 case COURIER_KIND_MATCH:
3500 rb_match_blob_load(shell, courier_child(c, shells, n->u.match.regexp_id),
3501 courier_child(c, shells, n->u.match.str_id),
3502 n->u.match.num_regs, n->u.match.regs);
3504 case COURIER_KIND_IO: {
3519 for (uint32_t j = 0; j < n->niv; j++) {
3520 rb_ivar_set(shell, n->iv_ids[j], courier_child(c, shells, n->iv_vals[j]));
3525 for (uint32_t i = 0; i < c->count; i++) {
3532 VALUE root = (c->count || c->refs_count) ? courier_child(c, shells, c->root) :
Qnil;
3540 for (uint32_t i = 0; i < c->count; i++) {
3542 ruby_xfree(n->iv_ids);
3543 ruby_xfree(n->iv_vals);
3545 case COURIER_KIND_STRING:
3546 ruby_xfree(n->u.str.ptr);
3548 case COURIER_KIND_ARRAY:
3549 ruby_xfree(n->u.ary.elems);
3551 case COURIER_KIND_HASH:
3552 ruby_xfree(n->u.hash.kv);
3554 case COURIER_KIND_STRUCT:
3555 ruby_xfree(n->u.strct.elems);
3557 case COURIER_KIND_MATCH:
3558 rb_match_blob_free(n->u.match.regs);
3560 case COURIER_KIND_BACKTRACE:
3561 ruby_xfree(n->u.bt.blob);
3563 case COURIER_KIND_IO:
3569 n->u.io.fptr = NULL;
3576 ruby_xfree(c->nodes);
3577 ruby_xfree(c->order);
3578 ruby_xfree(c->refs);
3590 if (c->seen) rb_mark_set(c->seen);
3591 for (uint32_t i = 0; i < c->refs_count; i++) {
3594 for (uint32_t i = 0; i < c->count; i++) {
3596 if (n->kind == COURIER_KIND_REF) {
3599 else if (n->kind == COURIER_KIND_OBJECT) {
3602 else if (n->kind == COURIER_KIND_STRUCT) {
3605 else if (n->kind == COURIER_KIND_MATCH) {
3608 else if (n->kind == COURIER_KIND_IO) {
3611 else if (n->kind == COURIER_KIND_STRING) {
3614 else if (n->kind == COURIER_KIND_BACKTRACE) {
3615 rb_backtrace_blob_mark_ctx(ctx, n->u.bt.blob, n->u.bt.size);
3617 else if (n->kind == COURIER_KIND_ARRAY) {
3620 else if (n->kind == COURIER_KIND_HASH) {
3623 else if (n->kind == COURIER_KIND_REGEXP) {
3627 else if (n->kind == COURIER_KIND_HOOKED) {
3637ractor_native_shallow_copy(
VALUE obj)
3651 rb_obj_copy_ivar(copy, obj);
3654 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3660 copy = rb_hash_dup(obj);
3664 rb_struct_init_copy(copy, obj);
3668 rb_match_init_copy(copy, obj);
3673 if (rb_backtrace_p(obj)) {
3674 copy = rb_backtrace_dup(obj);
3686 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3696 RBASIC_SET_SHAPE_ID(copy, rb_obj_shape_transition_frozen(copy));
3701static enum obj_traverse_iterator_result
3705 data->replacement = obj;
3706 return traverse_skip;
3709 VALUE copy = ractor_native_shallow_copy(obj);
3710 if (UNDEF_P(copy))
return traverse_stop;
3711 data->replacement = copy;
3712 return traverse_cont;
3716static enum obj_traverse_iterator_result
3719 return traverse_cont;
3725ractor_copy_native_try(
VALUE obj)
3727 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3733ractor_copy(
VALUE obj)
3735 VALUE copy = ractor_copy_native_try(obj);
3736 if (UNDEF_P(copy)) {
3738 ractor_marshal_dump_rescue, obj,
3755} freed_ractor_local_keys;
3759ractor_local_keys_purge(
st_table *local_storage)
3761 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3763 st_data_t val, k = (st_data_t)key;
3764 if (st_delete(local_storage, &k, &val) &&
3766 (*key->type->free)((
void *)val);
3773ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3776 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3780static enum rb_id_table_iterator_result
3781idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3784 return ID_TABLE_CONTINUE;
3790 if (r->local_storage) {
3791 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3796 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3797 ractor_local_keys_purge(r->local_storage);
3801 if (r->idkey_local_storage) {
3802 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3805 rb_gc_mark(r->local_storage_store_lock);
3809ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3812 if (k->type->
free) (*k->type->
free)((
void *)val);
3819 if (r->local_storage) {
3820 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3821 st_free_table(r->local_storage);
3824 if (r->idkey_local_storage) {
3825 rb_id_table_free(r->idkey_local_storage);
3830rb_ractor_local_storage_value_mark(
void *ptr)
3832 rb_gc_mark((
VALUE)ptr);
3846 rb_ractor_local_storage_value_mark,
3854 key->type =
type ?
type : &ractor_local_storage_type_null;
3855 key->main_cache = (
void *)
Qundef;
3869 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3870 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3871 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3873 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3880 if (rb_ractor_main_p()) {
3881 if (!UNDEF_P((
VALUE)key->main_cache)) {
3882 *pret = key->main_cache;
3892 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3906 if (cr->local_storage == NULL) {
3907 cr->local_storage = st_init_numtable();
3910 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3912 if (rb_ractor_main_p()) {
3913 key->main_cache = ptr;
3921 if (ractor_local_ref(key, &val)) {
3932 if (ractor_local_ref(key, (
void **)val)) {
3943 ractor_local_set(key, (
void *)val);
3950 if (ractor_local_ref(key, &ret)) {
3961 ractor_local_set(key, ptr);
3964#define DEFAULT_KEYS_CAPA 0x10
3967rb_ractor_finish_marking(
bool full_mark)
3972 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3982 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3983 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3984 if (owner == NULL || owner->local_storage == NULL)
continue;
3985 ractor_local_keys_purge(owner->local_storage);
3988 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3989 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3991 freed_ractor_local_keys.cnt = 0;
3992 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3993 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3994 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3999 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
4000 rb_ractor_reap_dead_ports(r);
4002 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
4003 rb_ractor_reap_dead_ports(vm->ractor.main_ractor);
4013 struct rb_id_table *tbl = cr->idkey_local_storage;
4016 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
4029 struct rb_id_table *tbl = cr->idkey_local_storage;
4032 tbl = cr->idkey_local_storage = rb_id_table_create(2);
4034 rb_id_table_insert(tbl,
id, val);
4046ractor_local_value_store_i(
VALUE ptr)
4051 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
4056 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
4069 .tbl = cr->idkey_local_storage,
4073 if (data.tbl == NULL) {
4074 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
4076 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
4081 if (!cr->local_storage_store_lock) {
4094 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
4098 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
4122RUBY_REFERENCES(cross_ractor_require_refs) = {
4129 "ractor/cross_ractor_require",
4131 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
4136 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
4140require_body(
VALUE crr_obj)
4144 VALUE feature = crr->as.require.feature;
4150 int rb_require_internal_silent(
VALUE fname);
4151 return INT2NUM(rb_require_internal_silent(feature));
4168require_result_send_body(
VALUE ary)
4175 ractor_port_send(ec, port, results,
Qfalse);
4180require_result_send_resuce(
VALUE port,
VALUE errinfo)
4183 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
4193 const bool silent = crr->silent;
4195 VALUE debug, errinfo;
4198 errinfo = rb_errinfo();
4206 rb_set_errinfo(errinfo);
4211 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
4219ractor_require_func(
void *crr_obj)
4221 return ractor_require_protect((
VALUE)crr_obj, require_body);
4225rb_ractor_require(
VALUE feature,
bool silent)
4228 ASSERT_vm_unlocking();
4237 crr->raised =
false;
4238 crr->silent = silent;
4241 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4242 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4245 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4246 ractor_port_close(ec, crr->port);
4263 return rb_ractor_require(feature,
false);
4267autoload_load_body(
VALUE crr_obj)
4275ractor_autoload_load_func(
void *crr_obj)
4277 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
4281rb_ractor_autoload_load(
VALUE module,
ID name)
4287 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
4292 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4293 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4296 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4297 ractor_port_close(ec, crr->port);
4314 return ractor_shareable_proc(ec, arg_self,
false);
4320 return ractor_shareable_proc(ec, arg_self,
true);
4323#include "ractor.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
static void RB_FL_SET_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_SET().
@ RUBY_FL_FREEZE
This flag has something to do with data immutability.
void rb_singleton_class_attached(VALUE klass, VALUE obj)
Attaches a singleton class to its corresponding object.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define TYPE(_)
Old name of rb_type.
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
#define T_FILE
Old name of RUBY_T_FILE.
#define FL_PROMOTED
Old name of RUBY_FL_PROMOTED.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define ALLOC
Old name of RB_ALLOC.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define T_FLOAT
Old name of RUBY_T_FLOAT.
#define T_IMEMO
Old name of RUBY_T_IMEMO.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
#define SYM2ID
Old name of RB_SYM2ID.
#define T_DATA
Old name of RUBY_T_DATA.
#define ZALLOC
Old name of RB_ZALLOC.
#define FL_SHAREABLE
Old name of RUBY_FL_SHAREABLE.
#define CLASS_OF
Old name of rb_class_of.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define FL_FINALIZE
Old name of RUBY_FL_FINALIZE.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define T_HASH
Old name of RUBY_T_HASH.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#define Qtrue
Old name of RUBY_Qtrue.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define T_OBJECT
Old name of RUBY_T_OBJECT.
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define T_MATCH
Old name of RUBY_T_MATCH.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eStopIteration
StopIteration exception.
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_eException
Mother of all exceptions.
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_cRactor
Ractor class.
VALUE rb_stdin
STDIN constant.
VALUE rb_cHash
Hash class.
VALUE rb_stderr
STDERR constant.
static VALUE rb_class_of(VALUE obj)
Object to class mapping function.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_cBasicObject
BasicObject class.
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_stdout
STDOUT constant.
VALUE rb_cString
String class.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_resize(VALUE ary, rb_len_t len)
Expands or shrinks the passed array to the passed length.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
VALUE rb_ary_hidden_new(rb_len_t capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_new_from_values(rb_len_t n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
VALUE rb_marshal_load(VALUE port)
Deserialises a previous output of rb_marshal_dump() into a network of objects.
VALUE rb_block_proc(void)
Constructs a Proc object from implicitly passed components.
VALUE rb_block_lambda(void)
Identical to rb_proc_new(), except it returns a lambda.
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
VALUE rb_mutex_new(void)
Creates a mutex.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_autoload_load(VALUE space, ID name)
Kicks the autoload procedure as if it was "touched".
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
void rb_free_generic_ivar(VALUE obj)
Frees the list of instance variables.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
int rb_obj_respond_to(VALUE obj, ID mid, int private_p)
Identical to rb_respond_to(), except it additionally takes the visibility parameter.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
int capa
Designed capacity of the buffer.
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
int len
Length of the buffer.
const struct rb_ractor_local_storage_type rb_ractor_local_storage_type_free
A type of ractor-local storage that destructs itself using ruby_xfree.
VALUE rb_ractor_make_shareable_copy(VALUE obj)
Identical to rb_ractor_make_shareable(), except it returns a (deep) copy of the passed one instead of...
struct rb_ractor_local_key_struct * rb_ractor_local_key_t
(Opaque) struct that holds a ractor-local storage key.
void * rb_ractor_local_storage_ptr(rb_ractor_local_key_t key)
Identical to rb_ractor_local_storage_value() except the return type.
void rb_ractor_local_storage_ptr_set(rb_ractor_local_key_t key, void *ptr)
Identical to rb_ractor_local_storage_value_set() except the parameter type.
rb_ractor_local_key_t rb_ractor_local_storage_ptr_newkey(const struct rb_ractor_local_storage_type *type)
Extended version of rb_ractor_local_storage_value_newkey().
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_local_storage_value_set(rb_ractor_local_key_t key, VALUE val)
Associates the passed value to the passed key.
bool rb_ractor_local_storage_value_lookup(rb_ractor_local_key_t key, VALUE *val)
Queries the key.
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
VALUE rb_obj_set_shareable(VALUE obj)
Marks the passed object as shareable, without any check.
rb_ractor_local_key_t rb_ractor_local_storage_value_newkey(void)
Issues a new key.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
VALUE rb_ractor_local_storage_value(rb_ractor_local_key_t key)
Queries the key.
VALUE rb_yield(VALUE val)
Yields the block.
rb_block_call_func * rb_block_call_func_t
Shorthand type that represents an iterator-written-in-C function pointer.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE rb_proc_new(type *q, VALUE w)
Creates a rb_cProc instance.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
void rb_ivar_foreach(VALUE q, int_type *w, VALUE e)
Iteration over each instance variable of the object.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY(obj)
Convenient casting macro.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
static void RARRAY_ASET(VALUE ary, rb_len_t i, VALUE v)
Assigns an object in an array.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RBASIC(obj)
Convenient casting macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RFILE(obj)
Convenient casting macro.
#define RHASH_SET_IFNONE(h, ifnone)
Destructively updates the default value of the hash.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RMATCH(obj)
Convenient casting macro.
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
#define RSTRING(obj)
Convenient casting macro.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
static VALUE RSTRUCT_SET(VALUE st, int k, VALUE v)
Resembles Struct#[]=.
static VALUE RSTRUCT_GET(VALUE st, int k)
Resembles Struct#[].
static rb_len_t RSTRUCT_LEN(VALUE st)
Returns the number of struct members.
#define RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
static const rb_data_type_t * RTYPEDDATA_TYPE(VALUE obj)
Queries for the type of given object.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define FilePathValue(v)
Ensures that the parameter object is a path.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
Ruby object's base components.
Regular expression execution context.
VALUE regexp
The expression of this match.
VALUE str
The target string that the match was made against.
This is the struct that holds necessary info for a struct.
VALUE ecopts
Flags as Ruby hash.
Ruby's IO, metadata and buffers.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
VALUE pathv
pathname for file
Type that defines a ractor-local storage.
void(* free)(void *ptr)
A function to destruct a ractor-local storage.
void(* mark)(void *ptr)
A function to mark a ractor-local storage.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_destroy.
void rb_native_cond_signal(rb_nativethread_cond_t *cond)
Signals a condition variable.
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.