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);
367 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
368 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
369 ractor_mark_unshareable_parts(r);
374 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;
413free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
416 rb_hook_list_free(hook_list);
421free_targeted_hooks(
st_table *hooks_tbl)
423 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
429ractor_free(
void *ptr)
432 RUBY_DEBUG_LOG(
"free r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
434 free_targeted_hooks(&r->pub.targeted_hooks);
435 rb_thread_sched_destroy(&r->threads.sched);
437 ractor_local_storage_free(r);
438 rb_hook_list_free(&r->pub.hooks);
439 rb_st_free_embedded_table(&r->pub.targeted_hooks);
441 if (r->newobj_cache) {
444 rb_gc_ractor_cache_free(r->newobj_cache);
445 r->newobj_cache = NULL;
452 if (r->objspace && !r->main_ractor) {
453 rb_gc_objspace_disown(r->objspace);
459 if (r->in_terminated_set) {
461 ccan_list_del(&r->vmlr_node);
462 r->in_terminated_set =
false;
469 if (!r->main_ractor) {
470 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
472 free(r->registered_marks);
473 r->registered_marks = NULL;
474 r->registered_marks_cnt = r->registered_marks_capa = 0;
476 if (!r->main_ractor) {
482ractor_memsize(
const void *ptr)
487 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
491ractor_update_references(
void *ptr)
503 ractor_update_references,
511 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
520RACTOR_PTR(
VALUE self)
522 VM_ASSERT(rb_ractor_p(self));
527#define MAIN_RACTOR_ID 1
528static rb_serial_t ractor_last_id = MAIN_RACTOR_ID;
530#include "ractor_sync.c"
541 VM_ASSERT(RB_VM_LOCKED_P() || !rb_multi_ractor_p());
542 return ++ractor_last_id;
548 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
549 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
554 if (vm->ractor.cnt == 1) {
558 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
561 if (r->newobj_cache) {
562 VM_ASSERT(r == ruby_single_main_ractor);
565 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
570cancel_single_ractor_mode(
void)
573 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
575 ruby_single_main_ractor = NULL;
576 rb_yjit_invalidate_single_ractor();
577 rb_zjit_invalidate_single_ractor();
579 ASSERT_vm_unlocking();
586 VM_ASSERT(ractor_status_p(r, ractor_created));
588 if (rb_multi_ractor_p()) {
591 vm_insert_ractor0(vm, r,
false);
592 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
597 if (cur && cur->creating_child_objspace == r->objspace) {
598 cur->creating_child_objspace = NULL;
604 if (vm->ractor.cnt == 0) {
606 vm_insert_ractor0(vm, r,
true);
607 ractor_status_set(r, ractor_blocking);
608 ractor_status_set(r, ractor_running);
611 cancel_single_ractor_mode();
612 vm_insert_ractor0(vm, r,
true);
613 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
618 if (cur && cur->creating_child_objspace == r->objspace) {
619 cur->creating_child_objspace = NULL;
628 VM_ASSERT(ractor_status_p(cr, ractor_running));
629 VM_ASSERT(vm->ractor.cnt > 1);
630 VM_ASSERT(cr->threads.cnt == 1);
634 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
635 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
637 VM_ASSERT(vm->ractor.cnt > 0);
638 ccan_list_del(&cr->vmlr_node);
643 if (!rb_gc_multi_objspace_p()) {
645 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
646 cr->in_terminated_set =
true;
650 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
654 rb_gc_ractor_cache_free(cr->newobj_cache);
655 cr->newobj_cache = NULL;
665 rb_gc_objspace_retire(&cr->objspace);
669 ractor_status_set(cr, ractor_terminated);
681 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
682 VM_ASSERT(th->ec != NULL);
685 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
690 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
691 rb_gc_objspace_postmortem_self();
695 pf->th = (th->self == 0) ? th : NULL;
696 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
702 if (pf->fiber == NULL && pf->th == NULL)
return;
707#ifdef RB_THREAD_LOCAL_SPECIFIER
708 rb_current_ec_set(NULL);
710 native_tls_set(ruby_current_ec_key, NULL);
714 if (pf->fiber) rb_fiber_free_body(pf->fiber);
715 if (pf->th) rb_thread_free_body(pf->th);
719ractor_alloc(
VALUE klass)
725 r->next_ec_serial = 1;
726 VM_ASSERT(ractor_status_p(r, ractor_created));
733 .pub.id = MAIN_RACTOR_ID,
740rb_ractor_main_alloc(
void)
745 ruby_single_main_ractor = r;
750#if defined(HAVE_WORKING_FORK)
758 vm->ractor.blocking_cnt = 0;
761 rb_gc_disable_holders_atfork();
765 th->ractor->creating_child_objspace = NULL;
766 ruby_single_main_ractor = th->ractor;
767 th->ractor->status_ = ractor_created;
769 rb_ractor_living_threads_init(th->ractor);
770 rb_ractor_living_threads_insert(th->ractor, th);
772 VM_ASSERT(vm->ractor.blocking_cnt == 0);
773 VM_ASSERT(vm->ractor.cnt == 1);
779 rb_gc_ractor_cache_free(r->newobj_cache);
780 r->newobj_cache = NULL;
781 r->status_ = ractor_terminated;
783 r->threads.dying_th = NULL;
787 rb_gc_objspace_retire(&r->objspace);
789 ractor_sync_terminate_atfork(vm, r);
798 ccan_list_head_init(&r->threads.set);
800 r->threads.blocking_cnt = 0;
801 r->threads.terminating =
false;
803 r->threads.dying_th = NULL;
810 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
811 r->pub.hooks.type = hook_list_type_ractor_local;
814 rb_thread_sched_init(&r->threads.sched,
false);
815 rb_ractor_living_threads_init(r);
821 enc = rb_enc_get(name);
822 if (!rb_enc_asciicompat(enc)) {
823 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
840 r->threads.main = th;
841 rb_ractor_living_threads_insert(r, th);
842 rb_ractor_setup_default_port(r);
850 VALUE rv = ractor_alloc(self);
852 ractor_init(r, name, loc);
855 r->pub.id = ractor_next_id();
857 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", r->pub.id);
860 r->verbose = cr->verbose;
861 r->debug = cr->debug;
865 r->objspace = rb_gc_objspace_alloc();
867 rb_thread_create_ractor(r, args, block);
878 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
885 ractor_notify_exit(ec, cr, result, exc);
893 ractor_postmortem_collect(th, pf);
894 ractor_send_exit_tokens(th->ec, th->ractor);
901 ractor_atexit(ec, cr, result,
false);
908 ractor_atexit(ec, cr, ec->errinfo,
true);
918 VM_ASSERT(cr->threads.main != NULL);
919 cr->threads.main = NULL;
926 for (
int i=0; i<
len; i++) {
927 ptr[i] = ractor_receive(ec, ractor_default_port(r), NULL);
935 for (
int i=0; i<
len; i++) {
936 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
941rb_ractor_main_p_(
void)
943 VM_ASSERT(rb_multi_ractor_p());
945 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
951 return r->threads.cnt;
956rb_ractor_thread_list(
void)
962 ccan_list_for_each(&r->threads.set, th, lt_node) {
963 switch (th->status) {
964 case THREAD_RUNNABLE:
966 case THREAD_STOPPED_FOREVER:
979 VM_ASSERT(th != NULL);
983 RUBY_DEBUG_LOG(
"r(%"PRI_SERIALT_PREFIX
"u)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
984 ccan_list_add_tail(&r->threads.set, &th->lt_node);
990 if (r->threads.cnt == 1) {
991 VM_ASSERT(ractor_status_p(r, ractor_created));
992 vm_insert_ractor(th->vm, r);
999 ractor_status_set(r, ractor_blocking);
1001 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
1002 vm->ractor.blocking_cnt++;
1003 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
1007rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1009 ASSERT_vm_locking();
1010 VM_ASSERT(GET_RACTOR() == cr);
1011 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
1015rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1017 ASSERT_vm_locking();
1018 VM_ASSERT(GET_RACTOR() == cr);
1020 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
1021 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1022 vm->ractor.blocking_cnt--;
1024 ractor_status_set(cr, ractor_running);
1035 ccan_list_del(&th->lt_node);
1043 VM_ASSERT(vm->ractor.cnt > 1);
1044 ccan_list_del(&r->vmlr_node);
1049 VM_ASSERT(r->status_ == ractor_blocking);
1050 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1051 vm->ractor.blocking_cnt--;
1053 rb_gc_ractor_cache_free(r->newobj_cache);
1054 r->newobj_cache = NULL;
1057 rb_gc_objspace_disown(r->objspace);
1060 r->status_ = ractor_terminated;
1068 VM_ASSERT(cr == GET_RACTOR());
1069 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
1071 if (cr->threads.cnt == 1) {
1072 vm_remove_ractor(th->vm, cr);
1077 ccan_list_del(&th->lt_node);
1085rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1087 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1089 VM_ASSERT(cr->threads.cnt > 0);
1090 VM_ASSERT(cr == GET_RACTOR());
1092 cr->threads.blocking_cnt++;
1096rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1098 RUBY_DEBUG_LOG2(file, line,
1099 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1100 cr->threads.blocking_cnt, cr->threads.cnt);
1102 VM_ASSERT(cr == GET_RACTOR());
1104 cr->threads.blocking_cnt--;
1108rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1110 VM_ASSERT(r != GET_RACTOR());
1111 ASSERT_ractor_unlocking(r);
1112 ASSERT_vm_locking();
1116 if (ractor_status_p(r, ractor_running)) {
1119 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1127rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1129 VM_ASSERT(r != GET_RACTOR());
1130 ASSERT_ractor_unlocking(r);
1131 ASSERT_vm_locking();
1135 if (main_th->status != THREAD_KILLED) {
1136 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1137 rb_threadptr_interrupt(main_th);
1140 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1148ractor_terminal_interrupt_all(
rb_vm_t *vm)
1150 if (vm->ractor.cnt > 1) {
1153 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1154 if (r != vm->ractor.main_ractor) {
1155 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
1156 rb_ractor_terminate_interrupt_main_thread(r);
1166rb_ractor_terminate_all(
void)
1171 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1173 VM_ASSERT(cr == GET_RACTOR());
1177 ractor_terminal_interrupt_all(vm);
1180 rb_thread_terminate_all(GET_THREAD());
1184 while (vm->ractor.cnt > 1) {
1185 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1186 vm->ractor.sync.terminate_waiting =
true;
1189 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1190 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1191 rb_ractor_sched_wait_terminate(vm, &vm->ractor.sync.terminate_cond, 1000 );
1192 while (vm->ractor.sched.barrier_is_waiting) {
1199 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1201 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1202 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1204 ractor_terminal_interrupt_all(vm);
1211 rb_gc_objspace_absorb_all_zombies();
1215rb_vm_main_ractor_ec(
rb_vm_t *vm)
1232 if (running_ec) {
return running_ec; }
1233 return vm->ractor.main_thread->ec;
1237ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1239 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1341 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1342 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1343 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1345 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1349 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1352 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1356 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1357 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1358 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1359 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1377 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1378 if (r != vm->ractor.main_ractor) {
1379 fprintf(stderr,
"r:%"PRI_SERIALT_PREFIX
"u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1387 if (rb_ractor_main_p()) {
1392 if (UNLIKELY(cr->r_stdin == 0)) {
1393 cr->r_stdin = rb_io_prep_stdin();
1400rb_ractor_stdout(
void)
1402 if (rb_ractor_main_p()) {
1407 if (UNLIKELY(cr->r_stdout == 0)) {
1408 cr->r_stdout = rb_io_prep_stdout();
1410 return cr->r_stdout;
1415rb_ractor_stderr(
void)
1417 if (rb_ractor_main_p()) {
1422 if (UNLIKELY(cr->r_stderr == 0)) {
1423 cr->r_stderr = rb_io_prep_stderr();
1425 return cr->r_stderr;
1432 if (rb_ractor_main_p()) {
1444 if (rb_ractor_main_p()) {
1456 if (rb_ractor_main_p()) {
1469 return &cr->pub.targeted_hooks;
1473rb_obj_set_shareable_no_assert(
VALUE obj)
1480 rb_gc_obj_became_shareable(obj);
1484 bool froze_ivars =
false;
1488 RBASIC_SET_SHAPE_ID(obj, rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj)));
1499 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1500 if (imemo_type_p(fields, imemo_fields)) {
1503 rb_gc_obj_became_shareable(fields);
1505 if (froze_ivars) RBASIC_SET_SHAPE_ID(fields, RBASIC_SHAPE_ID(obj));
1509 rb_imemo_fields_record_shrefs(fields);
1514#ifndef STRICT_VERIFY_SHAREABLE
1515#define STRICT_VERIFY_SHAREABLE 0
1519rb_ractor_verify_shareable(
VALUE obj)
1521#if STRICT_VERIFY_SHAREABLE
1522 rb_gc_verify_shareable(obj);
1532 rb_obj_set_shareable_no_assert(obj);
1544enum obj_traverse_iterator_result {
1550typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1551typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1552typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1554static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1557 rb_obj_traverse_enter_func enter_func;
1558 rb_obj_traverse_leave_func leave_func;
1577 if (obj_traverse_i(key, d->data)) {
1582 if (obj_traverse_i(val, d->data)) {
1591obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1595 if (obj_traverse_i(obj, d->data)) {
1608 RB_VM_LOCKING_NO_BARRIER() {
1609 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1617 if (UNLIKELY(!data->rec)) {
1618 data->rec_hash = rb_ident_hash_new();
1620 data->rec = RHASH_ST_TABLE(data->rec_hash);
1626obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1630 if (obj_traverse_i(val, d->data)) {
1643 switch (data->enter_func(obj)) {
1644 case traverse_cont:
break;
1645 case traverse_skip:
return 0;
1646 case traverse_stop:
return 1;
1649 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1655 if (rb_obj_shape_has_ivars(obj)) {
1661 if (d.stop)
return 1;
1679 rb_ary_cancel_sharing(obj);
1683 if (obj_traverse_i(e, data))
return 1;
1697 if (d.stop)
return 1;
1703 long len = RSTRUCT_LEN_RAW(obj);
1704 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1706 for (
long i=0; i<
len; i++) {
1707 if (obj_traverse_i(ptr[i], data))
return 1;
1713 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1717 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1718 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1721 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1722 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1727 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1730 if (!ptr || !
type->function.dmark) {
1733 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1734 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1735 for (; *offsets != RUBY_REF_END; offsets++) {
1736 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1737 if (obj_traverse_i(ref, data))
return 1;
1741 if (obj_traverse_reachable(obj, data))
return 1;
1748 if (obj_traverse_reachable(obj, data))
return 1;
1757 rb_bug(
"unreachable");
1760 if (data->leave_func(obj) == traverse_stop) {
1769 rb_obj_traverse_final_func final_func;
1774obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1777 if (data->final_func(key)) {
1787rb_obj_traverse(
VALUE obj,
1788 rb_obj_traverse_enter_func enter_func,
1789 rb_obj_traverse_leave_func leave_func,
1790 rb_obj_traverse_final_func final_func)
1793 .enter_func = enter_func,
1794 .leave_func = leave_func,
1798 if (obj_traverse_i(obj, &data))
return 1;
1799 if (final_func && data.rec) {
1801 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1808allow_frozen_shareable_p(
VALUE obj)
1818 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1827make_shareable_freeze(
VALUE obj)
1830 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1833 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1836 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1837 rb_hash_freeze(obj);
1844static enum obj_traverse_iterator_result
1845make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1848 make_shareable_freeze(obj);
1851 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1855 return traverse_skip;
1862static int obj_refer_only_shareables_p(
VALUE obj);
1864static enum obj_traverse_iterator_result
1865make_shareable_check_shareable(
VALUE obj)
1870 return traverse_skip;
1872 else if (!allow_frozen_shareable_p(obj)) {
1874 rb_raise(rb_eRactorError,
1875 "can not make shareable object for %+"PRIsVALUE, obj);
1877 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1878 if (obj_refer_only_shareables_p(obj)) {
1879 make_shareable_check_shareable_freeze(obj, traverse_skip);
1881 return traverse_skip;
1884 rb_raise(rb_eRactorError,
1885 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1889 rb_proc_ractor_make_shareable(obj,
Qundef);
1890 return traverse_cont;
1893 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1897 switch (
TYPE(obj)) {
1899 return traverse_skip;
1906 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1907 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1908 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1909 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1918 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1921static enum obj_traverse_iterator_result
1922mark_shareable(
VALUE obj)
1925 rb_str_make_independent(obj);
1928 rb_obj_set_shareable_no_assert(obj);
1929 return traverse_cont;
1935 rb_obj_traverse(obj,
1936 make_shareable_check_shareable,
1937 null_leave, mark_shareable);
1946 VALUE copy = ractor_copy(obj);
1951rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1954 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
1962rb_ractor_ensure_main_ractor(
const char *msg)
1964 if (!rb_ractor_main_p()) {
1965 rb_raise(rb_eRactorIsolationError,
"%s", msg);
1969static enum obj_traverse_iterator_result
1970shareable_p_enter(
VALUE obj)
1973 return traverse_skip;
1979 mark_shareable(obj);
1980 return traverse_skip;
1983 allow_frozen_shareable_p(obj)) {
1984 return traverse_cont;
1992 if (obj_refer_only_shareables_p(obj)) {
1993 mark_shareable(obj);
1994 return traverse_skip;
1998 return traverse_stop;
2002rb_ractor_shareable_p_continue(
VALUE obj)
2004 if (rb_obj_traverse(obj,
2005 shareable_p_enter, null_leave,
2014static enum obj_traverse_iterator_result
2015null_leave(
VALUE obj)
2017 return traverse_cont;
2033 rb_obj_traverse_replace_enter_func enter_func;
2034 rb_obj_traverse_replace_leave_func leave_func;
2040 VALUE rec_keepalive;
2053obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2059obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2064 if (obj_traverse_replace_i(*key, data)) {
2068 else if (*key != data->replacement) {
2069 VALUE v = *key = data->replacement;
2073 if (obj_traverse_replace_i(*val, data)) {
2077 else if (*val != data->replacement) {
2078 VALUE v = *val = data->replacement;
2086obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2092obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2097 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2101 else if (*(
VALUE *)val != data->replacement) {
2112 if (UNLIKELY(!data->rec)) {
2113 data->rec = st_init_numtable();
2120obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2122 int *pcnt = (
int *)ptr;
2130obj_refer_only_shareables_p(
VALUE obj)
2133 RB_VM_LOCKING_NO_BARRIER() {
2134 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
2142 st_data_t replacement;
2145 data->replacement = obj;
2152 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2153 data->replacement = (
VALUE)replacement;
2157 switch (data->enter_func(obj, data)) {
2158 case traverse_cont:
break;
2159 case traverse_skip:
return 0;
2160 case traverse_stop:
return 1;
2163 replacement = (st_data_t)data->replacement;
2164 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2173#define CHECK_AND_REPLACE(parent_obj, v) do { \
2175 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2176 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2179 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2180 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2182 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2188 rb_st_foreach_with_replace(
2189 rb_imemo_fields_complex_tbl(fields_obj),
2190 obj_iv_hash_traverse_replace_foreach_i,
2191 obj_iv_hash_traverse_replace_i,
2194 if (d.stop)
return 1;
2197 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2198 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2199 for (uint32_t i = 0; i < fields_count; i++) {
2200 CHECK_AND_REPLACE(fields_obj, fields[i]);
2214 rb_str_make_independent(obj);
2219 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2220 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2221 if (rb_shape_complex_p(shape_id)) {
2227 rb_st_foreach_with_replace(
2228 rb_imemo_fields_complex_tbl(fields_obj),
2229 obj_iv_hash_traverse_replace_foreach_i,
2230 obj_iv_hash_traverse_replace_i,
2233 if (d.stop)
return 1;
2236 attr_index_t
len = RSHAPE_LEN(shape_id);
2237 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2239 for (attr_index_t i = 0; i <
len; i++) {
2240 CHECK_AND_REPLACE(obj, ptr[i]);
2248 rb_ary_cancel_sharing(obj);
2253 if (obj_traverse_replace_i(e, data)) {
2256 else if (e != data->replacement) {
2270 rb_hash_stlike_foreach_with_replace(obj,
2271 obj_hash_traverse_replace_foreach_i,
2272 obj_hash_traverse_replace_i,
2274 if (d.stop)
return 1;
2278 if (obj_traverse_replace_i(ifnone, data)) {
2281 else if (ifnone != data->replacement) {
2289 long len = RSTRUCT_LEN_RAW(obj);
2290 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2292 for (
long i=0; i<
len; i++) {
2293 CHECK_AND_REPLACE(obj, ptr[i]);
2299 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2303 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2304 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2307 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2308 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2312 if (!data->move && obj_refer_only_shareables_p(obj)) {
2316 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2330 rb_bug(
"unreachable");
2333 data->replacement = (
VALUE)replacement;
2335 if (data->leave_func(obj, data) == traverse_stop) {
2346rb_obj_traverse_replace(
VALUE obj,
2347 rb_obj_traverse_replace_enter_func enter_func,
2348 rb_obj_traverse_replace_leave_func leave_func,
2352 .enter_func = enter_func,
2353 .leave_func = leave_func,
2360 int stopped = obj_traverse_replace_i(obj, &data);
2364 if (data.rec) st_free_table(data.rec);
2371 return data.replacement;
2381enum courier_node_kind {
2383 COURIER_KIND_BACKTRACE,
2384 COURIER_KIND_STRING,
2387 COURIER_KIND_OBJECT,
2388 COURIER_KIND_STRUCT,
2391 COURIER_KIND_REGEXP,
2392 COURIER_KIND_HOOKED,
2399 COURIER_HOOK_MARSHAL_DUMP,
2401 COURIER_HOOK_COMPAT,
2402 COURIER_HOOK_DUMP_DATA,
2406static enum courier_hook
2407courier_hook_of(
VALUE obj)
2409 if (
rb_obj_respond_to(obj, id_marshal_dump, TRUE))
return COURIER_HOOK_MARSHAL_DUMP;
2411 if (rb_marshal_compat_lookup(
CLASS_OF(obj), NULL, NULL))
return COURIER_HOOK_COMPAT;
2413 return COURIER_HOOK_NONE;
2417 enum courier_node_kind kind;
2426 struct {
char *ptr;
long len, capa;
int encidx;
VALUE klass; } str;
2427 struct {
long len; uint32_t *elems;
VALUE klass; } ary;
2428 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2429 struct {
VALUE klass; } obj;
2430 struct {
long len; uint32_t *elems;
VALUE klass; } strct;
2431 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2432 struct {
void *blob;
int size; } bt;
2433 struct {
VALUE src;
int options;
VALUE klass; } re;
2434 struct {
VALUE klass; uint32_t payload_id;
enum courier_hook hook; } hooked;
2441 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2449#define COURIER_ID_REF_BIT 0x80000000u
2457 uint32_t refs_count;
2485 uint32_t
capa = c->capa ? c->capa * 2 : 8;
2491 ruby_xfree(old_nodes);
2498 uint32_t
capa = c->refs_capa ? c->refs_capa * 2 : 8;
2500 if (c->refs_count > 0)
MEMCPY(refs, c->refs,
VALUE, c->refs_count);
2501 VALUE *old_refs = c->refs;
2503 c->refs_capa =
capa;
2504 ruby_xfree(old_refs);
2510 if (RB_UNLIKELY(c->count == c->capa)) courier_grow_nodes(c);
2515 n->kind = COURIER_KIND_REF;
2531 c->order =
ALLOC_N(uint32_t, nodes);
2536 c->refs_capa = refs;
2548 if (RB_UNLIKELY(c->refs_count == c->refs_capa)) courier_grow_refs(c);
2549 c->refs[c->refs_count] = v;
2550 return COURIER_ID_REF_BIT | c->refs_count++;
2557 if (
id & COURIER_ID_REF_BIT)
return c->refs[
id & ~COURIER_ID_REF_BIT];
2564move_neutralize_source(
VALUE obj)
2569 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2570 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2580 bool wipe_body =
true;
2583 if (!STR_EMBED_P(obj) && !rb_str_reembeddable_p(obj)) {
2588 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2590 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2594 wipe_body = !rb_str_embedded_shared_root_p(obj);
2597 if (!ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && (ARY_SHARED_ROOT_P(obj) ||
OBJ_FROZEN(obj))) {
2602 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2604 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2605 if (!ARY_SHARED_ROOT_P(obj)) {
2608 RARRAY(obj)->as.heap.len = 0;
2612 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2624 size_t slot_size = rb_gc_obj_slot_size(obj);
2625 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2626 RBASIC(obj)->flags = flags;
2627 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2645courier_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2648 uint32_t kid = courier_capture(hc->b, (
VALUE)key);
2649 uint32_t vid = courier_capture(hc->b, (
VALUE)val);
2650 hc->kv[hc->i++] = kid;
2651 hc->kv[hc->i++] = vid;
2664courier_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2667 if (oc->n == oc->capa) {
2668 oc->capa = oc->capa ? oc->capa * 2 : 4;
2670 REALLOC_N(oc->vals, uint32_t, oc->capa);
2672 uint32_t vid = courier_capture(oc->b, val);
2673 oc->ids[oc->n] = name;
2674 oc->vals[oc->n] = vid;
2686 rb_ivar_foreach_buffered(obj, courier_capture_ivar_i, (st_data_t)&oc);
2687 b->c->nodes[id].niv = (uint32_t)oc.n;
2688 b->c->nodes[id].iv_ids = oc.ids;
2689 b->c->nodes[id].iv_vals = oc.vals;
2697courier_capture_hooked(
struct courier_build *b,
VALUE obj, uint32_t
id,
enum courier_hook hook)
2703 case COURIER_HOOK_DUMP: {
2712 case COURIER_HOOK_MARSHAL_DUMP:
2713 payload =
rb_funcallv(obj, id_marshal_dump, 0, 0);
2715 case COURIER_HOOK_DUMP_DATA:
2718 case COURIER_HOOK_COMPAT: {
2720 rb_marshal_compat_lookup(klass, &dumper, NULL);
2721 payload = dumper(obj);
2725 rb_bug(
"courier_capture_hooked: no dump protocol");
2728 uint32_t payload_id = courier_capture(b, payload);
2730 b->c->nodes[id].kind = COURIER_KIND_HOOKED;
2731 b->c->nodes[id].u.hooked.klass = klass;
2732 b->c->nodes[id].u.hooked.hook = hook;
2733 b->c->nodes[id].u.hooked.payload_id = payload_id;
2753 return courier_alloc_ref(b->c, obj);
2761 if (st_lookup(b->c->seen, (st_data_t)obj, &existing)) {
2762 return (uint32_t)existing - 1;
2766 return courier_alloc_ref(b->c, obj);
2769 uint32_t
id = courier_alloc_node(b->c);
2770 st_insert(b->c->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2774 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2778 b->c->nodes[id].frozen = frozen;
2779 courier_capture_ivars(b, obj,
id);
2786 if (!b->copy) rb_str_make_independent(obj);
2787 long len = RSTRING_LEN(obj);
2791 const int termlen = rb_enc_mbminlen(rb_enc_from_index(encidx));
2794 if (!b->copy && !STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2797 ptr =
RSTRING(obj)->as.heap.ptr;
2805 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2806 memset(ptr +
len, 0, termlen);
2809 b->c->nodes[id].kind = COURIER_KIND_STRING;
2810 b->c->nodes[id].u.str.klass = courier_klass(b, obj);
2811 b->c->nodes[id].u.str.ptr = ptr;
2812 b->c->nodes[id].u.str.len =
len;
2813 b->c->nodes[id].u.str.capa =
capa;
2814 b->c->nodes[id].u.str.encidx = encidx;
2821 for (
long i = 0; i <
len; i++) {
2822 elems[i] = courier_capture(b,
RARRAY_AREF(obj, i));
2824 b->c->nodes[id].kind = COURIER_KIND_ARRAY;
2825 b->c->nodes[id].u.ary.klass = courier_klass(b, obj);
2826 b->c->nodes[id].u.ary.len =
len;
2827 b->c->nodes[id].u.ary.elems = elems;
2831 if (!b->copy && !ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2838 uint32_t ifnone_id = courier_capture(b,
RHASH_IFNONE(obj));
2840 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2842 rb_hash_stlike_foreach(obj, courier_capture_hash_i, (st_data_t)&hc);
2843 b->c->nodes[id].kind = COURIER_KIND_HASH;
2844 b->c->nodes[id].u.hash.klass = courier_klass(b, obj);
2845 b->c->nodes[id].u.hash.size = size;
2846 b->c->nodes[id].u.hash.kv = kv;
2847 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2848 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2849 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2851 if (!b->copy) rb_hash_free(obj);
2856 b->c->nodes[id].kind = COURIER_KIND_OBJECT;
2857 b->c->nodes[id].u.obj.klass = courier_klass(b, obj);
2863 for (
long i = 0; i <
len; i++) {
2864 elems[i] = courier_capture(b,
RSTRUCT_GET(obj, (
int)i));
2866 b->c->nodes[id].kind = COURIER_KIND_STRUCT;
2867 b->c->nodes[id].u.strct.len =
len;
2868 b->c->nodes[id].u.strct.elems = elems;
2869 b->c->nodes[id].u.strct.klass = courier_klass(b, obj);
2871 if (!b->copy && RSTRUCT_EMBED_LEN(obj) == 0) {
2872 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2882 void *regs = rb_match_blob_dump(obj, &re, &st, &nregs, !b->copy);
2883 uint32_t rid = courier_capture(b, re);
2884 uint32_t sid = courier_capture(b, st);
2885 b->c->nodes[id].kind = COURIER_KIND_MATCH;
2886 b->c->nodes[id].u.match.regexp_id = rid;
2887 b->c->nodes[id].u.match.str_id = sid;
2888 b->c->nodes[id].u.match.num_regs = nregs;
2889 b->c->nodes[id].u.match.regs = regs;
2890 b->c->nodes[id].u.match.klass = courier_klass(b, obj);
2896 VM_ASSERT(!b->copy);
2902 uint32_t pathv_id = courier_capture(b, fptr->
pathv);
2903 uint32_t ecopts_id = courier_capture(b, fptr->
encs.
ecopts);
2906 uint32_t timeout_id = courier_capture(b, fptr->
timeout);
2914 fptr->wakeup_mutex =
Qnil;
2916 b->c->nodes[id].kind = COURIER_KIND_IO;
2917 b->c->nodes[id].u.io.fptr = fptr;
2918 b->c->nodes[id].u.io.klass = courier_klass(b, obj);
2919 b->c->nodes[id].u.io.pathv_id = pathv_id;
2920 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
2921 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
2922 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
2923 b->c->nodes[id].u.io.timeout_id = timeout_id;
2934 b->c->nodes[id].kind = COURIER_KIND_REGEXP;
2935 b->c->nodes[id].u.re.klass = courier_klass(b, obj);
2936 b->c->nodes[id].u.re.src = src;
2944 if (b->copy && rb_backtrace_p(obj)) {
2946 void *blob = rb_backtrace_blob_dump(obj, &size);
2947 b->c->nodes[id].kind = COURIER_KIND_BACKTRACE;
2948 b->c->nodes[id].u.bt.blob = blob;
2949 b->c->nodes[id].u.bt.size = size;
2956 enum courier_hook hook = b->copy ? courier_hook_of(obj) : COURIER_HOOK_NONE;
2957 if (hook == COURIER_HOOK_NONE) {
2958 rb_raise(rb_eRactorError,
"can not %s a %"PRIsVALUE
" object",
2961 courier_capture_hooked(b, obj,
id, hook);
2966 if (!b->copy) move_neutralize_source(obj);
2968 b->c->order[b->ordered++] = id;
2975 uint32_t nodes, refs;
2981move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
2988move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3007 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
3008 st_insert(seen, (st_data_t)obj, 0);
3015 rb_class_check_singleton_movable(klass);
3024 move_preflight(rm->
regexp, ctx);
3025 move_preflight(rm->
str, ctx);
3034 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)ctx);
3045 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
3050 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
3052 if (
RTEST(fptr->wakeup_mutex)) {
3054 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
3056 move_preflight(fptr->
pathv, ctx);
3060 move_preflight(fptr->
timeout, ctx);
3064 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
3076 uint32_t nodes, refs;
3083copy_support_val_i(st_data_t val, st_data_t arg)
3086 if (!copy_courier_supported_p((
VALUE)val, ctx)) {
3094copy_support_ivar_i(
ID name,
VALUE val, st_data_t arg)
3096 return copy_support_val_i((st_data_t)val, arg);
3100copy_support_hash_i(st_data_t key, st_data_t val, st_data_t arg)
3102 if (copy_support_val_i(key, arg) == ST_STOP)
return ST_STOP;
3103 return copy_support_val_i(val, arg);
3116 if (st_lookup(seen, (st_data_t)obj, NULL))
return true;
3117 st_insert(seen, (st_data_t)obj, 0);
3129 if (!copy_courier_supported_p(rm->
regexp, ctx))
return false;
3130 if (!copy_courier_supported_p(rm->
str, ctx))
return false;
3135 if (!rb_backtrace_p(obj) && courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3139 if (!copy_courier_supported_p(
RARRAY_AREF(obj, i), ctx))
return false;
3143 rb_hash_stlike_foreach(obj, copy_support_hash_i, (st_data_t)ctx);
3144 if (!ctx->ok)
return false;
3145 if (!copy_courier_supported_p(
RHASH_IFNONE(obj), ctx))
return false;
3149 if (!copy_courier_supported_p(
RSTRUCT_GET(obj, (
int)i), ctx))
return false;
3156 if (courier_hook_of(obj) == COURIER_HOOK_NONE)
return false;
3171 bool ok = copy_courier_supported_p(obj, &scan);
3172 st_free_table(scan.seen);
3173 if (!ok)
return NULL;
3177 courier_reserve(c, scan.nodes, scan.refs);
3178 c->seen = st_init_numtable();
3185 enum ruby_tag_type state;
3188 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3189 c->root = courier_capture(&b, obj);
3192 st_free_table(c->seen);
3195 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3208 enum ruby_tag_type state;
3211 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3212 move_preflight(obj, &scan);
3215 st_free_table(scan.seen);
3216 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3220 courier_reserve(c, scan.nodes, scan.refs);
3221 c->seen = st_init_numtable();
3229 enum ruby_tag_type state;
3232 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3233 c->root = courier_capture(&b, obj);
3236 st_free_table(c->seen);
3238 if (state != TAG_NONE) {
3242 EC_JUMP_TAG(ec, state);
3254 RBASIC_SET_CLASS(shell, klass);
3259 rb_class_take_ownership(klass);
3272 for (uint32_t i = 0; i < c->count; i++) {
3276 case COURIER_KIND_REF:
3279 case COURIER_KIND_STRING:
3283 shell = rb_str_new_owned(n->u.str.ptr, n->u.str.len, n->u.str.capa, n->u.str.encidx);
3284 n->u.str.ptr = NULL;
3285 courier_apply_klass(shell, n->u.str.klass);
3287 case COURIER_KIND_ARRAY:
3289 courier_apply_klass(shell, n->u.ary.klass);
3291 case COURIER_KIND_HASH:
3292 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
3293 courier_apply_klass(shell, n->u.hash.klass);
3295 case COURIER_KIND_OBJECT:
3299 courier_apply_klass(shell, n->u.obj.klass);
3301 case COURIER_KIND_STRUCT:
3303 courier_apply_klass(shell, n->u.strct.klass);
3305 case COURIER_KIND_MATCH:
3306 shell = rb_match_blob_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
3307 courier_apply_klass(shell, n->u.match.klass);
3309 case COURIER_KIND_BACKTRACE:
3310 shell = rb_backtrace_blob_load(n->u.bt.blob, n->u.bt.size);
3312 case COURIER_KIND_REGEXP:
3315 shell = rb_reg_init_str(rb_reg_s_alloc(
rb_class_real(n->u.re.klass)), n->u.re.src, n->u.re.options);
3316 courier_apply_klass(shell, n->u.re.klass);
3318 case COURIER_KIND_HOOKED:
3319 if (n->u.hooked.hook == COURIER_HOOK_DUMP) {
3326 courier_apply_klass(shell, n->u.hooked.klass);
3328 case COURIER_KIND_IO:
3330 courier_apply_klass(shell, n->u.io.klass);
3331 RFILE(shell)->fptr = n->u.io.fptr;
3332 n->u.io.fptr->
self = shell;
3333 n->u.io.fptr = NULL;
3336 rb_bug(
"rb_ractor_courier_materialize: bad node kind");
3347 for (uint32_t k = 0; k < c->count; k++) {
3348 uint32_t i = c->order[k];
3352 case COURIER_KIND_ARRAY: {
3355 const long len = n->u.ary.len;
3358 for (
long j = 0; j <
len; j++) {
3359 RARRAY_ASET(shell, j, courier_child(c, shells, n->u.ary.elems[j]));
3364 case COURIER_KIND_HASH:
3365 for (
long j = 0; j < n->u.hash.size; j++) {
3366 rb_hash_aset(shell, courier_child(c, shells, n->u.hash.kv[2 * j]),
3367 courier_child(c, shells, n->u.hash.kv[2 * j + 1]));
3370 VALUE ifnone = courier_child(c, shells, n->u.hash.ifnone_id);
3371 if (n->u.hash.proc_default) {
3372 rb_hash_set_default_proc(shell, ifnone);
3374 else if (ifnone !=
Qnil) {
3375 rb_hash_set_default(shell, ifnone);
3378 case COURIER_KIND_HOOKED: {
3379 VALUE payload = courier_child(c, shells, n->u.hooked.payload_id);
3380 VALUE klass = n->u.hooked.klass;
3382 switch (n->u.hooked.hook) {
3383 case COURIER_HOOK_DUMP:
3385 rb_raise(
rb_eTypeError,
"class %"PRIsVALUE
" needs to have method '_load'", klass);
3393 case COURIER_HOOK_MARSHAL_DUMP:
3394 case COURIER_HOOK_DUMP_DATA:
3395 mid = n->u.hooked.hook == COURIER_HOOK_MARSHAL_DUMP ? id_marshal_load : id_load_data;
3397 rb_raise(
rb_eTypeError,
"instance of %"PRIsVALUE
" needs to have method '%"PRIsVALUE
"'",
3398 klass, rb_id2str(mid));
3402 case COURIER_HOOK_COMPAT: {
3404 rb_marshal_compat_lookup(klass, NULL, &loader);
3405 loader(shell, payload);
3409 rb_bug(
"rb_ractor_courier_materialize: no dump protocol");
3413 case COURIER_KIND_STRUCT:
3414 for (
long j = 0; j < n->u.strct.len; j++) {
3415 RSTRUCT_SET(shell, (
int)j, courier_child(c, shells, n->u.strct.elems[j]));
3418 case COURIER_KIND_MATCH:
3419 rb_match_blob_load(shell, courier_child(c, shells, n->u.match.regexp_id),
3420 courier_child(c, shells, n->u.match.str_id),
3421 n->u.match.num_regs, n->u.match.regs);
3423 case COURIER_KIND_IO: {
3438 for (uint32_t j = 0; j < n->niv; j++) {
3439 rb_ivar_set(shell, n->iv_ids[j], courier_child(c, shells, n->iv_vals[j]));
3444 for (uint32_t i = 0; i < c->count; i++) {
3451 VALUE root = (c->count || c->refs_count) ? courier_child(c, shells, c->root) :
Qnil;
3459 for (uint32_t i = 0; i < c->count; i++) {
3461 ruby_xfree(n->iv_ids);
3462 ruby_xfree(n->iv_vals);
3464 case COURIER_KIND_STRING:
3465 ruby_xfree(n->u.str.ptr);
3467 case COURIER_KIND_ARRAY:
3468 ruby_xfree(n->u.ary.elems);
3470 case COURIER_KIND_HASH:
3471 ruby_xfree(n->u.hash.kv);
3473 case COURIER_KIND_STRUCT:
3474 ruby_xfree(n->u.strct.elems);
3476 case COURIER_KIND_MATCH:
3477 rb_match_blob_free(n->u.match.regs);
3479 case COURIER_KIND_BACKTRACE:
3480 ruby_xfree(n->u.bt.blob);
3482 case COURIER_KIND_IO:
3488 n->u.io.fptr = NULL;
3495 ruby_xfree(c->nodes);
3496 ruby_xfree(c->order);
3497 ruby_xfree(c->refs);
3509 if (c->seen) rb_mark_set(c->seen);
3510 for (uint32_t i = 0; i < c->refs_count; i++) {
3511 rb_gc_mark(c->refs[i]);
3513 for (uint32_t i = 0; i < c->count; i++) {
3515 if (n->kind == COURIER_KIND_REF) {
3516 rb_gc_mark(n->u.ref);
3518 else if (n->kind == COURIER_KIND_OBJECT) {
3519 rb_gc_mark(n->u.obj.klass);
3521 else if (n->kind == COURIER_KIND_STRUCT) {
3522 rb_gc_mark(n->u.strct.klass);
3524 else if (n->kind == COURIER_KIND_MATCH) {
3525 rb_gc_mark(n->u.match.klass);
3527 else if (n->kind == COURIER_KIND_IO) {
3528 rb_gc_mark(n->u.io.klass);
3530 else if (n->kind == COURIER_KIND_STRING) {
3531 rb_gc_mark(n->u.str.klass);
3533 else if (n->kind == COURIER_KIND_BACKTRACE) {
3534 rb_backtrace_blob_mark(n->u.bt.blob, n->u.bt.size);
3536 else if (n->kind == COURIER_KIND_ARRAY) {
3537 rb_gc_mark(n->u.ary.klass);
3539 else if (n->kind == COURIER_KIND_HASH) {
3540 rb_gc_mark(n->u.hash.klass);
3542 else if (n->kind == COURIER_KIND_REGEXP) {
3543 rb_gc_mark(n->u.re.src);
3544 rb_gc_mark(n->u.re.klass);
3546 else if (n->kind == COURIER_KIND_HOOKED) {
3547 rb_gc_mark(n->u.hooked.klass);
3556ractor_native_shallow_copy(
VALUE obj)
3570 rb_obj_copy_ivar(copy, obj);
3573 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3579 copy = rb_hash_dup(obj);
3583 rb_struct_init_copy(copy, obj);
3587 rb_match_init_copy(copy, obj);
3592 if (rb_backtrace_p(obj)) {
3593 copy = rb_backtrace_dup(obj);
3605 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3615 RBASIC_SET_SHAPE_ID(copy, rb_obj_shape_transition_frozen(copy));
3620static enum obj_traverse_iterator_result
3624 data->replacement = obj;
3625 return traverse_skip;
3628 VALUE copy = ractor_native_shallow_copy(obj);
3629 if (UNDEF_P(copy))
return traverse_stop;
3630 data->replacement = copy;
3631 return traverse_cont;
3635static enum obj_traverse_iterator_result
3638 return traverse_cont;
3644ractor_copy_native_try(
VALUE obj)
3646 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3652ractor_copy(
VALUE obj)
3654 VALUE copy = ractor_copy_native_try(obj);
3655 if (UNDEF_P(copy)) {
3657 ractor_marshal_dump_rescue, obj,
3674} freed_ractor_local_keys;
3678ractor_local_keys_purge(
st_table *local_storage)
3680 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3682 st_data_t val, k = (st_data_t)key;
3683 if (st_delete(local_storage, &k, &val) &&
3685 (*key->type->free)((
void *)val);
3692ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3695 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3699static enum rb_id_table_iterator_result
3700idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3703 return ID_TABLE_CONTINUE;
3709 if (r->local_storage) {
3710 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3715 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3716 ractor_local_keys_purge(r->local_storage);
3720 if (r->idkey_local_storage) {
3721 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3724 rb_gc_mark(r->local_storage_store_lock);
3728ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3731 if (k->type->
free) (*k->type->
free)((
void *)val);
3738 if (r->local_storage) {
3739 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3740 st_free_table(r->local_storage);
3743 if (r->idkey_local_storage) {
3744 rb_id_table_free(r->idkey_local_storage);
3749rb_ractor_local_storage_value_mark(
void *ptr)
3751 rb_gc_mark((
VALUE)ptr);
3765 rb_ractor_local_storage_value_mark,
3773 key->type =
type ?
type : &ractor_local_storage_type_null;
3774 key->main_cache = (
void *)
Qundef;
3788 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3789 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3790 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3792 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3799 if (rb_ractor_main_p()) {
3800 if (!UNDEF_P((
VALUE)key->main_cache)) {
3801 *pret = key->main_cache;
3811 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3825 if (cr->local_storage == NULL) {
3826 cr->local_storage = st_init_numtable();
3829 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3831 if (rb_ractor_main_p()) {
3832 key->main_cache = ptr;
3840 if (ractor_local_ref(key, &val)) {
3851 if (ractor_local_ref(key, (
void **)val)) {
3862 ractor_local_set(key, (
void *)val);
3869 if (ractor_local_ref(key, &ret)) {
3880 ractor_local_set(key, ptr);
3883#define DEFAULT_KEYS_CAPA 0x10
3886rb_ractor_finish_marking(
bool full_mark)
3891 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3901 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3902 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3903 if (owner == NULL || owner->local_storage == NULL)
continue;
3904 ractor_local_keys_purge(owner->local_storage);
3907 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3908 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3910 freed_ractor_local_keys.cnt = 0;
3911 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3912 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3913 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3918 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3919 rb_ractor_reap_dead_ports(r);
3921 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
3922 rb_ractor_reap_dead_ports(vm->ractor.main_ractor);
3932 struct rb_id_table *tbl = cr->idkey_local_storage;
3935 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
3948 struct rb_id_table *tbl = cr->idkey_local_storage;
3951 tbl = cr->idkey_local_storage = rb_id_table_create(2);
3953 rb_id_table_insert(tbl,
id, val);
3965ractor_local_value_store_i(
VALUE ptr)
3970 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
3975 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
3988 .tbl = cr->idkey_local_storage,
3992 if (data.tbl == NULL) {
3993 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
3995 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
4000 if (!cr->local_storage_store_lock) {
4013 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
4017 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
4041RUBY_REFERENCES(cross_ractor_require_refs) = {
4048 "ractor/cross_ractor_require",
4050 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
4055 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
4059require_body(
VALUE crr_obj)
4063 VALUE feature = crr->as.require.feature;
4069 int rb_require_internal_silent(
VALUE fname);
4070 return INT2NUM(rb_require_internal_silent(feature));
4087require_result_send_body(
VALUE ary)
4094 ractor_port_send(ec, port, results,
Qfalse);
4099require_result_send_resuce(
VALUE port,
VALUE errinfo)
4102 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
4112 const bool silent = crr->silent;
4114 VALUE debug, errinfo;
4117 errinfo = rb_errinfo();
4125 rb_set_errinfo(errinfo);
4130 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
4138ractor_require_func(
void *crr_obj)
4140 return ractor_require_protect((
VALUE)crr_obj, require_body);
4144rb_ractor_require(
VALUE feature,
bool silent)
4147 ASSERT_vm_unlocking();
4156 crr->raised =
false;
4157 crr->silent = silent;
4160 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4161 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4164 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4165 ractor_port_close(ec, crr->port);
4182 return rb_ractor_require(feature,
false);
4186autoload_load_body(
VALUE crr_obj)
4194ractor_autoload_load_func(
void *crr_obj)
4196 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
4200rb_ractor_autoload_load(
VALUE module,
ID name)
4206 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
4211 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4212 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4215 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4216 ractor_port_close(ec, crr->port);
4233 return ractor_shareable_proc(ec, arg_self,
false);
4239 return ractor_shareable_proc(ec, arg_self,
true);
4242#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.