mirror of
https://github.com/ruby/ruby.git
synced 2026-07-31 09:25:15 +08:00
merge revision(s) 78d9fe69479d32214a52ad7291c3973f1b6b7f6f, 04729fe68dceddab045be7324e26c2bb15aa62c7: [Backport #20286] [Backport #20286]
Ensure that exiting thread invokes end-of-life behaviour. (#10039) Fix exception handling in `rb_fiber_scheduler_set`. (#10042)
This commit is contained in:
parent
5577e5d396
commit
89de66dbb0
18
scheduler.c
18
scheduler.c
@ -161,6 +161,21 @@ verify_interface(VALUE scheduler)
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
fiber_scheduler_close(VALUE scheduler)
|
||||
{
|
||||
return rb_fiber_scheduler_close(scheduler);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
fiber_scheduler_close_ensure(VALUE _thread)
|
||||
{
|
||||
rb_thread_t *thread = (rb_thread_t*)_thread;
|
||||
thread->scheduler = Qnil;
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_fiber_scheduler_set(VALUE scheduler)
|
||||
{
|
||||
@ -178,7 +193,8 @@ rb_fiber_scheduler_set(VALUE scheduler)
|
||||
// That way, we do not need to consider interactions, e.g., of a Fiber from
|
||||
// the previous scheduler with the new scheduler.
|
||||
if (thread->scheduler != Qnil) {
|
||||
rb_fiber_scheduler_close(thread->scheduler);
|
||||
// rb_fiber_scheduler_close(thread->scheduler);
|
||||
rb_ensure(fiber_scheduler_close, thread->scheduler, fiber_scheduler_close_ensure, (VALUE)thread);
|
||||
}
|
||||
|
||||
thread->scheduler = scheduler;
|
||||
|
||||
@ -2738,4 +2738,52 @@ CODE
|
||||
Foo.foo
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_tracepoint_thread_begin
|
||||
target_thread = nil
|
||||
|
||||
trace = TracePoint.new(:thread_begin) do |tp|
|
||||
target_thread = tp.self
|
||||
end
|
||||
|
||||
trace.enable(target_thread: nil) do
|
||||
Thread.new{}.join
|
||||
end
|
||||
|
||||
assert_kind_of(Thread, target_thread)
|
||||
end
|
||||
|
||||
def test_tracepoint_thread_end
|
||||
target_thread = nil
|
||||
|
||||
trace = TracePoint.new(:thread_end) do |tp|
|
||||
target_thread = tp.self
|
||||
end
|
||||
|
||||
trace.enable(target_thread: nil) do
|
||||
Thread.new{}.join
|
||||
end
|
||||
|
||||
assert_kind_of(Thread, target_thread)
|
||||
end
|
||||
|
||||
def test_tracepoint_thread_end_with_exception
|
||||
target_thread = nil
|
||||
|
||||
trace = TracePoint.new(:thread_end) do |tp|
|
||||
target_thread = tp.self
|
||||
end
|
||||
|
||||
trace.enable(target_thread: nil) do
|
||||
thread = Thread.new do
|
||||
Thread.current.report_on_exception = false
|
||||
raise
|
||||
end
|
||||
|
||||
# Ignore the exception raised by the thread:
|
||||
thread.join rescue nil
|
||||
end
|
||||
|
||||
assert_kind_of(Thread, target_thread)
|
||||
end
|
||||
end
|
||||
|
||||
33
thread.c
33
thread.c
@ -605,14 +605,12 @@ thread_do_start_proc(rb_thread_t *th)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static VALUE
|
||||
thread_do_start(rb_thread_t *th)
|
||||
{
|
||||
native_set_thread_name(th);
|
||||
VALUE result = Qundef;
|
||||
|
||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, 0, Qundef);
|
||||
|
||||
switch (th->invoke_type) {
|
||||
case thread_invoke_type_proc:
|
||||
result = thread_do_start_proc(th);
|
||||
@ -631,11 +629,7 @@ thread_do_start(rb_thread_t *th)
|
||||
rb_bug("unreachable");
|
||||
}
|
||||
|
||||
rb_fiber_scheduler_set(Qnil);
|
||||
|
||||
th->value = result;
|
||||
|
||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_END, th->self, 0, 0, 0, Qundef);
|
||||
return result;
|
||||
}
|
||||
|
||||
void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec);
|
||||
@ -687,12 +681,31 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
|
||||
// Ensure that we are not joinable.
|
||||
VM_ASSERT(UNDEF_P(th->value));
|
||||
|
||||
int fiber_scheduler_closed = 0, event_thread_end_hooked = 0;
|
||||
VALUE result = Qundef;
|
||||
|
||||
EC_PUSH_TAG(th->ec);
|
||||
|
||||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||
SAVE_ROOT_JMPBUF(th, thread_do_start(th));
|
||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, 0, Qundef);
|
||||
|
||||
SAVE_ROOT_JMPBUF(th, result = thread_do_start(th));
|
||||
}
|
||||
else {
|
||||
|
||||
if (!fiber_scheduler_closed) {
|
||||
fiber_scheduler_closed = 1;
|
||||
rb_fiber_scheduler_set(Qnil);
|
||||
}
|
||||
|
||||
if (!event_thread_end_hooked) {
|
||||
event_thread_end_hooked = 1;
|
||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_END, th->self, 0, 0, 0, Qundef);
|
||||
}
|
||||
|
||||
if (state == TAG_NONE) {
|
||||
// This must be set AFTER doing all user-level code. At this point, the thread is effectively finished and calls to `Thread#join` will succeed.
|
||||
th->value = result;
|
||||
} else {
|
||||
errinfo = th->ec->errinfo;
|
||||
|
||||
VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
||||
#define RUBY_VERSION_TEENY 4
|
||||
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
||||
#define RUBY_PATCHLEVEL 180
|
||||
#define RUBY_PATCHLEVEL 181
|
||||
|
||||
#include "ruby/version.h"
|
||||
#include "ruby/internal/abi.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user