diff options
author | John Hawthorn <[email protected]> | 2025-06-05 13:48:34 -0700 |
---|---|---|
committer | John Hawthorn <[email protected]> | 2025-06-12 13:13:55 -0700 |
commit | a34fcf401b5b20c38eb98b42815e17bc2af9bad5 (patch) | |
tree | 6345fd91f8caba0646adae640cf0389b124c41d7 | |
parent | 97994c77fb5b82ca959e1188ecaee7d633d60a8e (diff) |
Add a new_thread flag to rb_interrupt_exec
Previously rb_ractor_interrupt_exec would use an intermediate function
to create a new thread with the actual target function, replacing the
data being passed in with a piece of malloc memory holding the "next"
function and the original data.
Because of this, passing rb_interrupt_exec_flag_value_data to
rb_ractor_interrupt_exec didn't have the intended effect of allowing
data to be passed in and marked.
This commit adds a rb_interrupt_exec_flag_new_thread flag, which
both simplifies the implementation and allows the original data to be
marked.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/13531
-rw-r--r-- | internal/thread.h | 1 | ||||
-rw-r--r-- | thread.c | 36 |
2 files changed, 7 insertions, 30 deletions
diff --git a/internal/thread.h b/internal/thread.h index 8403ac2663..00fcbfc560 100644 --- a/internal/thread.h +++ b/internal/thread.h @@ -90,6 +90,7 @@ typedef VALUE (rb_interrupt_exec_func_t)(void *data); enum rb_interrupt_exec_flag { rb_interrupt_exec_flag_none = 0x00, rb_interrupt_exec_flag_value_data = 0x01, + rb_interrupt_exec_flag_new_thread = 0x02, }; // interrupt the target_th and run func. @@ -6206,7 +6206,11 @@ threadptr_interrupt_exec_exec(rb_thread_t *th) RUBY_DEBUG_LOG("task:%p", task); if (task) { - (*task->func)(task->data); + if (task->flags & rb_interrupt_exec_flag_new_thread) { + rb_thread_create(task->func, task->data); + } else { + (*task->func)(task->data); + } ruby_xfree(task); } else { @@ -6229,43 +6233,15 @@ threadptr_interrupt_exec_cleanup(rb_thread_t *th) rb_native_mutex_unlock(&th->interrupt_lock); } -struct interrupt_ractor_new_thread_data { - rb_interrupt_exec_func_t *func; - void *data; -}; - -static VALUE -interrupt_ractor_new_thread_func(void *data) -{ - struct interrupt_ractor_new_thread_data d = *(struct interrupt_ractor_new_thread_data *)data; - ruby_xfree(data); - - d.func(d.data); - return Qnil; -} - -static VALUE -interrupt_ractor_func(void *data) -{ - rb_thread_create(interrupt_ractor_new_thread_func, data); - return Qnil; -} - // native thread safe // func/data should be native thread safe void rb_ractor_interrupt_exec(struct rb_ractor_struct *target_r, rb_interrupt_exec_func_t *func, void *data, enum rb_interrupt_exec_flag flags) { - struct interrupt_ractor_new_thread_data *d = ALLOC(struct interrupt_ractor_new_thread_data); - RUBY_DEBUG_LOG("flags:%d", (int)flags); - d->func = func; - d->data = data; rb_thread_t *main_th = target_r->threads.main; - rb_threadptr_interrupt_exec(main_th, interrupt_ractor_func, d, flags); - - // TODO MEMO: we can create a new thread in a ractor, but not sure how to do that now. + rb_threadptr_interrupt_exec(main_th, func, data, flags | rb_interrupt_exec_flag_new_thread); } |