diff options
author | nagachika <[email protected]> | 2021-11-23 14:26:20 +0900 |
---|---|---|
committer | nagachika <[email protected]> | 2021-11-23 14:52:30 +0900 |
commit | 949af69408e44b69cc7437b58e8edbe3cd77c966 (patch) | |
tree | 970c9e57a072020370708a2bd29b5ac2d8d7755d | |
parent | aadb8cad563ca23e54a775d4fee936a07466112f (diff) |
merge revision(s) 5680c38c75aeb5cbd219aafa8eb48c315f287d97,f5d20411386ff2552ff27661387ddc4bae1ebc30: [Backport #17573]
Use valid `ec` for postponed job.
Postponed job can be registered from non-Ruby thread, which means
`ec` in TLS can be NULL. In this case, use main thread's `ec` instead.
See https://github.com/ruby/ruby/pull/4108
and https://github.com/ruby/ruby/pull/4336
---
vm_trace.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
Avoid assert failure when NULL EC is expected
After 5680c38c75aeb5cbd219aafa8eb48c315f287d97, postponed job APIs now
expect to be called on native threads not managed by Ruby and handles
getting a NULL execution context. However, in debug builds the change
runs into an assertion failure with GET_EC() which asserts that EC is
non-NULL. Avoid the assertion failure by passing `false` for `expect_ec`
instead as the intention is to handle when there is no EC.
Add a test from John Crepezzi and John Hawthorn to exercise this
situation.
See GH-4108
See GH-5094
[Bug #17573]
Co-authored-by: John Hawthorn <[email protected]>
Co-authored-by: John Crepezzi <[email protected]>
---
ext/-test-/postponed_job/postponed_job.c | 31 ++++++++++++++++++++++++++
test/-ext-/postponed_job/test_postponed_job.rb | 7 ++++++
vm_trace.c | 2 +-
3 files changed, 39 insertions(+), 1 deletion(-)
-rw-r--r-- | ext/-test-/postponed_job/postponed_job.c | 31 | ||||
-rw-r--r-- | test/-ext-/postponed_job/test_postponed_job.rb | 7 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | vm_trace.c | 16 |
4 files changed, 51 insertions, 5 deletions
diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c index d8684d475a..fa57bef6f5 100644 --- a/ext/-test-/postponed_job/postponed_job.c +++ b/ext/-test-/postponed_job/postponed_job.c @@ -58,6 +58,34 @@ pjob_call_direct(VALUE self, VALUE obj) return self; } +#ifdef HAVE_PTHREAD_H +#include <pthread.h> + +static void * +pjob_register_in_c_thread_i(void *obj) +{ + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + return NULL; +} + +static VALUE +pjob_register_in_c_thread(VALUE self, VALUE obj) +{ + pthread_t thread; + if (pthread_create(&thread, NULL, pjob_register_in_c_thread_i, (void *)obj)) { + return Qfalse; + } + + if (pthread_join(thread, NULL)) { + return Qfalse; + } + + return Qtrue; +} +#endif + void Init_postponed_job(VALUE self) { @@ -65,5 +93,8 @@ Init_postponed_job(VALUE self) rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1); rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1); rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1); +#ifdef HAVE_PTHREAD_H + rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1); +#endif } diff --git a/test/-ext-/postponed_job/test_postponed_job.rb b/test/-ext-/postponed_job/test_postponed_job.rb index 7dc28776d0..fee0172d11 100644 --- a/test/-ext-/postponed_job/test_postponed_job.rb +++ b/test/-ext-/postponed_job/test_postponed_job.rb @@ -25,4 +25,11 @@ class TestPostponed_job < Test::Unit::TestCase Bug.postponed_job_register_one(ary = []) assert_equal [1], ary end + + if Bug.respond_to?(:postponed_job_register_in_c_thread) + def test_register_in_c_thread + assert Bug.postponed_job_register_in_c_thread(ary = []) + assert_equal [1], ary + end + end end @@ -12,7 +12,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 3 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 152 +#define RUBY_PATCHLEVEL 153 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 11 diff --git a/vm_trace.c b/vm_trace.c index b16ec77e5a..bb4fdefd7c 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -1592,6 +1592,14 @@ postponed_job_register(rb_execution_context_t *ec, rb_vm_t *vm, return PJRR_SUCCESS; } +static rb_execution_context_t * +get_valid_ec(rb_vm_t *vm) +{ + rb_execution_context_t *ec = rb_current_execution_context(); + if (ec == NULL) ec = rb_vm_main_ractor_ec(vm); + return ec; +} + /* * return 0 if job buffer is full * Async-signal-safe @@ -1599,8 +1607,8 @@ postponed_job_register(rb_execution_context_t *ec, rb_vm_t *vm, int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data) { - rb_execution_context_t *ec = GET_EC(); - rb_vm_t *vm = rb_ec_vm_ptr(ec); + rb_vm_t *vm = GET_VM(); + rb_execution_context_t *ec = get_valid_ec(vm); begin: switch (postponed_job_register(ec, vm, flags, func, data, MAX_POSTPONED_JOB, vm->postponed_job_index)) { @@ -1618,8 +1626,8 @@ rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data) { - rb_execution_context_t *ec = GET_EC(); - rb_vm_t *vm = rb_ec_vm_ptr(ec); + rb_vm_t *vm = GET_VM(); + rb_execution_context_t *ec = get_valid_ec(vm); rb_postponed_job_t *pjob; rb_atomic_t i, index; |