Skip to content

Commit b167d8d

Browse files
committed
Always deliver postponed job to main ractor
Profilers use `rb_postponed_job_register_one()` in signal handlers, and signals don't necessarily land on a thread that runs Ruby code and has a thread local execution context. The MJIT worker thread doesn't have an execution context, for example. Without an execution context, postponed job APIs were crashing. Always use the main ractor's execution context so postponed job APIs can work from non Ruby threads like in older versions. Tests courtesy of John Crepezzi <john.crepezzi@gmail.com> and John Hawthorn <john@hawthorn.email>. [Bug #17573]
1 parent 0fb782e commit b167d8d

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

ext/-test-/postponed_job/postponed_job.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,43 @@ pjob_call_direct(VALUE self, VALUE obj)
5858
return self;
5959
}
6060

61+
#ifdef HAVE_PTHREAD_H
62+
#include <pthread.h>
63+
64+
static void *
65+
pjob_register_in_c_thread_i(void *obj)
66+
{
67+
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
68+
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
69+
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
70+
return NULL;
71+
}
72+
73+
static VALUE
74+
pjob_register_in_c_thread(VALUE self, VALUE obj)
75+
{
76+
pthread_t thread;
77+
if (pthread_create(&thread, NULL, pjob_register_in_c_thread_i, (void *)obj)) {
78+
return Qfalse;
79+
}
80+
81+
if (pthread_join(thread, NULL)) {
82+
return Qfalse;
83+
}
84+
85+
return Qtrue;
86+
}
87+
#endif
88+
6189
void
6290
Init_postponed_job(VALUE self)
6391
{
6492
VALUE mBug = rb_define_module("Bug");
6593
rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1);
6694
rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1);
6795
rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1);
96+
#ifdef HAVE_PTHREAD_H
97+
rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1);
98+
#endif
6899
}
69100

test/-ext-/postponed_job/test_postponed_job.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ def test_register
2525
Bug.postponed_job_register_one(ary = [])
2626
assert_equal [1], ary
2727
end
28+
29+
if Bug.respond_to?(:postponed_job_register_in_c_thread)
30+
def test_register_in_c_thread
31+
assert Bug.postponed_job_register_in_c_thread(ary = [])
32+
assert_equal [1], ary
33+
end
34+
end
2835
end

vm_trace.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,8 +1599,8 @@ postponed_job_register(rb_execution_context_t *ec, rb_vm_t *vm,
15991599
int
16001600
rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
16011601
{
1602-
rb_execution_context_t *ec = GET_EC();
1603-
rb_vm_t *vm = rb_ec_vm_ptr(ec);
1602+
rb_vm_t *vm = GET_VM();
1603+
rb_execution_context_t *ec = rb_vm_main_ractor_ec(vm);
16041604

16051605
begin:
16061606
switch (postponed_job_register(ec, vm, flags, func, data, MAX_POSTPONED_JOB, vm->postponed_job_index)) {
@@ -1618,8 +1618,8 @@ rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void
16181618
int
16191619
rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
16201620
{
1621-
rb_execution_context_t *ec = GET_EC();
1622-
rb_vm_t *vm = rb_ec_vm_ptr(ec);
1621+
rb_vm_t *vm = GET_VM();
1622+
rb_execution_context_t *ec = rb_vm_main_ractor_ec(vm);
16231623
rb_postponed_job_t *pjob;
16241624
rb_atomic_t i, index;
16251625

0 commit comments

Comments
 (0)