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/ractor.h"
25#include "internal/rational.h"
26#include "internal/re.h"
27#include "internal/struct.h"
28#include "internal/st.h"
29#include "internal/thread.h"
30#include "internal/vm.h"
38static VALUE rb_cRactorSelector;
40VALUE rb_eRactorUnsafeError;
41VALUE rb_eRactorIsolationError;
42static VALUE rb_eRactorError;
43static VALUE rb_eRactorRemoteError;
44static VALUE rb_eRactorMovedError;
45static VALUE rb_eRactorClosedError;
46static VALUE rb_cRactorMovedObject;
48static void vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *r,
const char *file,
int line);
51#if RACTOR_CHECK_MODE > 0
52bool rb_ractor_ignore_belonging_flag =
false;
60#if RACTOR_CHECK_MODE > 0
62 if (ec != NULL && r->sync.locked_by == rb_ractor_self(rb_ec_ractor_ptr(ec))) {
63 rb_bug(
"recursive ractor locking");
71#if RACTOR_CHECK_MODE > 0
73 if (ec != NULL && r->sync.locked_by != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
74 rp(r->sync.locked_by);
75 rb_bug(
"ractor lock is not acquired.");
81ractor_lock(
rb_ractor_t *r,
const char *file,
int line)
83 RUBY_DEBUG_LOG2(file, line,
"locking r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
85 ASSERT_ractor_unlocking(r);
91 VM_ASSERT(!cr->malloc_gc_disabled);
92 cr->malloc_gc_disabled =
true;
95#if RACTOR_CHECK_MODE > 0
98 r->sync.locked_by = rb_ractor_self(cr);
102 RUBY_DEBUG_LOG2(file, line,
"locked r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
106ractor_lock_self(
rb_ractor_t *cr,
const char *file,
int line)
108 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
109#if RACTOR_CHECK_MODE > 0
110 VM_ASSERT(cr->sync.locked_by != cr->pub.self);
112 ractor_lock(cr, file, line);
116ractor_unlock(
rb_ractor_t *r,
const char *file,
int line)
118 ASSERT_ractor_locking(r);
119#if RACTOR_CHECK_MODE > 0
120 r->sync.locked_by =
Qnil;
126 VM_ASSERT(cr->malloc_gc_disabled);
127 cr->malloc_gc_disabled =
false;
132 RUBY_DEBUG_LOG2(file, line,
"r:%"PRI_SERIALT_PREFIX
"u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
136ractor_unlock_self(
rb_ractor_t *cr,
const char *file,
int line)
138 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
139#if RACTOR_CHECK_MODE > 0
140 VM_ASSERT(cr->sync.locked_by == cr->pub.self);
142 ractor_unlock(cr, file, line);
145#define RACTOR_LOCK(r) ractor_lock(r, __FILE__, __LINE__)
146#define RACTOR_UNLOCK(r) ractor_unlock(r, __FILE__, __LINE__)
147#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
148#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
159 RACTOR_UNLOCK_SELF(r);
165ractor_status_str(
enum ractor_status status)
168 case ractor_created:
return "created";
169 case ractor_running:
return "running";
170 case ractor_blocking:
return "blocking";
171 case ractor_terminated:
return "terminated";
173 rb_bug(
"unreachable");
177ractor_status_set(
rb_ractor_t *r,
enum ractor_status status)
179 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u [%s]->[%s]", r->pub.id, ractor_status_str(r->status_), ractor_status_str(status));
182 if (r->status_ != ractor_created) {
183 VM_ASSERT(r == GET_RACTOR());
188 switch (r->status_) {
190 VM_ASSERT(status == ractor_blocking);
193 VM_ASSERT(status == ractor_blocking||
194 status == ractor_terminated);
196 case ractor_blocking:
197 VM_ASSERT(status == ractor_running);
199 case ractor_terminated:
200 rb_bug(
"unreachable");
208ractor_status_p(
rb_ractor_t *r,
enum ractor_status status)
210 return rb_ractor_status_p(r, status);
215static void ractor_local_storage_mark(
rb_ractor_t *r);
216static void ractor_local_storage_free(
rb_ractor_t *r);
220static size_t ractor_sync_memsize(
const rb_ractor_t *r);
224mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
228 if (hook_list->type == hook_list_type_targeted_iseq) {
229 rb_gc_mark((
VALUE)key);
233 RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
234 rb_gc_mark(def->body.bmethod.proc);
236 rb_hook_list_mark(hook_list);
244 rb_gc_mark(th->self);
248 if (th->root_fiber) {
249 VALUE root_fiber_self = rb_fiberptr_self(th->root_fiber);
250 if (root_fiber_self) rb_gc_mark(root_fiber_self);
255 VALUE ec_fiber_self = (th->ec && th->ec->fiber_ptr) ? rb_fiberptr_self(th->ec->fiber_ptr) : 0;
257 rb_gc_mark(ec_fiber_self);
260 rb_execution_context_mark(th->ec);
265 rb_thread_mark_owned_roots(th);
274 rb_gc_mark(r->r_stdin);
275 rb_gc_mark(r->r_stdout);
276 rb_gc_mark(r->r_stderr);
277 rb_gc_mark(r->verbose);
278 rb_gc_mark(r->debug);
285 rb_hook_list_mark(&r->pub.hooks);
286 if (r->pub.targeted_hooks.num_entries) {
287 st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
290 if (r->threads.cnt > 0) {
292 ccan_list_for_each(&r->threads.set, th, lt_node) {
293 VM_ASSERT(th != NULL);
294 ractor_mark_thread(th);
305 if (dying_th) ractor_mark_thread(dying_th);
307 ractor_local_storage_mark(r);
311ractor_mark(
void *ptr)
323 rb_gc_mark(r->sync.default_port_value);
327 if (!rb_gc_multi_objspace_p()) {
328 ractor_mark_unshareable_parts(r);
329 rb_ractor_mark_terminated_join_value(r);
331 else if (rb_gc_during_global_gc_p()) {
336 rb_ractor_mark_terminated_join_value(r);
353 rb_ractor_mark_terminated_join_value(r);
354 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
363 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
364 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
365 ractor_mark_unshareable_parts(r);
370 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
378rb_ractor_mark_terminated_join_value(
rb_ractor_t *r)
383 rb_gc_mark_vm_stack_values((
long)numberof(slots), slots);
392 if (src->registered_marks_cnt == 0)
return;
393 size_t need = dst->registered_marks_cnt + src->registered_marks_cnt;
394 if (need > dst->registered_marks_capa) {
395 size_t nc = dst->registered_marks_capa ? dst->registered_marks_capa : 64;
396 while (nc < need) nc *= 2;
397 VALUE *p = realloc(dst->registered_marks, nc *
sizeof(
VALUE));
398 if (!p) rb_bug(
"rb_ractor_absorb_registered_marks: out of memory");
399 dst->registered_marks = p;
400 dst->registered_marks_capa = nc;
402 MEMCPY(dst->registered_marks + dst->registered_marks_cnt,
403 src->registered_marks,
VALUE, src->registered_marks_cnt);
404 dst->registered_marks_cnt = need;
405 src->registered_marks_cnt = 0;
409free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
412 rb_hook_list_free(hook_list);
417free_targeted_hooks(
st_table *hooks_tbl)
419 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
425ractor_free(
void *ptr)
428 RUBY_DEBUG_LOG(
"free r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
430 free_targeted_hooks(&r->pub.targeted_hooks);
431 rb_thread_sched_destroy(&r->threads.sched);
433 ractor_local_storage_free(r);
434 rb_hook_list_free(&r->pub.hooks);
435 rb_st_free_embedded_table(&r->pub.targeted_hooks);
437 if (r->newobj_cache) {
440 rb_gc_ractor_cache_free(r->newobj_cache);
441 r->newobj_cache = NULL;
448 if (r->objspace && !r->main_ractor) {
449 rb_gc_objspace_disown(r->objspace);
455 if (r->in_terminated_set) {
457 ccan_list_del(&r->vmlr_node);
458 r->in_terminated_set =
false;
465 if (!r->main_ractor) {
466 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
468 free(r->registered_marks);
469 r->registered_marks = NULL;
470 r->registered_marks_cnt = r->registered_marks_capa = 0;
472 if (!r->main_ractor) {
478ractor_memsize(
const void *ptr)
483 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
487ractor_update_references(
void *ptr)
499 ractor_update_references,
507 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
516RACTOR_PTR(
VALUE self)
518 VM_ASSERT(rb_ractor_p(self));
523#define MAIN_RACTOR_ID 1
524static rb_serial_t ractor_last_id = MAIN_RACTOR_ID;
526#include "ractor_sync.c"
537 VM_ASSERT(RB_VM_LOCKED_P() || !rb_multi_ractor_p());
538 return ++ractor_last_id;
544 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
545 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
550 if (vm->ractor.cnt == 1) {
554 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
557 if (r->newobj_cache) {
558 VM_ASSERT(r == ruby_single_main_ractor);
561 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
566cancel_single_ractor_mode(
void)
569 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
571 ruby_single_main_ractor = NULL;
572 rb_yjit_invalidate_single_ractor();
573 rb_zjit_invalidate_single_ractor();
581 VM_ASSERT(ractor_status_p(r, ractor_created));
583 if (rb_multi_ractor_p()) {
586 vm_insert_ractor0(vm, r,
false);
587 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
592 if (cur && cur->creating_child_objspace == r->objspace) {
593 cur->creating_child_objspace = NULL;
599 if (vm->ractor.cnt == 0) {
601 vm_insert_ractor0(vm, r,
true);
602 ractor_status_set(r, ractor_blocking);
603 ractor_status_set(r, ractor_running);
606 cancel_single_ractor_mode();
607 vm_insert_ractor0(vm, r,
true);
608 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
613 if (cur && cur->creating_child_objspace == r->objspace) {
614 cur->creating_child_objspace = NULL;
623 VM_ASSERT(ractor_status_p(cr, ractor_running));
624 VM_ASSERT(vm->ractor.cnt > 1);
625 VM_ASSERT(cr->threads.cnt == 1);
629 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
630 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
632 VM_ASSERT(vm->ractor.cnt > 0);
633 ccan_list_del(&cr->vmlr_node);
638 if (!rb_gc_multi_objspace_p()) {
640 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
641 cr->in_terminated_set =
true;
645 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
649 rb_gc_ractor_cache_free(cr->newobj_cache);
650 cr->newobj_cache = NULL;
660 rb_gc_objspace_retire(&cr->objspace);
664 ractor_status_set(cr, ractor_terminated);
676 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
677 VM_ASSERT(th->ec != NULL);
680 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
685 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
686 rb_gc_objspace_postmortem_self();
690 pf->th = (th->self == 0) ? th : NULL;
691 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
697 if (pf->fiber == NULL && pf->th == NULL)
return;
702#ifdef RB_THREAD_LOCAL_SPECIFIER
703 rb_current_ec_set(NULL);
705 native_tls_set(ruby_current_ec_key, NULL);
709 if (pf->fiber) rb_fiber_free_body(pf->fiber);
710 if (pf->th) rb_thread_free_body(pf->th);
714ractor_alloc(
VALUE klass)
719 rb_gc_obj_became_shareable(rv);
721 r->next_ec_serial = 1;
722 VM_ASSERT(ractor_status_p(r, ractor_created));
729 .pub.id = MAIN_RACTOR_ID,
736rb_ractor_main_alloc(
void)
741 ruby_single_main_ractor = r;
746#if defined(HAVE_WORKING_FORK)
754 vm->ractor.blocking_cnt = 0;
757 rb_gc_disable_holders_atfork();
761 th->ractor->creating_child_objspace = NULL;
762 ruby_single_main_ractor = th->ractor;
763 th->ractor->status_ = ractor_created;
765 rb_ractor_living_threads_init(th->ractor);
766 rb_ractor_living_threads_insert(th->ractor, th);
768 VM_ASSERT(vm->ractor.blocking_cnt == 0);
769 VM_ASSERT(vm->ractor.cnt == 1);
775 rb_gc_ractor_cache_free(r->newobj_cache);
776 r->newobj_cache = NULL;
777 r->status_ = ractor_terminated;
779 r->threads.dying_th = NULL;
783 rb_gc_objspace_retire(&r->objspace);
785 ractor_sync_terminate_atfork(vm, r);
794 ccan_list_head_init(&r->threads.set);
796 r->threads.blocking_cnt = 0;
797 r->threads.terminating =
false;
799 r->threads.dying_th = NULL;
806 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
807 r->pub.hooks.type = hook_list_type_ractor_local;
810 rb_thread_sched_init(&r->threads.sched,
false);
811 rb_ractor_living_threads_init(r);
817 enc = rb_enc_get(name);
818 if (!rb_enc_asciicompat(enc)) {
819 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
835 rb_gc_obj_became_shareable(r->pub.self);
837 r->threads.main = th;
838 rb_ractor_living_threads_insert(r, th);
839 rb_ractor_setup_default_port(r);
847 VALUE rv = ractor_alloc(self);
849 ractor_init(r, name, loc);
852 r->pub.id = ractor_next_id();
854 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", r->pub.id);
857 r->verbose = cr->verbose;
858 r->debug = cr->debug;
862 r->objspace = rb_gc_objspace_alloc();
864 rb_thread_create_ractor(r, args, block);
875 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
882 ractor_notify_exit(ec, cr, result, exc);
890 ractor_postmortem_collect(th, pf);
891 ractor_send_exit_tokens(th->ec, th->ractor);
898 ractor_atexit(ec, cr, result,
false);
905 ractor_atexit(ec, cr, ec->errinfo,
true);
915 VM_ASSERT(cr->threads.main != NULL);
916 cr->threads.main = NULL;
923 for (
int i=0; i<
len; i++) {
924 ptr[i] = ractor_receive(ec, ractor_default_port(r), NULL);
932 for (
int i=0; i<
len; i++) {
933 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
938rb_ractor_main_p_(
void)
940 VM_ASSERT(rb_multi_ractor_p());
942 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
948 return r->threads.cnt;
953rb_ractor_thread_list(
void)
959 ccan_list_for_each(&r->threads.set, th, lt_node) {
960 switch (th->status) {
961 case THREAD_RUNNABLE:
963 case THREAD_STOPPED_FOREVER:
976 VM_ASSERT(th != NULL);
980 RUBY_DEBUG_LOG(
"r(%"PRI_SERIALT_PREFIX
"u)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
981 ccan_list_add_tail(&r->threads.set, &th->lt_node);
987 if (r->threads.cnt == 1) {
988 VM_ASSERT(ractor_status_p(r, ractor_created));
989 vm_insert_ractor(th->vm, r);
996 ractor_status_set(r, ractor_blocking);
998 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
999 vm->ractor.blocking_cnt++;
1000 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
1004rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1006 ASSERT_vm_locking();
1007 VM_ASSERT(GET_RACTOR() == cr);
1008 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
1012rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
1014 ASSERT_vm_locking();
1015 VM_ASSERT(GET_RACTOR() == cr);
1017 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
1018 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1019 vm->ractor.blocking_cnt--;
1021 ractor_status_set(cr, ractor_running);
1032 ccan_list_del(&th->lt_node);
1040 VM_ASSERT(vm->ractor.cnt > 1);
1041 ccan_list_del(&r->vmlr_node);
1046 VM_ASSERT(r->status_ == ractor_blocking);
1047 VM_ASSERT(vm->ractor.blocking_cnt > 0);
1048 vm->ractor.blocking_cnt--;
1050 rb_gc_ractor_cache_free(r->newobj_cache);
1051 r->newobj_cache = NULL;
1054 rb_gc_objspace_disown(r->objspace);
1057 r->status_ = ractor_terminated;
1065 VM_ASSERT(cr == GET_RACTOR());
1066 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
1068 if (cr->threads.cnt == 1) {
1069 vm_remove_ractor(th->vm, cr);
1074 ccan_list_del(&th->lt_node);
1082rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1084 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1086 VM_ASSERT(cr->threads.cnt > 0);
1087 VM_ASSERT(cr == GET_RACTOR());
1089 cr->threads.blocking_cnt++;
1093rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1095 RUBY_DEBUG_LOG2(file, line,
1096 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1097 cr->threads.blocking_cnt, cr->threads.cnt);
1099 VM_ASSERT(cr == GET_RACTOR());
1101 cr->threads.blocking_cnt--;
1105rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1107 VM_ASSERT(r != GET_RACTOR());
1108 ASSERT_ractor_unlocking(r);
1109 ASSERT_vm_locking();
1113 if (ractor_status_p(r, ractor_running)) {
1116 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1124rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1126 VM_ASSERT(r != GET_RACTOR());
1127 ASSERT_ractor_unlocking(r);
1128 ASSERT_vm_locking();
1132 if (main_th->status != THREAD_KILLED) {
1133 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1134 rb_threadptr_interrupt(main_th);
1137 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1145ractor_terminal_interrupt_all(
rb_vm_t *vm)
1147 if (vm->ractor.cnt > 1) {
1150 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1151 if (r != vm->ractor.main_ractor) {
1152 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u", rb_ractor_id(r));
1153 rb_ractor_terminate_interrupt_main_thread(r);
1163rb_ractor_terminate_all(
void)
1168 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1170 VM_ASSERT(cr == GET_RACTOR());
1174 ractor_terminal_interrupt_all(vm);
1177 rb_thread_terminate_all(GET_THREAD());
1181 while (vm->ractor.cnt > 1) {
1182 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1183 vm->ractor.sync.terminate_waiting =
true;
1186 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1187 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1188 rb_ractor_sched_wait_terminate(vm, &vm->ractor.sync.terminate_cond, 1000 );
1189 while (vm->ractor.sched.barrier_is_waiting) {
1196 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1198 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1199 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1201 ractor_terminal_interrupt_all(vm);
1208 rb_gc_objspace_absorb_all_zombies();
1212rb_vm_main_ractor_ec(
rb_vm_t *vm)
1229 if (running_ec) {
return running_ec; }
1230 return vm->ractor.main_thread->ec;
1234ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1236 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1338 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1339 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1340 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1342 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1346 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1349 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1353 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1354 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1355 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1356 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1367 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1368 if (r != vm->ractor.main_ractor) {
1369 fprintf(stderr,
"r:%"PRI_SERIALT_PREFIX
"u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1377 if (rb_ractor_main_p()) {
1382 if (UNLIKELY(cr->r_stdin == 0)) {
1383 cr->r_stdin = rb_io_prep_stdin();
1390rb_ractor_stdout(
void)
1392 if (rb_ractor_main_p()) {
1397 if (UNLIKELY(cr->r_stdout == 0)) {
1398 cr->r_stdout = rb_io_prep_stdout();
1400 return cr->r_stdout;
1405rb_ractor_stderr(
void)
1407 if (rb_ractor_main_p()) {
1412 if (UNLIKELY(cr->r_stderr == 0)) {
1413 cr->r_stderr = rb_io_prep_stderr();
1415 return cr->r_stderr;
1422 if (rb_ractor_main_p()) {
1434 if (rb_ractor_main_p()) {
1446 if (rb_ractor_main_p()) {
1459 return &cr->pub.targeted_hooks;
1463rb_obj_set_shareable_no_assert(
VALUE obj)
1470 rb_gc_obj_became_shareable(obj);
1479 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1480 if (imemo_type_p(fields, imemo_fields)) {
1483 rb_gc_obj_became_shareable(fields);
1487 rb_imemo_fields_record_shrefs(fields);
1492#ifndef STRICT_VERIFY_SHAREABLE
1493#define STRICT_VERIFY_SHAREABLE 0
1497rb_ractor_verify_shareable(
VALUE obj)
1499#if STRICT_VERIFY_SHAREABLE
1500 rb_gc_verify_shareable(obj);
1510 rb_obj_set_shareable_no_assert(obj);
1522enum obj_traverse_iterator_result {
1528typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1529typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1530typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1532static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1535 rb_obj_traverse_enter_func enter_func;
1536 rb_obj_traverse_leave_func leave_func;
1555 if (obj_traverse_i(key, d->data)) {
1560 if (obj_traverse_i(val, d->data)) {
1569obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1573 if (obj_traverse_i(obj, d->data)) {
1586 RB_VM_LOCKING_NO_BARRIER() {
1587 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1595 if (UNLIKELY(!data->rec)) {
1596 data->rec_hash = rb_ident_hash_new();
1598 data->rec = RHASH_ST_TABLE(data->rec_hash);
1604obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1608 if (obj_traverse_i(val, d->data)) {
1621 switch (data->enter_func(obj)) {
1622 case traverse_cont:
break;
1623 case traverse_skip:
return 0;
1624 case traverse_stop:
return 1;
1627 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1633 if (rb_obj_shape_has_ivars(obj)) {
1639 if (d.stop)
return 1;
1657 rb_ary_cancel_sharing(obj);
1661 if (obj_traverse_i(e, data))
return 1;
1675 if (d.stop)
return 1;
1681 long len = RSTRUCT_LEN_RAW(obj);
1682 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1684 for (
long i=0; i<
len; i++) {
1685 if (obj_traverse_i(ptr[i], data))
return 1;
1691 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1695 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1696 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1699 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1700 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1705 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1708 if (!ptr || !
type->function.dmark) {
1711 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1712 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1713 for (; *offsets != RUBY_REF_END; offsets++) {
1714 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1715 if (obj_traverse_i(ref, data))
return 1;
1719 if (obj_traverse_reachable(obj, data))
return 1;
1726 if (obj_traverse_reachable(obj, data))
return 1;
1735 rb_bug(
"unreachable");
1738 if (data->leave_func(obj) == traverse_stop) {
1747 rb_obj_traverse_final_func final_func;
1752obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1755 if (data->final_func(key)) {
1765rb_obj_traverse(
VALUE obj,
1766 rb_obj_traverse_enter_func enter_func,
1767 rb_obj_traverse_leave_func leave_func,
1768 rb_obj_traverse_final_func final_func)
1771 .enter_func = enter_func,
1772 .leave_func = leave_func,
1776 if (obj_traverse_i(obj, &data))
return 1;
1777 if (final_func && data.rec) {
1779 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1786allow_frozen_shareable_p(
VALUE obj)
1796 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1805make_shareable_freeze(
VALUE obj)
1808 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1811 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1814 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1815 rb_hash_freeze(obj);
1822static enum obj_traverse_iterator_result
1823make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1826 make_shareable_freeze(obj);
1829 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1833 return traverse_skip;
1840static int obj_refer_only_shareables_p(
VALUE obj);
1842static enum obj_traverse_iterator_result
1843make_shareable_check_shareable(
VALUE obj)
1848 return traverse_skip;
1850 else if (!allow_frozen_shareable_p(obj)) {
1852 rb_raise(rb_eRactorError,
1853 "can not make shareable object for %+"PRIsVALUE, obj);
1855 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1856 if (obj_refer_only_shareables_p(obj)) {
1857 make_shareable_check_shareable_freeze(obj, traverse_skip);
1859 return traverse_skip;
1862 rb_raise(rb_eRactorError,
1863 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1867 rb_proc_ractor_make_shareable(obj,
Qundef);
1868 return traverse_cont;
1871 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1875 switch (
TYPE(obj)) {
1877 return traverse_skip;
1884 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1885 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1886 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1887 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1896 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1899static enum obj_traverse_iterator_result
1900mark_shareable(
VALUE obj)
1903 rb_str_make_independent(obj);
1906 rb_obj_set_shareable_no_assert(obj);
1907 return traverse_cont;
1913 rb_obj_traverse(obj,
1914 make_shareable_check_shareable,
1915 null_leave, mark_shareable);
1924 VALUE copy = ractor_copy(obj);
1929rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1932 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
1940rb_ractor_ensure_main_ractor(
const char *msg)
1942 if (!rb_ractor_main_p()) {
1943 rb_raise(rb_eRactorIsolationError,
"%s", msg);
1947static enum obj_traverse_iterator_result
1948shareable_p_enter(
VALUE obj)
1951 return traverse_skip;
1957 mark_shareable(obj);
1958 return traverse_skip;
1961 allow_frozen_shareable_p(obj)) {
1962 return traverse_cont;
1970 if (obj_refer_only_shareables_p(obj)) {
1971 mark_shareable(obj);
1972 return traverse_skip;
1976 return traverse_stop;
1980rb_ractor_shareable_p_continue(
VALUE obj)
1982 if (rb_obj_traverse(obj,
1983 shareable_p_enter, null_leave,
1992static enum obj_traverse_iterator_result
1993null_leave(
VALUE obj)
1995 return traverse_cont;
2011 rb_obj_traverse_replace_enter_func enter_func;
2012 rb_obj_traverse_replace_leave_func leave_func;
2018 VALUE rec_keepalive;
2031obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2037obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2042 if (obj_traverse_replace_i(*key, data)) {
2046 else if (*key != data->replacement) {
2047 VALUE v = *key = data->replacement;
2051 if (obj_traverse_replace_i(*val, data)) {
2055 else if (*val != data->replacement) {
2056 VALUE v = *val = data->replacement;
2064obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2070obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2075 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2079 else if (*(
VALUE *)val != data->replacement) {
2090 if (UNLIKELY(!data->rec)) {
2091 data->rec = st_init_numtable();
2098obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2100 int *pcnt = (
int *)ptr;
2108obj_refer_only_shareables_p(
VALUE obj)
2111 RB_VM_LOCKING_NO_BARRIER() {
2112 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
2120 st_data_t replacement;
2123 data->replacement = obj;
2130 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2131 data->replacement = (
VALUE)replacement;
2135 switch (data->enter_func(obj, data)) {
2136 case traverse_cont:
break;
2137 case traverse_skip:
return 0;
2138 case traverse_stop:
return 1;
2141 replacement = (st_data_t)data->replacement;
2142 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2151#define CHECK_AND_REPLACE(parent_obj, v) do { \
2153 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2154 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2157 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2158 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2160 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2166 rb_st_foreach_with_replace(
2167 rb_imemo_fields_complex_tbl(fields_obj),
2168 obj_iv_hash_traverse_replace_foreach_i,
2169 obj_iv_hash_traverse_replace_i,
2172 if (d.stop)
return 1;
2175 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2176 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2177 for (uint32_t i = 0; i < fields_count; i++) {
2178 CHECK_AND_REPLACE(fields_obj, fields[i]);
2192 rb_str_make_independent(obj);
2197 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2198 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2199 if (rb_shape_complex_p(shape_id)) {
2205 rb_st_foreach_with_replace(
2206 rb_imemo_fields_complex_tbl(fields_obj),
2207 obj_iv_hash_traverse_replace_foreach_i,
2208 obj_iv_hash_traverse_replace_i,
2211 if (d.stop)
return 1;
2214 attr_index_t
len = RSHAPE_LEN(shape_id);
2215 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2217 for (attr_index_t i = 0; i <
len; i++) {
2218 CHECK_AND_REPLACE(obj, ptr[i]);
2226 rb_ary_cancel_sharing(obj);
2231 if (obj_traverse_replace_i(e, data)) {
2234 else if (e != data->replacement) {
2248 rb_hash_stlike_foreach_with_replace(obj,
2249 obj_hash_traverse_replace_foreach_i,
2250 obj_hash_traverse_replace_i,
2252 if (d.stop)
return 1;
2256 if (obj_traverse_replace_i(ifnone, data)) {
2259 else if (ifnone != data->replacement) {
2267 long len = RSTRUCT_LEN_RAW(obj);
2268 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2270 for (
long i=0; i<
len; i++) {
2271 CHECK_AND_REPLACE(obj, ptr[i]);
2277 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2281 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2282 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2285 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2286 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2290 if (!data->move && obj_refer_only_shareables_p(obj)) {
2294 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2308 rb_bug(
"unreachable");
2311 data->replacement = (
VALUE)replacement;
2313 if (data->leave_func(obj, data) == traverse_stop) {
2324rb_obj_traverse_replace(
VALUE obj,
2325 rb_obj_traverse_replace_enter_func enter_func,
2326 rb_obj_traverse_replace_leave_func leave_func,
2330 .enter_func = enter_func,
2331 .leave_func = leave_func,
2338 int stopped = obj_traverse_replace_i(obj, &data);
2342 if (data.rec) st_free_table(data.rec);
2349 return data.replacement;
2359enum courier_node_kind {
2361 COURIER_KIND_BACKTRACE,
2362 COURIER_KIND_STRING,
2365 COURIER_KIND_OBJECT,
2366 COURIER_KIND_STRUCT,
2372 enum courier_node_kind kind;
2381 struct {
char *ptr;
long len, capa;
int encidx;
VALUE klass; } str;
2382 struct {
long len; uint32_t *elems;
VALUE klass; } ary;
2383 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2384 struct {
VALUE klass; } obj;
2385 struct {
long len; uint32_t *elems;
VALUE klass; } strct;
2386 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2387 struct {
void *blob;
int size; } bt;
2394 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2402#define COURIER_ID_REF_BIT 0x80000000u
2409 uint32_t refs_count;
2434 uint32_t
capa = c->capa ? c->capa * 2 : 8;
2440 ruby_xfree(old_nodes);
2446 uint32_t
capa = c->refs_capa ? c->refs_capa * 2 : 8;
2448 if (c->refs_count > 0)
MEMCPY(refs, c->refs,
VALUE, c->refs_count);
2449 VALUE *old_refs = c->refs;
2451 c->refs_capa =
capa;
2452 ruby_xfree(old_refs);
2458 if (RB_UNLIKELY(c->count == c->capa)) courier_grow_nodes(c);
2463 n->kind = COURIER_KIND_REF;
2483 c->refs_capa = refs;
2495 if (RB_UNLIKELY(c->refs_count == c->refs_capa)) courier_grow_refs(c);
2496 c->refs[c->refs_count] = v;
2497 return COURIER_ID_REF_BIT | c->refs_count++;
2504 if (
id & COURIER_ID_REF_BIT)
return c->refs[
id & ~COURIER_ID_REF_BIT];
2511move_neutralize_source(
VALUE obj)
2516 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2517 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2527 bool wipe_body =
true;
2530 if (!STR_EMBED_P(obj) && !rb_str_reembeddable_p(obj)) {
2535 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2537 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2541 wipe_body = !rb_str_embedded_shared_root_p(obj);
2544 if (!ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && (ARY_SHARED_ROOT_P(obj) ||
OBJ_FROZEN(obj))) {
2549 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2551 RBASIC_SET_FULL_SHAPE_ID(obj, (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_OTHER);
2552 if (!ARY_SHARED_ROOT_P(obj)) {
2555 RARRAY(obj)->as.heap.len = 0;
2559 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2571 size_t slot_size = rb_gc_obj_slot_size(obj);
2572 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2573 RBASIC(obj)->flags = flags;
2574 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2592courier_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2595 uint32_t kid = courier_capture(hc->b, (
VALUE)key);
2596 uint32_t vid = courier_capture(hc->b, (
VALUE)val);
2597 hc->kv[hc->i++] = kid;
2598 hc->kv[hc->i++] = vid;
2611courier_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2614 if (oc->n == oc->capa) {
2615 oc->capa = oc->capa ? oc->capa * 2 : 4;
2617 REALLOC_N(oc->vals, uint32_t, oc->capa);
2619 uint32_t vid = courier_capture(oc->b, val);
2620 oc->ids[oc->n] = name;
2621 oc->vals[oc->n] = vid;
2633 rb_ivar_foreach_buffered(obj, courier_capture_ivar_i, (st_data_t)&oc);
2634 b->c->nodes[id].niv = (uint32_t)oc.n;
2635 b->c->nodes[id].iv_ids = oc.ids;
2636 b->c->nodes[id].iv_vals = oc.vals;
2649 return courier_alloc_ref(b->c, obj);
2657 if (st_lookup(b->seen, (st_data_t)obj, &existing)) {
2658 return (uint32_t)existing - 1;
2662 return courier_alloc_ref(b->c, obj);
2665 uint32_t
id = courier_alloc_node(b->c);
2666 st_insert(b->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2670 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2674 b->c->nodes[id].frozen = frozen;
2675 courier_capture_ivars(b, obj,
id);
2682 if (!b->copy) rb_str_make_independent(obj);
2683 long len = RSTRING_LEN(obj);
2687 const int termlen = rb_enc_mbminlen(rb_enc_from_index(encidx));
2690 if (!b->copy && !STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2693 ptr =
RSTRING(obj)->as.heap.ptr;
2701 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2702 memset(ptr +
len, 0, termlen);
2705 b->c->nodes[id].kind = COURIER_KIND_STRING;
2707 b->c->nodes[id].u.str.ptr = ptr;
2708 b->c->nodes[id].u.str.len =
len;
2709 b->c->nodes[id].u.str.capa =
capa;
2710 b->c->nodes[id].u.str.encidx = encidx;
2717 for (
long i = 0; i <
len; i++) {
2718 elems[i] = courier_capture(b,
RARRAY_AREF(obj, i));
2720 b->c->nodes[id].kind = COURIER_KIND_ARRAY;
2722 b->c->nodes[id].u.ary.len =
len;
2723 b->c->nodes[id].u.ary.elems = elems;
2727 if (!b->copy && !ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2734 uint32_t ifnone_id = courier_capture(b,
RHASH_IFNONE(obj));
2736 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2738 rb_hash_stlike_foreach(obj, courier_capture_hash_i, (st_data_t)&hc);
2739 b->c->nodes[id].kind = COURIER_KIND_HASH;
2741 b->c->nodes[id].u.hash.size = size;
2742 b->c->nodes[id].u.hash.kv = kv;
2743 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2744 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2745 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2747 if (!b->copy) rb_hash_free(obj);
2752 b->c->nodes[id].kind = COURIER_KIND_OBJECT;
2762 for (
long i = 0; i <
len; i++) {
2763 elems[i] = courier_capture(b,
RSTRUCT_GET(obj, (
int)i));
2765 b->c->nodes[id].kind = COURIER_KIND_STRUCT;
2766 b->c->nodes[id].u.strct.len =
len;
2767 b->c->nodes[id].u.strct.elems = elems;
2770 if (!b->copy && RSTRUCT_EMBED_LEN(obj) == 0) {
2771 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2781 void *regs = rb_match_blob_dump(obj, &re, &st, &nregs, !b->copy);
2782 uint32_t rid = courier_capture(b, re);
2783 uint32_t sid = courier_capture(b, st);
2784 b->c->nodes[id].kind = COURIER_KIND_MATCH;
2785 b->c->nodes[id].u.match.regexp_id = rid;
2786 b->c->nodes[id].u.match.str_id = sid;
2787 b->c->nodes[id].u.match.num_regs = nregs;
2788 b->c->nodes[id].u.match.regs = regs;
2795 VM_ASSERT(!b->copy);
2801 uint32_t pathv_id = courier_capture(b, fptr->
pathv);
2802 uint32_t ecopts_id = courier_capture(b, fptr->
encs.
ecopts);
2805 uint32_t timeout_id = courier_capture(b, fptr->
timeout);
2813 fptr->wakeup_mutex =
Qnil;
2815 b->c->nodes[id].kind = COURIER_KIND_IO;
2816 b->c->nodes[id].u.io.fptr = fptr;
2818 b->c->nodes[id].u.io.pathv_id = pathv_id;
2819 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
2820 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
2821 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
2822 b->c->nodes[id].u.io.timeout_id = timeout_id;
2829 if (b->copy && rb_backtrace_p(obj)) {
2831 void *blob = rb_backtrace_blob_dump(obj, &size);
2832 b->c->nodes[id].kind = COURIER_KIND_BACKTRACE;
2833 b->c->nodes[id].u.bt.blob = blob;
2834 b->c->nodes[id].u.bt.size = size;
2839 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2843 if (!b->copy) move_neutralize_source(obj);
2850 uint32_t nodes, refs;
2856move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
2863move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2882 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
2883 st_insert(seen, (st_data_t)obj, 0);
2890 rb_class_check_singleton_movable(klass);
2899 move_preflight(rm->
regexp, ctx);
2900 move_preflight(rm->
str, ctx);
2909 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)ctx);
2920 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2925 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
2927 if (
RTEST(fptr->wakeup_mutex)) {
2929 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
2931 move_preflight(fptr->
pathv, ctx);
2935 move_preflight(fptr->
timeout, ctx);
2939 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2951 uint32_t nodes, refs;
2958copy_support_val_i(st_data_t val, st_data_t arg)
2961 if (!copy_courier_supported_p((
VALUE)val, ctx)) {
2969copy_support_ivar_i(
ID name,
VALUE val, st_data_t arg)
2971 return copy_support_val_i((st_data_t)val, arg);
2975copy_support_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2977 if (copy_support_val_i(key, arg) == ST_STOP)
return ST_STOP;
2978 return copy_support_val_i(val, arg);
2993 if (st_lookup(seen, (st_data_t)obj, NULL))
return true;
2994 st_insert(seen, (st_data_t)obj, 0);
3008 if (!copy_courier_supported_p(rm->
regexp, ctx))
return false;
3009 if (!copy_courier_supported_p(rm->
str, ctx))
return false;
3014 if (!rb_backtrace_p(obj))
return false;
3018 if (!copy_courier_supported_p(
RARRAY_AREF(obj, i), ctx))
return false;
3022 rb_hash_stlike_foreach(obj, copy_support_hash_i, (st_data_t)ctx);
3023 if (!ctx->ok)
return false;
3024 if (!copy_courier_supported_p(
RHASH_IFNONE(obj), ctx))
return false;
3028 if (!copy_courier_supported_p(
RSTRUCT_GET(obj, (
int)i), ctx))
return false;
3046 bool ok = copy_courier_supported_p(obj, &scan);
3047 st_free_table(scan.seen);
3048 if (!ok)
return NULL;
3052 courier_reserve(c, scan.nodes, scan.refs);
3059 enum ruby_tag_type state;
3062 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3063 c->root = courier_capture(&b, obj);
3066 st_free_table(b.seen);
3068 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3081 enum ruby_tag_type state;
3084 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3085 move_preflight(obj, &scan);
3088 st_free_table(scan.seen);
3089 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
3093 courier_reserve(c, scan.nodes, scan.refs);
3101 enum ruby_tag_type state;
3104 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
3105 c->root = courier_capture(&b, obj);
3108 st_free_table(b.seen);
3109 if (state != TAG_NONE) {
3113 EC_JUMP_TAG(ec, state);
3125 RBASIC_SET_CLASS(shell, klass);
3130 rb_class_take_ownership(klass);
3143 for (uint32_t i = 0; i < c->count; i++) {
3147 case COURIER_KIND_REF:
3150 case COURIER_KIND_STRING:
3154 shell = rb_str_new_owned(n->u.str.ptr, n->u.str.len, n->u.str.capa, n->u.str.encidx);
3155 n->u.str.ptr = NULL;
3156 courier_apply_klass(shell, n->u.str.klass);
3158 case COURIER_KIND_ARRAY:
3160 courier_apply_klass(shell, n->u.ary.klass);
3162 case COURIER_KIND_HASH:
3163 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
3164 courier_apply_klass(shell, n->u.hash.klass);
3166 case COURIER_KIND_OBJECT:
3170 courier_apply_klass(shell, n->u.obj.klass);
3172 case COURIER_KIND_STRUCT:
3174 courier_apply_klass(shell, n->u.strct.klass);
3176 case COURIER_KIND_MATCH:
3177 shell = rb_match_blob_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
3178 courier_apply_klass(shell, n->u.match.klass);
3180 case COURIER_KIND_BACKTRACE:
3181 shell = rb_backtrace_blob_load(n->u.bt.blob, n->u.bt.size);
3183 case COURIER_KIND_IO:
3185 courier_apply_klass(shell, n->u.io.klass);
3186 RFILE(shell)->fptr = n->u.io.fptr;
3187 n->u.io.fptr->
self = shell;
3188 n->u.io.fptr = NULL;
3191 rb_bug(
"rb_ractor_courier_materialize: bad node kind");
3196 for (uint32_t i = 0; i < c->count; i++) {
3200 case COURIER_KIND_ARRAY: {
3203 const long len = n->u.ary.len;
3206 for (
long j = 0; j <
len; j++) {
3207 RARRAY_ASET(shell, j, courier_child(c, shells, n->u.ary.elems[j]));
3212 case COURIER_KIND_HASH:
3217 case COURIER_KIND_STRUCT:
3218 for (
long j = 0; j < n->u.strct.len; j++) {
3219 RSTRUCT_SET(shell, (
int)j, courier_child(c, shells, n->u.strct.elems[j]));
3222 case COURIER_KIND_MATCH:
3223 rb_match_blob_load(shell, courier_child(c, shells, n->u.match.regexp_id),
3224 courier_child(c, shells, n->u.match.str_id),
3225 n->u.match.num_regs, n->u.match.regs);
3227 case COURIER_KIND_IO: {
3242 for (uint32_t j = 0; j < n->niv; j++) {
3243 rb_ivar_set(shell, n->iv_ids[j], courier_child(c, shells, n->iv_vals[j]));
3250 for (uint32_t i = c->count; i > 0; i--) {
3252 if (n->kind != COURIER_KIND_HASH)
continue;
3254 for (
long j = 0; j < n->u.hash.size; j++) {
3255 rb_hash_aset(shell, courier_child(c, shells, n->u.hash.kv[2 * j]),
3256 courier_child(c, shells, n->u.hash.kv[2 * j + 1]));
3259 VALUE ifnone = courier_child(c, shells, n->u.hash.ifnone_id);
3260 if (n->u.hash.proc_default) {
3261 rb_hash_set_default_proc(shell, ifnone);
3263 else if (ifnone !=
Qnil) {
3264 rb_hash_set_default(shell, ifnone);
3269 for (uint32_t i = 0; i < c->count; i++) {
3276 VALUE root = (c->count || c->refs_count) ? courier_child(c, shells, c->root) :
Qnil;
3284 for (uint32_t i = 0; i < c->count; i++) {
3286 ruby_xfree(n->iv_ids);
3287 ruby_xfree(n->iv_vals);
3289 case COURIER_KIND_STRING:
3290 ruby_xfree(n->u.str.ptr);
3292 case COURIER_KIND_ARRAY:
3293 ruby_xfree(n->u.ary.elems);
3295 case COURIER_KIND_HASH:
3296 ruby_xfree(n->u.hash.kv);
3298 case COURIER_KIND_STRUCT:
3299 ruby_xfree(n->u.strct.elems);
3301 case COURIER_KIND_MATCH:
3302 rb_match_blob_free(n->u.match.regs);
3304 case COURIER_KIND_BACKTRACE:
3305 ruby_xfree(n->u.bt.blob);
3307 case COURIER_KIND_IO:
3313 n->u.io.fptr = NULL;
3320 ruby_xfree(c->nodes);
3321 ruby_xfree(c->refs);
3332 for (uint32_t i = 0; i < c->refs_count; i++) {
3333 rb_gc_mark(c->refs[i]);
3335 for (uint32_t i = 0; i < c->count; i++) {
3337 if (n->kind == COURIER_KIND_REF) {
3338 rb_gc_mark(n->u.ref);
3340 else if (n->kind == COURIER_KIND_OBJECT) {
3341 rb_gc_mark(n->u.obj.klass);
3343 else if (n->kind == COURIER_KIND_STRUCT) {
3344 rb_gc_mark(n->u.strct.klass);
3346 else if (n->kind == COURIER_KIND_MATCH) {
3347 rb_gc_mark(n->u.match.klass);
3349 else if (n->kind == COURIER_KIND_IO) {
3350 rb_gc_mark(n->u.io.klass);
3352 else if (n->kind == COURIER_KIND_STRING) {
3353 rb_gc_mark(n->u.str.klass);
3355 else if (n->kind == COURIER_KIND_BACKTRACE) {
3356 rb_backtrace_blob_mark(n->u.bt.blob, n->u.bt.size);
3358 else if (n->kind == COURIER_KIND_ARRAY) {
3359 rb_gc_mark(n->u.ary.klass);
3361 else if (n->kind == COURIER_KIND_HASH) {
3362 rb_gc_mark(n->u.hash.klass);
3371ractor_native_shallow_copy(
VALUE obj)
3385 rb_obj_copy_ivar(copy, obj);
3388 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3394 copy = rb_hash_dup(obj);
3398 rb_struct_init_copy(copy, obj);
3402 rb_match_init_copy(copy, obj);
3407 if (rb_backtrace_p(obj)) {
3408 copy = rb_backtrace_dup(obj);
3420 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3432static enum obj_traverse_iterator_result
3436 data->replacement = obj;
3437 return traverse_skip;
3440 VALUE copy = ractor_native_shallow_copy(obj);
3441 if (UNDEF_P(copy))
return traverse_stop;
3442 data->replacement = copy;
3443 return traverse_cont;
3447static enum obj_traverse_iterator_result
3450 return traverse_cont;
3456ractor_copy_native_try(
VALUE obj)
3458 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3464ractor_copy(
VALUE obj)
3466 VALUE copy = ractor_copy_native_try(obj);
3467 if (UNDEF_P(copy)) {
3469 ractor_marshal_dump_rescue, obj,
3486} freed_ractor_local_keys;
3490ractor_local_keys_purge(
st_table *local_storage)
3492 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3494 st_data_t val, k = (st_data_t)key;
3495 if (st_delete(local_storage, &k, &val) &&
3497 (*key->type->free)((
void *)val);
3504ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3507 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3511static enum rb_id_table_iterator_result
3512idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3515 return ID_TABLE_CONTINUE;
3521 if (r->local_storage) {
3522 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3527 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3528 ractor_local_keys_purge(r->local_storage);
3532 if (r->idkey_local_storage) {
3533 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3536 rb_gc_mark(r->local_storage_store_lock);
3540ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3543 if (k->type->
free) (*k->type->
free)((
void *)val);
3550 if (r->local_storage) {
3551 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3552 st_free_table(r->local_storage);
3555 if (r->idkey_local_storage) {
3556 rb_id_table_free(r->idkey_local_storage);
3561rb_ractor_local_storage_value_mark(
void *ptr)
3563 rb_gc_mark((
VALUE)ptr);
3577 rb_ractor_local_storage_value_mark,
3585 key->type =
type ?
type : &ractor_local_storage_type_null;
3586 key->main_cache = (
void *)
Qundef;
3600 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3601 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3602 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3604 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3611 if (rb_ractor_main_p()) {
3612 if (!UNDEF_P((
VALUE)key->main_cache)) {
3613 *pret = key->main_cache;
3623 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3637 if (cr->local_storage == NULL) {
3638 cr->local_storage = st_init_numtable();
3641 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3643 if (rb_ractor_main_p()) {
3644 key->main_cache = ptr;
3652 if (ractor_local_ref(key, &val)) {
3663 if (ractor_local_ref(key, (
void **)val)) {
3674 ractor_local_set(key, (
void *)val);
3681 if (ractor_local_ref(key, &ret)) {
3692 ractor_local_set(key, ptr);
3695#define DEFAULT_KEYS_CAPA 0x10
3698rb_ractor_finish_marking(
bool full_mark)
3703 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3713 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3714 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3715 if (owner == NULL || owner->local_storage == NULL)
continue;
3716 ractor_local_keys_purge(owner->local_storage);
3719 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3720 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3722 freed_ractor_local_keys.cnt = 0;
3723 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3724 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3725 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3730 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3731 rb_ractor_reap_dead_ports(r);
3733 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
3734 rb_ractor_reap_dead_ports(vm->ractor.main_ractor);
3744 struct rb_id_table *tbl = cr->idkey_local_storage;
3747 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
3760 struct rb_id_table *tbl = cr->idkey_local_storage;
3763 tbl = cr->idkey_local_storage = rb_id_table_create(2);
3765 rb_id_table_insert(tbl,
id, val);
3777ractor_local_value_store_i(
VALUE ptr)
3782 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
3787 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
3800 .tbl = cr->idkey_local_storage,
3804 if (data.tbl == NULL) {
3805 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
3807 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
3812 if (!cr->local_storage_store_lock) {
3825 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
3829 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
3853RUBY_REFERENCES(cross_ractor_require_refs) = {
3860 "ractor/cross_ractor_require",
3862 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
3867 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
3871require_body(
VALUE crr_obj)
3875 VALUE feature = crr->as.require.feature;
3881 int rb_require_internal_silent(
VALUE fname);
3882 return INT2NUM(rb_require_internal_silent(feature));
3899require_result_send_body(
VALUE ary)
3906 ractor_port_send(ec, port, results,
Qfalse);
3911require_result_send_resuce(
VALUE port,
VALUE errinfo)
3914 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
3924 const bool silent = crr->silent;
3926 VALUE debug, errinfo;
3929 errinfo = rb_errinfo();
3937 rb_set_errinfo(errinfo);
3942 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
3950ractor_require_func(
void *crr_obj)
3952 return ractor_require_protect((
VALUE)crr_obj, require_body);
3956rb_ractor_require(
VALUE feature,
bool silent)
3959 ASSERT_vm_unlocking();
3968 crr->raised =
false;
3969 crr->silent = silent;
3972 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
3973 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
3976 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
3977 ractor_port_close(ec, crr->port);
3994 return rb_ractor_require(feature,
false);
3998autoload_load_body(
VALUE crr_obj)
4006ractor_autoload_load_func(
void *crr_obj)
4008 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
4012rb_ractor_autoload_load(
VALUE module,
ID name)
4018 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
4023 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
4024 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
4027 VALUE results = ractor_port_receive(ec, crr->port,
Qnil);
4028 ractor_port_close(ec, crr->port);
4042#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.
@ 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 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)
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().
#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.
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.
#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.
#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.