10#include "ractor_core.h"
11#include "internal/complex.h"
12#include "internal/error.h"
13#include "internal/gc.h"
14#include "internal/hash.h"
15#include "internal/object.h"
16#include "internal/ractor.h"
17#include "internal/rational.h"
18#include "internal/struct.h"
19#include "internal/thread.h"
25static VALUE rb_cRactorSelector;
27VALUE rb_eRactorUnsafeError;
28VALUE rb_eRactorIsolationError;
29static VALUE rb_eRactorError;
30static VALUE rb_eRactorRemoteError;
31static VALUE rb_eRactorMovedError;
32static VALUE rb_eRactorClosedError;
33static VALUE rb_cRactorMovedObject;
35static void vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *r,
const char *file,
int line);
38#if RACTOR_CHECK_MODE > 0
39bool rb_ractor_ignore_belonging_flag =
false;
47#if RACTOR_CHECK_MODE > 0
49 if (ec != NULL && r->sync.locked_by == rb_ractor_self(rb_ec_ractor_ptr(ec))) {
50 rb_bug(
"recursive ractor locking");
58#if RACTOR_CHECK_MODE > 0
60 if (ec != NULL && r->sync.locked_by != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
61 rp(r->sync.locked_by);
62 rb_bug(
"ractor lock is not acquired.");
68ractor_lock(
rb_ractor_t *r,
const char *file,
int line)
70 RUBY_DEBUG_LOG2(file, line,
"locking r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
72 ASSERT_ractor_unlocking(r);
78 VM_ASSERT(!cr->malloc_gc_disabled);
79 cr->malloc_gc_disabled =
true;
82#if RACTOR_CHECK_MODE > 0
85 r->sync.locked_by = rb_ractor_self(cr);
89 RUBY_DEBUG_LOG2(file, line,
"locked r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
93ractor_lock_self(
rb_ractor_t *cr,
const char *file,
int line)
95 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
96#if RACTOR_CHECK_MODE > 0
97 VM_ASSERT(cr->sync.locked_by != cr->pub.self);
99 ractor_lock(cr, file, line);
103ractor_unlock(
rb_ractor_t *r,
const char *file,
int line)
105 ASSERT_ractor_locking(r);
106#if RACTOR_CHECK_MODE > 0
107 r->sync.locked_by =
Qnil;
113 VM_ASSERT(cr->malloc_gc_disabled);
114 cr->malloc_gc_disabled =
false;
119 RUBY_DEBUG_LOG2(file, line,
"r:%u%s", r->pub.id, rb_current_ractor_raw(
false) == r ?
" (self)" :
"");
123ractor_unlock_self(
rb_ractor_t *cr,
const char *file,
int line)
125 VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
126#if RACTOR_CHECK_MODE > 0
127 VM_ASSERT(cr->sync.locked_by == cr->pub.self);
129 ractor_unlock(cr, file, line);
132#define RACTOR_LOCK(r) ractor_lock(r, __FILE__, __LINE__)
133#define RACTOR_UNLOCK(r) ractor_unlock(r, __FILE__, __LINE__)
134#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
135#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
146 RACTOR_UNLOCK_SELF(r);
152ractor_status_str(
enum ractor_status status)
155 case ractor_created:
return "created";
156 case ractor_running:
return "running";
157 case ractor_blocking:
return "blocking";
158 case ractor_terminated:
return "terminated";
160 rb_bug(
"unreachable");
164ractor_status_set(
rb_ractor_t *r,
enum ractor_status status)
166 RUBY_DEBUG_LOG(
"r:%u [%s]->[%s]", r->pub.id, ractor_status_str(r->status_), ractor_status_str(status));
169 if (r->status_ != ractor_created) {
170 VM_ASSERT(r == GET_RACTOR());
175 switch (r->status_) {
177 VM_ASSERT(status == ractor_blocking);
180 VM_ASSERT(status == ractor_blocking||
181 status == ractor_terminated);
183 case ractor_blocking:
184 VM_ASSERT(status == ractor_running);
186 case ractor_terminated:
187 rb_bug(
"unreachable");
195ractor_status_p(
rb_ractor_t *r,
enum ractor_status status)
197 return rb_ractor_status_p(r, status);
202static void ractor_local_storage_mark(
rb_ractor_t *r);
203static void ractor_local_storage_free(
rb_ractor_t *r);
207static size_t ractor_sync_memsize(
const rb_ractor_t *r);
211mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
215 if (hook_list->type == hook_list_type_targeted_iseq) {
216 rb_gc_mark((
VALUE)key);
220 RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
221 rb_gc_mark(def->body.bmethod.proc);
223 rb_hook_list_mark(hook_list);
229ractor_mark(
void *ptr)
232 bool checking_shareable = rb_gc_checking_shareable();
237 if (!checking_shareable) {
239 rb_gc_mark(r->r_stdin);
240 rb_gc_mark(r->r_stdout);
241 rb_gc_mark(r->r_stderr);
242 rb_gc_mark(r->verbose);
243 rb_gc_mark(r->debug);
248 rb_hook_list_mark(&r->pub.hooks);
249 if (r->pub.targeted_hooks) {
250 st_foreach(r->pub.targeted_hooks, mark_targeted_hook_list, 0);
253 if (r->threads.cnt > 0) {
255 ccan_list_for_each(&r->threads.set, th, lt_node) {
256 VM_ASSERT(th != NULL);
257 rb_gc_mark(th->self);
261 ractor_local_storage_mark(r);
266free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
269 rb_hook_list_free(hook_list);
274free_targeted_hooks(
st_table *hooks_tbl)
276 st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
280ractor_free(
void *ptr)
283 RUBY_DEBUG_LOG(
"free r:%d", rb_ractor_id(r));
284 free_targeted_hooks(r->pub.targeted_hooks);
286#ifdef RUBY_THREAD_WIN32_H
289 ractor_local_storage_free(r);
290 rb_hook_list_free(&r->pub.hooks);
291 st_free_table(r->pub.targeted_hooks);
293 if (r->newobj_cache) {
296 rb_gc_ractor_cache_free(r->newobj_cache);
297 r->newobj_cache = NULL;
301 if (!r->main_ractor) {
307ractor_memsize(
const void *ptr)
312 return sizeof(
rb_ractor_t) + ractor_sync_memsize(r);
329 if (rb_typeddata_is_kind_of(gv, &ractor_data_type)) {
338RACTOR_PTR(
VALUE self)
340 VM_ASSERT(rb_ractor_p(self));
347#if RACTOR_CHECK_MODE > 0
349rb_ractor_current_id(
void)
351 if (GET_THREAD()->ractor == NULL) {
355 return rb_ractor_id(GET_RACTOR());
360#include "ractor_sync.c"
377 RUBY_DEBUG_LOG(
"r:%u ractor.cnt:%u++", r->pub.id, vm->ractor.cnt);
378 VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
380 ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
383 if (r->newobj_cache) {
384 VM_ASSERT(r == ruby_single_main_ractor);
387 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
392cancel_single_ractor_mode(
void)
395 RUBY_DEBUG_LOG(
"enable multi-ractor mode");
397 ruby_single_main_ractor = NULL;
404 VM_ASSERT(ractor_status_p(r, ractor_created));
406 if (rb_multi_ractor_p()) {
409 vm_insert_ractor0(vm, r,
false);
410 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
415 if (vm->ractor.cnt == 0) {
417 vm_insert_ractor0(vm, r,
true);
418 ractor_status_set(r, ractor_blocking);
419 ractor_status_set(r, ractor_running);
422 cancel_single_ractor_mode();
423 vm_insert_ractor0(vm, r,
true);
424 vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
432 VM_ASSERT(ractor_status_p(cr, ractor_running));
433 VM_ASSERT(vm->ractor.cnt > 1);
434 VM_ASSERT(cr->threads.cnt == 1);
438 RUBY_DEBUG_LOG(
"ractor.cnt:%u-- terminate_waiting:%d",
439 vm->ractor.cnt, vm->ractor.sync.terminate_waiting);
441 VM_ASSERT(vm->ractor.cnt > 0);
442 ccan_list_del(&cr->vmlr_node);
444 if (vm->ractor.cnt <= 2 && vm->ractor.sync.terminate_waiting) {
449 rb_gc_ractor_cache_free(cr->newobj_cache);
450 cr->newobj_cache = NULL;
452 ractor_status_set(cr, ractor_terminated);
458ractor_alloc(
VALUE klass)
464 r->next_ec_serial = 1;
465 VM_ASSERT(ractor_status_p(r, ractor_created));
472rb_ractor_main_alloc(
void)
476 fprintf(stderr,
"[FATAL] failed to allocate memory for main ractor\n");
479 r->pub.id = ++ractor_last_id;
483 r->newobj_cache = rb_gc_ractor_cache_alloc(r);
484 r->next_ec_serial = 1;
485 r->main_ractor =
true;
486 ruby_single_main_ractor = r;
491#if defined(HAVE_WORKING_FORK)
499 vm->ractor.blocking_cnt = 0;
500 ruby_single_main_ractor = th->ractor;
501 th->ractor->status_ = ractor_created;
503 rb_ractor_living_threads_init(th->ractor);
504 rb_ractor_living_threads_insert(th->ractor, th);
506 VM_ASSERT(vm->ractor.blocking_cnt == 0);
507 VM_ASSERT(vm->ractor.cnt == 1);
513 rb_gc_ractor_cache_free(r->newobj_cache);
514 r->newobj_cache = NULL;
515 r->status_ = ractor_terminated;
516 ractor_sync_terminate_atfork(vm, r);
525 ccan_list_head_init(&r->threads.set);
527 r->threads.blocking_cnt = 0;
534 r->pub.targeted_hooks = st_init_numtable();
535 r->pub.hooks.type = hook_list_type_ractor_local;
538 rb_thread_sched_init(&r->threads.sched,
false);
539 rb_ractor_living_threads_init(r);
545 enc = rb_enc_get(name);
546 if (!rb_enc_asciicompat(enc)) {
547 rb_raise(rb_eArgError,
"ASCII incompatible encoding (%s)",
564 r->threads.main = th;
565 rb_ractor_living_threads_insert(r, th);
573 VALUE rv = ractor_alloc(self);
575 ractor_init(r, name, loc);
577 r->pub.id = ractor_next_id();
578 RUBY_DEBUG_LOG(
"r:%u", r->pub.id);
581 r->verbose = cr->verbose;
582 r->debug = cr->debug;
584 rb_yjit_before_ractor_spawn();
585 rb_zjit_before_ractor_spawn();
586 rb_thread_create_ractor(r, args, block);
597 return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
604 ractor_notify_exit(ec, cr, result, exc);
611 ractor_atexit(ec, cr, result,
false);
618 ractor_atexit(ec, cr, ec->errinfo,
true);
628 VM_ASSERT(cr->threads.main != NULL);
629 cr->threads.main = NULL;
636 for (
int i=0; i<
len; i++) {
637 ptr[i] = ractor_receive(ec, ractor_default_port(r));
645 for (
int i=0; i<
len; i++) {
646 ractor_send(ec, ractor_default_port(r),
RARRAY_AREF(args, i),
false);
651rb_ractor_main_p_(
void)
653 VM_ASSERT(rb_multi_ractor_p());
655 return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
661 return r->threads.cnt;
666rb_ractor_thread_list(
void)
672 ccan_list_for_each(&r->threads.set, th, lt_node) {
673 switch (th->status) {
674 case THREAD_RUNNABLE:
676 case THREAD_STOPPED_FOREVER:
689 VM_ASSERT(th != NULL);
693 RUBY_DEBUG_LOG(
"r(%d)->threads.cnt:%d++", r->pub.id, r->threads.cnt);
694 ccan_list_add_tail(&r->threads.set, &th->lt_node);
700 if (r->threads.cnt == 1) {
701 VM_ASSERT(ractor_status_p(r, ractor_created));
702 vm_insert_ractor(th->vm, r);
709 ractor_status_set(r, ractor_blocking);
711 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d++", vm->ractor.blocking_cnt);
712 vm->ractor.blocking_cnt++;
713 VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
717rb_vm_ractor_blocking_cnt_inc(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
720 VM_ASSERT(GET_RACTOR() == cr);
721 vm_ractor_blocking_cnt_inc(vm, cr, file, line);
725rb_vm_ractor_blocking_cnt_dec(
rb_vm_t *vm,
rb_ractor_t *cr,
const char *file,
int line)
728 VM_ASSERT(GET_RACTOR() == cr);
730 RUBY_DEBUG_LOG2(file, line,
"vm->ractor.blocking_cnt:%d--", vm->ractor.blocking_cnt);
731 VM_ASSERT(vm->ractor.blocking_cnt > 0);
732 vm->ractor.blocking_cnt--;
734 ractor_status_set(cr, ractor_running);
738ractor_check_blocking(
rb_ractor_t *cr,
unsigned int remained_thread_cnt,
const char *file,
int line)
740 VM_ASSERT(cr == GET_RACTOR());
742 RUBY_DEBUG_LOG2(file, line,
743 "cr->threads.cnt:%u cr->threads.blocking_cnt:%u vm->ractor.cnt:%u vm->ractor.blocking_cnt:%u",
744 cr->threads.cnt, cr->threads.blocking_cnt,
745 GET_VM()->ractor.cnt, GET_VM()->ractor.blocking_cnt);
747 VM_ASSERT(cr->threads.cnt >= cr->threads.blocking_cnt + 1);
749 if (remained_thread_cnt > 0 &&
751 cr->threads.cnt == cr->threads.blocking_cnt + 1) {
756 rb_vm_ractor_blocking_cnt_inc(vm, cr, file, line);
766 VM_ASSERT(cr == GET_RACTOR());
767 RUBY_DEBUG_LOG(
"r->threads.cnt:%d--", cr->threads.cnt);
768 ractor_check_blocking(cr, cr->threads.cnt - 1, __FILE__, __LINE__);
770 rb_threadptr_remove(th);
772 if (cr->threads.cnt == 1) {
773 vm_remove_ractor(th->vm, cr);
778 ccan_list_del(&th->lt_node);
786rb_ractor_blocking_threads_inc(
rb_ractor_t *cr,
const char *file,
int line)
788 RUBY_DEBUG_LOG2(file, line,
"cr->threads.blocking_cnt:%d++", cr->threads.blocking_cnt);
790 VM_ASSERT(cr->threads.cnt > 0);
791 VM_ASSERT(cr == GET_RACTOR());
793 ractor_check_blocking(cr, cr->threads.cnt, __FILE__, __LINE__);
794 cr->threads.blocking_cnt++;
798rb_ractor_blocking_threads_dec(
rb_ractor_t *cr,
const char *file,
int line)
800 RUBY_DEBUG_LOG2(file, line,
801 "r->threads.blocking_cnt:%d--, r->threads.cnt:%u",
802 cr->threads.blocking_cnt, cr->threads.cnt);
804 VM_ASSERT(cr == GET_RACTOR());
806 if (cr->threads.cnt == cr->threads.blocking_cnt) {
810 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
814 cr->threads.blocking_cnt--;
818rb_ractor_vm_barrier_interrupt_running_thread(
rb_ractor_t *r)
820 VM_ASSERT(r != GET_RACTOR());
821 ASSERT_ractor_unlocking(r);
826 if (ractor_status_p(r, ractor_running)) {
829 RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec);
837rb_ractor_terminate_interrupt_main_thread(
rb_ractor_t *r)
839 VM_ASSERT(r != GET_RACTOR());
840 ASSERT_ractor_unlocking(r);
845 if (main_th->status != THREAD_KILLED) {
846 RUBY_VM_SET_TERMINATE_INTERRUPT(main_th->ec);
847 rb_threadptr_interrupt(main_th);
850 RUBY_DEBUG_LOG(
"killed (%p)", (
void *)main_th);
858ractor_terminal_interrupt_all(
rb_vm_t *vm)
860 if (vm->ractor.cnt > 1) {
863 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
864 if (r != vm->ractor.main_ractor) {
865 RUBY_DEBUG_LOG(
"r:%d", rb_ractor_id(r));
866 rb_ractor_terminate_interrupt_main_thread(r);
876rb_ractor_terminate_all(
void)
881 RUBY_DEBUG_LOG(
"ractor.cnt:%d", (
int)vm->ractor.cnt);
883 VM_ASSERT(cr == GET_RACTOR());
887 ractor_terminal_interrupt_all(vm);
890 rb_thread_terminate_all(GET_THREAD());
894 while (vm->ractor.cnt > 1) {
895 RUBY_DEBUG_LOG(
"terminate_waiting:%d", vm->ractor.sync.terminate_waiting);
896 vm->ractor.sync.terminate_waiting =
true;
899 rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
900 rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
901 rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 );
902#ifdef RUBY_THREAD_PTHREAD_H
903 while (vm->ractor.sched.barrier_waiting) {
910 RB_VM_LOCK_ENTER_LEV_NB(&lev);
913 rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
914 rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
916 ractor_terminal_interrupt_all(vm);
923rb_vm_main_ractor_ec(
rb_vm_t *vm)
940 if (running_ec) {
return running_ec; }
941 return vm->ractor.main_thread->ec;
945ractor_moved_missing(
int argc,
VALUE *argv,
VALUE self)
947 rb_raise(rb_eRactorMovedError,
"can not send any methods to a moved object");
1057 rb_define_method(rb_cRactorMovedObject,
"method_missing", ractor_moved_missing, -1);
1060 rb_define_method(rb_cRactorMovedObject,
"__send__", ractor_moved_missing, -1);
1064 rb_define_method(rb_cRactorMovedObject,
"__id__", ractor_moved_missing, -1);
1065 rb_define_method(rb_cRactorMovedObject,
"equal?", ractor_moved_missing, -1);
1066 rb_define_method(rb_cRactorMovedObject,
"instance_eval", ractor_moved_missing, -1);
1067 rb_define_method(rb_cRactorMovedObject,
"instance_exec", ractor_moved_missing, -1);
1078 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
1079 if (r != vm->ractor.main_ractor) {
1080 fprintf(stderr,
"r:%u (%s)\n", r->pub.id, ractor_status_str(r->status_));
1088 if (rb_ractor_main_p()) {
1098rb_ractor_stdout(
void)
1100 if (rb_ractor_main_p()) {
1105 return cr->r_stdout;
1110rb_ractor_stderr(
void)
1112 if (rb_ractor_main_p()) {
1117 return cr->r_stderr;
1124 if (rb_ractor_main_p()) {
1136 if (rb_ractor_main_p()) {
1148 if (rb_ractor_main_p()) {
1160 return &cr->pub.hooks;
1166 return cr->pub.targeted_hooks;
1170rb_obj_set_shareable_no_assert(
VALUE obj)
1174 if (rb_obj_gen_fields_p(obj)) {
1175 VALUE fields = rb_obj_fields_no_ractor_check(obj);
1176 if (imemo_type_p(fields, imemo_fields)) {
1183#ifndef STRICT_VERIFY_SHAREABLE
1184#define STRICT_VERIFY_SHAREABLE 0
1188rb_ractor_verify_shareable(
VALUE obj)
1190#if STRICT_VERIFY_SHAREABLE
1191 rb_gc_verify_shareable(obj);
1197rb_obj_set_shareable(
VALUE obj)
1201 rb_obj_set_shareable_no_assert(obj);
1213enum obj_traverse_iterator_result {
1219typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(
VALUE obj);
1220typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(
VALUE obj);
1221typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(
VALUE obj);
1223static enum obj_traverse_iterator_result null_leave(
VALUE obj);
1226 rb_obj_traverse_enter_func enter_func;
1227 rb_obj_traverse_leave_func leave_func;
1246 if (obj_traverse_i(key, d->data)) {
1251 if (obj_traverse_i(val, d->data)) {
1260obj_traverse_reachable_i(
VALUE obj,
void *ptr)
1264 if (obj_traverse_i(obj, d->data)) {
1272 if (UNLIKELY(!data->rec)) {
1273 data->rec_hash = rb_ident_hash_new();
1274 data->rec = RHASH_ST_TABLE(data->rec_hash);
1280obj_traverse_ivar_foreach_i(
ID key,
VALUE val, st_data_t ptr)
1284 if (obj_traverse_i(val, d->data)) {
1297 switch (data->enter_func(obj)) {
1298 case traverse_cont:
break;
1299 case traverse_skip:
return 0;
1300 case traverse_stop:
return 1;
1303 if (UNLIKELY(st_insert(obj_traverse_rec(data), obj, 1))) {
1314 if (d.stop)
return 1;
1332 rb_ary_cancel_sharing(obj);
1336 if (obj_traverse_i(e, data))
return 1;
1350 if (d.stop)
return 1;
1356 long len = RSTRUCT_LEN_RAW(obj);
1357 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1359 for (
long i=0; i<
len; i++) {
1360 if (obj_traverse_i(ptr[i], data))
return 1;
1366 if (obj_traverse_i(
RMATCH(obj)->str, data))
return 1;
1370 if (obj_traverse_i(RRATIONAL(obj)->num, data))
return 1;
1371 if (obj_traverse_i(RRATIONAL(obj)->den, data))
return 1;
1374 if (obj_traverse_i(RCOMPLEX(obj)->real, data))
return 1;
1375 if (obj_traverse_i(RCOMPLEX(obj)->imag, data))
return 1;
1385 RB_VM_LOCKING_NO_BARRIER() {
1386 rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
1388 if (d.stop)
return 1;
1398 rb_bug(
"unreachable");
1401 if (data->leave_func(obj) == traverse_stop) {
1410 rb_obj_traverse_final_func final_func;
1415obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg)
1418 if (data->final_func(key)) {
1428rb_obj_traverse(
VALUE obj,
1429 rb_obj_traverse_enter_func enter_func,
1430 rb_obj_traverse_leave_func leave_func,
1431 rb_obj_traverse_final_func final_func)
1434 .enter_func = enter_func,
1435 .leave_func = leave_func,
1439 if (obj_traverse_i(obj, &data))
return 1;
1440 if (final_func && data.rec) {
1442 st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f);
1449allow_frozen_shareable_p(
VALUE obj)
1456 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
1464static enum obj_traverse_iterator_result
1465make_shareable_check_shareable_freeze(
VALUE obj,
enum obj_traverse_iterator_result result)
1471 rb_raise(rb_eRactorError,
"#freeze does not freeze object correctly");
1475 return traverse_skip;
1482static int obj_refer_only_shareables_p(
VALUE obj);
1484static enum obj_traverse_iterator_result
1485make_shareable_check_shareable(
VALUE obj)
1490 return traverse_skip;
1492 else if (!allow_frozen_shareable_p(obj)) {
1496 if (
type->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
1497 if (obj_refer_only_shareables_p(obj)) {
1498 make_shareable_check_shareable_freeze(obj, traverse_skip);
1499 RB_OBJ_SET_SHAREABLE(obj);
1500 return traverse_skip;
1503 rb_raise(rb_eRactorError,
1504 "can not make shareable object for %+"PRIsVALUE
" because it refers unshareable objects", obj);
1508 rb_proc_ractor_make_shareable(obj,
Qundef);
1509 return traverse_cont;
1512 rb_raise(rb_eRactorError,
"can not make shareable object for %+"PRIsVALUE, obj);
1516 switch (
TYPE(obj)) {
1518 return traverse_skip;
1525 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1526 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1527 attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
1528 if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
1537 return make_shareable_check_shareable_freeze(obj, traverse_cont);
1540static enum obj_traverse_iterator_result
1541mark_shareable(
VALUE obj)
1544 rb_str_make_independent(obj);
1547 rb_obj_set_shareable_no_assert(obj);
1548 return traverse_cont;
1554 rb_obj_traverse(obj,
1555 make_shareable_check_shareable,
1556 null_leave, mark_shareable);
1563 VALUE copy = ractor_copy(obj);
1568rb_ractor_ensure_shareable(
VALUE obj,
VALUE name)
1571 VALUE message = rb_sprintf(
"cannot assign unshareable object to %"PRIsVALUE,
1579rb_ractor_ensure_main_ractor(
const char *msg)
1581 if (!rb_ractor_main_p()) {
1582 rb_raise(rb_eRactorIsolationError,
"%s", msg);
1586static enum obj_traverse_iterator_result
1587shareable_p_enter(
VALUE obj)
1590 return traverse_skip;
1596 mark_shareable(obj);
1597 return traverse_skip;
1600 allow_frozen_shareable_p(obj)) {
1601 return traverse_cont;
1604 return traverse_stop;
1608rb_ractor_shareable_p_continue(
VALUE obj)
1610 if (rb_obj_traverse(obj,
1611 shareable_p_enter, null_leave,
1620#if RACTOR_CHECK_MODE > 0
1622rb_ractor_setup_belonging(
VALUE obj)
1624 rb_ractor_setup_belonging_to(obj, rb_ractor_current_id());
1627static enum obj_traverse_iterator_result
1628reset_belonging_enter(
VALUE obj)
1631 return traverse_skip;
1634 rb_ractor_setup_belonging(obj);
1635 return traverse_cont;
1640static enum obj_traverse_iterator_result
1641null_leave(
VALUE obj)
1643 return traverse_cont;
1647ractor_reset_belonging(
VALUE obj)
1649#if RACTOR_CHECK_MODE > 0
1650 rb_obj_traverse(obj, reset_belonging_enter, null_leave, NULL);
1668 rb_obj_traverse_replace_enter_func enter_func;
1669 rb_obj_traverse_replace_leave_func leave_func;
1685obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
1691obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr,
int exists)
1696 if (obj_traverse_replace_i(*key, data)) {
1700 else if (*key != data->replacement) {
1701 VALUE v = *key = data->replacement;
1705 if (obj_traverse_replace_i(*val, data)) {
1709 else if (*val != data->replacement) {
1710 VALUE v = *val = data->replacement;
1718obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data,
int _x)
1724obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr,
int exists)
1729 if (obj_traverse_replace_i(*(
VALUE *)val, data)) {
1733 else if (*(
VALUE *)val != data->replacement) {
1744 if (UNLIKELY(!data->rec)) {
1745 data->rec_hash = rb_ident_hash_new();
1746 data->rec = RHASH_ST_TABLE(data->rec_hash);
1752obj_refer_only_shareables_p_i(
VALUE obj,
void *ptr)
1754 int *pcnt = (
int *)ptr;
1762obj_refer_only_shareables_p(
VALUE obj)
1765 RB_VM_LOCKING_NO_BARRIER() {
1766 rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
1774 st_data_t replacement;
1777 data->replacement = obj;
1781 switch (data->enter_func(obj, data)) {
1782 case traverse_cont:
break;
1783 case traverse_skip:
return 0;
1784 case traverse_stop:
return 1;
1787 replacement = (st_data_t)data->replacement;
1789 if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, &replacement))) {
1790 data->replacement = (
VALUE)replacement;
1794 st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
1803#define CHECK_AND_REPLACE(parent_obj, v) do { \
1805 if (obj_traverse_replace_i(_val, data)) { return 1; } \
1806 else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
1809 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
1810 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
1812 if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) {
1818 rb_st_foreach_with_replace(
1819 rb_imemo_fields_complex_tbl(fields_obj),
1820 obj_iv_hash_traverse_replace_foreach_i,
1821 obj_iv_hash_traverse_replace_i,
1824 if (d.stop)
return 1;
1827 uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
1828 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
1829 for (uint32_t i = 0; i < fields_count; i++) {
1830 CHECK_AND_REPLACE(fields_obj, fields[i]);
1844 rb_str_make_independent(obj);
1849 if (rb_shape_obj_too_complex_p(obj)) {
1855 rb_st_foreach_with_replace(
1856 ROBJECT_FIELDS_HASH(obj),
1857 obj_iv_hash_traverse_replace_foreach_i,
1858 obj_iv_hash_traverse_replace_i,
1861 if (d.stop)
return 1;
1864 uint32_t
len = ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
1867 for (uint32_t i = 0; i <
len; i++) {
1868 CHECK_AND_REPLACE(obj, ptr[i]);
1876 rb_ary_cancel_sharing(obj);
1881 if (obj_traverse_replace_i(e, data)) {
1884 else if (e != data->replacement) {
1898 rb_hash_stlike_foreach_with_replace(obj,
1899 obj_hash_traverse_replace_foreach_i,
1900 obj_hash_traverse_replace_i,
1902 if (d.stop)
return 1;
1906 if (obj_traverse_replace_i(ifnone, data)) {
1909 else if (ifnone != data->replacement) {
1917 long len = RSTRUCT_LEN_RAW(obj);
1918 const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
1920 for (
long i=0; i<
len; i++) {
1921 CHECK_AND_REPLACE(obj, ptr[i]);
1927 CHECK_AND_REPLACE(obj,
RMATCH(obj)->str);
1931 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
1932 CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
1935 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
1936 CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
1940 if (!data->move && obj_refer_only_shareables_p(obj)) {
1944 rb_raise(rb_eRactorError,
"can not %s %"PRIsVALUE
" object.",
1958 rb_bug(
"unreachable");
1961 data->replacement = (
VALUE)replacement;
1963 if (data->leave_func(obj, data) == traverse_stop) {
1974rb_obj_traverse_replace(
VALUE obj,
1975 rb_obj_traverse_replace_enter_func enter_func,
1976 rb_obj_traverse_replace_leave_func leave_func,
1980 .enter_func = enter_func,
1981 .leave_func = leave_func,
1987 if (obj_traverse_replace_i(obj, &data)) {
1991 return data.replacement;
1995static const bool wb_protected_types[
RUBY_T_MASK] = {
2008static enum obj_traverse_iterator_result
2012 data->replacement = obj;
2013 return traverse_skip;
2017 size_t slot_size = rb_gc_obj_slot_size(obj);
2019 NEWOBJ_OF(moved,
struct RBasic, 0,
type, slot_size, 0);
2020 MEMZERO(&moved[1],
char, slot_size -
sizeof(*moved));
2021 data->replacement = (
VALUE)moved;
2022 return traverse_cont;
2026static enum obj_traverse_iterator_result
2031 RBASIC(data->replacement)->flags = (
RBASIC(obj)->flags & ~ignored_flags) | (
RBASIC(data->replacement)->flags & ignored_flags);
2034 (
char *)data->replacement +
sizeof(
VALUE),
2035 (
char *)obj +
sizeof(
VALUE),
2036 rb_gc_obj_slot_size(obj) -
sizeof(
VALUE)
2040 rb_gc_writebarrier_remember(data->replacement);
2042 void rb_replace_generic_ivar(
VALUE clone,
VALUE obj);
2043 if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
2044 rb_replace_generic_ivar(data->replacement, obj);
2047 rb_gc_obj_id_moved(data->replacement);
2053 RBASIC(obj)->flags = flags;
2054 RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
2055 return traverse_cont;
2059ractor_move(
VALUE obj)
2061 VALUE val = rb_obj_traverse_replace(obj, move_enter, move_leave,
true);
2062 if (!UNDEF_P(val)) {
2066 rb_raise(rb_eRactorError,
"can not move the object");
2070static enum obj_traverse_iterator_result
2074 data->replacement = obj;
2075 return traverse_skip;
2079 rb_raise(rb_eRactorError,
"can not copy unshareable object %+"PRIsVALUE, obj);
2082 return traverse_cont;
2086static enum obj_traverse_iterator_result
2089 return traverse_cont;
2093ractor_copy(
VALUE obj)
2095 VALUE val = rb_obj_traverse_replace(obj, copy_enter, copy_leave,
false);
2096 if (!UNDEF_P(val)) {
2100 rb_raise(rb_eRactorError,
"can not copy the object");
2115} freed_ractor_local_keys;
2118ractor_local_storage_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
2121 if (k->type->
mark) (*k->type->
mark)((
void *)val);
2125static enum rb_id_table_iterator_result
2126idkey_local_storage_mark_i(
VALUE val,
void *dmy)
2129 return ID_TABLE_CONTINUE;
2135 if (r->local_storage) {
2136 st_foreach(r->local_storage, ractor_local_storage_mark_i, 0);
2138 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
2140 st_data_t val, k = (st_data_t)key;
2141 if (st_delete(r->local_storage, &k, &val) &&
2143 (*key->type->free)((
void *)val);
2148 if (r->idkey_local_storage) {
2149 rb_id_table_foreach_values(r->idkey_local_storage, idkey_local_storage_mark_i, NULL);
2152 rb_gc_mark(r->local_storage_store_lock);
2156ractor_local_storage_free_i(st_data_t key, st_data_t val, st_data_t dmy)
2159 if (k->type->
free) (*k->type->
free)((
void *)val);
2166 if (r->local_storage) {
2167 st_foreach(r->local_storage, ractor_local_storage_free_i, 0);
2168 st_free_table(r->local_storage);
2171 if (r->idkey_local_storage) {
2172 rb_id_table_free(r->idkey_local_storage);
2177rb_ractor_local_storage_value_mark(
void *ptr)
2179 rb_gc_mark((
VALUE)ptr);
2193 rb_ractor_local_storage_value_mark,
2201 key->type =
type ?
type : &ractor_local_storage_type_null;
2202 key->main_cache = (
void *)
Qundef;
2216 if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
2217 freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
2218 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
2220 freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
2227 if (rb_ractor_main_p()) {
2228 if (!UNDEF_P((
VALUE)key->main_cache)) {
2229 *pret = key->main_cache;
2239 if (cr->local_storage && st_lookup(cr->local_storage, (st_data_t)key, (st_data_t *)pret)) {
2253 if (cr->local_storage == NULL) {
2254 cr->local_storage = st_init_numtable();
2257 st_insert(cr->local_storage, (st_data_t)key, (st_data_t)ptr);
2259 if (rb_ractor_main_p()) {
2260 key->main_cache = ptr;
2268 if (ractor_local_ref(key, &val)) {
2279 if (ractor_local_ref(key, (
void **)val)) {
2290 ractor_local_set(key, (
void *)val);
2297 if (ractor_local_ref(key, &ret)) {
2308 ractor_local_set(key, ptr);
2311#define DEFAULT_KEYS_CAPA 0x10
2314rb_ractor_finish_marking(
void)
2316 for (
int i=0; i<freed_ractor_local_keys.cnt; i++) {
2317 SIZED_FREE(freed_ractor_local_keys.keys[i]);
2319 freed_ractor_local_keys.cnt = 0;
2320 if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
2321 freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
2322 SIZED_REALLOC_N(freed_ractor_local_keys.keys,
rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
2331 struct rb_id_table *tbl = cr->idkey_local_storage;
2334 if (
id && tbl && rb_id_table_lookup(tbl,
id, &val)) {
2347 struct rb_id_table *tbl = cr->idkey_local_storage;
2350 tbl = cr->idkey_local_storage = rb_id_table_create(2);
2352 rb_id_table_insert(tbl,
id, val);
2364ractor_local_value_store_i(
VALUE ptr)
2369 if (rb_id_table_lookup(data->tbl, data->id, &val)) {
2374 ractor_local_value_set(data->ec,
Qnil, data->sym, val);
2387 .tbl = cr->idkey_local_storage,
2391 if (data.tbl == NULL) {
2392 data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
2394 else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
2399 if (!cr->local_storage_store_lock) {
2412 rb_raise(rb_eRactorIsolationError,
"self should be shareable: %" PRIsVALUE, replace_self);
2416 return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
2440RUBY_REFERENCES(cross_ractor_require_refs) = {
2447 "ractor/cross_ractor_require",
2449 RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
2458require_body(
VALUE crr_obj)
2462 VALUE feature = crr->as.require.feature;
2468 int rb_require_internal_silent(
VALUE fname);
2469 return INT2NUM(rb_require_internal_silent(feature));
2472 return rb_funcallv(
Qnil, require, 1, &feature);
2486require_result_send_body(
VALUE ary)
2493 ractor_port_send(ec, port, results,
Qfalse);
2498require_result_send_resuce(
VALUE port,
VALUE errinfo)
2501 ractor_port_send(GET_EC(), port, errinfo,
Qfalse);
2511 const bool silent = crr->silent;
2513 VALUE debug, errinfo;
2516 errinfo = rb_errinfo();
2524 rb_set_errinfo(errinfo);
2529 rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ?
Qtrue :
Qfalse)),
2537ractor_require_func(
void *crr_obj)
2539 return ractor_require_protect((
VALUE)crr_obj, require_body);
2543rb_ractor_require(
VALUE feature,
bool silent)
2546 ASSERT_vm_unlocking();
2550 RB_OBJ_SET_SHAREABLE(crr_obj);
2555 crr->raised =
false;
2556 crr->silent = silent;
2559 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
2560 rb_ractor_interrupt_exec(main_r, ractor_require_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
2563 VALUE results = ractor_port_receive(ec, crr->port);
2564 ractor_port_close(ec, crr->port);
2581 return rb_ractor_require(feature,
false);
2585autoload_load_body(
VALUE crr_obj)
2593ractor_autoload_load_func(
void *crr_obj)
2595 return ractor_require_protect((
VALUE)crr_obj, autoload_load_body);
2599rb_ractor_autoload_load(
VALUE module,
ID name)
2603 RB_OBJ_SET_SHAREABLE(crr_obj);
2605 RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
2610 rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
2611 rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (
void *)crr_obj, rb_interrupt_exec_flag_value_data);
2614 VALUE results = ractor_port_receive(ec, crr->port);
2615 ractor_port_close(ec, crr->port);
2629#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().
@ RUBY_FL_PROMOTED
Ruby objects are "generational".
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define TYPE(_)
Old name of rb_type.
#define T_FILE
Old name of RUBY_T_FILE.
#define FL_PROMOTED
Old name of RUBY_FL_PROMOTED.
#define ALLOC
Old name of RB_ALLOC.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#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 FL_SHAREABLE
Old name of RUBY_FL_SHAREABLE.
#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 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 FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
#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_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_cObject
Object class.
VALUE rb_cRactor
Ractor class.
VALUE rb_stdin
STDIN constant.
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_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
VALUE rb_stdout
STDOUT constant.
#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.
#define RGENGC_WB_PROTECTED_STRUCT
This is a compile-time flag to enable/disable write barrier for struct RStruct.
#define RGENGC_WB_PROTECTED_STRING
This is a compile-time flag to enable/disable write barrier for struct RString.
#define RGENGC_WB_PROTECTED_HASH
This is a compile-time flag to enable/disable write barrier for struct RHash.
#define RGENGC_WB_PROTECTED_MATCH
This is a compile-time flag to enable/disable write barrier for struct RMatch.
#define RGENGC_WB_PROTECTED_ARRAY
This is a compile-time flag to enable/disable write barrier for struct RArray.
#define RGENGC_WB_PROTECTED_COMPLEX
This is a compile-time flag to enable/disable write barrier for struct RComplex.
#define RGENGC_WB_PROTECTED_FLOAT
This is a compile-time flag to enable/disable write barrier for struct RFloat.
#define RGENGC_WB_PROTECTED_RATIONAL
This is a compile-time flag to enable/disable write barrier for struct RRational.
#define RGENGC_WB_PROTECTED_REGEXP
This is a compile-time flag to enable/disable write barrier for struct RRegexp.
#define RGENGC_WB_PROTECTED_OBJECT
This is a compile-time flag to enable/disable write barrier for struct RObject.
VALUE rb_ary_new(void)
Allocates a new, empty array.
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_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
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_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_autoload_load(VALUE space, ID name)
Kicks the autoload procedure as if it was "touched".
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries 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 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.
#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.
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 RBASIC(obj)
Convenient casting macro.
#define DATA_PTR(obj)
Convenient getter macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RHASH_SET_IFNONE(h, ifnone)
Destructively updates the default value of the hash.
#define RMATCH(obj)
Convenient casting macro.
static VALUE * ROBJECT_FIELDS(VALUE obj)
Queries the instance variables.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
static bool RTYPEDDATA_P(VALUE obj)
Checks whether the passed object is RTypedData or RData.
#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.
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.
This is the struct that holds necessary info for a struct.
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_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.
@ RUBY_T_MASK
Bitmask of ruby_value_type.