Ensure that exiting thread invokes end-of-life behaviour. (#10039)
This commit is contained in:
parent
fd91354628
commit
78d9fe6947
@ -2874,4 +2874,52 @@ CODE
|
|||||||
assert err.kind_of?(RuntimeError)
|
assert err.kind_of?(RuntimeError)
|
||||||
assert_equal err.message.to_i + 3, line
|
assert_equal err.message.to_i + 3, line
|
||||||
end
|
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
|
end
|
||||||
|
33
thread.c
33
thread.c
@ -601,14 +601,12 @@ thread_do_start_proc(rb_thread_t *th)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static VALUE
|
||||||
thread_do_start(rb_thread_t *th)
|
thread_do_start(rb_thread_t *th)
|
||||||
{
|
{
|
||||||
native_set_thread_name(th);
|
native_set_thread_name(th);
|
||||||
VALUE result = Qundef;
|
VALUE result = Qundef;
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, 0, Qundef);
|
|
||||||
|
|
||||||
switch (th->invoke_type) {
|
switch (th->invoke_type) {
|
||||||
case thread_invoke_type_proc:
|
case thread_invoke_type_proc:
|
||||||
result = thread_do_start_proc(th);
|
result = thread_do_start_proc(th);
|
||||||
@ -627,11 +625,7 @@ thread_do_start(rb_thread_t *th)
|
|||||||
rb_bug("unreachable");
|
rb_bug("unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_fiber_scheduler_set(Qnil);
|
return result;
|
||||||
|
|
||||||
th->value = result;
|
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_END, th->self, 0, 0, 0, Qundef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec);
|
void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec);
|
||||||
@ -662,12 +656,31 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
|
|||||||
// Ensure that we are not joinable.
|
// Ensure that we are not joinable.
|
||||||
VM_ASSERT(UNDEF_P(th->value));
|
VM_ASSERT(UNDEF_P(th->value));
|
||||||
|
|
||||||
|
int fiber_scheduler_closed = 0, event_thread_end_hooked = 0;
|
||||||
|
VALUE result = Qundef;
|
||||||
|
|
||||||
EC_PUSH_TAG(th->ec);
|
EC_PUSH_TAG(th->ec);
|
||||||
|
|
||||||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
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;
|
errinfo = th->ec->errinfo;
|
||||||
|
|
||||||
VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
|
VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user