diff options
Diffstat (limited to 'ractor.c')
-rw-r--r-- | ractor.c | 455 |
1 files changed, 301 insertions, 154 deletions
@@ -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; } } |