Skip to content

Commit 0cab608

Browse files
pockejeremyevans
andauthored
[Bug #21127] Thread deadlock does not display backtraces (ruby#12721)
Previously, Ruby displayed backtraces for each thread on deadlock. However, it has not been shown since Ruby 3.0. It should display the backtrace for debugging. Co-authored-by: Jeremy Evans <[email protected]>
1 parent b4ed6db commit 0cab608

File tree

4 files changed

+40
-9
lines changed

4 files changed

+40
-9
lines changed

eval_intern.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ void rb_vm_set_progname(VALUE filename);
300300
VALUE rb_vm_cbase(void);
301301

302302
/* vm_backtrace.c */
303+
#define RUBY_BACKTRACE_START 0
304+
#define RUBY_ALL_BACKTRACE_LINES -1
303305
VALUE rb_ec_backtrace_object(const rb_execution_context_t *ec);
304306
VALUE rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n);
305307
VALUE rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal);

test/ruby/test_thread.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,4 +1553,36 @@ def test_pending_interrupt?
15531553
assert_equal(true, t.pending_interrupt?(Exception))
15541554
assert_equal(false, t.pending_interrupt?(ArgumentError))
15551555
end
1556+
1557+
def test_deadlock_backtrace
1558+
bug21127 = '[ruby-core:120930] [Bug #21127]'
1559+
1560+
expected_stderr = [
1561+
/-:12:in 'Thread#join': No live threads left. Deadlock\? \(fatal\)\n/,
1562+
/2 threads, 2 sleeps current:\w+ main thread:\w+\n/,
1563+
/\* #<Thread:\w+ sleep_forever>\n/,
1564+
:*,
1565+
/^\s*-:6:in 'Object#frame_for_deadlock_test_2'/,
1566+
:*,
1567+
/\* #<Thread:\w+ -:10 sleep_forever>\n/,
1568+
:*,
1569+
/^\s*-:2:in 'Object#frame_for_deadlock_test_1'/,
1570+
:*,
1571+
]
1572+
1573+
assert_in_out_err([], <<-INPUT, [], expected_stderr, bug21127)
1574+
def frame_for_deadlock_test_1
1575+
yield
1576+
end
1577+
1578+
def frame_for_deadlock_test_2
1579+
yield
1580+
end
1581+
1582+
q = Thread::Queue.new
1583+
t = Thread.new { frame_for_deadlock_test_1 { q.pop } }
1584+
1585+
frame_for_deadlock_test_2 { t.join }
1586+
INPUT
1587+
end
15561588
end

thread.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5588,7 +5588,7 @@ debug_deadlock_check(rb_ractor_t *r, VALUE msg)
55885588
}
55895589
}
55905590
rb_str_catf(msg, "\n ");
5591-
rb_str_concat(msg, rb_ary_join(rb_ec_backtrace_str_ary(th->ec, 0, 0), sep));
5591+
rb_str_concat(msg, rb_ary_join(rb_ec_backtrace_str_ary(th->ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES), sep));
55925592
rb_str_catf(msg, "\n");
55935593
}
55945594
}

vm_backtrace.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ id2str(ID id)
3131
}
3232
#define rb_id2str(id) id2str(id)
3333

34-
#define BACKTRACE_START 0
35-
#define ALL_BACKTRACE_LINES -1
36-
3734
inline static int
3835
calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
3936
{
@@ -758,7 +755,7 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
758755
VALUE
759756
rb_ec_backtrace_object(const rb_execution_context_t *ec)
760757
{
761-
return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
758+
return rb_ec_partial_backtrace_object(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
762759
}
763760

764761
static VALUE
@@ -1191,7 +1188,7 @@ rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
11911188
VALUE
11921189
rb_make_backtrace(void)
11931190
{
1194-
return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1191+
return rb_ec_backtrace_str_ary(GET_EC(), RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES);
11951192
}
11961193

11971194
static long
@@ -1210,7 +1207,7 @@ ec_backtrace_range(const rb_execution_context_t *ec, int argc, const VALUE *argv
12101207
switch (argc) {
12111208
case 0:
12121209
lev = lev_default + lev_plus;
1213-
n = ALL_BACKTRACE_LINES;
1210+
n = RUBY_ALL_BACKTRACE_LINES;
12141211
break;
12151212
case 1:
12161213
{
@@ -1222,7 +1219,7 @@ ec_backtrace_range(const rb_execution_context_t *ec, int argc, const VALUE *argv
12221219
rb_raise(rb_eArgError, "negative level (%ld)", lev);
12231220
}
12241221
lev += lev_plus;
1225-
n = ALL_BACKTRACE_LINES;
1222+
n = RUBY_ALL_BACKTRACE_LINES;
12261223
break;
12271224
case Qnil:
12281225
return -1;
@@ -1626,7 +1623,7 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
16261623

16271624
dbg_context.ec = ec;
16281625
dbg_context.cfp = dbg_context.ec->cfp;
1629-
dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE);
1626+
dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, FALSE);
16301627
dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
16311628
dbg_context.contexts = collect_caller_bindings(ec);
16321629

0 commit comments

Comments
 (0)