* thread.c: add `Thread#backtrace_locations' method.
This method is similart to `caller_locations' method for specific method. And fix to accept `level' and `n' parameters for `Thread#backtrace' and `Thread#backtrace_locations'. `caller' (and `caller_locations') do not return `caller' method frame. However, `Thread#backtrace' (and `Thread#backtrace_locations') return `Thread#backtrace' method frame itself if `Thread.current.backtrace' was called. * vm_backtrace.c: ditto. * internal.h: ditto. * test/ruby/test_backtrace.rb: add tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37716 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3918bbfac4
commit
15d940b8b0
19
ChangeLog
19
ChangeLog
@ -1,3 +1,22 @@
|
||||
Mon Nov 19 14:55:51 2012 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* thread.c: add `Thread#backtrace_locations' method.
|
||||
This method is similart to `caller_locations' method for
|
||||
specific method.
|
||||
And fix to accept `level' and `n' parameters for `Thread#backtrace'
|
||||
and `Thread#backtrace_locations'.
|
||||
`caller' (and `caller_locations') do not return `caller' method
|
||||
frame.
|
||||
However, `Thread#backtrace' (and `Thread#backtrace_locations')
|
||||
return `Thread#backtrace' method frame itself
|
||||
if `Thread.current.backtrace' was called.
|
||||
|
||||
* vm_backtrace.c: ditto.
|
||||
|
||||
* internal.h: ditto.
|
||||
|
||||
* test/ruby/test_backtrace.rb: add tests.
|
||||
|
||||
Mon Nov 19 14:54:32 2012 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||
|
||||
* Makefile.in, common.mk (probes.h): moved to common.mk and changed to
|
||||
|
4
NEWS
4
NEWS
@ -56,6 +56,8 @@ with all sufficient information, see the ChangeLog file.
|
||||
* added Kernel#using, which imports refinements into the current scope.
|
||||
[experimental]
|
||||
* added Kernel#__dir__ which returns a current dirname.
|
||||
* added Kernel#caller_locations which returns an array of
|
||||
frame information objects.
|
||||
* extended method:
|
||||
* Kernel#warn accepts multiple args in like puts.
|
||||
* Kernel#caller accepts second optional argument `n' which specify
|
||||
@ -125,6 +127,8 @@ with all sufficient information, see the ChangeLog file.
|
||||
variable keys.
|
||||
* added Thread#thread_variable? for testing to see if a particular thread
|
||||
variable has been set.
|
||||
* added Thread#backtrace_locations which returns similar information of
|
||||
Kernel#caller_locations.
|
||||
|
||||
* Time
|
||||
* change return value:
|
||||
|
@ -310,7 +310,9 @@ void Init_prelude(void);
|
||||
|
||||
/* vm_backtrace.c */
|
||||
void Init_vm_backtrace(void);
|
||||
VALUE rb_thread_backtrace(VALUE thval);
|
||||
VALUE vm_thread_backtrace(int argc, VALUE *argv, VALUE thval);
|
||||
VALUE vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval);
|
||||
|
||||
VALUE rb_make_backtrace(void);
|
||||
void rb_backtrace_print_as_bugreport(void);
|
||||
int rb_backtrace_p(VALUE obj);
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
require 'test/unit'
|
||||
require 'thread'
|
||||
|
||||
class TestBacktrace < Test::Unit::TestCase
|
||||
def test_exception
|
||||
@ -91,4 +91,39 @@ class TestBacktrace < Test::Unit::TestCase
|
||||
}
|
||||
assert_equal(cs, locs)
|
||||
end
|
||||
|
||||
def th_rec q, n=10
|
||||
if n > 1
|
||||
th_rec q, n-1
|
||||
else
|
||||
q.pop
|
||||
end
|
||||
end
|
||||
|
||||
def test_thread_backtrace
|
||||
begin
|
||||
q = Queue.new
|
||||
th = Thread.new{
|
||||
th_rec q
|
||||
}
|
||||
sleep 0.5
|
||||
th_backtrace = th.backtrace
|
||||
th_locations = th.backtrace_locations
|
||||
|
||||
assert_equal(10, th_backtrace.count{|e| e =~ /th_rec/})
|
||||
assert_equal(th_backtrace, th_locations.map{|e| e.to_s})
|
||||
assert_equal(th_backtrace, th.backtrace(0))
|
||||
assert_equal(th_locations.map{|e| e.to_s},
|
||||
th.backtrace_locations(0).map{|e| e.to_s})
|
||||
th_backtrace.size.times{|n|
|
||||
assert_equal(n, th.backtrace(0, n).size)
|
||||
assert_equal(n, th.backtrace_locations(0, n).size)
|
||||
}
|
||||
n = th_backtrace.size
|
||||
assert_equal(n, th.backtrace(0, n + 1).size)
|
||||
assert_equal(n, th.backtrace_locations(0, n + 1).size)
|
||||
ensure
|
||||
q << true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
13
thread.c
13
thread.c
@ -4623,9 +4623,15 @@ rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_thread_backtrace_m(VALUE thval)
|
||||
rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
|
||||
{
|
||||
return rb_thread_backtrace(thval);
|
||||
return vm_thread_backtrace(argc, argv, thval);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
|
||||
{
|
||||
return vm_thread_backtrace_locations(argc, argv, thval);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4705,7 +4711,8 @@ Init_Thread(void)
|
||||
rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
|
||||
rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
|
||||
rb_define_method(rb_cThread, "group", rb_thread_group, 0);
|
||||
rb_define_method(rb_cThread, "backtrace", rb_thread_backtrace_m, 0);
|
||||
rb_define_method(rb_cThread, "backtrace", rb_thread_backtrace_m, -1);
|
||||
rb_define_method(rb_cThread, "backtrace_locations", rb_thread_backtrace_locations_m, -1);
|
||||
|
||||
rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
|
||||
|
||||
|
105
vm_backtrace.c
105
vm_backtrace.c
@ -697,8 +697,43 @@ rb_make_backtrace(void)
|
||||
return vm_backtrace_str_ary(GET_THREAD(), 0, 0);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_thread_backtrace(VALUE thval)
|
||||
static VALUE
|
||||
vm_backtrace_to_ary(rb_thread_t *th, int argc, VALUE *argv, int lev_deafult, int lev_plus, int to_str)
|
||||
{
|
||||
VALUE level, vn;
|
||||
int lev, n;
|
||||
|
||||
rb_scan_args(argc, argv, "02", &level, &vn);
|
||||
|
||||
lev = NIL_P(level) ? lev_deafult : NUM2INT(level);
|
||||
|
||||
if (NIL_P(vn)) {
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
n = NUM2INT(vn);
|
||||
if (n == 0) {
|
||||
return rb_ary_new();
|
||||
}
|
||||
}
|
||||
|
||||
if (lev < 0) {
|
||||
rb_raise(rb_eArgError, "negative level (%d)", lev);
|
||||
}
|
||||
if (n < 0) {
|
||||
rb_raise(rb_eArgError, "negative n (%d)", n);
|
||||
}
|
||||
|
||||
if (to_str) {
|
||||
return vm_backtrace_str_ary(th, lev+lev_plus, n);
|
||||
}
|
||||
else {
|
||||
return vm_backtrace_frame_ary(th, lev+lev_plus, n);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
|
||||
{
|
||||
rb_thread_t *th;
|
||||
GetThreadPtr(thval, th);
|
||||
@ -713,7 +748,19 @@ rb_thread_backtrace(VALUE thval)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
return vm_backtrace_str_ary(th, 0, 0);
|
||||
return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
|
||||
}
|
||||
|
||||
VALUE
|
||||
vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
|
||||
{
|
||||
return thread_backtrace_to_ary(argc, argv, thval, 1);
|
||||
}
|
||||
|
||||
VALUE
|
||||
vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
|
||||
{
|
||||
return thread_backtrace_to_ary(argc, argv, thval, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -749,61 +796,13 @@ rb_thread_backtrace(VALUE thval)
|
||||
static VALUE
|
||||
rb_f_caller(int argc, VALUE *argv)
|
||||
{
|
||||
VALUE level, vn;
|
||||
int lev, n;
|
||||
|
||||
rb_scan_args(argc, argv, "02", &level, &vn);
|
||||
|
||||
lev = NIL_P(level) ? 1 : NUM2INT(level);
|
||||
|
||||
if (NIL_P(vn)) {
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
n = NUM2INT(vn);
|
||||
if (n == 0) {
|
||||
return rb_ary_new();
|
||||
}
|
||||
}
|
||||
|
||||
if (lev < 0) {
|
||||
rb_raise(rb_eArgError, "negative level (%d)", lev);
|
||||
}
|
||||
if (n < 0) {
|
||||
rb_raise(rb_eArgError, "negative n (%d)", n);
|
||||
}
|
||||
|
||||
return vm_backtrace_str_ary(GET_THREAD(), lev+1, n);
|
||||
return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_f_caller_locations(int argc, VALUE *argv)
|
||||
{
|
||||
VALUE level, vn;
|
||||
int lev, n;
|
||||
|
||||
rb_scan_args(argc, argv, "02", &level, &vn);
|
||||
|
||||
lev = NIL_P(level) ? 1 : NUM2INT(level);
|
||||
|
||||
if (NIL_P(vn)) {
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
n = NUM2INT(vn);
|
||||
if (n == 0) {
|
||||
return rb_ary_new();
|
||||
}
|
||||
}
|
||||
|
||||
if (lev < 0) {
|
||||
rb_raise(rb_eArgError, "negative level (%d)", lev);
|
||||
}
|
||||
if (n < 0) {
|
||||
rb_raise(rb_eArgError, "negative n (%d)", n);
|
||||
}
|
||||
|
||||
return vm_backtrace_frame_ary(GET_THREAD(), lev+1, n);
|
||||
return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
|
||||
}
|
||||
|
||||
/* called from Init_vm() in vm.c */
|
||||
|
Loading…
x
Reference in New Issue
Block a user