* 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>
|
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
|
* 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.
|
* added Kernel#using, which imports refinements into the current scope.
|
||||||
[experimental]
|
[experimental]
|
||||||
* added Kernel#__dir__ which returns a current dirname.
|
* added Kernel#__dir__ which returns a current dirname.
|
||||||
|
* added Kernel#caller_locations which returns an array of
|
||||||
|
frame information objects.
|
||||||
* extended method:
|
* extended method:
|
||||||
* Kernel#warn accepts multiple args in like puts.
|
* Kernel#warn accepts multiple args in like puts.
|
||||||
* Kernel#caller accepts second optional argument `n' which specify
|
* Kernel#caller accepts second optional argument `n' which specify
|
||||||
@ -125,6 +127,8 @@ with all sufficient information, see the ChangeLog file.
|
|||||||
variable keys.
|
variable keys.
|
||||||
* added Thread#thread_variable? for testing to see if a particular thread
|
* added Thread#thread_variable? for testing to see if a particular thread
|
||||||
variable has been set.
|
variable has been set.
|
||||||
|
* added Thread#backtrace_locations which returns similar information of
|
||||||
|
Kernel#caller_locations.
|
||||||
|
|
||||||
* Time
|
* Time
|
||||||
* change return value:
|
* change return value:
|
||||||
|
@ -310,7 +310,9 @@ void Init_prelude(void);
|
|||||||
|
|
||||||
/* vm_backtrace.c */
|
/* vm_backtrace.c */
|
||||||
void Init_vm_backtrace(void);
|
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);
|
VALUE rb_make_backtrace(void);
|
||||||
void rb_backtrace_print_as_bugreport(void);
|
void rb_backtrace_print_as_bugreport(void);
|
||||||
int rb_backtrace_p(VALUE obj);
|
int rb_backtrace_p(VALUE obj);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
|
require 'thread'
|
||||||
|
|
||||||
class TestBacktrace < Test::Unit::TestCase
|
class TestBacktrace < Test::Unit::TestCase
|
||||||
def test_exception
|
def test_exception
|
||||||
@ -91,4 +91,39 @@ class TestBacktrace < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
assert_equal(cs, locs)
|
assert_equal(cs, locs)
|
||||||
end
|
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
|
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
|
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, "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, "safe_level", rb_thread_safe_level, 0);
|
||||||
rb_define_method(rb_cThread, "group", rb_thread_group, 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);
|
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);
|
return vm_backtrace_str_ary(GET_THREAD(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
static VALUE
|
||||||
rb_thread_backtrace(VALUE thval)
|
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;
|
rb_thread_t *th;
|
||||||
GetThreadPtr(thval, th);
|
GetThreadPtr(thval, th);
|
||||||
@ -713,7 +748,19 @@ rb_thread_backtrace(VALUE thval)
|
|||||||
return Qnil;
|
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
|
static VALUE
|
||||||
rb_f_caller(int argc, VALUE *argv)
|
rb_f_caller(int argc, VALUE *argv)
|
||||||
{
|
{
|
||||||
VALUE level, vn;
|
return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_f_caller_locations(int argc, VALUE *argv)
|
rb_f_caller_locations(int argc, VALUE *argv)
|
||||||
{
|
{
|
||||||
VALUE level, vn;
|
return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called from Init_vm() in vm.c */
|
/* called from Init_vm() in vm.c */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user