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);
278 rb_gc_mark(r->r_stdin);
279 rb_gc_mark(r->r_stdout);
280 rb_gc_mark(r->r_stderr);
281 rb_gc_mark(r->verbose);
282 rb_gc_mark(r->debug);
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)
327 rb_gc_mark(r->sync.default_port_value);
331 if (!rb_gc_multi_objspace_p()) {
332 ractor_mark_unshareable_parts(r);
333 rb_ractor_mark_terminated_join_value(r);
335 else if (rb_gc_during_global_gc_p()) {
340 rb_ractor_mark_terminated_join_value(r);
357 rb_ractor_mark_terminated_join_value(r);
358 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
359 rb_gc_mark_registered_addrs(r,
true);
368 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
369 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
370 ractor_mark_unshareable_parts(r);
375 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
382rb_ractor_mark_terminated_join_value(
rb_ractor_t *r)
387 rb_gc_mark_vm_stack_values((
long)numberof(slots), slots);
396 if (src->registered_marks_cnt == 0)
return;
397 size_t need = dst->registered_marks_cnt + src->registered_marks_cnt;
398 if (need > dst->registered_marks_capa) {
399 size_t nc = dst->registered_marks_capa ? dst->registered_marks_capa : 64;
400 while (nc < need) nc *= 2;
401 VALUE *p = realloc(dst->registered_marks, nc *
sizeof(
VALUE));
402 if (!p) rb_bug(
"rb_ractor_absorb_registered_marks: out of memory");
403 dst->registered_marks = p;
404 dst->registered_marks_capa = nc;
406 MEMCPY(dst->registered_marks + dst->registered_marks_cnt,
407 src->registered_marks,
VALUE, src->registered_marks_cnt);
408 dst->registered_marks_cnt = need;
409 src->registered_marks_cnt = 0;
418 if (src->registered_addrs_cnt > 0) {
419 size_t need = dst->registered_addrs_cnt + src->registered_addrs_cnt;
420 if (need > dst->registered_addrs_capa) {
421 size_t nc = dst->registered_addrs_capa ? dst->registered_addrs_capa : 64;
422 while (nc < need) nc *= 2;
425 if (!p) rb_bug(
"rb_ractor_absorb_registered_addrs_without_gc: out of memory");
426 dst->registered_addrs = p;
427 dst->registered_addrs_capa = nc;
429 MEMCPY(dst->registered_addrs + dst->registered_addrs_cnt,
431 dst->registered_addrs_cnt = need;
432 src->registered_addrs_cnt = 0;
433 rb_gc_registered_addrs_enroll_without_gc(vm, dst);
435 rb_gc_registered_addrs_unenroll_without_gc(vm, src);
440free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
443 rb_hook_list_free(hook_list);
448free_targeted_hooks(
st_table *hooks_tbl)
450 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
456ractor_free(
void *ptr)
459 RUBY_DEBUG_LOG(
"free r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
461 free_targeted_hooks(&r->pub.targeted_hooks);
462 rb_thread_sched_destroy(&r->threads.sched);
464 ractor_local_storage_free(r);
465 rb_hook_list_free(&r->pub.hooks);
466 rb_st_free_embedded_table(&r->pub.targeted_hooks);
468 if (r->newobj_cache) {
471 rb_gc_ractor_cache_free(r->newobj_cache);
472 r->newobj_cache = NULL;
479 if (r->objspace && !r->main_ractor) {
480 rb_gc_objspace_disown(r->objspace);
486 if (r->in_terminated_set) {
488 ccan_list_del(&r->vmlr_node);
489 r->in_terminated_set =
false;
496 if (!r->main_ractor) {
497 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
498 rb_ractor_absorb_registered_addrs_without_gc(GET_VM()->ractor.main_ractor, r);
502 rb_gc_registered_addrs_unenroll_without_gc(GET_VM(), r);
505 free(r->registered_marks);
506 r->registered_marks = NULL;
507 r->registered_marks_cnt = r->registered_marks_capa = 0;
509 free(r->registered_addrs);
510 r->registered_addrs = NULL;
511 r->registered_addrs_cnt = r->registered_addrs_capa = 0;
513 if (!r->main_ractor) {
519ractor_memsize(
const void *ptr)
524 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
528ractor_update_references(
void *ptr)
540 ractor_update_references,
548 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
557RACTOR_PTR(
VALUE self)
559 VM_ASSERT(rb_ractor_p(self));
564#define MAIN_RACTOR_ID 1
565static rb_serial_t ractor_last_id = MAIN_RACTOR_ID;
567#include "ractor_sync.c"
578 VM_ASSERT(RB_VM_LOCKED_P() || !rb_multi_ractor_p());
579 return ++ractor_last_id;
585 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
586 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
591 if (vm->ractor.cnt == 1) {
595 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
598 if (r->newobj_cache) {
599 VM_ASSERT(r == ruby_single_main_ractor);
602 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
607cancel_single_ractor_mode(
void)
610 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
612 ruby_single_main_ractor = NULL;
613 rb_yjit_invalidate_single_ractor();
614 rb_zjit_invalidate_single_ractor();
616 ASSERT_vm_unlocking();
623 VM_ASSERT(ractor_status_p(r, ractor_created));
625 if (rb_multi_ractor_p()) {
628 vm_insert_ractor0(vm, r,
false);
629 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
634 if (cur && cur->creating_child_objspace == r->objspace) {
635 cur->creating_child_objspace = NULL;
641 if (vm->ractor.cnt == 0) {
643 vm_insert_ractor0(vm, r,
true);
644 ractor_status_set(r, ractor_blocking);
645 ractor_status_set(r, ractor_running);
648 cancel_single_ractor_mode();
649 vm_insert_ractor0(vm, r,
true);
650 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
655 if (cur && cur->creating_child_objspace == r->objspace) {
656 cur->creating_child_objspace = NULL;
665 VM_ASSERT(ractor_status_p(cr, ractor_running));
666 VM_ASSERT(vm->ractor.cnt > 1);
667 VM_ASSERT(cr->threads.cnt == 1);
671 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
672 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
674 VM_ASSERT(vm->ractor.cnt > 0);
675 ccan_list_del(&cr->vmlr_node);
680 if (!rb_gc_multi_objspace_p()) {
682 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
683 cr->in_terminated_set =
true;
687 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
691 rb_gc_ractor_cache_free(cr->newobj_cache);
692 cr->newobj_cache = NULL;
702 rb_gc_objspace_retire(&cr->objspace);
706 ractor_status_set(cr, ractor_terminated);
718 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
719 VM_ASSERT(th->ec != NULL);
722 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
727 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
728 rb_gc_objspace_postmortem_self();
732 pf->th = (th->self == 0) ? th : NULL;
733 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
739 if (pf->fiber == NULL && pf->th == NULL)
return;
744#ifdef RB_THREAD_LOCAL_SPECIFIER
745 rb_current_ec_set(NULL);
747 native_tls_set(ruby_current_ec_key, NULL);
751 if (pf->fiber) rb_fiber_free_body(pf->fiber);
752 if (pf->th) rb_thread_free_body(pf->th);
756ractor_alloc(
VALUE klass)
762 r->next_ec_serial = 1;
763 VM_ASSERT(ractor_status_p(r, ractor_created));
770 .pub.id = MAIN_RACTOR_ID,
777rb_ractor_main_alloc(
void)
782 ruby_single_main_ractor = r;
787#if defined(HAVE_WORKING_FORK)
795 vm->ractor.blocking_cnt = 0;
798 rb_gc_disable_holders_atfork();
802 th->ractor->creating_child_objspace = NULL;
803 ruby_single_main_ractor = th->ractor;
804 th->ractor->status_ = ractor_created;
806 rb_ractor_living_threads_init(th->ractor);
807 rb_ractor_living_threads_insert(th->ractor, th);
809 VM_ASSERT(vm->ractor.blocking_cnt == 0);
810 VM_ASSERT(vm->ractor.cnt == 1);
816 rb_gc_ractor_cache_free(r->newobj_cache);
817 r->newobj_cache = NULL;
818 r->status_ = ractor_terminated;
820 r->threads.dying_th = NULL;
821 if (!rb_gc_multi_objspace_p()) {
822 ccan_list_del(&r->vmlr_node);
823 ccan_list_add(&vm->ractor.terminated_set, &r->vmlr_node);
824 r->in_terminated_set =
true;
830 rb_gc_objspace_retire(&r->objspace);
832 ractor_sync_terminate_atfork(vm, r);
841 ccan_list_head_init(&r->threads.set);
843 r->threads.blocking_cnt = 0;
844 r->threads.terminating =
false;
846 r->threads.dying_th = NULL;
853 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
854 r->pub.hooks.type = hook_list_type_ractor_local;
857 rb_thread_sched_init(&r->threads.sched,
false);
858 rb_ractor_living_threads_init(r);
864 enc = rb_enc_get(name);
865 if (!rb_enc_asciicompat(enc)) {
866 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
883 r->threads.main = th;
884 rb_ractor_living_threads_insert(r, th);
885 rb_ractor_setup_default_port(r);
893 VALUE rv = ractor_alloc(self);
895 ractor_init(r, name, loc);
898 r->pub.id = ractor_next_id();
900 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", r->pub.id);
903 r->verbose = cr->verbose;
904 r->debug = cr->debug;
908 r->objspace = rb_gc_objspace_alloc();
910 rb_thread_create_ractor(r, args, block);
921 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
928 ractor_notify_exit(ec, cr, result, exc);
936 ractor_postmortem_collect(th, pf);
937 ractor_send_exit_tokens(th->ec, th->ractor);
944 ractor_atexit(ec, cr, result,
false);
951 ractor_atexit(ec, cr, ec->errinfo,
true);
961 VM_ASSERT(cr->threads.main != NULL);
962 cr->threads.main = NULL;
969 for (
int i=0; i<
len; i++) {
970 ptr[i] = ractor_receive(ec, ractor_default_port(r), NULL);
978 for (
int i=0; i<
len; i++) {
979 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
984rb_ractor_main_p_(
void)
986 VM_ASSERT(rb_multi_ractor_p());
988 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
994 return r->threads.cnt;
999rb_ractor_thread_list(
void)
1005 ccan_list_for_each(&r->threads.set, th, lt_node) {
1006 switch (th->status) {
1007 case THREAD_RUNNABLE:
1008 case THREAD_STOPPED:
1009 case THREAD_STOPPED_FOREVER:
1022 VM_ASSERT(th != NULL);
1026 RUBY_DEBUG_LOG(
"r(%"PRI_SERIALT_PREFIX
"u)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
1027 ccan_list_add_tail(&r->threads.set, &th->lt_node);
1033 if (r->threads.cnt == 1) {
1034 VM_ASSERT(ractor_status_p(r, ractor_created));
1035 vm_insert_ractor(th->vm, r);
1042 ractor_status_set(r, ractor_blocking);
1044 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
1045 vm->ractor.blocking_cnt++;
1046 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
1050rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1052 ASSERT_vm_locking();
1053 VM_ASSERT(GET_RACTOR() == cr);
1054 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
1058rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1060 ASSERT_vm_locking();
1061 VM_ASSERT(GET_RACTOR() == cr);
1063 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
1064 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1065 vm->ractor.blocking_cnt--;
1067 ractor_status_set(cr, ractor_running);
1078 ccan_list_del(&th->lt_node);
1086 VM_ASSERT(vm->ractor.cnt > 1);
1087 ccan_list_del(&r->vmlr_node);
1092 VM_ASSERT(r->status_ == ractor_blocking);
1093 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1094 vm->ractor.blocking_cnt--;
1096 rb_gc_ractor_cache_free(r->newobj_cache);
1097 r->newobj_cache = NULL;
1100 rb_gc_objspace_disown(r->objspace);
1103 r->status_ = ractor_terminated;
1111 VM_ASSERT(cr == GET_RACTOR());
1112 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
1114 if (cr->threads.cnt == 1) {
1115 vm_remove_ractor(th->vm, cr);
1120 ccan_list_del(&th->lt_node);
1128rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1130 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1132 VM_ASSERT(cr->threads.cnt > 0);
1133 VM_ASSERT(cr == GET_RACTOR());
1135 cr->threads.blocking_cnt++;
1139rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1141 RUBY_DEBUG_LOG2(file, line,
1142 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1143 cr->threads.blocking_cnt, cr->threads.cnt);
1145 VM_ASSERT(cr == GET_RACTOR());
1147 cr->threads.blocking_cnt--;
1151rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1153 VM_ASSERT(r != GET_RACTOR());
1154 ASSERT_ractor_unlocking(r);
1155 ASSERT_vm_locking();
1159 if (ractor_status_p(r, ractor_running)) {
1162 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1170rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1172 VM_ASSERT(r != GET_RACTOR());
1173 ASSERT_ractor_unlocking(r);
1174 ASSERT_vm_locking();
1178 if (main_th->status != THREAD_KILLED) {
1179 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1180 rb_threadptr_interrupt(main_th);
1183 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1191ractor_terminal_interrupt_all(
rb_vm_t *vm)
1193 if (vm->ractor.cnt > 1) {
1196 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1197 if (r != vm->ractor.main_ractor) {
1198 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
1199 rb_ractor_terminate_interrupt_main_thread(r);
1209rb_ractor_terminate_all(
void)
1214 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1216 VM_ASSERT(cr == GET_RACTOR());
1220 ractor_terminal_interrupt_all(vm);
1223 rb_thread_terminate_all(GET_THREAD());
1227 while (vm->ractor.cnt > 1) {
1228 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1229 vm->ractor.sync.terminate_waiting =
true;
1232 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1233 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1234 rb_ractor_sched_wait_terminate(vm, &vm->ractor.sync.terminate_cond, 1000 );
1235 while (vm->ractor.sched.barrier_is_waiting) {
1242 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1244 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1245 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1247 ractor_terminal_interrupt_all(vm);
1254 rb_gc_objspace_absorb_all_zombies();
1258rb_vm_main_ractor_ec(
rb_vm_t *vm)
1275 if (running_ec) {
return running_ec; }
1276 return vm->ractor.main_thread->ec;
1280ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1282 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1384 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1385 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1386 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1388 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1392 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1395 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1399 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1400 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1401 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1402 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1420 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1421 if (r != vm->ractor.main_ractor) {
1422 fprintf(stderr,
"r:%"PRI_SERIALT_PREFIX
"u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1430 if (rb_ractor_main_p()) {
1435 if (UNLIKELY(cr->r_stdin == 0)) {
1436 cr->r_stdin = rb_io_prep_stdin();
1443rb_ractor_stdout(
void)
1445 if (rb_ractor_main_p()) {
1450 if (UNLIKELY(cr->r_stdout == 0)) {
1451 cr->r_stdout = rb_io_prep_stdout();
1453 return cr->r_stdout;
1458rb_ractor_stderr(
void)
1460 if (rb_ractor_main_p()) {
1465 if (UNLIKELY(cr->r_stderr == 0)) {
1466 cr->r_stderr = rb_io_prep_stderr();
1468 return cr->r_stderr;
1475 if (rb_ractor_main_p()) {
1487 if (rb_ractor_main_p()) {
1499 if (rb_ractor_main_p()) {
1512 return &cr->pub.targeted_hooks;
1516rb_obj_set_shareable_no_assert(
VALUE obj)
1523 rb_gc_obj_became_shareable(obj);
1527 bool froze_ivars =
false;
1531 RBASIC_SET_SHAPE_ID(obj, rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj)));
1542 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1543 if (imemo_type_p(fields, imemo_fields)) {
1546 rb_gc_obj_became_shareable(fields);
1548 if (froze_ivars) RBASIC_SET_SHAPE_ID(fields, RBASIC_SHAPE_ID(obj));
1552 rb_imemo_fields_record_shrefs(fields);
1557#ifndef STRICT_VERIFY_SHAREABLE
1558#define STRICT_VERIFY_SHAREABLE 0
1562rb_ractor_verify_shareable(
VALUE obj)
1564#if STRICT_VERIFY_SHAREABLE
1565 rb_gc_verify_shareable(obj);
1575 rb_obj_set_shareable_no_assert(obj);
1587enum obj_traverse_iterator_result {
1593typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1594typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1595typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1597static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1600 rb_obj_traverse_enter_func enter_func;
1601 rb_obj_traverse_leave_func leave_func;
1620 if (obj_traverse_i(key, d->data)) {
1625 if (obj_traverse_i(val, d->data)) {
1634obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1638 if (obj_traverse_i(obj, d->data)) {
1651 RB_VM_LOCKING_NO_BARRIER() {
1652 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1660 if (UNLIKELY(!data->rec)) {
1661 data->rec_hash = rb_ident_hash_new();
1663 data->rec = RHASH_ST_TABLE(data->rec_hash);
1669obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1673 if (obj_traverse_i(val, d->data)) {
1686 switch (data->enter_func(obj)) {
1687 case traverse_cont:
break;
1688 case traverse_skip:
return 0;
1689 case traverse_stop:
return 1;
1692 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1698 if (rb_obj_shape_has_ivars(obj)) {
1704 if (d.stop)
return 1;
1722 rb_ary_cancel_sharing(obj);
1726 if (obj_traverse_i(e, data))
return 1;
1740 if (d.stop)
return 1;
1746 long len = RSTRUCT_LEN_RAW(obj);
1747 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1749 for (
long i=0; i<
len; i++) {
1750 if (obj_traverse_i(ptr[i], data))
return 1;
1756 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1760 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1761 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1764 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1765 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1770 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1773 if (!ptr || !
type->function.dmark) {
1776 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1777 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1778 for (; *offsets != RUBY_REF_END; offsets++) {
1779 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1780 if (obj_traverse_i(ref, data))
return 1;
1784 if (obj_traverse_reachable(obj, data))
return 1;
1791 if (obj_traverse_reachable(obj, data))
return 1;
1800 rb_bug(
"unreachable");
1803 if (data->leave_func(obj) == traverse_stop) {
1812 rb_obj_traverse_final_func final_func;
1817obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1820 if (data->final_func(key)) {
1830rb_obj_traverse(
VALUE obj,
1831 rb_obj_traverse_enter_func enter_func,
1832 rb_obj_traverse_leave_func leave_func,
1833 rb_obj_traverse_final_func final_func)
1836 .enter_func = enter_func,
1837 .leave_func = leave_func,
1841 if (obj_traverse_i(obj, &data))
return 1;
1842 if (final_func && data.rec) {
1844 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1851allow_frozen_shareable_p(
VALUE obj)
1861 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1870make_shareable_freeze(
VALUE obj)
1873 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1876 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1879 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1880 rb_hash_freeze(obj);
1887static enum obj_traverse_iterator_result
1888make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1891 make_shareable_freeze(obj);
1894 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1898 return traverse_skip;
1905static int obj_refer_only_shareables_p(
VALUE obj);
1907static enum obj_traverse_iterator_result
1908make_shareable_check_shareable(
VALUE obj)
1913 return traverse_skip;
1915 else if (!allow_frozen_shareable_p(obj)) {
1917 rb_raise(rb_eRactorError,
1918 "can not make shareable object for %+"PRIsVALUE, obj);
1920 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1921 if (obj_refer_only_shareables_p(obj)) {
1922 make_shareable_check_shareable_freeze(obj, traverse_skip);
1924 return traverse_skip;
1927 rb_raise(rb_eRactorError,
1928 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1932 rb_proc_ractor_make_shareable(obj,
Qundef);
1933 return traverse_cont;
1936 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1940 switch (
TYPE(obj)) {
1942 return traverse_skip;
1949 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1950 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1951 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1952 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1961 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1964static enum obj_traverse_iterator_result
1965mark_shareable(
VALUE obj)
1968 rb_str_make_independent(obj);
1971 rb_obj_set_shareable_no_assert(obj);
1972 return traverse_cont;
1978 rb_obj_traverse(obj,
1979 make_shareable_check_shareable,
1980 null_leave, mark_shareable);
1989 VALUE copy = ractor_copy(obj);
1994rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1997 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
2005rb_ractor_ensure_main_ractor(
const char *msg)
2007 if (!rb_ractor_main_p()) {
2008 rb_raise(rb_eRactorIsolationError,
"%s", msg);
2012static enum obj_traverse_iterator_result
2013shareable_p_enter(
VALUE obj)
2016 return traverse_skip;
2022 mark_shareable(obj);
2023 return traverse_skip;
2026 allow_frozen_shareable_p(obj)) {
2027 return traverse_cont;
2035 if (obj_refer_only_shareables_p(obj)) {
2036 mark_shareable(obj);
2037 return traverse_skip;
2041 return traverse_stop;
2045rb_ractor_shareable_p_continue(
VALUE obj)
2047 if (rb_obj_traverse(obj,
2048 shareable_p_enter, null_leave,
2057static enum obj_traverse_iterator_result
2058null_leave(
VALUE obj)
2060 return traverse_cont;
2076 rb_obj_traverse_replace_enter_func enter_func;
2077 rb_obj_traverse_replace_leave_func leave_func;
2083 VALUE rec_keepalive;
2096obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2102obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2107 if (obj_traverse_replace_i(*key, data)) {
2111 else if (*key != data->replacement) {
2112 VALUE v = *key = data->replacement;
2116 if (obj_traverse_replace_i(*val, data)) {
2120 else if (*val != data->replacement) {
2121 VALUE v = *val = data->replacement;
2129obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2135obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2140 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2144 else if (*(
VALUE *)val != data->replacement) {
2155 if (UNLIKELY(!data->rec)) {
2156 data->rec = st_init_numtable();
2163obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2165 int *pcnt = (
int *)ptr;
2173obj_refer_only_shareables_p(
VALUE obj)
2176 RB_VM_LOCKING_NO_BARRIER() {
2177 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
2185 st_data_t replacement;
2188 data->replacement = obj;
2195 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2196 data->replacement = (
VALUE)replacement;
2200 switch (data->enter_func(obj, data)) {
2201 case traverse_cont:
break;
2202 case traverse_skip:
return 0;
2203 case traverse_stop:
return 1;
2206 replacement = (st_data_t)data->replacement;
2207 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2216#define CHECK_AND_REPLACE(parent_obj, v) do { \
2218 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2219 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2222 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2223 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2225 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2231 rb_st_foreach_with_replace(
2232 rb_imemo_fields_complex_tbl(fields_obj),
2233 obj_iv_hash_traverse_replace_foreach_i,
2234 obj_iv_hash_traverse_replace_i,
2237 if (d.stop)
return 1;
2240 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2241 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2242 for (uint32_t i = 0; i < fields_count; i++) {
2243 CHECK_AND_REPLACE(fields_obj, fields[i]);
2257 rb_str_make_independent(obj);
2262 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2263 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2264 if (rb_shape_complex_p(shape_id)) {
2270 rb_st_foreach_with_replace(
2271 rb_imemo_fields_complex_tbl(fields_obj),
2272 obj_iv_hash_traverse_replace_foreach_i,
2273 obj_iv_hash_traverse_replace_i,
2276 if (d.stop)
return 1;
2279 attr_index_t
len = RSHAPE_LEN(shape_id);
2280 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2282 for (attr_index_t i = 0; i <
len; i++) {
2283 CHECK_AND_REPLACE(obj, ptr[i]);
2291 rb_ary_cancel_sharing(obj);
2296 if (obj_traverse_replace_i(e, data)) {
2299 else if (e != data->replacement) {
2313 rb_hash_stlike_foreach_with_replace(obj,
2314 obj_hash_traverse_replace_foreach_i,
2315 obj_hash_traverse_replace_i,
2317 if (d.stop)
return 1;
2321 if (obj_traverse_replace_i(ifnone, data)) {
2324 else if (ifnone != data->replacement) {
2332 long len = RSTRUCT_LEN_RAW(obj);
2333 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2335 for (
long i=0; i<
len; i++) {
2336 CHECK_AND_REPLACE(obj, ptr[i]);
2342 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2346 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2347 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2350 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2351 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2355 if (!data->move && obj_refer_only_shareables_p(obj)) {
2359 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2373 rb_bug(
"unreachable");
2376 data->replacement = (
VALUE)replacement;
2378 if (data->leave_func(obj, data) == traverse_stop) {
2389rb_obj_traverse_replace(
VALUE obj,
2390 rb_obj_traverse_replace_enter_func enter_func,
2391 rb_obj_traverse_replace_leave_func leave_func,
2395 .enter_func = enter_func,
2396 .leave_func = leave_func,
2403 int stopped = obj_traverse_replace_i(obj, &data);
2407 if (data.rec) st_free_table(data.rec);
2414 return data.replacement;
2424enum courier_node_kind {
2426 COURIER_KIND_BACKTRACE,
2427 COURIER_KIND_STRING,
2430 COURIER_KIND_OBJECT,
2431 COURIER_KIND_STRUCT,
2434 COURIER_KIND_REGEXP,
2435 COURIER_KIND_HOOKED,
2442 COURIER_HOOK_MARSHAL_DUMP,
2444 COURIER_HOOK_COMPAT,
2445 COURIER_HOOK_DUMP_DATA,
2449static enum courier_hook
2450courier_hook_of(
VALUE obj)
2452 if (
rb_obj_respond_to(obj, id_marshal_dump, TRUE))
return COURIER_HOOK_MARSHAL_DUMP;
2454 if (rb_marshal_compat_lookup(
CLASS_OF(obj), NULL, NULL))
return COURIER_HOOK_COMPAT;
2456 return COURIER_HOOK_NONE;
2460 enum courier_node_kind kind;
2469 struct {
char *ptr;
long len, capa;
int encidx;
VALUE klass; } str;
2470 struct {
long len; uint32_t *elems;
VALUE klass; } ary;
2471 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2472 struct {
VALUE klass; } obj;
2473 struct {
long len; uint32_t *elems;
VALUE klass; } strct;
2474 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2475 struct {
void *blob;
int size; } bt;
2476 struct {
VALUE src;
int options;
VALUE klass; } re;
2477 struct {
VALUE klass; uint32_t payload_id;
enum courier_hook hook; } hooked;
2484 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2492#define COURIER_ID_REF_BIT 0x80000000u
2500 uint32_t refs_count;
2528 uint32_t
capa = c->capa ? c->capa * 2 : 8;
2534 ruby_xfree(old_nodes);
2541 uint32_t
capa = c->refs_capa ? c->refs_capa * 2 : 8;
2543 if (c->refs_count > 0)
MEMCPY(refs, c->refs,
VALUE, c->refs_count);
2544 VALUE *old_refs = c->refs;
2546 c->refs_capa =
capa;
2547 ruby_xfree(old_refs);
2553 if (RB_UNLIKELY(c->count == c->capa)) courier_grow_nodes(c);
2558 n->kind = COURIER_KIND_REF;
2574 c->order =
ALLOC_N(uint32_t, nodes);
2579 c->refs_capa = refs;
2591 if (RB_UNLIKELY(c->refs_count == c->refs_capa)) courier_grow_refs(c);
2592 c->refs[c->refs_count] = v;
2593 return COURIER_ID_REF_BIT | c->refs_count++;
2600 if (
id & COURIER_ID_REF_BIT)
return c->refs[
id & ~COURIER_ID_REF_BIT];
2607move_neutralize_source(
VALUE obj)
2612 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2613 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2623 bool wipe_body =
true;
2626 if (!STR_EMBED_P(obj) && !rb_str_reembeddable_p(obj)) {
2631 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2633 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2637 wipe_body = !rb_str_embedded_shared_root_p(obj);
2640 if (!ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && (ARY_SHARED_ROOT_P(obj) ||
OBJ_FROZEN(obj))) {
2645 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2647 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2648 if (!ARY_SHARED_ROOT_P(obj)) {
2651 RARRAY(obj)->as.heap.len = 0;
2655 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2667 size_t slot_size = rb_gc_obj_slot_size(obj);
2668 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2669 RBASIC(obj)->flags = flags;
2670 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2688courier_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2691 uint32_t kid = courier_capture(hc->b, (
VALUE)key);
2692 uint32_t vid = courier_capture(hc->b, (
VALUE)val);
2693 hc->kv[hc->i++] = kid;
2694 hc->kv[hc->i++] = vid;
2707courier_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2710 if (oc->n == oc->capa) {
2711 oc->capa = oc->capa ? oc->capa * 2 : 4;
2713 REALLOC_N(oc->vals, uint32_t, oc->capa);
2715 uint32_t vid = courier_capture(oc->b, val);
2716 oc->ids[oc->n] = name;
2717 oc->vals[oc->n] = vid;
2729 rb_ivar_foreach_buffered(obj, courier_capture_ivar_i, (st_data_t)&oc);
2730 b->c->nodes[id].niv = (uint32_t)oc.n;
2731 b->c->nodes[id].iv_ids = oc.ids;
2732 b->c->nodes[id].iv_vals = oc.vals;
2740courier_capture_hooked(
struct courier_build *b,
VALUE obj, uint32_t
id,
enum courier_hook hook)
2746 case COURIER_HOOK_DUMP: {
2755 case COURIER_HOOK_MARSHAL_DUMP:
2756 payload =
rb_funcallv(obj, id_marshal_dump, 0, 0);
2758 case COURIER_HOOK_DUMP_DATA:
2761 case COURIER_HOOK_COMPAT: {
2763 rb_marshal_compat_lookup(klass, &dumper, NULL);
2764 payload = dumper(obj);
2768 rb_bug(
"courier_capture_hooked: no dump protocol");
2771 uint32_t payload_id = courier_capture(b, payload);
2773 b->c->nodes[id].kind = COURIER_KIND_HOOKED;
2774 b->c->nodes[id].u.hooked.klass = klass;
2775 b->c->nodes[id].u.hooked.hook = hook;
2776 b->c->nodes[id].u.hooked.payload_id = payload_id;
2796 return courier_alloc_ref(b->c, obj);
2804 if (st_lookup(b->c->seen, (st_data_t)obj, &existing)) {
2805 return (uint32_t)existing - 1;
2809 return courier_alloc_ref(b->c, obj);
2812 uint32_t
id = courier_alloc_node(b->c);
2813 st_insert(b->c->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2817 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2821 b->c->nodes[id].frozen = frozen;
2822 courier_capture_ivars(b, obj,
id);
2829 if (!b->copy) rb_str_make_independent(obj);
2830 long len = RSTRING_LEN(obj);
2834 const int termlen = rb_enc_mbminlen(rb_enc_from_index(encidx));
2837 if (!b->copy && !STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2840 ptr =
RSTRING(obj)->as.heap.ptr;
2848 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2849 memset(ptr +
len, 0, termlen);
2852 b->c->nodes[id].kind = COURIER_KIND_STRING;
2853 b->c->nodes[id].u.str.klass = courier_klass(b, obj);
2854 b->c->nodes[id].u.str.ptr = ptr;
2855 b->c->nodes[id].u.str.len =
len;
2856 b->c->nodes[id].u.str.capa =
capa;
2857 b->c->nodes[id].u.str.encidx = encidx;
2864 for (
long i = 0; i <
len; i++) {
2865 elems[i] = courier_capture(b,
RARRAY_AREF(obj, i));
2867 b->c->nodes[id].kind = COURIER_KIND_ARRAY;
2868 b->c->nodes[id].u.ary.klass = courier_klass(b, obj);
2869 b->c->nodes[id].u.ary.len =
len;
2870 b->c->nodes[id].u.ary.elems = elems;
2874 if (!b->copy && !ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2881 uint32_t ifnone_id = courier_capture(b,
RHASH_IFNONE(obj));
2883 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2885 rb_hash_stlike_foreach(obj, courier_capture_hash_i, (st_data_t)&hc);
2886 b->c->nodes[id].kind = COURIER_KIND_HASH;
2887 b->c->nodes[id].u.hash.klass = courier_klass(b, obj);
2888 b->c->nodes[id].u.hash.size = size;
2889 b->c->nodes[id].u.hash.kv = kv;
2890 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2891 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2892 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2894 if (!b->copy) rb_hash_free(obj);
2899 b->c->nodes[id].kind = COURIER_KIND_OBJECT;
2900 b->c->nodes[id].u.obj.klass = courier_klass(b, obj);
2906 for (
long i = 0; i <
len; i++) {
2907 elems[i] = courier_capture(b,
RSTRUCT_GET(obj, (
int)i));
2909 b->c->nodes[id].kind = COURIER_KIND_STRUCT;
2910 b->c->nodes[id].u.strct.len =
len;
2911 b->c->nodes[id].u.strct.elems = elems;
2912 b->c->nodes[id].u.strct.klass = courier_klass(b, obj);
2914 if (!b->copy && RSTRUCT_EMBED_LEN(obj) == 0) {
2915 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2925 void *regs = rb_match_blob_dump(obj, &re, &st, &nregs, !b->copy);
2926 uint32_t rid = courier_capture(b, re);
2927 uint32_t sid = courier_capture(b, st);
2928 b->c->nodes[id].kind = COURIER_KIND_MATCH;
2929 b->c->nodes[id].u.match.regexp_id = rid;
2930 b->c->nodes[id].u.match.str_id = sid;
2931 b->c->nodes[id].u.match.num_regs = nregs;
2932 b->c->nodes[id].u.match.regs = regs;
2933 b->c->nodes[id].u.match.klass = courier_klass(b, obj);
2939 VM_ASSERT(!b->copy);
2945 uint32_t pathv_id = courier_capture(b, fptr->
pathv);
2946 uint32_t ecopts_id = courier_capture(b, fptr->
encs.
ecopts);
2949 uint32_t timeout_id = courier_capture(b, fptr->
timeout);
2957 fptr->wakeup_mutex =
Qnil;
2959 b->c->nodes[id].kind = COURIER_KIND_IO;
2960 b->c->nodes[id].u.io.fptr = fptr;
2961 b->c->nodes[id].u.io.klass = courier_klass(b, obj);
2962 b->c->nodes[id].u.io.pathv_id = pathv_id;
2963 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
2964 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
2965 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
2966 b->c->nodes[id].u.io.timeout_id = timeout_id;
2977 b->c->nodes[id].kind = COURIER_KIND_REGEXP;
2978 b->c->nodes[id].u.re.klass = courier_klass(b, obj);
2979 b->c->nodes[id].u.re.src = src;
2987 if (b->copy && rb_backtrace_p(obj)) {
2989 void *blob = rb_backtrace_blob_dump(obj, &size);
2990 b->c->nodes[id].kind = COURIER_KIND_BACKTRACE;
2991 b->c->nodes[id].u.bt.blob = blob;
2992 b->c->nodes[id].u.bt.size = size;
2999 enum courier_hook hook = b->copy ? courier_hook_of(obj) : COURIER_HOOK_NONE;
3000 if (hook == COURIER_HOOK_NONE) {
3001 rb_raise(rb_eRactorError,
"can not %s a %"PRIsVALUE
" object",
3004 courier_capture_hooked(b, obj,
id, hook);
3009 if (!b->copy) move_neutralize_source(obj);
3011 b->c->order[b->ordered++] = id;
3018 uint32_t nodes, refs;
3024move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
3031move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3050 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
3051 st_insert(seen, (st_data_t)obj, 0);
3058 rb_class_check_singleton_movable(klass);
3067 move_preflight(rm->
regexp, ctx);
3068 move_preflight(rm->
str, ctx);
3077 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)ctx);
3088 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
3093 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
3095 if (
RTEST(fptr->wakeup_mutex)) {
3097 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
3099 move_preflight(fptr->
pathv, ctx);
3103 move_preflight(fptr->
timeout, ctx);
3107 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
3119 uint32_t nodes, refs;
3126copy_support_val_i(st_data_t val, st_data_t arg)
3129 if (!copy_courier_supported_p((
VALUE)val, ctx)) {
3137copy_support_ivar_i(
ID name,
VALUE val, st_data_t arg)
3139 return copy_support_val_i((st_data_t)val, arg);
3143copy_support_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3145 if (copy_support_val_i(key, arg) == ST_STOP)
return ST_STOP;
3146 return copy_support_val_i(val, arg);
3159 if (st_lookup(seen, (st_data_t)obj, NULL))
return true;
3160 st_insert(seen, (st_data_t)obj, 0);
3172 if (!copy_courier_supported_p(rm->
regexp, ctx))
return false;
3173 if (!copy_courier_supported_p(rm->
str, ctx))
return false;
3178 if (!rb_backtrace_p(obj) && courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3182 if (!copy_courier_supported_p(
RARRAY_AREF(obj, i), ctx))
return false;
3186 rb_hash_stlike_foreach(obj, copy_support_hash_i, (st_data_t)ctx);
3187 if (!ctx->ok)
return false;
3188 if (!copy_courier_supported_p(
RHASH_IFNONE(obj), ctx))
return false;
3192 if (!copy_courier_supported_p(
RSTRUCT_GET(obj, (
int)i), ctx))
return false;
3199 if (courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3214 bool ok = copy_courier_supported_p(obj, &scan);
3215 st_free_table(scan.seen);
3216 if (!ok)
return NULL;
3220 courier_reserve(c, scan.nodes, scan.refs);
3221 c->seen = st_init_numtable();
3228 enum ruby_tag_type state;
3231 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3232 c->root = courier_capture(&b, obj);
3235 st_free_table(c->seen);
3238 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3251 enum ruby_tag_type state;
3254 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3255 move_preflight(obj, &scan);
3258 st_free_table(scan.seen);
3259 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3263 courier_reserve(c, scan.nodes, scan.refs);
3264 c->seen = st_init_numtable();
3272 enum ruby_tag_type state;
3275 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3276 c->root = courier_capture(&b, obj);
3279 st_free_table(c->seen);
3281 if (state != TAG_NONE) {
3285 EC_JUMP_TAG(ec, state);
3297 RBASIC_SET_CLASS(shell, klass);
3302 rb_class_take_ownership(klass);
3315 for (uint32_t i = 0; i < c->count; i++) {
3319 case COURIER_KIND_REF:
3322 case COURIER_KIND_STRING:
3326 shell = rb_str_new_owned(n->u.str.ptr, n->u.str.len, n->u.str.capa, n->u.str.encidx);
3327 n->u.str.ptr = NULL;
3328 courier_apply_klass(shell, n->u.str.klass);
3330 case COURIER_KIND_ARRAY:
3332 courier_apply_klass(shell, n->u.ary.klass);
3334 case COURIER_KIND_HASH:
3335 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
3336 courier_apply_klass(shell, n->u.hash.klass);
3338 case COURIER_KIND_OBJECT:
3342 courier_apply_klass(shell, n->u.obj.klass);
3344 case COURIER_KIND_STRUCT:
3346 courier_apply_klass(shell, n->u.strct.klass);
3348 case COURIER_KIND_MATCH:
3349 shell = rb_match_blob_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
3350 courier_apply_klass(shell, n->u.match.klass);
3352 case COURIER_KIND_BACKTRACE:
3353 shell = rb_backtrace_blob_load(n->u.bt.blob, n->u.bt.size);
3355 case COURIER_KIND_REGEXP:
3358 shell = rb_reg_init_str(rb_reg_s_alloc(
rb_class_real(n->u.re.klass)), n->u.re.src, n->u.re.options);
3359 courier_apply_klass(shell, n->u.re.klass);
3361 case COURIER_KIND_HOOKED:
3362 if (n->u.hooked.hook == COURIER_HOOK_DUMP) {
3369 courier_apply_klass(shell, n->u.hooked.klass);
3371 case COURIER_KIND_IO:
3373 courier_apply_klass(shell, n->u.io.klass);
3374 RFILE(shell)->fptr = n->u.io.fptr;
3375 n->u.io.fptr->
self = shell;
3376 n->u.io.fptr = NULL;
3379 rb_bug(
"rb_ractor_courier_materialize: bad node kind");
3390 for (uint32_t k = 0; k < c->count; k++) {
3391 uint32_t i = c->order[k];
3395 case COURIER_KIND_ARRAY: {
3398 const long len = n->u.ary.len;
3401 for (
long j = 0; j <
len; j++) {
3402 RARRAY_ASET(shell, j, courier_child(c, shells, n->u.ary.elems[j]));
3407 case COURIER_KIND_HASH:
3408 for (
long j = 0; j < n->u.hash.size; j++) {
3409 rb_hash_aset(shell, courier_child(c, shells, n->u.hash.kv[2 * j]),
3410 courier_child(c, shells, n->u.hash.kv[2 * j + 1]));
3413 VALUE ifnone = courier_child(c, shells, n->u.hash.ifnone_id);
3414 if (n->u.hash.proc_default) {
3415 rb_hash_set_default_proc(shell, ifnone);
3417 else if (ifnone !=
Qnil) {
3418 rb_hash_set_default(shell, ifnone);
3421 case COURIER_KIND_HOOKED: {
3422 VALUE payload = courier_child(c, shells, n->u.hooked.payload_id);
3423 VALUE klass = n->u.hooked.klass;
3425 switch (n->u.hooked.hook) {
3426 case COURIER_HOOK_DUMP:
3428 rb_raise(
rb_eTypeError,
"class %"PRIsVALUE
" needs to have method '_load'", klass);
3436 case COURIER_HOOK_MARSHAL_DUMP:
3437 case COURIER_HOOK_DUMP_DATA:
3438 mid = n->u.hooked.hook == COURIER_HOOK_MARSHAL_DUMP ? id_marshal_load : id_load_data;
3440 rb_raise(
rb_eTypeError,
"instance of %"PRIsVALUE
" needs to have method '%"PRIsVALUE
"'",
3441 klass, rb_id2str(mid));
3445 case COURIER_HOOK_COMPAT: {
3447 rb_marshal_compat_lookup(klass, NULL, &loader);
3448 loader(shell, payload);
3452 rb_bug(
"rb_ractor_courier_materialize: no dump protocol");
3456 case COURIER_KIND_STRUCT:
3457 for (
long j = 0; j < n->u.strct.len; j++) {
3458 RSTRUCT_SET(shell, (
int)j, courier_child(c, shells, n->u.strct.elems[j]));
3461 case COURIER_KIND_MATCH:
3462 rb_match_blob_load(shell, courier_child(c, shells, n->u.match.regexp_id),
3463 courier_child(c, shells, n->u.match.str_id),
3464 n->u.match.num_regs, n->u.match.regs);
3466 case COURIER_KIND_IO: {
3481 for (uint32_t j = 0; j < n->niv; j++) {
3482 rb_ivar_set(shell, n->iv_ids[j], courier_child(c, shells, n->iv_vals[j]));
3487 for (uint32_t i = 0; i < c->count; i++) {
3494 VALUE root = (c->count || c->refs_count) ? courier_child(c, shells, c->root) :
Qnil;
3502 for (uint32_t i = 0; i < c->count; i++) {
3504 ruby_xfree(n->iv_ids);
3505 ruby_xfree(n->iv_vals);
3507 case COURIER_KIND_STRING:
3508 ruby_xfree(n->u.str.ptr);
3510 case COURIER_KIND_ARRAY:
3511 ruby_xfree(n->u.ary.elems);
3513 case COURIER_KIND_HASH:
3514 ruby_xfree(n->u.hash.kv);
3516 case COURIER_KIND_STRUCT:
3517 ruby_xfree(n->u.strct.elems);
3519 case COURIER_KIND_MATCH:
3520 rb_match_blob_free(n->u.match.regs);
3522 case COURIER_KIND_BACKTRACE:
3523 ruby_xfree(n->u.bt.blob);
3525 case COURIER_KIND_IO:
3531 n->u.io.fptr = NULL;
3538 ruby_xfree(c->nodes);
3539 ruby_xfree(c->order);
3540 ruby_xfree(c->refs);
3552 if (c->seen) rb_mark_set(c->seen);
3553 for (uint32_t i = 0; i < c->refs_count; i++) {
3554 rb_gc_mark(c->refs[i]);
3556 for (uint32_t i = 0; i < c->count; i++) {
3558 if (n->kind == COURIER_KIND_REF) {
3559 rb_gc_mark(n->u.ref);
3561 else if (n->kind == COURIER_KIND_OBJECT) {
3562 rb_gc_mark(n->u.obj.klass);
3564 else if (n->kind == COURIER_KIND_STRUCT) {
3565 rb_gc_mark(n->u.strct.klass);
3567 else if (n->kind == COURIER_KIND_MATCH) {
3568 rb_gc_mark(n->u.match.klass);
3570 else if (n->kind == COURIER_KIND_IO) {
3571 rb_gc_mark(n->u.io.klass);
3573 else if (n->kind == COURIER_KIND_STRING) {
3574 rb_gc_mark(n->u.str.klass);
3576 else if (n->kind == COURIER_KIND_BACKTRACE) {
3577 rb_backtrace_blob_mark(n->u.bt.blob, n->u.bt.size);
3579 else if (n->kind == COURIER_KIND_ARRAY) {
3580 rb_gc_mark(n->u.ary.klass);
3582 else if (n->kind == COURIER_KIND_HASH) {
3583 rb_gc_mark(n->u.hash.klass);
3585 else if (n->kind == COURIER_KIND_REGEXP) {
3586 rb_gc_mark(n->u.re.src);
3587 rb_gc_mark(n->u.re.klass);
3589 else if (n->kind == COURIER_KIND_HOOKED) {
3590 rb_gc_mark(n->u.hooked.klass);
3599ractor_native_shallow_copy(
VALUE obj)
3613 rb_obj_copy_ivar(copy, obj);
3616 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3622 copy = rb_hash_dup(obj);
3626 rb_struct_init_copy(copy, obj);
3630 rb_match_init_copy(copy, obj);
3635 if (rb_backtrace_p(obj)) {
3636 copy = rb_backtrace_dup(obj);
3648 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3658 RBASIC_SET_SHAPE_ID(copy, rb_obj_shape_transition_frozen(copy));
3663static enum obj_traverse_iterator_result
3667 data->replacement = obj;
3668 return traverse_skip;
3671 VALUE copy = ractor_native_shallow_copy(obj);
3672 if (UNDEF_P(copy))
return traverse_stop;
3673 data->replacement = copy;
3674 return traverse_cont;
3678static enum obj_traverse_iterator_result
3681 return traverse_cont;
3687ractor_copy_native_try(
VALUE obj)
3689 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3695ractor_copy(
VALUE obj)
3697 VALUE copy = ractor_copy_native_try(obj);
3698 if (UNDEF_P(copy)) {
3700 ractor_marshal_dump_rescue, obj,
3717} freed_ractor_local_keys;
3721ractor_local_keys_purge(
st_table *local_storage)
3723 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3725 st_data_t val, k = (st_data_t)key;
3726 if (st_delete(local_storage, &k, &val) &&
3728 (*key->type->free)((
void *)val);
3735ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3738 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3742static enum rb_id_table_iterator_result
3743idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3746 return ID_TABLE_CONTINUE;
3752 if (r->local_storage) {
3753 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3758 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3759 ractor_local_keys_purge(r->local_storage);
3763 if (r->idkey_local_storage) {
3764 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3767 rb_gc_mark(r->local_storage_store_lock);
3771ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3774 if (k->type->
free) (*k->type->
free)((
void *)val);
3781 if (r->local_storage) {
3782 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3783 st_free_table(r->local_storage);
3786 if (r->idkey_local_storage) {
3787 rb_id_table_free(r->idkey_local_storage);
3792rb_ractor_local_storage_value_mark(
void *ptr)
3794 rb_gc_mark((
VALUE)ptr);
3808 rb_ractor_local_storage_value_mark,
3816 key->type =
type ?
type : &ractor_local_storage_type_null;
3817 key->main_cache = (
void *)
Qundef;
3831 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3832 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3833 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3835 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3842 if (rb_ractor_main_p()) {
3843 if (!UNDEF_P((
VALUE)key->main_cache)) {
3844 *pret = key->main_cache;
3854 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3868 if (cr->local_storage == NULL) {
3869 cr->local_storage = st_init_numtable();
3872 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3874 if (rb_ractor_main_p()) {
3875 key->main_cache = ptr;
3883 if (ractor_local_ref(key, &val)) {
3894 if (ractor_local_ref(key, (
void **)val)) {
3905 ractor_local_set(key, (
void *)val);
3912 if (ractor_local_ref(key, &ret)) {
3923 ractor_local_set(key, ptr);
3926#define DEFAULT_KEYS_CAPA 0x10
3929rb_ractor_finish_marking(
bool full_mark)
3934 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3944 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3945 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3946 if (owner == NULL || owner->local_storage == NULL)
continue;
3947 ractor_local_keys_purge(owner->local_storage);
3950 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3951 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3953 freed_ractor_local_keys.cnt = 0;
3954 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3955 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3956 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3961 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3962 rb_ractor_reap_dead_ports(r);
3964 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
3965 rb_ractor_reap_dead_ports(vm->ractor.main_ractor);
3975 struct rb_id_table *tbl = cr->idkey_local_storage;
3978 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
3991 struct rb_id_table *tbl = cr->idkey_local_storage;
3994 tbl = cr->idkey_local_storage = rb_id_table_create(2);
3996 rb_id_table_insert(tbl,
id, val);
4008ractor_local_value_store_i(
VALUE ptr)
4013 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
4018 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
4031 .tbl = cr->idkey_local_storage,
4035 if (data.tbl == NULL) {
4036 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
4038 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
4043 if (!cr->local_storage_store_lock) {
4056 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
4060 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
4084RUBY_REFERENCES(cross_ractor_require_refs) = {
4091 "ractor/cross_ractor_require",
4093 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
4098 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
4102require_body(
VALUE crr_obj)
4106 VALUE feature = crr->as.require.feature;
4112 int rb_require_internal_silent(
VALUE fname);
4113 return INT2NUM(rb_require_internal_silent(feature));
4130require_result_send_body(
VALUE ary)
4137 ractor_port_send(ec, port, results,
Qfalse);
4142require_result_send_resuce(
VALUE port,
VALUE errinfo)
4145 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
4155 const bool silent = crr->silent;
4157 VALUE debug, errinfo;
4160 errinfo = rb_errinfo();
4168 rb_set_errinfo(errinfo);
4173 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
4181ractor_require_func(
void *crr_obj)
4183 return ractor_require_protect((
VALUE)crr_obj, require_body);
4187rb_ractor_require(
VALUE feature,
bool silent)
4190 ASSERT_vm_unlocking();
4199 crr->raised =
false;
4200 crr->silent = silent;
4203 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4204 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4207 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4208 ractor_port_close(ec, crr->port);
4225 return rb_ractor_require(feature,
false);
4229autoload_load_body(
VALUE crr_obj)
4237ractor_autoload_load_func(
void *crr_obj)
4239 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
4243rb_ractor_autoload_load(
VALUE module,
ID name)
4249 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
4254 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4255 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4258 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4259 ractor_port_close(ec, crr->port);
4276 return ractor_shareable_proc(ec, arg_self,
false);
4282 return ractor_shareable_proc(ec, arg_self,
true);
4285#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_from_values(long n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_resize(VALUE ary, long len)
Expands or shrinks the passed array to the passed length.
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(long 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_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.
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
#define RARRAY_AREF(a, i)
#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 long RSTRUCT_LEN(VALUE st)
Returns the number of struct members.
static VALUE RSTRUCT_SET(VALUE st, int k, VALUE v)
Resembles Struct#[]=.
static VALUE RSTRUCT_GET(VALUE st, int k)
Resembles Struct#[].
#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.
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.