diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | internal.h | 4 | ||||
-rw-r--r-- | test/ruby/test_backtrace.rb | 37 | ||||
-rw-r--r-- | thread.c | 13 | ||||
-rw-r--r-- | vm_backtrace.c | 105 |
6 files changed, 124 insertions, 58 deletions
@@ -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 @@ -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: diff --git a/internal.h b/internal.h index 1ea0ca9f45..508fae3c18 100644 --- a/internal.h +++ b/internal.h @@ -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); diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index cfdbd72d9f..ebbde9f060 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -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 @@ -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); diff --git a/vm_backtrace.c b/vm_backtrace.c index 4e01c7b723..12617443e5 100644 --- a/vm_backtrace.c +++ b/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 */ |