mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 12:14:51 +00:00
Always allocate Fiber objects in Thread
Currently, root fibers of threads do not have a corresponding Ruby object backing it by default (it does have one when an object is required, such as when Fiber.current is called). This is a problem for the new GC weak references design in #12606 since Thread is not declared as having weak references but it does hold weak references (the generic ivar cache). This commit changes it to always allocate a Fiber object for the root fiber.
This commit is contained in:
parent
3fe2ebf8e4
commit
eaa83e505f
Notes:
git
2025-12-28 13:56:03 +00:00
65
cont.c
65
cont.c
@ -953,7 +953,9 @@ fiber_verify(const rb_fiber_t *fiber)
|
|||||||
|
|
||||||
switch (fiber->status) {
|
switch (fiber->status) {
|
||||||
case FIBER_RESUMED:
|
case FIBER_RESUMED:
|
||||||
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
|
if (fiber->cont.saved_ec.thread_ptr->self == 0) {
|
||||||
|
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case FIBER_SUSPENDED:
|
case FIBER_SUSPENDED:
|
||||||
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
|
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
|
||||||
@ -1141,12 +1143,7 @@ rb_fiber_update_self(rb_fiber_t *fiber)
|
|||||||
void
|
void
|
||||||
rb_fiber_mark_self(const rb_fiber_t *fiber)
|
rb_fiber_mark_self(const rb_fiber_t *fiber)
|
||||||
{
|
{
|
||||||
if (fiber->cont.self) {
|
rb_gc_mark_movable(fiber->cont.self);
|
||||||
rb_gc_mark_movable(fiber->cont.self);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rb_execution_context_mark(&fiber->cont.saved_ec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2067,32 +2064,10 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
|
|||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rb_fiber_t *
|
|
||||||
root_fiber_alloc(rb_thread_t *th)
|
|
||||||
{
|
|
||||||
VALUE fiber_value = fiber_alloc(rb_cFiber);
|
|
||||||
rb_fiber_t *fiber = th->ec->fiber_ptr;
|
|
||||||
|
|
||||||
VM_ASSERT(DATA_PTR(fiber_value) == NULL);
|
|
||||||
VM_ASSERT(fiber->cont.type == FIBER_CONTEXT);
|
|
||||||
VM_ASSERT(FIBER_RESUMED_P(fiber));
|
|
||||||
|
|
||||||
th->root_fiber = fiber;
|
|
||||||
DATA_PTR(fiber_value) = fiber;
|
|
||||||
fiber->cont.self = fiber_value;
|
|
||||||
|
|
||||||
coroutine_initialize_main(&fiber->context);
|
|
||||||
|
|
||||||
return fiber;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline rb_fiber_t*
|
static inline rb_fiber_t*
|
||||||
fiber_current(void)
|
fiber_current(void)
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
if (ec->fiber_ptr->cont.self == 0) {
|
|
||||||
root_fiber_alloc(rb_ec_thread_ptr(ec));
|
|
||||||
}
|
|
||||||
return ec->fiber_ptr;
|
return ec->fiber_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2598,6 +2573,7 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
|
|||||||
if (!fiber) {
|
if (!fiber) {
|
||||||
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
|
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
|
||||||
}
|
}
|
||||||
|
|
||||||
fiber->cont.type = FIBER_CONTEXT;
|
fiber->cont.type = FIBER_CONTEXT;
|
||||||
fiber->cont.saved_ec.fiber_ptr = fiber;
|
fiber->cont.saved_ec.fiber_ptr = fiber;
|
||||||
fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
|
fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
|
||||||
@ -2605,10 +2581,23 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
|
|||||||
fiber->blocking = 1;
|
fiber->blocking = 1;
|
||||||
fiber->killed = 0;
|
fiber->killed = 0;
|
||||||
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
|
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
|
||||||
|
|
||||||
|
coroutine_initialize_main(&fiber->context);
|
||||||
|
|
||||||
th->ec = &fiber->cont.saved_ec;
|
th->ec = &fiber->cont.saved_ec;
|
||||||
|
|
||||||
cont_init_jit_cont(&fiber->cont);
|
cont_init_jit_cont(&fiber->cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_root_fiber_obj_setup(rb_thread_t *th)
|
||||||
|
{
|
||||||
|
rb_fiber_t *fiber = th->ec->fiber_ptr;
|
||||||
|
VALUE fiber_value = fiber_alloc(rb_cFiber);
|
||||||
|
DATA_PTR(fiber_value) = fiber;
|
||||||
|
fiber->cont.self = fiber_value;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_threadptr_root_fiber_release(rb_thread_t *th)
|
rb_threadptr_root_fiber_release(rb_thread_t *th)
|
||||||
{
|
{
|
||||||
@ -2679,15 +2668,7 @@ rb_fiber_current(void)
|
|||||||
static inline void
|
static inline void
|
||||||
fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
|
fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
|
||||||
{
|
{
|
||||||
rb_fiber_t *fiber;
|
rb_fiber_t *fiber = th->ec->fiber_ptr;
|
||||||
|
|
||||||
if (th->ec->fiber_ptr != NULL) {
|
|
||||||
fiber = th->ec->fiber_ptr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* create root fiber */
|
|
||||||
fiber = root_fiber_alloc(th);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FIBER_CREATED_P(next_fiber)) {
|
if (FIBER_CREATED_P(next_fiber)) {
|
||||||
fiber_prepare_stack(next_fiber);
|
fiber_prepare_stack(next_fiber);
|
||||||
@ -2723,7 +2704,9 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
|
|||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
/* make sure the root_fiber object is available */
|
/* make sure the root_fiber object is available */
|
||||||
if (th->root_fiber == NULL) root_fiber_alloc(th);
|
if (th->root_fiber == NULL) {
|
||||||
|
th->root_fiber = th->ec->fiber_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (th->ec->fiber_ptr == fiber) {
|
if (th->ec->fiber_ptr == fiber) {
|
||||||
/* ignore fiber context switch
|
/* ignore fiber context switch
|
||||||
@ -3558,6 +3541,10 @@ Init_Cont(void)
|
|||||||
|
|
||||||
rb_define_singleton_method(rb_cFiber, "schedule", rb_fiber_s_schedule, -1);
|
rb_define_singleton_method(rb_cFiber, "schedule", rb_fiber_s_schedule, -1);
|
||||||
|
|
||||||
|
rb_thread_t *current_thread = rb_current_thread();
|
||||||
|
RUBY_ASSERT(CLASS_OF(current_thread->ec->fiber_ptr->cont.self) == 0);
|
||||||
|
*(VALUE *)&((struct RBasic *)current_thread->ec->fiber_ptr->cont.self)->klass = rb_cFiber;
|
||||||
|
|
||||||
#ifdef RB_EXPERIMENTAL_FIBER_POOL
|
#ifdef RB_EXPERIMENTAL_FIBER_POOL
|
||||||
/*
|
/*
|
||||||
* Document-class: Fiber::Pool
|
* Document-class: Fiber::Pool
|
||||||
|
|||||||
21
vm.c
21
vm.c
@ -3738,6 +3738,7 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
|
|||||||
void rb_fiber_mark_self(rb_fiber_t *fib);
|
void rb_fiber_mark_self(rb_fiber_t *fib);
|
||||||
void rb_fiber_update_self(rb_fiber_t *fib);
|
void rb_fiber_update_self(rb_fiber_t *fib);
|
||||||
void rb_threadptr_root_fiber_setup(rb_thread_t *th);
|
void rb_threadptr_root_fiber_setup(rb_thread_t *th);
|
||||||
|
void rb_root_fiber_obj_setup(rb_thread_t *th);
|
||||||
void rb_threadptr_root_fiber_release(rb_thread_t *th);
|
void rb_threadptr_root_fiber_release(rb_thread_t *th);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3746,10 +3747,6 @@ thread_compact(void *ptr)
|
|||||||
rb_thread_t *th = ptr;
|
rb_thread_t *th = ptr;
|
||||||
|
|
||||||
th->self = rb_gc_location(th->self);
|
th->self = rb_gc_location(th->self);
|
||||||
|
|
||||||
if (!th->root_fiber) {
|
|
||||||
rb_execution_context_update(th->ec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3757,7 +3754,11 @@ thread_mark(void *ptr)
|
|||||||
{
|
{
|
||||||
rb_thread_t *th = ptr;
|
rb_thread_t *th = ptr;
|
||||||
RUBY_MARK_ENTER("thread");
|
RUBY_MARK_ENTER("thread");
|
||||||
rb_fiber_mark_self(th->ec->fiber_ptr);
|
|
||||||
|
// ec is null when setting up the thread in rb_threadptr_root_fiber_setup
|
||||||
|
if (th->ec) {
|
||||||
|
rb_fiber_mark_self(th->ec->fiber_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* mark ruby objects */
|
/* mark ruby objects */
|
||||||
switch (th->invoke_type) {
|
switch (th->invoke_type) {
|
||||||
@ -3813,8 +3814,6 @@ thread_free(void *ptr)
|
|||||||
|
|
||||||
ruby_xfree(th->specific_storage);
|
ruby_xfree(th->specific_storage);
|
||||||
|
|
||||||
rb_threadptr_root_fiber_release(th);
|
|
||||||
|
|
||||||
if (th->vm && th->vm->ractor.main_thread == th) {
|
if (th->vm && th->vm->ractor.main_thread == th) {
|
||||||
RUBY_GC_INFO("MRI main thread\n");
|
RUBY_GC_INFO("MRI main thread\n");
|
||||||
}
|
}
|
||||||
@ -3917,6 +3916,8 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
|
|||||||
|
|
||||||
th->self = self;
|
th->self = self;
|
||||||
|
|
||||||
|
ccan_list_head_init(&th->interrupt_exec_tasks);
|
||||||
|
|
||||||
rb_threadptr_root_fiber_setup(th);
|
rb_threadptr_root_fiber_setup(th);
|
||||||
|
|
||||||
/* All threads are blocking until a non-blocking fiber is scheduled */
|
/* All threads are blocking until a non-blocking fiber is scheduled */
|
||||||
@ -3961,8 +3962,6 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
|
|||||||
th->report_on_exception = vm->thread_report_on_exception;
|
th->report_on_exception = vm->thread_report_on_exception;
|
||||||
th->ext_config.ractor_safe = true;
|
th->ext_config.ractor_safe = true;
|
||||||
|
|
||||||
ccan_list_head_init(&th->interrupt_exec_tasks);
|
|
||||||
|
|
||||||
#if USE_RUBY_DEBUG_LOG
|
#if USE_RUBY_DEBUG_LOG
|
||||||
static rb_atomic_t thread_serial = 1;
|
static rb_atomic_t thread_serial = 1;
|
||||||
th->serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
|
th->serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
|
||||||
@ -3978,6 +3977,7 @@ rb_thread_alloc(VALUE klass)
|
|||||||
rb_thread_t *target_th = rb_thread_ptr(self);
|
rb_thread_t *target_th = rb_thread_ptr(self);
|
||||||
target_th->ractor = GET_RACTOR();
|
target_th->ractor = GET_RACTOR();
|
||||||
th_init(target_th, self, target_th->vm = GET_VM());
|
th_init(target_th, self, target_th->vm = GET_VM());
|
||||||
|
rb_root_fiber_obj_setup(target_th);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4525,6 +4525,8 @@ Init_VM(void)
|
|||||||
th->top_wrapper = 0;
|
th->top_wrapper = 0;
|
||||||
th->top_self = rb_vm_top_self();
|
th->top_self = rb_vm_top_self();
|
||||||
|
|
||||||
|
rb_root_fiber_obj_setup(th);
|
||||||
|
|
||||||
rb_vm_register_global_object((VALUE)iseq);
|
rb_vm_register_global_object((VALUE)iseq);
|
||||||
th->ec->cfp->iseq = iseq;
|
th->ec->cfp->iseq = iseq;
|
||||||
th->ec->cfp->pc = ISEQ_BODY(iseq)->iseq_encoded;
|
th->ec->cfp->pc = ISEQ_BODY(iseq)->iseq_encoded;
|
||||||
@ -4599,6 +4601,7 @@ Init_BareVM(void)
|
|||||||
th_init(th, 0, vm);
|
th_init(th, 0, vm);
|
||||||
|
|
||||||
rb_ractor_set_current_ec(th->ractor, th->ec);
|
rb_ractor_set_current_ec(th->ractor, th->ec);
|
||||||
|
|
||||||
/* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */
|
/* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */
|
||||||
ruby_thread_init_stack(th, native_main_thread_stack_top);
|
ruby_thread_init_stack(th, native_main_thread_stack_top);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user