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);
246 rb_gc_mark(r->r_stdin);
247 rb_gc_mark(r->r_stdout);
248 rb_gc_mark(r->r_stderr);
249 rb_gc_mark(r->verbose);
250 rb_gc_mark(r->debug);
258 VM_ASSERT(r == rb_current_ractor_raw(
false) || rb_gc_during_global_gc_p());
259 VM_ASSERT(!rb_ractor_status_p(r, ractor_terminated));
261 rb_hook_list_mark(&r->pub.hooks);
262 if (r->pub.targeted_hooks.num_entries) {
263 st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
266 if (r->threads.cnt > 0) {
268 ccan_list_for_each(&r->threads.set, th, lt_node) {
269 VM_ASSERT(th != NULL);
270 rb_gc_mark(th->self);
274 if (th->root_fiber) {
275 VALUE root_fiber_self = rb_fiberptr_self(th->root_fiber);
276 if (root_fiber_self) rb_gc_mark(root_fiber_self);
281 VALUE ec_fiber_self = (th->ec && th->ec->fiber_ptr) ? rb_fiberptr_self(th->ec->fiber_ptr) : 0;
283 rb_gc_mark(ec_fiber_self);
286 rb_execution_context_mark(th->ec);
291 rb_thread_mark_owned_roots(th);
295 ractor_local_storage_mark(r);
299ractor_mark(
void *ptr)
311 rb_gc_mark(r->sync.default_port_value);
315 if (!rb_gc_multi_objspace_p()) {
316 ractor_mark_unshareable_parts(r);
317 rb_ractor_mark_in_flight_for_single_objspace(r);
330 rb_ractor_mark_terminated_join_value(r);
331 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
337 ractor_mark_unshareable_parts(r);
342 rb_gc_mark_vm_stack_values((
long)r->registered_marks_cnt, r->registered_marks);
350rb_ractor_mark_terminated_join_value(
rb_ractor_t *r)
355 rb_gc_mark_vm_stack_values((
long)numberof(slots), slots);
364 if (src->registered_marks_cnt == 0)
return;
365 size_t need = dst->registered_marks_cnt + src->registered_marks_cnt;
366 if (need > dst->registered_marks_capa) {
367 size_t nc = dst->registered_marks_capa ? dst->registered_marks_capa : 64;
368 while (nc < need) nc *= 2;
369 VALUE *p = realloc(dst->registered_marks, nc *
sizeof(
VALUE));
370 if (!p) rb_bug(
"rb_ractor_absorb_registered_marks: out of memory");
371 dst->registered_marks = p;
372 dst->registered_marks_capa = nc;
374 MEMCPY(dst->registered_marks + dst->registered_marks_cnt,
375 src->registered_marks,
VALUE, src->registered_marks_cnt);
376 dst->registered_marks_cnt = need;
377 src->registered_marks_cnt = 0;
381free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
384 rb_hook_list_free(hook_list);
389free_targeted_hooks(
st_table *hooks_tbl)
391 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
395ractor_free(
void *ptr)
398 RUBY_DEBUG_LOG(
"free r:%d", rb_ractor_id(r));
400 free_targeted_hooks(&r->pub.targeted_hooks);
402#ifdef RUBY_THREAD_WIN32_H
405 ractor_local_storage_free(r);
406 rb_hook_list_free(&r->pub.hooks);
407 rb_st_free_embedded_table(&r->pub.targeted_hooks);
409 if (r->newobj_cache) {
412 rb_gc_ractor_cache_free(r->newobj_cache);
413 r->newobj_cache = NULL;
420 if (r->objspace && !r->main_ractor) {
421 rb_gc_objspace_disown(r->objspace);
427 if (r->in_terminated_set) {
429 ccan_list_del(&r->vmlr_node);
430 r->in_terminated_set =
false;
437 if (!r->main_ractor) {
438 rb_ractor_absorb_registered_marks(GET_VM()->ractor.main_ractor, r);
440 free(r->registered_marks);
441 r->registered_marks = NULL;
442 r->registered_marks_cnt = r->registered_marks_capa = 0;
444 free(r->pin_capture);
445 r->pin_capture = NULL;
446 r->pin_capture_cnt = r->pin_capture_capa = 0;
448 if (!r->main_ractor) {
454ractor_memsize(
const void *ptr)
459 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
463ractor_update_references(
void *ptr)
475 ractor_update_references,
483 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
492RACTOR_PTR(
VALUE self)
494 VM_ASSERT(rb_ractor_p(self));
499#define MAIN_RACTOR_ID 1
502#include "ractor_sync.c"
519 RUBY_DEBUG_LOG(
"r:%u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
520 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
524 if (vm->ractor.cnt == 1) {
525 rb_gc_finish_in_flight_gc();
528 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
531 if (r->newobj_cache) {
532 VM_ASSERT(r == ruby_single_main_ractor);
535 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
540cancel_single_ractor_mode(
void)
543 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
545 ruby_single_main_ractor = NULL;
546 rb_yjit_invalidate_single_ractor();
547 rb_zjit_invalidate_single_ractor();
555 VM_ASSERT(ractor_status_p(r, ractor_created));
557 if (rb_multi_ractor_p()) {
560 vm_insert_ractor0(vm, r,
false);
561 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
566 if (cur && cur->creating_child_objspace == r->objspace) {
567 cur->creating_child_objspace = NULL;
573 if (vm->ractor.cnt == 0) {
575 vm_insert_ractor0(vm, r,
true);
576 ractor_status_set(r, ractor_blocking);
577 ractor_status_set(r, ractor_running);
580 cancel_single_ractor_mode();
581 vm_insert_ractor0(vm, r,
true);
582 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
587 if (cur && cur->creating_child_objspace == r->objspace) {
588 cur->creating_child_objspace = NULL;
597 VM_ASSERT(ractor_status_p(cr, ractor_running));
598 VM_ASSERT(vm->ractor.cnt > 1);
599 VM_ASSERT(cr->threads.cnt == 1);
603 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
604 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
606 VM_ASSERT(vm->ractor.cnt > 0);
607 ccan_list_del(&cr->vmlr_node);
612 if (!rb_gc_multi_objspace_p()) {
614 ccan_list_add(&vm->ractor.terminated_set, &cr->vmlr_node);
615 cr->in_terminated_set =
true;
619 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
623 rb_gc_ractor_cache_free(cr->newobj_cache);
624 cr->newobj_cache = NULL;
634 rb_gc_objspace_retire(&cr->objspace);
638 ractor_status_set(cr, ractor_terminated);
650 VM_ASSERT(cr != GET_VM()->ractor.main_ractor);
651 VM_ASSERT(th->ec != NULL);
654 const bool fiber_wrapped = fiber && rb_fiberptr_self(fiber) != 0;
659 cr->postmortem = rb_gc_multi_objspace_p() && !rb_thread_event_hooks_registered_p();
660 rb_gc_objspace_postmortem_self();
664 pf->th = (th->self == 0) ? th : NULL;
665 pf->fiber = (fiber_wrapped && rb_fiberptr_self(fiber) == 0) ? fiber : NULL;
671 if (pf->fiber == NULL && pf->th == NULL)
return;
676#ifdef RB_THREAD_LOCAL_SPECIFIER
677 rb_current_ec_set(NULL);
679 native_tls_set(ruby_current_ec_key, NULL);
683 if (pf->fiber) rb_fiber_free_body(pf->fiber);
684 if (pf->th) rb_thread_free_body(pf->th);
688ractor_alloc(
VALUE klass)
693 rb_gc_obj_became_shareable(rv);
695 r->next_ec_serial = 1;
696 VM_ASSERT(ractor_status_p(r, ractor_created));
703 .pub.id = MAIN_RACTOR_ID,
710rb_ractor_main_alloc(
void)
715 ruby_single_main_ractor = r;
720#if defined(HAVE_WORKING_FORK)
728 vm->ractor.blocking_cnt = 0;
735 rb_gc_disable_holders_atfork();
739 th->ractor->creating_child_objspace = NULL;
740 ruby_single_main_ractor = th->ractor;
741 th->ractor->status_ = ractor_created;
743 rb_ractor_living_threads_init(th->ractor);
744 rb_ractor_living_threads_insert(th->ractor, th);
746 VM_ASSERT(vm->ractor.blocking_cnt == 0);
747 VM_ASSERT(vm->ractor.cnt == 1);
753 rb_gc_ractor_cache_free(r->newobj_cache);
754 r->newobj_cache = NULL;
755 r->status_ = ractor_terminated;
759 rb_gc_objspace_retire(&r->objspace);
761 ractor_sync_terminate_atfork(vm, r);
770 ccan_list_head_init(&r->threads.set);
772 r->threads.blocking_cnt = 0;
779 r->gen_fields_capturing =
false;
780 r->pin_capture = NULL;
781 r->pin_capture_cnt = r->pin_capture_capa = 0;
782 r->sending_basket = NULL;
783 st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
784 r->pub.hooks.type = hook_list_type_ractor_local;
787 rb_thread_sched_init(&r->threads.sched,
false);
788 rb_ractor_living_threads_init(r);
794 enc = rb_enc_get(name);
795 if (!rb_enc_asciicompat(enc)) {
796 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
812 rb_gc_obj_became_shareable(r->pub.self);
814 r->threads.main = th;
815 rb_ractor_living_threads_insert(r, th);
816 rb_ractor_setup_default_port(r);
824 VALUE rv = ractor_alloc(self);
826 ractor_init(r, name, loc);
828 r->pub.id = ractor_next_id();
829 RUBY_DEBUG_LOG(
"r:%u", r->pub.id);
832 r->verbose = cr->verbose;
833 r->debug = cr->debug;
837 r->objspace = rb_gc_objspace_alloc();
839 rb_thread_create_ractor(r, args, block);
850 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
857 ractor_notify_exit(ec, cr, result, exc);
865 ractor_postmortem_collect(th, pf);
866 ractor_send_exit_tokens(th->ec, th->ractor);
873 ractor_atexit(ec, cr, result,
false);
880 ractor_atexit(ec, cr, ec->errinfo,
true);
890 VM_ASSERT(cr->threads.main != NULL);
891 cr->threads.main = NULL;
898 for (
int i=0; i<
len; i++) {
899 ptr[i] = ractor_receive(ec, ractor_default_port(r));
907 for (
int i=0; i<
len; i++) {
908 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
913rb_ractor_main_p_(
void)
915 VM_ASSERT(rb_multi_ractor_p());
917 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
923 return r->threads.cnt;
928rb_ractor_thread_list(
void)
934 ccan_list_for_each(&r->threads.set, th, lt_node) {
935 switch (th->status) {
936 case THREAD_RUNNABLE:
938 case THREAD_STOPPED_FOREVER:
951 VM_ASSERT(th != NULL);
955 RUBY_DEBUG_LOG(
"r(%d)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
956 ccan_list_add_tail(&r->threads.set, &th->lt_node);
962 if (r->threads.cnt == 1) {
963 VM_ASSERT(ractor_status_p(r, ractor_created));
964 vm_insert_ractor(th->vm, r);
971 ractor_status_set(r, ractor_blocking);
973 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
974 vm->ractor.blocking_cnt++;
975 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
979rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
982 VM_ASSERT(GET_RACTOR() == cr);
983 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
987rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
990 VM_ASSERT(GET_RACTOR() == cr);
992 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
993 VM_ASSERT(vm->ractor.blocking_cnt > 0);
994 vm->ractor.blocking_cnt--;
996 ractor_status_set(cr, ractor_running);
1000ractor_check_blocking(
rb_ractor_t *cr,
unsigned int remained_thread_cnt,
const char *file,
int line)
1002 VM_ASSERT(cr == GET_RACTOR());
1004 RUBY_DEBUG_LOG2(file, line,
1005 "cr->threads.cnt:%u cr->threads.blocking_cnt:%u vm->ractor.cnt:%u vm->ractor.blocking_cnt:%u",
1006 cr->threads.cnt, cr->threads.blocking_cnt,
1007 GET_VM()->ractor.cnt, GET_VM()->ractor.blocking_cnt);
1009 VM_ASSERT(cr->threads.cnt >= cr->threads.blocking_cnt + 1);
1011 if (remained_thread_cnt > 0 &&
1013 cr->threads.cnt == cr->threads.blocking_cnt + 1) {
1018 rb_vm_ractor_blocking_cnt_inc(vm, cr, file, line);
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);
1067 ractor_check_blocking(cr, cr->threads.cnt - 1, __FILE__, __LINE__);
1070 if (cr->threads.cnt == 1) {
1071 vm_remove_ractor(th->vm, cr);
1076 ccan_list_del(&th->lt_node);
1084rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
1086 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
1088 VM_ASSERT(cr->threads.cnt > 0);
1089 VM_ASSERT(cr == GET_RACTOR());
1091 ractor_check_blocking(cr, cr->threads.cnt, __FILE__, __LINE__);
1092 cr->threads.blocking_cnt++;
1096rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
1098 RUBY_DEBUG_LOG2(file, line,
1099 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
1100 cr->threads.blocking_cnt, cr->threads.cnt);
1102 VM_ASSERT(cr == GET_RACTOR());
1104 if (cr->threads.cnt == cr->threads.blocking_cnt) {
1108 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1112 cr->threads.blocking_cnt--;
1116rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
1118 VM_ASSERT(r != GET_RACTOR());
1119 ASSERT_ractor_unlocking(r);
1120 ASSERT_vm_locking();
1124 if (ractor_status_p(r, ractor_running)) {
1127 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
1135rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
1137 VM_ASSERT(r != GET_RACTOR());
1138 ASSERT_ractor_unlocking(r);
1139 ASSERT_vm_locking();
1143 if (main_th->status != THREAD_KILLED) {
1144 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
1145 rb_threadptr_interrupt(main_th);
1148 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
1156ractor_terminal_interrupt_all(
rb_vm_t *vm)
1158 if (vm->ractor.cnt > 1) {
1161 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1162 if (r != vm->ractor.main_ractor) {
1163 RUBY_DEBUG_LOG(
"r:%d", rb_ractor_id(r));
1164 rb_ractor_terminate_interrupt_main_thread(r);
1174rb_ractor_terminate_all(
void)
1179 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
1181 VM_ASSERT(cr == GET_RACTOR());
1185 ractor_terminal_interrupt_all(vm);
1188 rb_thread_terminate_all(GET_THREAD());
1192 while (vm->ractor.cnt > 1) {
1193 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
1194 vm->ractor.sync.terminate_waiting =
true;
1197 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
1198 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1199 rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 );
1200#ifdef RUBY_THREAD_PTHREAD_H
1201 while (vm->ractor.sched.barrier_waiting) {
1208 RB_VM_LOCK_ENTER_LEV_NB(&lev);
1211 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
1212 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
1214 ractor_terminal_interrupt_all(vm);
1221 rb_gc_objspace_absorb_all_zombies();
1225rb_vm_main_ractor_ec(
rb_vm_t *vm)
1242 if (running_ec) {
return running_ec; }
1243 return vm->ractor.main_thread->ec;
1247ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
1249 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1351 rb_eRactorIsolationError = rb_define_class_under(
rb_cRactor,
"IsolationError", rb_eRactorError);
1352 rb_eRactorRemoteError = rb_define_class_under(
rb_cRactor,
"RemoteError", rb_eRactorError);
1353 rb_eRactorMovedError = rb_define_class_under(
rb_cRactor,
"MovedError", rb_eRactorError);
1355 rb_eRactorUnsafeError = rb_define_class_under(
rb_cRactor,
"UnsafeError", rb_eRactorError);
1359 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1362 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1366 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1367 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1368 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1369 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1380 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1381 if (r != vm->ractor.main_ractor) {
1382 fprintf(stderr,
"r:%u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1390 if (rb_ractor_main_p()) {
1395 if (UNLIKELY(cr->r_stdin == 0)) {
1396 cr->r_stdin = rb_io_prep_stdin();
1403rb_ractor_stdout(
void)
1405 if (rb_ractor_main_p()) {
1410 if (UNLIKELY(cr->r_stdout == 0)) {
1411 cr->r_stdout = rb_io_prep_stdout();
1413 return cr->r_stdout;
1418rb_ractor_stderr(
void)
1420 if (rb_ractor_main_p()) {
1425 if (UNLIKELY(cr->r_stderr == 0)) {
1426 cr->r_stderr = rb_io_prep_stderr();
1428 return cr->r_stderr;
1435 if (rb_ractor_main_p()) {
1447 if (rb_ractor_main_p()) {
1459 if (rb_ractor_main_p()) {
1471 return &cr->pub.hooks;
1477 return &cr->pub.targeted_hooks;
1481rb_obj_set_shareable_no_assert(
VALUE obj)
1488 rb_gc_obj_became_shareable(obj);
1497 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1498 if (imemo_type_p(fields, imemo_fields)) {
1501 rb_gc_obj_became_shareable(fields);
1505 rb_imemo_fields_record_shrefs(fields);
1510#ifndef STRICT_VERIFY_SHAREABLE
1511#define STRICT_VERIFY_SHAREABLE 0
1515rb_ractor_verify_shareable(
VALUE obj)
1517#if STRICT_VERIFY_SHAREABLE
1518 rb_gc_verify_shareable(obj);
1524rb_obj_set_shareable(
VALUE obj)
1528 rb_obj_set_shareable_no_assert(obj);
1540enum obj_traverse_iterator_result {
1546typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1547typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1548typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1550static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1553 rb_obj_traverse_enter_func enter_func;
1554 rb_obj_traverse_leave_func leave_func;
1573 if (obj_traverse_i(key, d->data)) {
1578 if (obj_traverse_i(val, d->data)) {
1587obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1591 if (obj_traverse_i(obj, d->data)) {
1604 RB_VM_LOCKING_NO_BARRIER() {
1605 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1613 if (UNLIKELY(!data->rec)) {
1614 data->rec_hash = rb_ident_hash_new();
1616 data->rec = RHASH_ST_TABLE(data->rec_hash);
1622obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1626 if (obj_traverse_i(val, d->data)) {
1639 switch (data->enter_func(obj)) {
1640 case traverse_cont:
break;
1641 case traverse_skip:
return 0;
1642 case traverse_stop:
return 1;
1645 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1651 if (rb_obj_shape_has_ivars(obj)) {
1657 if (d.stop)
return 1;
1675 rb_ary_cancel_sharing(obj);
1679 if (obj_traverse_i(e, data))
return 1;
1693 if (d.stop)
return 1;
1699 long len = RSTRUCT_LEN_RAW(obj);
1700 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1702 for (
long i=0; i<
len; i++) {
1703 if (obj_traverse_i(ptr[i], data))
return 1;
1709 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1713 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1714 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1717 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1718 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1723 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
1726 if (!ptr || !
type->function.dmark) {
1729 else if (
type->flags & RUBY_TYPED_DECL_MARKING) {
1730 const size_t *offsets = (
const size_t *)(uintptr_t)
type->function.dmark;
1731 for (; *offsets != RUBY_REF_END; offsets++) {
1732 VALUE ref = *(
VALUE *)((
char *)ptr + *offsets);
1733 if (obj_traverse_i(ref, data))
return 1;
1737 if (obj_traverse_reachable(obj, data))
return 1;
1744 if (obj_traverse_reachable(obj, data))
return 1;
1753 rb_bug(
"unreachable");
1756 if (data->leave_func(obj) == traverse_stop) {
1765 rb_obj_traverse_final_func final_func;
1770obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1773 if (data->final_func(key)) {
1783rb_obj_traverse(
VALUE obj,
1784 rb_obj_traverse_enter_func enter_func,
1785 rb_obj_traverse_leave_func leave_func,
1786 rb_obj_traverse_final_func final_func)
1789 .enter_func = enter_func,
1790 .leave_func = leave_func,
1794 if (obj_traverse_i(obj, &data))
return 1;
1795 if (final_func && data.rec) {
1797 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1804allow_frozen_shareable_p(
VALUE obj)
1814 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1823make_shareable_freeze(
VALUE obj)
1826 if (klass ==
rb_cString && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
1829 else if (klass ==
rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, ARRAY_REDEFINED_OP_FLAG)) {
1832 else if (klass ==
rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_FREEZE, HASH_REDEFINED_OP_FLAG)) {
1833 rb_hash_freeze(obj);
1840static enum obj_traverse_iterator_result
1841make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1844 make_shareable_freeze(obj);
1847 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1851 return traverse_skip;
1858static int obj_refer_only_shareables_p(
VALUE obj);
1860static enum obj_traverse_iterator_result
1861make_shareable_check_shareable(
VALUE obj)
1866 return traverse_skip;
1868 else if (!allow_frozen_shareable_p(obj)) {
1870 rb_raise(rb_eRactorError,
1871 "can not make shareable object for %+"PRIsVALUE, obj);
1873 else if (
RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1874 if (obj_refer_only_shareables_p(obj)) {
1875 make_shareable_check_shareable_freeze(obj, traverse_skip);
1876 RB_OBJ_SET_SHAREABLE(obj);
1877 return traverse_skip;
1880 rb_raise(rb_eRactorError,
1881 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1885 rb_proc_ractor_make_shareable(obj,
Qundef);
1886 return traverse_cont;
1889 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1893 switch (
TYPE(obj)) {
1895 return traverse_skip;
1902 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1903 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1904 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1905 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1914 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1917static enum obj_traverse_iterator_result
1918mark_shareable(
VALUE obj)
1921 rb_str_make_independent(obj);
1924 rb_obj_set_shareable_no_assert(obj);
1925 return traverse_cont;
1931 rb_obj_traverse(obj,
1932 make_shareable_check_shareable,
1933 null_leave, mark_shareable);
1942 VALUE copy = ractor_copy(obj);
1947rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1950 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
1958rb_ractor_ensure_main_ractor(
const char *msg)
1960 if (!rb_ractor_main_p()) {
1961 rb_raise(rb_eRactorIsolationError,
"%s", msg);
1965static enum obj_traverse_iterator_result
1966shareable_p_enter(
VALUE obj)
1969 return traverse_skip;
1975 mark_shareable(obj);
1976 return traverse_skip;
1979 allow_frozen_shareable_p(obj)) {
1980 return traverse_cont;
1988 if (obj_refer_only_shareables_p(obj)) {
1989 mark_shareable(obj);
1990 return traverse_skip;
1994 return traverse_stop;
1998rb_ractor_shareable_p_continue(
VALUE obj)
2000 if (rb_obj_traverse(obj,
2001 shareable_p_enter, null_leave,
2010static enum obj_traverse_iterator_result
2011null_leave(
VALUE obj)
2013 return traverse_cont;
2029 rb_obj_traverse_replace_enter_func enter_func;
2030 rb_obj_traverse_replace_leave_func leave_func;
2036 VALUE rec_keepalive;
2049obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
2055obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
2060 if (obj_traverse_replace_i(*key, data)) {
2064 else if (*key != data->replacement) {
2065 VALUE v = *key = data->replacement;
2069 if (obj_traverse_replace_i(*val, data)) {
2073 else if (*val != data->replacement) {
2074 VALUE v = *val = data->replacement;
2082obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
2088obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
2093 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
2097 else if (*(
VALUE *)val != data->replacement) {
2108 if (UNLIKELY(!data->rec)) {
2109 data->rec = st_init_numtable();
2116obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
2118 int *pcnt = (
int *)ptr;
2126obj_refer_only_shareables_p(
VALUE obj)
2129 RB_VM_LOCKING_NO_BARRIER() {
2130 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
2138 st_data_t replacement;
2141 data->replacement = obj;
2148 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
2149 data->replacement = (
VALUE)replacement;
2153 switch (data->enter_func(obj, data)) {
2154 case traverse_cont:
break;
2155 case traverse_skip:
return 0;
2156 case traverse_stop:
return 1;
2159 replacement = (st_data_t)data->replacement;
2160 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
2169#define CHECK_AND_REPLACE(parent_obj, v) do { \
2171 if (obj_traverse_replace_i(_val, data)) { return 1; } \
2172 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
2175 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2176 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2178 if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
2184 rb_st_foreach_with_replace(
2185 rb_imemo_fields_complex_tbl(fields_obj),
2186 obj_iv_hash_traverse_replace_foreach_i,
2187 obj_iv_hash_traverse_replace_i,
2190 if (d.stop)
return 1;
2193 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
2194 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
2195 for (uint32_t i = 0; i < fields_count; i++) {
2196 CHECK_AND_REPLACE(fields_obj, fields[i]);
2210 rb_str_make_independent(obj);
2215 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
2216 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2217 if (rb_shape_complex_p(shape_id)) {
2223 rb_st_foreach_with_replace(
2224 rb_imemo_fields_complex_tbl(fields_obj),
2225 obj_iv_hash_traverse_replace_foreach_i,
2226 obj_iv_hash_traverse_replace_i,
2229 if (d.stop)
return 1;
2232 attr_index_t
len = RSHAPE_LEN(shape_id);
2233 VALUE *ptr = rb_imemo_fields_ptr(fields_obj);
2235 for (attr_index_t i = 0; i <
len; i++) {
2236 CHECK_AND_REPLACE(obj, ptr[i]);
2244 rb_ary_cancel_sharing(obj);
2249 if (obj_traverse_replace_i(e, data)) {
2252 else if (e != data->replacement) {
2266 rb_hash_stlike_foreach_with_replace(obj,
2267 obj_hash_traverse_replace_foreach_i,
2268 obj_hash_traverse_replace_i,
2270 if (d.stop)
return 1;
2274 if (obj_traverse_replace_i(ifnone, data)) {
2277 else if (ifnone != data->replacement) {
2285 long len = RSTRUCT_LEN_RAW(obj);
2286 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
2288 for (
long i=0; i<
len; i++) {
2289 CHECK_AND_REPLACE(obj, ptr[i]);
2295 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
2299 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
2300 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
2303 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
2304 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
2308 if (!data->move && obj_refer_only_shareables_p(obj)) {
2312 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
2326 rb_bug(
"unreachable");
2329 data->replacement = (
VALUE)replacement;
2331 if (data->leave_func(obj, data) == traverse_stop) {
2342rb_obj_traverse_replace(
VALUE obj,
2343 rb_obj_traverse_replace_enter_func enter_func,
2344 rb_obj_traverse_replace_leave_func leave_func,
2348 .enter_func = enter_func,
2349 .leave_func = leave_func,
2356 int stopped = obj_traverse_replace_i(obj, &data);
2360 if (data.rec) st_free_table(data.rec);
2367 return data.replacement;
2376enum move_node_kind {
2388 enum move_node_kind kind;
2397 struct {
char *ptr;
long len;
int encidx;
VALUE klass; } str;
2398 struct {
long len; uint32_t *elems;
VALUE klass; } ary;
2399 struct {
long size; uint32_t *kv; uint32_t ifnone_id;
bool compare_by_id;
bool proc_default;
VALUE klass; } hash;
2400 struct {
VALUE klass; } obj;
2401 struct {
long len; uint32_t *elems;
VALUE klass; } strct;
2402 struct { uint32_t regexp_id, str_id;
int num_regs;
void *regs;
VALUE klass; } match;
2409 uint32_t pathv_id, ecopts_id, wc_pre_ecopts_id, wc_asciicompat_id, timeout_id;
2419 struct ccan_list_node reg_node;
2435 ccan_list_add(&GET_VM()->ractor.move_courier_registry, &c->reg_node);
2443 ccan_list_del(&c->reg_node);
2451rb_ractor_move_courier_registry_mark(
void)
2454 ccan_list_for_each(&GET_VM()->ractor.move_courier_registry, c, reg_node) {
2455 rb_ractor_move_courier_mark(c);
2469 if (c->count == c->capa) {
2470 c->capa = c->capa ? c->capa * 2 : 8;
2473 uint32_t
id = c->count++;
2476 c->nodes[id].kind = MOVE_KIND_REF;
2477 c->nodes[id].frozen =
false;
2478 c->nodes[id].niv = 0;
2479 c->nodes[id].iv_ids = NULL;
2480 c->nodes[id].iv_vals = NULL;
2481 c->nodes[id].u.ref =
Qnil;
2488move_neutralize_source(
VALUE obj)
2493 shape_id_t shape_id = (RBASIC_SHAPE_ID(obj) & SHAPE_ID_CAPACITY_MASK) |
2494 ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_ROBJECT | SHAPE_ID_FL_FROZEN;
2504 bool wipe_body =
true;
2507 wipe_body = !rb_str_embedded_shared_root_p(obj);
2510 wipe_body = !rb_ary_embedded_shared_root_p(obj);
2518 size_t slot_size = rb_gc_obj_slot_size(obj);
2519 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2520 RBASIC(obj)->flags = flags;
2521 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
2539move_capture_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2542 uint32_t kid = move_capture(hc->b, (
VALUE)key);
2543 uint32_t vid = move_capture(hc->b, (
VALUE)val);
2544 hc->kv[hc->i++] = kid;
2545 hc->kv[hc->i++] = vid;
2558move_capture_ivar_i(
ID name,
VALUE val, st_data_t arg)
2561 if (oc->n == oc->capa) {
2562 oc->capa = oc->capa ? oc->capa * 2 : 4;
2564 REALLOC_N(oc->vals, uint32_t, oc->capa);
2566 uint32_t vid = move_capture(oc->b, val);
2567 oc->ids[oc->n] = name;
2568 oc->vals[oc->n] = vid;
2580 rb_ivar_foreach_buffered(obj, move_capture_ivar_i, (st_data_t)&oc);
2581 b->c->nodes[id].niv = (uint32_t)oc.n;
2582 b->c->nodes[id].iv_ids = oc.ids;
2583 b->c->nodes[id].iv_vals = oc.vals;
2594 if (st_lookup(b->seen, (st_data_t)obj, &existing)) {
2595 return (uint32_t)existing - 1;
2598 uint32_t
id = move_alloc_node(b->c);
2599 st_insert(b->seen, (st_data_t)obj, (st_data_t)(uintptr_t)(
id + 1));
2602 b->c->nodes[id].kind = MOVE_KIND_REF;
2603 b->c->nodes[id].frozen =
false;
2604 b->c->nodes[id].niv = 0;
2605 b->c->nodes[id].iv_ids = NULL;
2606 b->c->nodes[id].iv_vals = NULL;
2607 b->c->nodes[id].u.ref = obj;
2613 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2617 b->c->nodes[id].frozen = frozen;
2618 move_capture_ivars(b, obj,
id);
2625 rb_str_make_independent(obj);
2626 long len = RSTRING_LEN(obj);
2629 if (!STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
2632 ptr =
RSTRING(obj)->as.heap.ptr;
2639 if (
len) memcpy(ptr, RSTRING_PTR(obj),
len);
2642 b->c->nodes[id].kind = MOVE_KIND_STRING;
2644 b->c->nodes[id].u.str.ptr = ptr;
2645 b->c->nodes[id].u.str.len =
len;
2646 b->c->nodes[id].u.str.encidx = encidx;
2653 for (
long i = 0; i <
len; i++) {
2656 b->c->nodes[id].kind = MOVE_KIND_ARRAY;
2658 b->c->nodes[id].u.ary.len =
len;
2659 b->c->nodes[id].u.ary.elems = elems;
2663 if (!ARY_EMBED_P(obj) && !ARY_SHARED_P(obj) && !ARY_SHARED_ROOT_P(obj) && !
OBJ_FROZEN(obj)) {
2670 uint32_t ifnone_id = move_capture(b,
RHASH_IFNONE(obj));
2672 uint32_t *kv = size ?
ALLOC_N(uint32_t, size * 2) : NULL;
2674 rb_hash_stlike_foreach(obj, move_capture_hash_i, (st_data_t)&hc);
2675 b->c->nodes[id].kind = MOVE_KIND_HASH;
2677 b->c->nodes[id].u.hash.size = size;
2678 b->c->nodes[id].u.hash.kv = kv;
2679 b->c->nodes[id].u.hash.ifnone_id = ifnone_id;
2680 b->c->nodes[id].u.hash.compare_by_id =
RTEST(rb_hash_compare_by_id_p(obj));
2681 b->c->nodes[id].u.hash.proc_default =
FL_TEST_RAW(obj, RHASH_PROC_DEFAULT) != 0;
2688 b->c->nodes[id].kind = MOVE_KIND_OBJECT;
2698 for (
long i = 0; i <
len; i++) {
2699 elems[i] = move_capture(b,
RSTRUCT_GET(obj, (
int)i));
2701 b->c->nodes[id].kind = MOVE_KIND_STRUCT;
2702 b->c->nodes[id].u.strct.len =
len;
2703 b->c->nodes[id].u.strct.elems = elems;
2706 if (RSTRUCT_EMBED_LEN(obj) == 0) {
2707 ruby_xfree((
void *)RSTRUCT_CONST_PTR(obj));
2717 void *regs = rb_match_move_dump(obj, &re, &st, &nregs);
2718 uint32_t rid = move_capture(b, re);
2719 uint32_t sid = move_capture(b, st);
2720 b->c->nodes[id].kind = MOVE_KIND_MATCH;
2721 b->c->nodes[id].u.match.regexp_id = rid;
2722 b->c->nodes[id].u.match.str_id = sid;
2723 b->c->nodes[id].u.match.num_regs = nregs;
2724 b->c->nodes[id].u.match.regs = regs;
2736 uint32_t pathv_id = move_capture(b, fptr->
pathv);
2737 uint32_t ecopts_id = move_capture(b, fptr->
encs.
ecopts);
2740 uint32_t timeout_id = move_capture(b, fptr->
timeout);
2748 fptr->wakeup_mutex =
Qnil;
2750 b->c->nodes[id].kind = MOVE_KIND_IO;
2751 b->c->nodes[id].u.io.fptr = fptr;
2753 b->c->nodes[id].u.io.pathv_id = pathv_id;
2754 b->c->nodes[id].u.io.ecopts_id = ecopts_id;
2755 b->c->nodes[id].u.io.wc_pre_ecopts_id = wc_pre_id;
2756 b->c->nodes[id].u.io.wc_asciicompat_id = wc_ac_id;
2757 b->c->nodes[id].u.io.timeout_id = timeout_id;
2762 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2766 move_neutralize_source(obj);
2773move_preflight_ivar_i(
ID name,
VALUE val, st_data_t arg)
2775 move_preflight(val, (
st_table *)arg);
2780move_preflight_hash_i(st_data_t key, st_data_t val, st_data_t arg)
2794 if (st_lookup(seen, (st_data_t)obj, NULL))
return;
2795 st_insert(seen, (st_data_t)obj, 0);
2803 move_preflight(rm->
regexp, seen);
2804 move_preflight(rm->
str, seen);
2813 rb_hash_stlike_foreach(obj, move_preflight_hash_i, (st_data_t)seen);
2824 rb_raise(rb_eRactorError,
"can not move an uninitialized IO");
2829 rb_raise(rb_eRactorError,
"can not move an IO tied to a writer IO");
2831 if (
RTEST(fptr->wakeup_mutex)) {
2833 rb_raise(rb_eRactorError,
"can not move an IO that is being closed");
2835 move_preflight(fptr->
pathv, seen);
2839 move_preflight(fptr->
timeout, seen);
2843 rb_raise(rb_eRactorError,
"can not move a %"PRIsVALUE
" object",
2853rb_ractor_move_courier_build(
VALUE obj)
2858 st_table *pf_seen = st_init_numtable();
2859 enum ruby_tag_type state;
2862 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
2863 move_preflight(obj, pf_seen);
2866 st_free_table(pf_seen);
2867 if (state != TAG_NONE) EC_JUMP_TAG(ec, state);
2871 struct move_build b = { c, st_init_numtable() };
2877 move_courier_registry_add(c);
2879 enum ruby_tag_type state;
2882 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
2883 c->root = move_capture(&b, obj);
2886 st_free_table(b.seen);
2887 if (state != TAG_NONE) {
2891 rb_ractor_move_courier_free(c);
2892 EC_JUMP_TAG(ec, state);
2901move_apply_moved_klass(
VALUE shell,
VALUE klass)
2904 RBASIC_SET_CLASS(shell, klass);
2920 for (uint32_t i = 0; i < c->count; i++) {
2927 case MOVE_KIND_STRING:
2928 shell = rb_enc_str_new(n->u.str.ptr, n->u.str.len, rb_enc_from_index(n->u.str.encidx));
2929 move_apply_moved_klass(shell, n->u.str.klass);
2931 case MOVE_KIND_ARRAY:
2933 move_apply_moved_klass(shell, n->u.ary.klass);
2935 case MOVE_KIND_HASH:
2936 shell = n->u.hash.compare_by_id ? rb_ident_hash_new() : rb_hash_new();
2937 move_apply_moved_klass(shell, n->u.hash.klass);
2939 case MOVE_KIND_OBJECT:
2943 move_apply_moved_klass(shell, n->u.obj.klass);
2945 case MOVE_KIND_STRUCT:
2947 move_apply_moved_klass(shell, n->u.strct.klass);
2949 case MOVE_KIND_MATCH:
2950 shell = rb_match_move_alloc(
rb_class_real(n->u.match.klass), n->u.match.num_regs);
2951 move_apply_moved_klass(shell, n->u.match.klass);
2955 move_apply_moved_klass(shell, n->u.io.klass);
2956 RFILE(shell)->fptr = n->u.io.fptr;
2957 n->u.io.fptr->
self = shell;
2958 n->u.io.fptr = NULL;
2961 rb_bug(
"rb_ractor_move_courier_materialize: bad node kind");
2966 for (uint32_t i = 0; i < c->count; i++) {
2970 case MOVE_KIND_ARRAY:
2971 for (
long j = 0; j < n->u.ary.len; j++) {
2975 case MOVE_KIND_HASH:
2980 case MOVE_KIND_STRUCT:
2981 for (
long j = 0; j < n->u.strct.len; j++) {
2985 case MOVE_KIND_MATCH:
2986 rb_match_move_load(shell,
RARRAY_AREF(shells, n->u.match.regexp_id),
2988 n->u.match.num_regs, n->u.match.regs);
2990 case MOVE_KIND_IO: {
3005 for (uint32_t j = 0; j < n->niv; j++) {
3013 for (uint32_t i = c->count; i > 0; i--) {
3015 if (n->kind != MOVE_KIND_HASH)
continue;
3017 for (
long j = 0; j < n->u.hash.size; j++) {
3018 rb_hash_aset(shell,
RARRAY_AREF(shells, n->u.hash.kv[2 * j]),
3023 if (n->u.hash.proc_default) {
3024 rb_hash_set_default_proc(shell, ifnone);
3026 else if (ifnone !=
Qnil) {
3027 rb_hash_set_default(shell, ifnone);
3032 for (uint32_t i = 0; i < c->count; i++) {
3047 for (uint32_t i = 0; i < c->count; i++) {
3049 ruby_xfree(n->iv_ids);
3050 ruby_xfree(n->iv_vals);
3052 case MOVE_KIND_STRING:
3053 ruby_xfree(n->u.str.ptr);
3055 case MOVE_KIND_ARRAY:
3056 ruby_xfree(n->u.ary.elems);
3058 case MOVE_KIND_HASH:
3059 ruby_xfree(n->u.hash.kv);
3061 case MOVE_KIND_STRUCT:
3062 ruby_xfree(n->u.strct.elems);
3064 case MOVE_KIND_MATCH:
3065 rb_match_move_free(n->u.match.regs);
3073 n->u.io.fptr = NULL;
3080 move_courier_registry_remove(c);
3081 ruby_xfree(c->nodes);
3092 for (uint32_t i = 0; i < c->count; i++) {
3094 if (n->kind == MOVE_KIND_REF) {
3095 rb_gc_mark(n->u.ref);
3097 else if (n->kind == MOVE_KIND_OBJECT) {
3098 rb_gc_mark(n->u.obj.klass);
3100 else if (n->kind == MOVE_KIND_STRUCT) {
3101 rb_gc_mark(n->u.strct.klass);
3103 else if (n->kind == MOVE_KIND_MATCH) {
3104 rb_gc_mark(n->u.match.klass);
3106 else if (n->kind == MOVE_KIND_IO) {
3107 rb_gc_mark(n->u.io.klass);
3109 else if (n->kind == MOVE_KIND_STRING) {
3110 rb_gc_mark(n->u.str.klass);
3112 else if (n->kind == MOVE_KIND_ARRAY) {
3113 rb_gc_mark(n->u.ary.klass);
3115 else if (n->kind == MOVE_KIND_HASH) {
3116 rb_gc_mark(n->u.hash.klass);
3125ractor_native_shallow_copy(
VALUE obj)
3139 rb_obj_copy_ivar(copy, obj);
3142 copy = rb_enc_str_new(RSTRING_PTR(obj), RSTRING_LEN(obj), rb_enc_get(obj));
3148 copy = rb_hash_dup(obj);
3152 rb_struct_init_copy(copy, obj);
3156 rb_match_init_copy(copy, obj);
3161 if (rb_backtrace_p(obj)) {
3162 copy = rb_backtrace_dup(obj);
3174 UNLIKELY(rb_obj_gen_fields_p(obj))) {
3190 if (cr->pin_capture_cnt == cr->pin_capture_capa) {
3191 size_t nc = cr->pin_capture_capa ? cr->pin_capture_capa * 2 : 16;
3192 VALUE *p = realloc(cr->pin_capture, nc *
sizeof(
VALUE));
3193 if (!p) rb_bug(
"ractor_pin_capture_push: out of memory");
3194 cr->pin_capture = p;
3195 cr->pin_capture_capa = nc;
3197 cr->pin_capture[cr->pin_capture_cnt++] = v;
3198 rb_gc_pin_in_flight_message(v);
3201static enum obj_traverse_iterator_result
3205 data->replacement = obj;
3206 return traverse_skip;
3209 VALUE copy = ractor_native_shallow_copy(obj);
3210 if (UNDEF_P(copy))
return traverse_stop;
3211 data->replacement = copy;
3217 if (cr->gen_fields_capturing) {
3221 ractor_pin_capture_push(cr, copy);
3223 return traverse_cont;
3227static enum obj_traverse_iterator_result
3230 return traverse_cont;
3236ractor_copy_native_try(
VALUE obj)
3238 return rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
3244ractor_copy(
VALUE obj)
3246 VALUE copy = ractor_copy_native_try(obj);
3247 if (UNDEF_P(copy)) {
3249 ractor_marshal_dump_rescue, obj,
3266} freed_ractor_local_keys;
3270ractor_local_keys_purge(
st_table *local_storage)
3272 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3274 st_data_t val, k = (st_data_t)key;
3275 if (st_delete(local_storage, &k, &val) &&
3277 (*key->type->free)((
void *)val);
3284ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
3287 if (k->type->
mark) (*k->type->
mark)((
void *)val);
3291static enum rb_id_table_iterator_result
3292idkey_local_storage_mark_i(
VALUE val,
void *dmy)
3295 return ID_TABLE_CONTINUE;
3301 if (r->local_storage) {
3302 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
3307 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
3308 ractor_local_keys_purge(r->local_storage);
3312 if (r->idkey_local_storage) {
3313 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
3316 rb_gc_mark(r->local_storage_store_lock);
3320ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
3323 if (k->type->
free) (*k->type->
free)((
void *)val);
3330 if (r->local_storage) {
3331 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
3332 st_free_table(r->local_storage);
3335 if (r->idkey_local_storage) {
3336 rb_id_table_free(r->idkey_local_storage);
3341rb_ractor_local_storage_value_mark(
void *ptr)
3343 rb_gc_mark((
VALUE)ptr);
3357 rb_ractor_local_storage_value_mark,
3365 key->type =
type ?
type : &ractor_local_storage_type_null;
3366 key->main_cache = (
void *)
Qundef;
3380 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
3381 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
3382 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
3384 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
3391 if (rb_ractor_main_p()) {
3392 if (!UNDEF_P((
VALUE)key->main_cache)) {
3393 *pret = key->main_cache;
3403 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
3417 if (cr->local_storage == NULL) {
3418 cr->local_storage = st_init_numtable();
3421 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
3423 if (rb_ractor_main_p()) {
3424 key->main_cache = ptr;
3432 if (ractor_local_ref(key, &val)) {
3443 if (ractor_local_ref(key, (
void **)val)) {
3454 ractor_local_set(key, (
void *)val);
3461 if (ractor_local_ref(key, &ret)) {
3472 ractor_local_set(key, ptr);
3475#define DEFAULT_KEYS_CAPA 0x10
3478rb_ractor_finish_marking(
void)
3483 if (!(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p())) {
3491 for (
size_t zi = 0; zi < vm->gc.zombie_objspaces_count; zi++) {
3492 rb_ractor_t *owner = vm->gc.zombie_objspaces[zi].owner;
3493 if (owner == NULL || owner->local_storage == NULL)
continue;
3494 ractor_local_keys_purge(owner->local_storage);
3497 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
3498 SIZED_FREE(freed_ractor_local_keys.keys[i]);
3500 freed_ractor_local_keys.cnt = 0;
3501 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
3502 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
3503 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
3512 struct rb_id_table *tbl = cr->idkey_local_storage;
3515 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
3528 struct rb_id_table *tbl = cr->idkey_local_storage;
3531 tbl = cr->idkey_local_storage = rb_id_table_create(2);
3533 rb_id_table_insert(tbl,
id, val);
3545ractor_local_value_store_i(
VALUE ptr)
3550 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
3555 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
3568 .tbl = cr->idkey_local_storage,
3572 if (data.tbl == NULL) {
3573 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
3575 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
3580 if (!cr->local_storage_store_lock) {
3593 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
3597 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
3621RUBY_REFERENCES(cross_ractor_require_refs) = {
3628 "ractor/cross_ractor_require",
3630 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
3635 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
3639require_body(
VALUE crr_obj)
3643 VALUE feature = crr->as.require.feature;
3649 int rb_require_internal_silent(
VALUE fname);
3650 return INT2NUM(rb_require_internal_silent(feature));
3667require_result_send_body(
VALUE ary)
3674 ractor_port_send(ec, port, results,
Qfalse);
3679require_result_send_resuce(
VALUE port,
VALUE errinfo)
3682 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
3692 const bool silent = crr->silent;
3694 VALUE debug, errinfo;
3697 errinfo = rb_errinfo();
3705 rb_set_errinfo(errinfo);
3710 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
3718ractor_require_func(
void *crr_obj)
3720 return ractor_require_protect((
VALUE)crr_obj, require_body);
3724rb_ractor_require(
VALUE feature,
bool silent)
3727 ASSERT_vm_unlocking();
3731 RB_OBJ_SET_SHAREABLE(crr_obj);
3736 crr->raised =
false;
3737 crr->silent = silent;
3740 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
3741 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
3744 VALUE results = ractor_port_receive(ec, crr->port);
3745 ractor_port_close(ec, crr->port);
3762 return rb_ractor_require(feature,
false);
3766autoload_load_body(
VALUE crr_obj)
3774ractor_autoload_load_func(
void *crr_obj)
3776 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
3780rb_ractor_autoload_load(
VALUE module,
ID name)
3784 RB_OBJ_SET_SHAREABLE(crr_obj);
3786 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
3791 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
3792 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
3795 VALUE results = ractor_port_receive(ec, crr->port);
3796 ractor_port_close(ec, crr->port);
3810#include "ractor.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
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_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_initialize(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_initialize.
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_destroy(rb_nativethread_cond_t *cond)
Destroys the passed condition variable.
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.