summaryrefslogtreecommitdiff
path: root/ractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'ractor.c')
-rw-r--r--ractor.c455
1 files changed, 301 insertions, 154 deletions
diff --git a/ractor.c b/ractor.c
index 77acf3a97f..231a83db6f 100644
--- a/ractor.c
+++ b/ractor.c
@@ -16,7 +16,6 @@
#include "internal/struct.h"
#include "internal/thread.h"
#include "variable.h"
-#include "transient_heap.h"
#include "yjit.h"
#include "rjit.h"
@@ -113,18 +112,16 @@ ractor_unlock_self(rb_ractor_t *cr, const char *file, int line)
#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
-static void
-ractor_cond_wait(rb_ractor_t *r)
+void
+rb_ractor_lock_self(rb_ractor_t *r)
{
-#if RACTOR_CHECK_MODE > 0
- VALUE locked_by = r->sync.locked_by;
- r->sync.locked_by = Qnil;
-#endif
- rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
+ RACTOR_LOCK_SELF(r);
+}
-#if RACTOR_CHECK_MODE > 0
- r->sync.locked_by = locked_by;
-#endif
+void
+rb_ractor_unlock_self(rb_ractor_t *r)
+{
+ RACTOR_UNLOCK_SELF(r);
}
// Ractor status
@@ -244,7 +241,9 @@ ractor_free(void *ptr)
rb_ractor_t *r = (rb_ractor_t *)ptr;
RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));
rb_native_mutex_destroy(&r->sync.lock);
+#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_destroy(&r->sync.cond);
+#endif
ractor_queue_free(&r->sync.recv_queue);
ractor_queue_free(&r->sync.takers_queue);
ractor_local_storage_free(r);
@@ -532,6 +531,19 @@ ractor_sleeping_by(const rb_ractor_t *r, enum rb_ractor_wait_status wait_status)
return (r->sync.wait.status & wait_status) && r->sync.wait.wakeup_status == wakeup_none;
}
+#ifdef RUBY_THREAD_PTHREAD_H
+// thread_*.c
+void rb_ractor_sched_wakeup(rb_ractor_t *r);
+#else
+
+static void
+rb_ractor_sched_wakeup(rb_ractor_t *r)
+{
+ rb_native_cond_broadcast(&r->sync.cond);
+}
+#endif
+
+
static bool
ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ractor_wakeup_status wakeup_status)
{
@@ -545,7 +557,7 @@ ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ra
if (ractor_sleeping_by(r, wait_status)) {
r->sync.wait.wakeup_status = wakeup_status;
- rb_native_cond_broadcast(&r->sync.cond);
+ rb_ractor_sched_wakeup(r);
return true;
}
else {
@@ -553,6 +565,73 @@ ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ra
}
}
+static void
+ractor_sleep_interrupt(void *ptr)
+{
+ rb_ractor_t *r = ptr;
+
+ RACTOR_LOCK(r);
+ {
+ ractor_wakeup(r, wait_receiving | wait_taking | wait_yielding, wakeup_by_interrupt);
+ }
+ RACTOR_UNLOCK(r);
+}
+
+typedef void (*ractor_sleep_cleanup_function)(rb_ractor_t *cr, void *p);
+
+static void
+ractor_check_ints(rb_execution_context_t *ec, rb_ractor_t *cr, ractor_sleep_cleanup_function cf_func, void *cf_data)
+{
+ if (cr->sync.wait.status != wait_none) {
+ enum rb_ractor_wait_status prev_wait_status = cr->sync.wait.status;
+ cr->sync.wait.status = wait_none;
+ cr->sync.wait.wakeup_status = wakeup_by_interrupt;
+
+ RACTOR_UNLOCK(cr);
+ {
+ if (cf_func) {
+ enum ruby_tag_type state;
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ rb_thread_check_ints();
+ }
+ EC_POP_TAG();
+
+ if (state) {
+ (*cf_func)(cr, cf_data);
+ EC_JUMP_TAG(ec, state);
+ }
+ }
+ else {
+ rb_thread_check_ints();
+ }
+ }
+
+ // reachable?
+ RACTOR_LOCK(cr);
+ cr->sync.wait.status = prev_wait_status;
+ }
+}
+
+#ifdef RUBY_THREAD_PTHREAD_H
+void rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf);
+#else
+
+// win32
+static void
+ractor_cond_wait(rb_ractor_t *r)
+{
+#if RACTOR_CHECK_MODE > 0
+ VALUE locked_by = r->sync.locked_by;
+ r->sync.locked_by = Qnil;
+#endif
+ rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
+
+#if RACTOR_CHECK_MODE > 0
+ r->sync.locked_by = locked_by;
+#endif
+}
+
static void *
ractor_sleep_wo_gvl(void *ptr)
{
@@ -570,18 +649,17 @@ ractor_sleep_wo_gvl(void *ptr)
}
static void
-ractor_sleep_interrupt(void *ptr)
+rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf)
{
- rb_ractor_t *r = ptr;
-
- RACTOR_LOCK(r);
+ RACTOR_UNLOCK(cr);
{
- ractor_wakeup(r, wait_receiving | wait_taking | wait_yielding, wakeup_by_interrupt);
+ rb_nogvl(ractor_sleep_wo_gvl, cr,
+ ubf, cr,
+ RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_INTR_FAIL);
}
- RACTOR_UNLOCK(r);
+ RACTOR_LOCK(cr);
}
-
-typedef void (*ractor_sleep_cleanup_function)(rb_ractor_t *cr, void *p);
+#endif
static enum rb_ractor_wakeup_status
ractor_sleep_with_cleanup(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status,
@@ -601,40 +679,12 @@ ractor_sleep_with_cleanup(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_r
RUBY_DEBUG_LOG("sleep by %s", wait_status_str(wait_status));
- RACTOR_UNLOCK(cr);
- {
- rb_nogvl(ractor_sleep_wo_gvl, cr,
- ractor_sleep_interrupt, cr,
- RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_INTR_FAIL);
+ while (cr->sync.wait.wakeup_status == wakeup_none) {
+ rb_ractor_sched_sleep(ec, cr, ractor_sleep_interrupt);
+ ractor_check_ints(ec, cr, cf_func, cf_data);
}
- RACTOR_LOCK(cr);
-
- // rb_nogvl() can be canceled by interrupts
- if (cr->sync.wait.status != wait_none) {
- cr->sync.wait.status = wait_none;
- cr->sync.wait.wakeup_status = wakeup_by_interrupt;
-
- RACTOR_UNLOCK(cr);
- {
- if (cf_func) {
- int state;
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- rb_thread_check_ints();
- }
- EC_POP_TAG();
- if (state) {
- (*cf_func)(cr, cf_data);
- EC_JUMP_TAG(ec, state);
- }
- }
- else {
- rb_thread_check_ints();
- }
- }
- RACTOR_LOCK(cr); // reachable?
- }
+ cr->sync.wait.status = wait_none;
// TODO: multi-thread
wakeup_status = cr->sync.wait.wakeup_status;
@@ -648,7 +698,7 @@ ractor_sleep_with_cleanup(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_r
static enum rb_ractor_wakeup_status
ractor_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status)
{
- return ractor_sleep_with_cleanup(ec, cr, wait_status, NULL, NULL);
+ return ractor_sleep_with_cleanup(ec, cr, wait_status, 0, NULL);
}
// Ractor.receive
@@ -1269,7 +1319,7 @@ ractor_try_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_q
type = basket_type_will;
}
else {
- int state;
+ enum ruby_tag_type state;
// begin
EC_PUSH_TAG(ec);
@@ -1426,10 +1476,10 @@ RACTOR_SELECTOR_PTR(VALUE selv)
// Ractor::Selector.new
static VALUE
-ractor_selector_create(VALUE crv)
+ractor_selector_create(VALUE klass)
{
struct rb_ractor_selector *s;
- VALUE selv = TypedData_Make_Struct(rb_cRactorSelector, struct rb_ractor_selector, &ractor_selector_data_type, s);
+ VALUE selv = TypedData_Make_Struct(klass, struct rb_ractor_selector, &ractor_selector_data_type, s);
s->take_basket.type.e = basket_type_reserved;
s->take_ractors = st_init_numtable(); // ractor (ptr) -> take_config
return selv;
@@ -1438,7 +1488,7 @@ ractor_selector_create(VALUE crv)
// Ractor::Selector#add(r)
static VALUE
-ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
+ractor_selector_add(VALUE selv, VALUE rv)
{
if (!rb_ractor_p(rv)) {
rb_raise(rb_eArgError, "Not a ractor object");
@@ -1456,7 +1506,7 @@ ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
config->closed = false;
config->oneshot = false;
- if (ractor_register_take(rb_ec_ractor_ptr(ec), r, &s->take_basket, false, config, true)) {
+ if (ractor_register_take(GET_RACTOR(), r, &s->take_basket, false, config, true)) {
st_insert(s->take_ractors, (st_data_t)r, (st_data_t)config);
}
@@ -1466,7 +1516,7 @@ ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
// Ractor::Selector#remove(r)
static VALUE
-ractor_selector_remove(rb_execution_context_t *ec, VALUE selv, VALUE rv)
+ractor_selector_remove(VALUE selv, VALUE rv)
{
if (!rb_ractor_p(rv)) {
rb_raise(rb_eArgError, "Not a ractor object");
@@ -1499,28 +1549,24 @@ struct ractor_selector_clear_data {
static int
ractor_selector_clear_i(st_data_t key, st_data_t val, st_data_t data)
{
- struct ractor_selector_clear_data *ptr = (struct ractor_selector_clear_data *)data;
+ VALUE selv = (VALUE)data;
rb_ractor_t *r = (rb_ractor_t *)key;
- ractor_selector_remove(ptr->ec, ptr->selv, r->pub.self);
+ ractor_selector_remove(selv, r->pub.self);
return ST_CONTINUE;
}
static VALUE
-ractor_selector_clear(rb_execution_context_t *ec, VALUE selv)
+ractor_selector_clear(VALUE selv)
{
- struct ractor_selector_clear_data data = {
- .selv = selv,
- .ec = ec,
- };
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
- st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)&data);
+ st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)selv);
st_clear(s->take_ractors);
return selv;
}
static VALUE
-ractor_selector_empty_p(rb_execution_context_t *ec, VALUE selv)
+ractor_selector_empty_p(VALUE selv)
{
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
@@ -1592,8 +1638,9 @@ ractor_selector_wait_cleaup(rb_ractor_t *cr, void *ptr)
}
static VALUE
-ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
+ractor_selector__wait(VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
{
+ rb_execution_context_t *ec = GET_EC();
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
struct rb_ractor_basket *tb = &s->take_basket;
struct rb_ractor_basket taken_basket;
@@ -1623,7 +1670,7 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
}
// check recv_queue
- if (do_receive && (ret_v = ractor_try_receive(ec, cr, rq)) != Qundef) {
+ if (do_receive && !UNDEF_P(ret_v = ractor_try_receive(ec, cr, rq))) {
ret_r = ID2SYM(rb_intern("receive"));
goto success;
}
@@ -1689,7 +1736,7 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
case basket_type_yielding:
rb_bug("unreachable");
case basket_type_deleted: {
- ractor_selector_remove(ec, selv, taken_basket.sender);
+ ractor_selector_remove(selv, taken_basket.sender);
rb_ractor_t *r = RACTOR_PTR(taken_basket.sender);
if (ractor_take_will_lock(r, &taken_basket)) {
@@ -1705,7 +1752,7 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
}
case basket_type_will:
// no more messages
- ractor_selector_remove(ec, selv, taken_basket.sender);
+ ractor_selector_remove(selv, taken_basket.sender);
break;
default:
break;
@@ -1719,6 +1766,60 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
return rb_ary_new_from_args(2, ret_r, ret_v);
}
+static VALUE
+ractor_selector_wait(int argc, VALUE *argv, VALUE selector)
+{
+ VALUE options;
+ ID keywords[3];
+ VALUE values[3];
+
+ keywords[0] = rb_intern("receive");
+ keywords[1] = rb_intern("yield_value");
+ keywords[2] = rb_intern("move");
+
+ rb_scan_args(argc, argv, "0:", &options);
+ rb_get_kwargs(options, keywords, 0, numberof(values), values);
+ return ractor_selector__wait(selector,
+ values[0] == Qundef ? Qfalse : RTEST(values[0]),
+ values[1] != Qundef, values[1], values[2]);
+}
+
+static VALUE
+ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
+{
+ VALUE selector = ractor_selector_create(klass);
+
+ for (int i=0; i<argc; i++) {
+ ractor_selector_add(selector, ractors[i]);
+ }
+
+ return selector;
+}
+
+static VALUE
+ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ractors, VALUE do_receive, VALUE do_yield, VALUE yield_value, VALUE move)
+{
+ VALUE selector = ractor_selector_new(RARRAY_LENINT(ractors), (VALUE *)RARRAY_CONST_PTR(ractors), rb_cRactorSelector);
+ VALUE result;
+ int state;
+
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ result = ractor_selector__wait(selector, do_receive, do_yield, yield_value, move);
+ }
+ EC_POP_TAG();
+ if (state != TAG_NONE) {
+ // ensure
+ ractor_selector_clear(selector);
+
+ // jump
+ EC_JUMP_TAG(ec, state);
+ }
+
+ RB_GC_GUARD(ractors);
+ return result;
+}
+
// Ractor#close_incoming
static VALUE
@@ -1833,7 +1934,6 @@ cancel_single_ractor_mode(void)
VALUE was_disabled = rb_gc_enable();
rb_gc_start();
- rb_transient_heap_evacuate();
if (was_disabled) {
rb_gc_disable();
@@ -1912,12 +2012,11 @@ ractor_alloc(VALUE klass)
rb_ractor_t *
rb_ractor_main_alloc(void)
{
- rb_ractor_t *r = ruby_mimmalloc(sizeof(rb_ractor_t));
+ rb_ractor_t *r = ruby_mimcalloc(1, sizeof(rb_ractor_t));
if (r == NULL) {
fprintf(stderr, "[FATAL] failed to allocate memory for main ractor\n");
exit(EXIT_FAILURE);
}
- MEMZERO(r, rb_ractor_t, 1);
r->pub.id = ++ractor_last_id;
r->loc = Qnil;
r->name = Qnil;
@@ -1945,7 +2044,7 @@ rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th)
}
#endif
-void rb_thread_sched_init(struct rb_thread_sched *);
+void rb_thread_sched_init(struct rb_thread_sched *, bool atfork);
void
rb_ractor_living_threads_init(rb_ractor_t *r)
@@ -1961,11 +2060,15 @@ ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
ractor_queue_setup(&r->sync.recv_queue);
ractor_queue_setup(&r->sync.takers_queue);
rb_native_mutex_initialize(&r->sync.lock);
+ rb_native_cond_initialize(&r->barrier_wait_cond);
+
+#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_initialize(&r->sync.cond);
rb_native_cond_initialize(&r->barrier_wait_cond);
+#endif
// thread management
- rb_thread_sched_init(&r->threads.sched);
+ rb_thread_sched_init(&r->threads.sched, false);
rb_ractor_living_threads_init(r);
// naming
@@ -2220,6 +2323,8 @@ ractor_check_blocking(rb_ractor_t *cr, unsigned int remained_thread_cnt, const c
}
}
+void rb_threadptr_remove(rb_thread_t *th);
+
void
rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
{
@@ -2227,6 +2332,8 @@ rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
RUBY_DEBUG_LOG("r->threads.cnt:%d--", cr->threads.cnt);
ractor_check_blocking(cr, cr->threads.cnt - 1, __FILE__, __LINE__);
+ rb_threadptr_remove(th);
+
if (cr->threads.cnt == 1) {
vm_remove_ractor(th->vm, cr);
}
@@ -2329,6 +2436,9 @@ ractor_terminal_interrupt_all(rb_vm_t *vm)
}
}
+void rb_add_running_thread(rb_thread_t *th);
+void rb_del_running_thread(rb_thread_t *th);
+
void
rb_ractor_terminate_all(void)
{
@@ -2356,7 +2466,9 @@ rb_ractor_terminate_all(void)
// wait for 1sec
rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
+ rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 /* ms */);
+ rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
ractor_terminal_interrupt_all(vm);
@@ -2368,7 +2480,23 @@ rb_ractor_terminate_all(void)
rb_execution_context_t *
rb_vm_main_ractor_ec(rb_vm_t *vm)
{
- return vm->ractor.main_ractor->threads.running_ec;
+ /* This code needs to carefully work around two bugs:
+ * - Bug #20016: When M:N threading is enabled, running_ec is NULL if no thread is
+ * actually currently running (as opposed to without M:N threading, when
+ * running_ec will still point to the _last_ thread which ran)
+ * - Bug #20197: If the main thread is sleeping, setting its postponed job
+ * interrupt flag is pointless; it won't look at the flag until it stops sleeping
+ * for some reason. It would be better to set the flag on the running ec, which
+ * will presumably look at it soon.
+ *
+ * Solution: use running_ec if it's set, otherwise fall back to the main thread ec.
+ * This is still susceptible to some rare race conditions (what if the last thread
+ * to run just entered a long-running sleep?), but seems like the best balance of
+ * robustness and complexity.
+ */
+ rb_execution_context_t *running_ec = vm->ractor.main_ractor->threads.running_ec;
+ if (running_ec) { return running_ec; }
+ return vm->ractor.main_thread->ec;
}
static VALUE
@@ -2377,6 +2505,29 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
rb_raise(rb_eRactorMovedError, "can not send any methods to a moved object");
}
+#ifndef USE_RACTOR_SELECTOR
+#define USE_RACTOR_SELECTOR 0
+#endif
+
+RUBY_SYMBOL_EXPORT_BEGIN
+void rb_init_ractor_selector(void);
+RUBY_SYMBOL_EXPORT_END
+
+void
+rb_init_ractor_selector(void)
+{
+ rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
+ rb_undef_alloc_func(rb_cRactorSelector);
+
+ rb_define_singleton_method(rb_cRactorSelector, "new", ractor_selector_new , -1);
+ rb_define_method(rb_cRactorSelector, "add", ractor_selector_add, 1);
+ rb_define_method(rb_cRactorSelector, "remove", ractor_selector_remove, 1);
+ rb_define_method(rb_cRactorSelector, "clear", ractor_selector_clear, 0);
+ rb_define_method(rb_cRactorSelector, "empty?", ractor_selector_empty_p, 0);
+ rb_define_method(rb_cRactorSelector, "wait", ractor_selector_wait, -1);
+ rb_define_method(rb_cRactorSelector, "_wait", ractor_selector__wait, 4);
+}
+
/*
* Document-class: Ractor::ClosedError
*
@@ -2497,8 +2648,9 @@ Init_Ractor(void)
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
- rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
- rb_undef_alloc_func(rb_cRactorSelector);
+#if USE_RACTOR_SELECTOR
+ rb_init_ractor_selector();
+#endif
}
void
@@ -2644,19 +2796,6 @@ obj_hash_traverse_i(VALUE key, VALUE val, VALUE ptr)
return ST_CONTINUE;
}
-static int
-obj_hash_iv_traverse_i(st_data_t key, st_data_t val, st_data_t ptr)
-{
- struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
-
- if (obj_traverse_i((VALUE)val, d->data)) {
- d->stop = true;
- return ST_STOP;
- }
-
- return ST_CONTINUE;
-}
-
static void
obj_traverse_reachable_i(VALUE obj, void *ptr)
{
@@ -2678,6 +2817,19 @@ obj_traverse_rec(struct obj_traverse_data *data)
}
static int
+obj_traverse_ivar_foreach_i(ID key, VALUE val, st_data_t ptr)
+{
+ struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
+
+ if (obj_traverse_i(val, d->data)) {
+ d->stop = true;
+ return ST_STOP;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
{
if (RB_SPECIAL_CONST_P(obj)) return 0;
@@ -2693,14 +2845,12 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
return 0;
}
- if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
- struct gen_ivtbl *ivtbl;
- rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
- for (uint32_t i = 0; i < ivtbl->numiv; i++) {
- VALUE val = ivtbl->ivptr[i];
- if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
- }
- }
+ struct obj_traverse_callback_data d = {
+ .stop = false,
+ .data = data,
+ };
+ rb_ivar_foreach(obj, obj_traverse_ivar_foreach_i, (st_data_t)&d);
+ if (d.stop) return 1;
switch (BUILTIN_TYPE(obj)) {
// no child node
@@ -2714,25 +2864,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
break;
case T_OBJECT:
- {
- if (rb_shape_obj_too_complex(obj)) {
- struct obj_traverse_callback_data d = {
- .stop = false,
- .data = data,
- };
- rb_st_foreach(ROBJECT_IV_HASH(obj), obj_hash_iv_traverse_i, (st_data_t)&d);
- if (d.stop) return 1;
- }
- else {
- uint32_t len = ROBJECT_IV_COUNT(obj);
- VALUE *ptr = ROBJECT_IVPTR(obj);
-
- for (uint32_t i=0; i<len; i++) {
- VALUE val = ptr[i];
- if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
- }
- }
- }
+ /* Instance variables already traversed. */
break;
case T_ARRAY:
@@ -2852,7 +2984,10 @@ rb_obj_traverse(VALUE obj,
static int
frozen_shareable_p(VALUE obj, bool *made_shareable)
{
- if (!RB_TYPE_P(obj, T_DATA)) {
+ if (CHILLED_STRING_P(obj)) {
+ return false;
+ }
+ else if (!RB_TYPE_P(obj, T_DATA)) {
return true;
}
else if (RTYPEDDATA_P(obj)) {
@@ -2881,6 +3016,17 @@ make_shareable_check_shareable(VALUE obj)
if (rb_ractor_shareable_p(obj)) {
return traverse_skip;
}
+ else if (CHILLED_STRING_P(obj)) {
+ rb_funcall(obj, idFreeze, 0);
+
+ if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
+ rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
+ }
+
+ if (RB_OBJ_SHAREABLE_P(obj)) {
+ return traverse_skip;
+ }
+ }
else if (!frozen_shareable_p(obj, &made_shareable)) {
if (made_shareable) {
return traverse_skip;
@@ -2925,10 +3071,7 @@ VALUE
rb_ractor_make_shareable_copy(VALUE obj)
{
VALUE copy = ractor_copy(obj);
- rb_obj_traverse(copy,
- make_shareable_check_shareable,
- null_leave, mark_shareable);
- return copy;
+ return rb_ractor_make_shareable(copy);
}
VALUE
@@ -3109,12 +3252,6 @@ obj_traverse_replace_rec(struct obj_traverse_replace_data *data)
return data->rec;
}
-#if USE_TRANSIENT_HEAP
-void rb_ary_transient_heap_evacuate(VALUE ary, int promote);
-void rb_obj_transient_heap_evacuate(VALUE obj, int promote);
-void rb_struct_transient_heap_evacuate(VALUE st, int promote);
-#endif
-
static void
obj_refer_only_shareables_p_i(VALUE obj, void *ptr)
{
@@ -3176,9 +3313,26 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
struct gen_ivtbl *ivtbl;
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
- for (uint32_t i = 0; i < ivtbl->numiv; i++) {
- if (!UNDEF_P(ivtbl->ivptr[i])) {
- CHECK_AND_REPLACE(ivtbl->ivptr[i]);
+
+ if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
+ struct obj_traverse_replace_callback_data d = {
+ .stop = false,
+ .data = data,
+ .src = obj,
+ };
+ rb_st_foreach_with_replace(
+ ivtbl->as.complex.table,
+ obj_iv_hash_traverse_replace_foreach_i,
+ obj_iv_hash_traverse_replace_i,
+ (st_data_t)&d
+ );
+ if (d.stop) return 1;
+ }
+ else {
+ for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
+ if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
+ CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
+ }
}
}
}
@@ -3199,30 +3353,25 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
if (rb_shape_obj_too_complex(obj)) {
- st_table * table = ROBJECT_IV_HASH(obj);
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
.src = obj,
};
rb_st_foreach_with_replace(
- table,
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (st_data_t)&d);
+ ROBJECT_IV_HASH(obj),
+ obj_iv_hash_traverse_replace_foreach_i,
+ obj_iv_hash_traverse_replace_i,
+ (st_data_t)&d
+ );
+ if (d.stop) return 1;
}
else {
-#if USE_TRANSIENT_HEAP
- if (data->move) rb_obj_transient_heap_evacuate(obj, TRUE);
-#endif
-
uint32_t len = ROBJECT_IV_COUNT(obj);
VALUE *ptr = ROBJECT_IVPTR(obj);
- for (uint32_t i=0; i<len; i++) {
- if (!UNDEF_P(ptr[i])) {
- CHECK_AND_REPLACE(ptr[i]);
- }
+ for (uint32_t i = 0; i < len; i++) {
+ CHECK_AND_REPLACE(ptr[i]);
}
}
}
@@ -3231,9 +3380,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_ARRAY:
{
rb_ary_cancel_sharing(obj);
-#if USE_TRANSIENT_HEAP
- if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
-#endif
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
VALUE e = rb_ary_entry(obj, i);
@@ -3274,9 +3420,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_STRUCT:
{
-#if USE_TRANSIENT_HEAP
- if (data->move) rb_struct_transient_heap_evacuate(obj, TRUE);
-#endif
long len = RSTRUCT_LEN(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
@@ -3377,6 +3520,8 @@ ractor_moved_bang(VALUE obj)
rv->v3 = 0;
rv->flags = rv->flags & ~fl_users;
+ if (BUILTIN_TYPE(obj) == T_OBJECT) ROBJECT_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
+
// TODO: record moved location
}
@@ -3388,7 +3533,9 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_skip;
}
else {
- data->replacement = rb_obj_alloc(RBASIC_CLASS(obj));
+ VALUE moved = rb_obj_alloc(RBASIC_CLASS(obj));
+ rb_shape_set_shape(moved, rb_shape_get_shape(obj));
+ data->replacement = moved;
return traverse_cont;
}
}