10#include "ractor_core.h"
11#include "internal/array.h"
12#include "internal/complex.h"
13#include "internal/cont.h"
14#include "internal/error.h"
15#include "internal/gc.h"
16#include "internal/hash.h"
17#include "internal/object.h"
18#include "internal/array.h"
19#include "internal/string.h"
20#include "internal/variable.h"
21#include "eval_intern.h"
22#include "internal/io.h"
23#include "internal/ractor.h"
24#include "internal/rational.h"
25#include "internal/re.h"
26#include "internal/struct.h"
27#include "internal/st.h"
28#include "internal/thread.h"
29#include "internal/vm.h"
37static VALUE rb_cRactorSelector;
39VALUE rb_eRactorUnsafeError;
40VALUE rb_eRactorIsolationError;
41static VALUE rb_eRactorError;
42static VALUE rb_eRactorRemoteError;
43static VALUE rb_eRactorMovedError;
44static VALUE rb_eRactorClosedError;
45static VALUE rb_cRactorMovedObject;
47static void vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *r,
const char *file,
int line);
50#if RACTOR_CHECK_MODE > 0
51bool rb_ractor_ignore_belonging_flag =
false;
59#if RACTOR_CHECK_MODE > 0
61 if (ec != NULL && r->sync.locked_by == rb_ractor_self(rb_ec_ractor_ptr(ec))) {
62 rb_bug(
"recursive ractor locking");
70#if RACTOR_CHECK_MODE > 0
72 if (ec != NULL && r->sync.locked_by != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
73 rp(r->sync.locked_by);
74 rb_bug(
"ractor lock is not acquired.");
80ractor_lock(
rb_ractor_t *r,
const char *file,
int line)
82 RUBY_DEBUG_LOG2(file, line,
"locking r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
84 ASSERT_ractor_unlocking(r);
90 VM_ASSERT(!cr->malloc_gc_disabled);
91 cr->malloc_gc_disabled =
true;
94#if RACTOR_CHECK_MODE > 0
97 r->sync.locked_by = rb_ractor_self(cr);
101 RUBY_DEBUG_LOG2(file, line,
"locked r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
105ractor_lock_self(
rb_ractor_t *cr,
const char *file,
int line)
107 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
108#if RACTOR_CHECK_MODE > 0
109 VM_ASSERT(cr->sync.locked_by != cr->pub.self);
111 ractor_lock(cr, file, line);
115ractor_unlock(
rb_ractor_t *r,
const char *file,
int line)
117 ASSERT_ractor_locking(r);
118#if RACTOR_CHECK_MODE > 0
119 r->sync.locked_by =
Qnil;
125 VM_ASSERT(cr->malloc_gc_disabled);
126 cr->malloc_gc_disabled =
false;
131 RUBY_DEBUG_LOG2(file, line,
"r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
135ractor_unlock_self(
rb_ractor_t *cr,
const char *file,
int line)
137 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
138#if RACTOR_CHECK_MODE > 0
139 VM_ASSERT(cr->sync.locked_by == cr->pub.self);
141 ractor_unlock(cr, file, line);
144#define RACTOR_LOCK(r) ractor_lock(r, __FILE__, __LINE__)
145#define RACTOR_UNLOCK(r) ractor_unlock(r, __FILE__, __LINE__)
146#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
147#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
158 RACTOR_UNLOCK_SELF(r);
164ractor_status_str(
enum ractor_status status)
167 case ractor_created:
return "created";
168 case ractor_running:
return "running";
169 case ractor_blocking:
return "blocking";
170 case ractor_terminated:
return "terminated";
172 rb_bug(
"unreachable");
176ractor_status_set(
rb_ractor_t *r,
enum ractor_status status)
178 RUBY_DEBUG_LOG(
"r:%u [%s]->[%s]", r->pub.id, ractor_status_str(r->status_), ractor_status_str(status));
181 if (r->status_ != ractor_created) {
182 VM_ASSERT(r == GET_RACTOR());
187 switch (r->status_) {
189 VM_ASSERT(status == ractor_blocking);
192 VM_ASSERT(status == ractor_blocking||
193 status == ractor_terminated);
195 case ractor_blocking:
196 VM_ASSERT(status == ractor_running);
198 case ractor_terminated:
199 rb_bug(
"unreachable");
207ractor_status_p(
rb_ractor_t *r,
enum ractor_status status)
209 return rb_ractor_status_p(r, status);
214static void ractor_local_storage_mark(
rb_ractor_t *r);
215static void ractor_local_storage_free(
rb_ractor_t *r);
219static size_t ractor_sync_memsize(
const rb_ractor_t *r);
223mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
227 if (hook_list->type == hook_list_type_targeted_iseq) {
228 rb_gc_mark((
VALUE)key);
232 RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
233 rb_gc_mark(def->body.bmethod.proc);
235 rb_hook_list_mark(hook_list);
243 rb_gc_mark(th->self);
247 if (th->root_fiber) {
248 VALUE root_fiber_self = rb_fiberptr_self(th->root_fiber);
249 if (root_fiber_self) rb_gc_mark(root_fiber_self);
254 VALUE ec_fiber_self = (th->ec && th->ec->fiber_ptr) ? rb_fiberptr_self(th->ec->fiber_ptr) : 0;
256 rb_gc_mark(ec_fiber_self);
259 rb_execution_context_mark(th->ec);
264 rb_thread_mark_owned_roots(th);
273 rb_gc_mark(r->r_stdin);
274 rb_gc_mark(r->r_stdout);
275 rb_gc_mark(r->r_stderr);
276 rb_gc_mark(r->verbose);
277 rb_gc_mark(r->debug);
284 rb_hook_list_mark(&r->pub.hooks);
285 if (r->pub.targeted_hooks.num_entries) {
286 st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
289 if (r->threads.cnt > 0) {
291 ccan_list_for_each(&r->threads.set, th, lt_node) {
292 VM_ASSERT(th != NULL);
293 ractor_mark_thread(th);
304 if (dying_th) ractor_mark_thread(dying_th);
306 ractor_local_storage_mark(r);
310ractor_mark(
void *ptr)
322 rb_gc_mark(r->sync.default_port_value);
326 if (!rb_gc_multi_objspace_p()) {
327 ractor_mark_unshareable_parts(r);
328 rb_ractor_mark_terminated_join_value(r);
330 else if (rb_gc_during_global_gc_p()) {
335 rb_ractor_mark_terminated_join_value(r);
352 rb_ractor_mark_terminated_join_value(r);
353 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
362 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
363 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
364 ractor_mark_unshareable_parts(r);
369 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
377rb_ractor_mark_terminated_join_value(
rb_ractor_t *r)
382 rb_gc_mark_vm_stack_values((
long)numberof(slots), slots);
391 if (src->registered_marks_cnt == 0)
return;
392 size_t need = dst->registered_marks_cnt + src->registered_marks_cnt;
393 if (need > dst->registered_marks_capa) {
394 size_t nc = dst->registered_marks_capa ? dst->registered_marks_capa : 64;
395 while (nc < need) nc *= 2;
396 VALUE *p = realloc(dst->registered_marks, nc *
sizeof(
VALUE));
397 if (!p) rb_bug(
"rb_ractor_absorb_registered_marks: out of memory");
398 dst->registered_marks = p;
399 dst->registered_marks_capa = nc;
401 MEMCPY(dst->registered_marks + dst->registered_marks_cnt,
402 src->registered_marks,
VALUE, src->registered_marks_cnt);
403 dst->registered_marks_cnt = need;
404 src->registered_marks_cnt = 0;
408free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
411 rb_hook_list_free(hook_list);
416free_targeted_hooks(
st_table *hooks_tbl)
418 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
424ractor_free(
void *ptr)
427 RUBY_DEBUG_LOG(
"free r:%d", rb_ractor_id(r));
429 free_targeted_hooks(&r->pub.targeted_hooks);
430 rb_thread_sched_destroy(&r->threads.sched);
432 ractor_local_storage_free(r);
433 rb_hook_list_free(&r->pub.hooks);
434 rb_st_free_embedded_table(&r->pub.targeted_hooks);
436 if (r->newobj_cache) {
439 rb_gc_ractor_cache_free(r->newobj_cache);
440 r->newobj_cache = NULL;
447 if (r->objspace && !r->main_ractor) {
448 rb_gc_objspace_disown(r->objspace);
454 if (r->in_terminated_set) {
456 ccan_list_del(&r->vmlr_node);
457 r->in_terminated_set =
false;
464 if (!r->main_ractor) {
465 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
467 free(r->registered_marks);
468 r->registered_marks = NULL;
469 r->registered_marks_cnt = r->registered_marks_capa = 0;
471 if (!r->main_ractor) {
477ractor_memsize(
const void *ptr)
482 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
486ractor_update_references(
void *ptr)
498 ractor_update_references,
506 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
515RACTOR_PTR(
VALUE self)
517 VM_ASSERT(rb_ractor_p(self));
522#define MAIN_RACTOR_ID 1
525#include "ractor_sync.c"
542 RUBY_DEBUG_LOG(
"r:%u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
543 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
548 if (vm->ractor.cnt == 1) {
552 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
555 if (r->newobj_cache) {
556 VM_ASSERT(r == ruby_single_main_ractor);
559 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
564cancel_single_ractor_mode(
void)
567 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
569 ruby_single_main_ractor = NULL;
570 rb_yjit_invalidate_single_ractor();
571 rb_zjit_invalidate_single_ractor();
579 VM_ASSERT(ractor_status_p(r, ractor_created));
581 if (rb_multi_ractor_p()) {
584 vm_insert_ractor0(vm, r,
false);
585 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
590 if (cur && cur->creating_child_objspace == r->objspace) {
591 cur->creating_child_objspace = NULL;
597 if (vm->ractor.cnt == 0) {
599 vm_insert_ractor0(vm, r,
true);
600 ractor_status_set(r, ractor_blocking);
601 ractor_status_set(r, ractor_running);
604 cancel_single_ractor_mode();
605 vm_insert_ractor0(vm, r,
true);
606 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
611 if (cur && cur->creating_child_objspace == r->objspace) {
612 cur->creating_child_objspace = NULL;
621 VM_ASSERT(ractor_status_p(cr, ractor_running));
622 VM_ASSERT(vm->ractor.cnt > 1);
623 VM_ASSERT(cr->threads.cnt == 1);
627 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
628 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
630 VM_ASSERT(vm->ractor.cnt > 0);
631 ccan_list_del(&cr->vmlr_node);
636 if (!rb_gc_multi_objspace_p()) {
638 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
639 cr->in_terminated_set =
true;
643 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
647 rb_gc_ractor_cache_free(cr->newobj_cache);
648 cr->newobj_cache = NULL;
658 rb_gc_objspace_retire(&cr->objspace);
662 ractor_status_set(cr, ractor_terminated);
674 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
675 VM_ASSERT(th->ec != NULL);
678 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
683 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
684 rb_gc_objspace_postmortem_self();
688 pf->th = (th->self == 0) ? th : NULL;
689 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
695 if (pf->fiber == NULL && pf->th == NULL)
return;
700#ifdef RB_THREAD_LOCAL_SPECIFIER
701 rb_current_ec_set(NULL);
703 native_tls_set(ruby_current_ec_key, NULL);
707 if (pf->fiber) rb_fiber_free_body(pf->fiber);
708 if (pf->th) rb_thread_free_body(pf->th);
712ractor_alloc(
VALUE klass)
717 rb_gc_obj_became_shareable(rv);
719 r->next_ec_serial = 1;
720 VM_ASSERT(ractor_status_p(r, ractor_created));
727 .pub.id = MAIN_RACTOR_ID,
734rb_ractor_main_alloc(
void)
739 ruby_single_main_ractor = r;
744#if defined(HAVE_WORKING_FORK)
752 vm->ractor.blocking_cnt = 0;
755 rb_gc_disable_holders_atfork();
759 th->ractor->creating_child_objspace = NULL;
760 ruby_single_main_ractor = th->ractor;
761 th->ractor->status_ = ractor_created;
763 rb_ractor_living_threads_init(th->ractor);
764 rb_ractor_living_threads_insert(th->ractor, th);
766 VM_ASSERT(vm->ractor.blocking_cnt == 0);
767 VM_ASSERT(vm->ractor.cnt == 1);
773 rb_gc_ractor_cache_free(r->newobj_cache);
774 r->newobj_cache = NULL;
775 r->status_ = ractor_terminated;
777 r->threads.dying_th = NULL;
781 rb_gc_objspace_retire(&r->objspace);
783 ractor_sync_terminate_atfork(vm, r);
792 ccan_list_head_init(&r->threads.set);
794 r->threads.blocking_cnt = 0;
795 r->threads.terminating =
false;
797 r->threads.dying_th = NULL;
804 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
805 r->pub.hooks.type = hook_list_type_ractor_local;
808 rb_thread_sched_init(&r->threads.sched,
false);
809 rb_ractor_living_threads_init(r);
815 enc = rb_enc_get(name);
816 if (!rb_enc_asciicompat(enc)) {
817 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
833 rb_gc_obj_became_shareable(r->pub.self);
835 r->threads.main = th;
836 rb_ractor_living_threads_insert(r, th);
837 rb_ractor_setup_default_port(r);
845 VALUE rv = ractor_alloc(self);
847 ractor_init(r, name, loc);
849 r->pub.id = ractor_next_id();
850 RUBY_DEBUG_LOG(
"r:%u", r->pub.id);
853 r->verbose = cr->verbose;
854 r->debug = cr->debug;
858 r->objspace = rb_gc_objspace_alloc();
860 rb_thread_create_ractor(r, args, block);
871 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
878 ractor_notify_exit(ec, cr, result, exc);
886 ractor_postmortem_collect(th, pf);
887 ractor_send_exit_tokens(th->ec, th->ractor);
894 ractor_atexit(ec, cr, result,
false);
901 ractor_atexit(ec, cr, ec->errinfo,
true);
911 VM_ASSERT(cr->threads.main != NULL);
912 cr->threads.main = NULL;
919 for (
int i=0; i<
len; i++) {
920 ptr[i] = ractor_receive(ec, ractor_default_port(r), NULL);
928 for (
int i=0; i<
len; i++) {
929 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
934rb_ractor_main_p_(
void)
936 VM_ASSERT(rb_multi_ractor_p());
938 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
944 return r->threads.cnt;
949rb_ractor_thread_list(
void)
955 ccan_list_for_each(&r->threads.set, th, lt_node) {
956 switch (th->status) {
957 case THREAD_RUNNABLE:
959 case THREAD_STOPPED_FOREVER:
972 VM_ASSERT(th != NULL);
976 RUBY_DEBUG_LOG(
"r(%d)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
977 ccan_list_add_tail(&r->threads.set, &th->lt_node);
983 if (r->threads.cnt == 1) {
984 VM_ASSERT(ractor_status_p(r, ractor_created));
985 vm_insert_ractor(th->vm, r);
992 ractor_status_set(r, ractor_blocking);
994 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
995 vm->ractor.blocking_cnt++;
996 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
1000rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1002 ASSERT_vm_locking();
1003 VM_ASSERT(GET_RACTOR() == cr);
1004 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
1008rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1010 ASSERT_vm_locking();
1011 VM_ASSERT(GET_RACTOR() == cr);
1013 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
1014 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1015 vm->ractor.blocking_cnt--;
1017 ractor_status_set(cr, ractor_running);
1028 ccan_list_del(&th->lt_node);
1036 VM_ASSERT(vm->ractor.cnt > 1);
1037 ccan_list_del(&r->vmlr_node);
1042 VM_ASSERT(r->status_ == ractor_blocking);
1043 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1044 vm->ractor.blocking_cnt--;
1046 rb_gc_ractor_cache_free(r->newobj_cache);
1047 r->newobj_cache = NULL;
1050 rb_gc_objspace_disown(r->objspace);
1053 r->status_ = ractor_terminated;
1061 VM_ASSERT(cr == GET_RACTOR());
1062 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
1064 if (cr->threads.cnt == 1) {
1065 vm_remove_ractor(th->vm, cr);
1070 ccan_list_del(&th->lt_node);
1078rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1080 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1082 VM_ASSERT(cr->threads.cnt > 0);
1083 VM_ASSERT(cr == GET_RACTOR());
1085 cr->threads.blocking_cnt++;
1089rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1091 RUBY_DEBUG_LOG2(file, line,
1092 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1093 cr->threads.blocking_cnt, cr->threads.cnt);
1095 VM_ASSERT(cr == GET_RACTOR());
1097 cr->threads.blocking_cnt--;
1101rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1103 VM_ASSERT(r != GET_RACTOR());
1104 ASSERT_ractor_unlocking(r);
1105 ASSERT_vm_locking();
1109 if (ractor_status_p(r, ractor_running)) {
1112 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1120rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1122 VM_ASSERT(r != GET_RACTOR());
1123 ASSERT_ractor_unlocking(r);
1124 ASSERT_vm_locking();
1128 if (main_th->status != THREAD_KILLED) {
1129 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1130 rb_threadptr_interrupt(main_th);
1133 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1141ractor_terminal_interrupt_all(
rb_vm_t *vm)
1143 if (vm->ractor.cnt > 1) {
1146 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1147 if (r != vm->ractor.main_ractor) {
1148 RUBY_DEBUG_LOG(
"r:%d", rb_ractor_id(r));
1149 rb_ractor_terminate_interrupt_main_thread(r);
1159rb_ractor_terminate_all(
void)
1164 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1166 VM_ASSERT(cr == GET_RACTOR());
1170 ractor_terminal_interrupt_all(vm);
1173 rb_thread_terminate_all(GET_THREAD());
1177 while (vm->ractor.cnt > 1) {
1178 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1179 vm->ractor.sync.terminate_waiting =
true;
1182 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1183 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1184 rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 );
1185 while (vm->ractor.sched.barrier_is_waiting) {
1192 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1194 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1195 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1197 ractor_terminal_interrupt_all(vm);
1204 rb_gc_objspace_absorb_all_zombies();
1208rb_vm_main_ractor_ec(
rb_vm_t *vm)
1225 if (running_ec) {
return running_ec; }
1226 return vm->ractor.main_thread->ec;
1230ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1232 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1334 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1335 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1336 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1338 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1342 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1345 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1349 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1350 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1351 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1352 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1363 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1364 if (r != vm->ractor.main_ractor) {
1365 fprintf(stderr,
"r:%u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1373 if (rb_ractor_main_p()) {
1378 if (UNLIKELY(cr->r_stdin == 0)) {
1379 cr->r_stdin = rb_io_prep_stdin();
1386rb_ractor_stdout(
void)
1388 if (rb_ractor_main_p()) {
1393 if (UNLIKELY(cr->r_stdout == 0)) {
1394 cr->r_stdout = rb_io_prep_stdout();
1396 return cr->r_stdout;
1401rb_ractor_stderr(
void)
1403 if (rb_ractor_main_p()) {
1408 if (UNLIKELY(cr->r_stderr == 0)) {
1409 cr->r_stderr = rb_io_prep_stderr();
1411 return cr->r_stderr;
1418 if (rb_ractor_main_p()) {
1430 if (rb_ractor_main_p()) {
1442 if (rb_ractor_main_p()) {
1454 return &cr->pub.hooks;
1460 return &cr->pub.targeted_hooks;
1464rb_obj_set_shareable_no_assert(
VALUE obj)
1471 rb_gc_obj_became_shareable(obj);
1480 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1481 if (imemo_type_p(fields, imemo_fields)) {
1484 rb_gc_obj_became_shareable(fields);
1488 rb_imemo_fields_record_shrefs(fields);
1493#ifndef STRICT_VERIFY_SHAREABLE
1494#define STRICT_VERIFY_SHAREABLE 0
1498rb_ractor_verify_shareable(
VALUE obj)
1500#if STRICT_VERIFY_SHAREABLE
1501 rb_gc_verify_shareable(obj);
1507rb_obj_set_shareable(
VALUE obj)
1511 rb_obj_set_shareable_no_assert(obj);
1523enum obj_traverse_iterator_result {
1529typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1530typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1531typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1533static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1536 rb_obj_traverse_enter_func enter_func;
1537 rb_obj_traverse_leave_func leave_func;
1556 if (obj_traverse_i(key, d->data)) {
1561 if (obj_traverse_i(val, d->data)) {
1570obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1574 if (obj_traverse_i(obj, d->data)) {
1587 RB_VM_LOCKING_NO_BARRIER() {
1588 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1596 if (UNLIKELY(!data->rec)) {
1597 data->rec_hash = rb_ident_hash_new();
1599 data->rec = RHASH_ST_TABLE(data->rec_hash);
1605obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1609 if (obj_traverse_i(val, d->data)) {
1622 switch (data->enter_func(obj)) {
1623 case traverse_cont:
break;
1624 case traverse_skip:
return 0;
1625 case traverse_stop:
return 1;
1628 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1634 if (rb_obj_shape_has_ivars(obj)) {
1640 if (d.stop)
return 1;
1658 rb_ary_cancel_sharing(obj);
1662 if (obj_traverse_i(e, data))
return 1;
1676 if (d.stop)
return 1;
1682 long len = RSTRUCT_LEN_RAW(obj);
1683 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1685 for (
long i=0; i<
len; i++) {
1686 if (obj_traverse_i(ptr[i], data))
return 1;
1692 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1696 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1697 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1700 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1701 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1706 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1709 if (!ptr || !
type->function.dmark) {
1712 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1713 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1714 for (; *offsets != RUBY_REF_END; offsets++) {
1715 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1716 if (obj_traverse_i(ref, data))
return 1;
1720 if (obj_traverse_reachable(obj, data))
return 1;
1727 if (obj_traverse_reachable(obj, data))
return 1;
1736 rb_bug(
"unreachable");
1739 if (data->leave_func(obj) == traverse_stop) {
1748 rb_obj_traverse_final_func final_func;
1753obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1756 if (data->final_func(key)) {
1766rb_obj_traverse(
VALUE obj,
1767 rb_obj_traverse_enter_func enter_func,
1768 rb_obj_traverse_leave_func leave_func,
1769 rb_obj_traverse_final_func final_func)
1772 .enter_func = enter_func,
1773 .leave_func = leave_func,
1777 if (obj_traverse_i(obj, &data))
return 1;
1778 if (final_func && data.rec) {
1780 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1787allow_frozen_shareable_p(
VALUE obj)
1797 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1806make_shareable_freeze(
VALUE obj)
1809 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1812 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1815 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1816 rb_hash_freeze(obj);
1823static enum obj_traverse_iterator_result
1824make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1827 make_shareable_freeze(obj);
1830 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1834 return traverse_skip;
1841static int obj_refer_only_shareables_p(
VALUE obj);
1843static enum obj_traverse_iterator_result
1844make_shareable_check_shareable(
VALUE obj)
1849 return traverse_skip;
1851 else if (!allow_frozen_shareable_p(obj)) {
1853 rb_raise(rb_eRactorError,
1854 "can not make shareable object for %+"PRIsVALUE, obj);
1856 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1857 if (obj_refer_only_shareables_p(obj)) {
1858 make_shareable_check_shareable_freeze(obj, traverse_skip);
1859 RB_OBJ_SET_SHAREABLE(obj);
1860 return traverse_skip;
1863 rb_raise(rb_eRactorError,
1864 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1868 rb_proc_ractor_make_shareable(obj,
Qundef);
1869 return traverse_cont;
1872 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1876 switch (
TYPE(obj)) {
1878 return traverse_skip;
1885 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1886 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1887 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1888 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1897 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1900static enum obj_traverse_iterator_result
1901mark_shareable(
VALUE obj)
1904 rb_str_make_independent(obj);
1907 rb_obj_set_shareable_no_assert(obj);
1908 return traverse_cont;
1914 rb_obj_traverse(obj,
1915 make_shareable_check_shareable,
1916 null_leave, mark_shareable);
1925 VALUE copy = ractor_copy(obj);
1930rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1933 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
1941rb_ractor_ensure_main_ractor(
const char *msg)
1943 if (!rb_ractor_main_p()) {
1944 rb_raise(rb_eRactorIsolationError,
"%s", msg);
1948static enum obj_traverse_iterator_result
1949shareable_p_enter(
VALUE obj)
1952 return traverse_skip;
1958 mark_shareable(obj);
1959 return traverse_skip;
1962 allow_frozen_shareable_p(obj)) {
1963 return traverse_cont;
1971 if (obj_refer_only_shareables_p(obj)) {
1972 mark_shareable(obj);
1973 return traverse_skip;
1977 return traverse_stop;
1981rb_ractor_shareable_p_continue(
VALUE obj)
1983 if (rb_obj_traverse(obj,
1984 shareable_p_enter, null_leave,
1993static enum obj_traverse_iterator_result
1994null_leave(
VALUE obj)
1996 return traverse_cont;
2012 rb_obj_traverse_replace_enter_func enter_func;
2013 rb_obj_traverse_replace_leave_func leave_func;
2019 VALUE rec_keepalive;
2032obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2038obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2043 if (obj_traverse_replace_i(*key, data)) {
2047 else if (*key != data->replacement) {
2048 VALUE v = *key = data->replacement;
2052 if (obj_traverse_replace_i(*val, data)) {
2056 else if (*val != data->replacement) {
2057 VALUE v = *val = data->replacement;
2065obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2071obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2076 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2080 else if (*(
VALUE *)val != data->replacement) {
2091 if (UNLIKELY(!data->rec)) {
2092 data->rec = st_init_numtable();
2099obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2101 int *pcnt = (
int *)ptr;
2109obj_refer_only_shareables_p(
VALUE obj)
2112 RB_VM_LOCKING_NO_BARRIER() {
2113 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
2121 st_data_t replacement;
2124 data->replacement = obj;
2131 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2132 data->replacement = (
VALUE)replacement;
2136 switch (data->enter_func(obj, data)) {
2137 case traverse_cont:
break;
2138 case traverse_skip:
return 0;
2139 case traverse_stop:
return 1;
2142 replacement = (st_data_t)data->replacement;
2143 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2152#define CHECK_AND_REPLACE(parent_obj, v) do { \
2154 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2155 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2158 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2159 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2161 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2167 rb_st_foreach_with_replace(
2168 rb_imemo_fields_complex_tbl(fields_obj),
2169 obj_iv_hash_traverse_replace_foreach_i,
2170 obj_iv_hash_traverse_replace_i,
2173 if (d.stop)
return 1;
2176 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2177 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2178 for (uint32_t i = 0; i < fields_count; i++) {
2179 CHECK_AND_REPLACE(fields_obj, fields[i]);
2193 rb_str_make_independent(obj);
2198 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2199 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2200 if (rb_shape_complex_p(shape_id)) {
2206 rb_st_foreach_with_replace(
2207 rb_imemo_fields_complex_tbl(fields_obj),
2208 obj_iv_hash_traverse_replace_foreach_i,
2209 obj_iv_hash_traverse_replace_i,
2212 if (d.stop)
return 1;
2215 attr_index_t
len = RSHAPE_LEN(shape_id);
2216 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2218 for (attr_index_t i = 0; i <
len; i++) {
2219 CHECK_AND_REPLACE(obj, ptr[i]);
2227 rb_ary_cancel_sharing(obj);
2232 if (obj_traverse_replace_i(e, data)) {
2235 else if (e != data->replacement) {
2249 rb_hash_stlike_foreach_with_replace(obj,
2250 obj_hash_traverse_replace_foreach_i,
2251 obj_hash_traverse_replace_i,
2253 if (d.stop)
return 1;
2257 if (obj_traverse_replace_i(ifnone, data)) {
2260 else if (ifnone != data->replacement) {
2268 long len = RSTRUCT_LEN_RAW(obj);
2269 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2271 for (
long i=0; i<
len; i++) {
2272 CHECK_AND_REPLACE(obj, ptr[i]);
2278 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2282 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2283 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2286 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2287 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2291 if (!data->move && obj_refer_only_shareables_p(obj)) {
2295 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2309 rb_bug(
"unreachable");
2312 data->replacement = (
VALUE)replacement;
2314 if (data->leave_func(obj, data) == traverse_stop) {
2325rb_obj_traverse_replace(
VALUE obj,
2326 rb_obj_traverse_replace_enter_func enter_func,
2327 rb_obj_traverse_replace_leave_func leave_func,
2331 .enter_func = enter_func,
2332 .leave_func = leave_func,
2339 int stopped = obj_traverse_replace_i(obj, &data);
2343 if (data.rec) st_free_table(data.rec);
2350 return data.replacement;
2360enum courier_node_kind {
2362 COURIER_KIND_BACKTRACE,
2363 COURIER_KIND_STRING,
2366 COURIER_KIND_OBJECT,
2367 COURIER_KIND_STRUCT,
2373 enum courier_node_kind kind;
2382 struct {
char *ptr;
long len, capa;
int encidx;
VALUE klass; } str;
2383 struct {
long len; uint32_t *elems;
VALUE klass; } ary;
2384 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2385 struct {
VALUE klass; } obj;
2386 struct {
long len; uint32_t *elems;
VALUE klass; } strct;
2387 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2388 struct {
void *blob;
int size; } bt;
2395 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2403#define COURIER_ID_REF_BIT 0x80000000u
2410 uint32_t refs_count;
2435 uint32_t
capa = c->capa ? c->capa * 2 : 8;
2441 ruby_xfree(old_nodes);
2447 uint32_t
capa = c->refs_capa ? c->refs_capa * 2 : 8;
2449 if (c->refs_count > 0)
MEMCPY(refs, c->refs,
VALUE, c->refs_count);
2450 VALUE *old_refs = c->refs;
2452 c->refs_capa =
capa;
2453 ruby_xfree(old_refs);
2459 if (RB_UNLIKELY(c->count == c->capa)) courier_grow_nodes(c);
2464 n->kind = COURIER_KIND_REF;
2484 c->refs_capa = refs;
2496 if (RB_UNLIKELY(c->refs_count == c->refs_capa)) courier_grow_refs(c);
2497 c->refs[c->refs_count] = v;
2498 return COURIER_ID_REF_BIT | c->refs_count++;
2505 if (
id & COURIER_ID_REF_BIT)
return c->refs[
id & ~COURIER_ID_REF_BIT];
2512move_neutralize_source(
VALUE obj)
2517 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2518 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2528 bool wipe_body =
true;
2531 wipe_body = !rb_str_embedded_shared_root_p(obj);
2534 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2542 size_t slot_size = rb_gc_obj_slot_size(obj);
2543 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2544 RBASIC(obj)->flags = flags;
2545 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2563courier_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2566 uint32_t kid = courier_capture(hc->b, (
VALUE)key);
2567 uint32_t vid = courier_capture(hc->b, (
VALUE)val);
2568 hc->kv[hc->i++] = kid;
2569 hc->kv[hc->i++] = vid;
2582courier_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2585 if (oc->n == oc->capa) {
2586 oc->capa = oc->capa ? oc->capa * 2 : 4;
2588 REALLOC_N(oc->vals, uint32_t, oc->capa);
2590 uint32_t vid = courier_capture(oc->b, val);
2591 oc->ids[oc->n] = name;
2592 oc->vals[oc->n] = vid;
2604 rb_ivar_foreach_buffered(obj, courier_capture_ivar_i, (st_data_t)&oc);
2605 b->c->nodes[id].niv = (uint32_t)oc.n;
2606 b->c->nodes[id].iv_ids = oc.ids;
2607 b->c->nodes[id].iv_vals = oc.vals;
2620 return courier_alloc_ref(b->c, obj);
2628 if (st_lookup(b->seen, (st_data_t)obj, &existing)) {
2629 return (uint32_t)existing - 1;
2633 return courier_alloc_ref(b->c, obj);
2636 uint32_t
id = courier_alloc_node(b->c);
2637 st_insert(b->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2641 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2645 b->c->nodes[id].frozen = frozen;
2646 courier_capture_ivars(b, obj,
id);
2653 if (!b->copy) rb_str_make_independent(obj);
2654 long len = RSTRING_LEN(obj);
2658 const int termlen = rb_enc_mbminlen(rb_enc_from_index(encidx));
2661 if (!b->copy && !STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2664 ptr =
RSTRING(obj)->as.heap.ptr;
2672 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2673 memset(ptr +
len, 0, termlen);
2676 b->c->nodes[id].kind = COURIER_KIND_STRING;
2678 b->c->nodes[id].u.str.ptr = ptr;
2679 b->c->nodes[id].u.str.len =
len;
2680 b->c->nodes[id].u.str.capa =
capa;
2681 b->c->nodes[id].u.str.encidx = encidx;
2688 for (
long i = 0; i <
len; i++) {
2689 elems[i] = courier_capture(b,
RARRAY_AREF(obj, i));
2691 b->c->nodes[id].kind = COURIER_KIND_ARRAY;
2693 b->c->nodes[id].u.ary.len =
len;
2694 b->c->nodes[id].u.ary.elems = elems;
2698 if (!b->copy && !ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2705 uint32_t ifnone_id = courier_capture(b,
RHASH_IFNONE(obj));
2707 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2709 rb_hash_stlike_foreach(obj, courier_capture_hash_i, (st_data_t)&hc);
2710 b->c->nodes[id].kind = COURIER_KIND_HASH;
2712 b->c->nodes[id].u.hash.size = size;
2713 b->c->nodes[id].u.hash.kv = kv;
2714 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2715 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2716 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2718 if (!b->copy) rb_hash_free(obj);
2723 b->c->nodes[id].kind = COURIER_KIND_OBJECT;
2733 for (
long i = 0; i <
len; i++) {
2734 elems[i] = courier_capture(b,
RSTRUCT_GET(obj, (
int)i));
2736 b->c->nodes[id].kind = COURIER_KIND_STRUCT;
2737 b->c->nodes[id].u.strct.len =
len;
2738 b->c->nodes[id].u.strct.elems = elems;
2741 if (!b->copy && RSTRUCT_EMBED_LEN(obj) == 0) {
2742 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2752 void *regs = rb_match_blob_dump(obj, &re, &st, &nregs, !b->copy);
2753 uint32_t rid = courier_capture(b, re);
2754 uint32_t sid = courier_capture(b, st);
2755 b->c->nodes[id].kind = COURIER_KIND_MATCH;
2756 b->c->nodes[id].u.match.regexp_id = rid;
2757 b->c->nodes[id].u.match.str_id = sid;
2758 b->c->nodes[id].u.match.num_regs = nregs;
2759 b->c->nodes[id].u.match.regs = regs;
2766 VM_ASSERT(!b->copy);
2772 uint32_t pathv_id = courier_capture(b, fptr->
pathv);
2773 uint32_t ecopts_id = courier_capture(b, fptr->
encs.
ecopts);
2776 uint32_t timeout_id = courier_capture(b, fptr->
timeout);
2784 fptr->wakeup_mutex =
Qnil;
2786 b->c->nodes[id].kind = COURIER_KIND_IO;
2787 b->c->nodes[id].u.io.fptr = fptr;
2789 b->c->nodes[id].u.io.pathv_id = pathv_id;
2790 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
2791 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
2792 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
2793 b->c->nodes[id].u.io.timeout_id = timeout_id;
2800 if (b->copy && rb_backtrace_p(obj)) {
2802 void *blob = rb_backtrace_blob_dump(obj, &size);
2803 b->c->nodes[id].kind = COURIER_KIND_BACKTRACE;
2804 b->c->nodes[id].u.bt.blob = blob;
2805 b->c->nodes[id].u.bt.size = size;
2810 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2814 if (!b->copy) move_neutralize_source(obj);
2821 uint32_t nodes, refs;
2827move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
2834move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2853 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
2854 st_insert(seen, (st_data_t)obj, 0);
2863 move_preflight(rm->
regexp, ctx);
2864 move_preflight(rm->
str, ctx);
2873 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)ctx);
2884 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2889 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
2891 if (
RTEST(fptr->wakeup_mutex)) {
2893 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
2895 move_preflight(fptr->
pathv, ctx);
2899 move_preflight(fptr->
timeout, ctx);
2903 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2915 uint32_t nodes, refs;
2922copy_support_val_i(st_data_t val, st_data_t arg)
2925 if (!copy_courier_supported_p((
VALUE)val, ctx)) {
2933copy_support_ivar_i(
ID name,
VALUE val, st_data_t arg)
2935 return copy_support_val_i((st_data_t)val, arg);
2939copy_support_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2941 if (copy_support_val_i(key, arg) == ST_STOP)
return ST_STOP;
2942 return copy_support_val_i(val, arg);
2957 if (st_lookup(seen, (st_data_t)obj, NULL))
return true;
2958 st_insert(seen, (st_data_t)obj, 0);
2972 if (!copy_courier_supported_p(rm->
regexp, ctx))
return false;
2973 if (!copy_courier_supported_p(rm->
str, ctx))
return false;
2978 if (!rb_backtrace_p(obj))
return false;
2982 if (!copy_courier_supported_p(
RARRAY_AREF(obj, i), ctx))
return false;
2986 rb_hash_stlike_foreach(obj, copy_support_hash_i, (st_data_t)ctx);
2987 if (!ctx->ok)
return false;
2988 if (!copy_courier_supported_p(
RHASH_IFNONE(obj), ctx))
return false;
2992 if (!copy_courier_supported_p(
RSTRUCT_GET(obj, (
int)i), ctx))
return false;
3010 bool ok = copy_courier_supported_p(obj, &scan);
3011 st_free_table(scan.seen);
3012 if (!ok)
return NULL;
3016 courier_reserve(c, scan.nodes, scan.refs);
3023 enum ruby_tag_type state;
3026 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3027 c->root = courier_capture(&b, obj);
3030 st_free_table(b.seen);
3032 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3045 enum ruby_tag_type state;
3048 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3049 move_preflight(obj, &scan);
3052 st_free_table(scan.seen);
3053 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3057 courier_reserve(c, scan.nodes, scan.refs);
3065 enum ruby_tag_type state;
3068 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3069 c->root = courier_capture(&b, obj);
3072 st_free_table(b.seen);
3073 if (state != TAG_NONE) {
3077 EC_JUMP_TAG(ec, state);
3089 RBASIC_SET_CLASS(shell, klass);
3105 for (uint32_t i = 0; i < c->count; i++) {
3109 case COURIER_KIND_REF:
3112 case COURIER_KIND_STRING:
3116 shell = rb_str_new_owned(n->u.str.ptr, n->u.str.len, n->u.str.capa, n->u.str.encidx);
3117 n->u.str.ptr = NULL;
3118 courier_apply_klass(shell, n->u.str.klass);
3120 case COURIER_KIND_ARRAY:
3122 courier_apply_klass(shell, n->u.ary.klass);
3124 case COURIER_KIND_HASH:
3125 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
3126 courier_apply_klass(shell, n->u.hash.klass);
3128 case COURIER_KIND_OBJECT:
3132 courier_apply_klass(shell, n->u.obj.klass);
3134 case COURIER_KIND_STRUCT:
3136 courier_apply_klass(shell, n->u.strct.klass);
3138 case COURIER_KIND_MATCH:
3139 shell = rb_match_blob_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
3140 courier_apply_klass(shell, n->u.match.klass);
3142 case COURIER_KIND_BACKTRACE:
3143 shell = rb_backtrace_blob_load(n->u.bt.blob, n->u.bt.size);
3145 case COURIER_KIND_IO:
3147 courier_apply_klass(shell, n->u.io.klass);
3148 RFILE(shell)->fptr = n->u.io.fptr;
3149 n->u.io.fptr->
self = shell;
3150 n->u.io.fptr = NULL;
3153 rb_bug(
"rb_ractor_courier_materialize: bad node kind");
3158 for (uint32_t i = 0; i < c->count; i++) {
3162 case COURIER_KIND_ARRAY: {
3165 const long len = n->u.ary.len;
3168 for (
long j = 0; j <
len; j++) {
3169 RARRAY_ASET(shell, j, courier_child(c, shells, n->u.ary.elems[j]));
3174 case COURIER_KIND_HASH:
3179 case COURIER_KIND_STRUCT:
3180 for (
long j = 0; j < n->u.strct.len; j++) {
3181 RSTRUCT_SET(shell, (
int)j, courier_child(c, shells, n->u.strct.elems[j]));
3184 case COURIER_KIND_MATCH:
3185 rb_match_blob_load(shell, courier_child(c, shells, n->u.match.regexp_id),
3186 courier_child(c, shells, n->u.match.str_id),
3187 n->u.match.num_regs, n->u.match.regs);
3189 case COURIER_KIND_IO: {
3204 for (uint32_t j = 0; j < n->niv; j++) {
3205 rb_ivar_set(shell, n->iv_ids[j], courier_child(c, shells, n->iv_vals[j]));
3212 for (uint32_t i = c->count; i > 0; i--) {
3214 if (n->kind != COURIER_KIND_HASH)
continue;
3216 for (
long j = 0; j < n->u.hash.size; j++) {
3217 rb_hash_aset(shell, courier_child(c, shells, n->u.hash.kv[2 * j]),
3218 courier_child(c, shells, n->u.hash.kv[2 * j + 1]));
3221 VALUE ifnone = courier_child(c, shells, n->u.hash.ifnone_id);
3222 if (n->u.hash.proc_default) {
3223 rb_hash_set_default_proc(shell, ifnone);
3225 else if (ifnone !=
Qnil) {
3226 rb_hash_set_default(shell, ifnone);
3231 for (uint32_t i = 0; i < c->count; i++) {
3238 VALUE root = (c->count || c->refs_count) ? courier_child(c, shells, c->root) :
Qnil;
3246 for (uint32_t i = 0; i < c->count; i++) {
3248 ruby_xfree(n->iv_ids);
3249 ruby_xfree(n->iv_vals);
3251 case COURIER_KIND_STRING:
3252 ruby_xfree(n->u.str.ptr);
3254 case COURIER_KIND_ARRAY:
3255 ruby_xfree(n->u.ary.elems);
3257 case COURIER_KIND_HASH:
3258 ruby_xfree(n->u.hash.kv);
3260 case COURIER_KIND_STRUCT:
3261 ruby_xfree(n->u.strct.elems);
3263 case COURIER_KIND_MATCH:
3264 rb_match_blob_free(n->u.match.regs);
3266 case COURIER_KIND_BACKTRACE:
3267 ruby_xfree(n->u.bt.blob);
3269 case COURIER_KIND_IO:
3275 n->u.io.fptr = NULL;
3282 ruby_xfree(c->nodes);
3283 ruby_xfree(c->refs);
3294 for (uint32_t i = 0; i < c->refs_count; i++) {
3295 rb_gc_mark(c->refs[i]);
3297 for (uint32_t i = 0; i < c->count; i++) {
3299 if (n->kind == COURIER_KIND_REF) {
3300 rb_gc_mark(n->u.ref);
3302 else if (n->kind == COURIER_KIND_OBJECT) {
3303 rb_gc_mark(n->u.obj.klass);
3305 else if (n->kind == COURIER_KIND_STRUCT) {
3306 rb_gc_mark(n->u.strct.klass);
3308 else if (n->kind == COURIER_KIND_MATCH) {
3309 rb_gc_mark(n->u.match.klass);
3311 else if (n->kind == COURIER_KIND_IO) {
3312 rb_gc_mark(n->u.io.klass);
3314 else if (n->kind == COURIER_KIND_STRING) {
3315 rb_gc_mark(n->u.str.klass);
3317 else if (n->kind == COURIER_KIND_BACKTRACE) {
3318 rb_backtrace_blob_mark(n->u.bt.blob, n->u.bt.size);
3320 else if (n->kind == COURIER_KIND_ARRAY) {
3321 rb_gc_mark(n->u.ary.klass);
3323 else if (n->kind == COURIER_KIND_HASH) {
3324 rb_gc_mark(n->u.hash.klass);
3333ractor_native_shallow_copy(
VALUE obj)
3347 rb_obj_copy_ivar(copy, obj);
3350 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3356 copy = rb_hash_dup(obj);
3360 rb_struct_init_copy(copy, obj);
3364 rb_match_init_copy(copy, obj);
3369 if (rb_backtrace_p(obj)) {
3370 copy = rb_backtrace_dup(obj);
3382 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3394static enum obj_traverse_iterator_result
3398 data->replacement = obj;
3399 return traverse_skip;
3402 VALUE copy = ractor_native_shallow_copy(obj);
3403 if (UNDEF_P(copy))
return traverse_stop;
3404 data->replacement = copy;
3405 return traverse_cont;
3409static enum obj_traverse_iterator_result
3412 return traverse_cont;
3418ractor_copy_native_try(
VALUE obj)
3420 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3426ractor_copy(
VALUE obj)
3428 VALUE copy = ractor_copy_native_try(obj);
3429 if (UNDEF_P(copy)) {
3431 ractor_marshal_dump_rescue, obj,
3448} freed_ractor_local_keys;
3452ractor_local_keys_purge(
st_table *local_storage)
3454 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3456 st_data_t val, k = (st_data_t)key;
3457 if (st_delete(local_storage, &k, &val) &&
3459 (*key->type->free)((
void *)val);
3466ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3469 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3473static enum rb_id_table_iterator_result
3474idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3477 return ID_TABLE_CONTINUE;
3483 if (r->local_storage) {
3484 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3489 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3490 ractor_local_keys_purge(r->local_storage);
3494 if (r->idkey_local_storage) {
3495 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3498 rb_gc_mark(r->local_storage_store_lock);
3502ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3505 if (k->type->
free) (*k->type->
free)((
void *)val);
3512 if (r->local_storage) {
3513 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3514 st_free_table(r->local_storage);
3517 if (r->idkey_local_storage) {
3518 rb_id_table_free(r->idkey_local_storage);
3523rb_ractor_local_storage_value_mark(
void *ptr)
3525 rb_gc_mark((
VALUE)ptr);
3539 rb_ractor_local_storage_value_mark,
3547 key->type =
type ?
type : &ractor_local_storage_type_null;
3548 key->main_cache = (
void *)
Qundef;
3562 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3563 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3564 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3566 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3573 if (rb_ractor_main_p()) {
3574 if (!UNDEF_P((
VALUE)key->main_cache)) {
3575 *pret = key->main_cache;
3585 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3599 if (cr->local_storage == NULL) {
3600 cr->local_storage = st_init_numtable();
3603 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3605 if (rb_ractor_main_p()) {
3606 key->main_cache = ptr;
3614 if (ractor_local_ref(key, &val)) {
3625 if (ractor_local_ref(key, (
void **)val)) {
3636 ractor_local_set(key, (
void *)val);
3643 if (ractor_local_ref(key, &ret)) {
3654 ractor_local_set(key, ptr);
3657#define DEFAULT_KEYS_CAPA 0x10
3660rb_ractor_finish_marking(
bool full_mark)
3665 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3675 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3676 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3677 if (owner == NULL || owner->local_storage == NULL)
continue;
3678 ractor_local_keys_purge(owner->local_storage);
3681 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3682 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3684 freed_ractor_local_keys.cnt = 0;
3685 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3686 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3687 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3692 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3693 rb_ractor_reap_dead_ports(r);
3695 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
3696 rb_ractor_reap_dead_ports(vm->ractor.main_ractor);
3706 struct rb_id_table *tbl = cr->idkey_local_storage;
3709 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
3722 struct rb_id_table *tbl = cr->idkey_local_storage;
3725 tbl = cr->idkey_local_storage = rb_id_table_create(2);
3727 rb_id_table_insert(tbl,
id, val);
3739ractor_local_value_store_i(
VALUE ptr)
3744 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
3749 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
3762 .tbl = cr->idkey_local_storage,
3766 if (data.tbl == NULL) {
3767 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
3769 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
3774 if (!cr->local_storage_store_lock) {
3787 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
3791 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
3815RUBY_REFERENCES(cross_ractor_require_refs) = {
3822 "ractor/cross_ractor_require",
3824 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
3829 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
3833require_body(
VALUE crr_obj)
3837 VALUE feature = crr->as.require.feature;
3843 int rb_require_internal_silent(
VALUE fname);
3844 return INT2NUM(rb_require_internal_silent(feature));
3861require_result_send_body(
VALUE ary)
3868 ractor_port_send(ec, port, results,
Qfalse);
3873require_result_send_resuce(
VALUE port,
VALUE errinfo)
3876 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
3886 const bool silent = crr->silent;
3888 VALUE debug, errinfo;
3891 errinfo = rb_errinfo();
3899 rb_set_errinfo(errinfo);
3904 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
3912ractor_require_func(
void *crr_obj)
3914 return ractor_require_protect((
VALUE)crr_obj, require_body);
3918rb_ractor_require(
VALUE feature,
bool silent)
3921 ASSERT_vm_unlocking();
3925 RB_OBJ_SET_SHAREABLE(crr_obj);
3930 crr->raised =
false;
3931 crr->silent = silent;
3934 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
3935 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
3938 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
3939 ractor_port_close(ec, crr->port);
3956 return rb_ractor_require(feature,
false);
3960autoload_load_body(
VALUE crr_obj)
3968ractor_autoload_load_func(
void *crr_obj)
3970 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
3974rb_ractor_autoload_load(
VALUE module,
ID name)
3978 RB_OBJ_SET_SHAREABLE(crr_obj);
3980 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
3985 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
3986 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
3989 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
3990 ractor_port_close(ec, crr->port);
4004#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*.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define RUBY_ATOMIC_FETCH_ADD(var, val)
Atomically replaces the value pointed by var with the result of addition of val to the old value of v...
#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.
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
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 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 ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#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)
Just calls rb_obj_freeze_inline() inside.
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_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.
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.
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().
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.
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.
VALUE rb_marshal_load(VALUE port)
Deserialises a previous output of rb_marshal_dump() into a network of objects.
#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.
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.
#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.