1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/ext/-test-/postponed_job/postponed_job.c
Alan Wu f5d2041138
Avoid assert failure when NULL EC is expected
After 5680c38c75, 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 <john@hawthorn.email>
Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
2021-11-22 19:29:29 -05:00

100 lines
2.2 KiB
C

#include "ruby.h"
#include "ruby/debug.h"
static int counter;
static void
pjob_callback(void *data)
{
VALUE ary = (VALUE)data;
Check_Type(ary, T_ARRAY);
rb_ary_push(ary, INT2FIX(counter));
}
static VALUE
pjob_register(VALUE self, VALUE obj)
{
counter = 0;
rb_postponed_job_register(0, pjob_callback, (void *)obj);
rb_gc_start();
counter++;
rb_gc_start();
counter++;
rb_gc_start();
counter++;
return self;
}
static void
pjob_one_callback(void *data)
{
VALUE ary = (VALUE)data;
Check_Type(ary, T_ARRAY);
rb_ary_push(ary, INT2FIX(1));
}
static VALUE
pjob_register_one(VALUE self, VALUE 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 self;
}
static VALUE
pjob_call_direct(VALUE self, VALUE obj)
{
counter = 0;
pjob_callback((void *)obj);
rb_gc_start();
counter++;
rb_gc_start();
counter++;
rb_gc_start();
counter++;
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)
{
VALUE mBug = rb_define_module("Bug");
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
}