ruby-changes:25659
From: ko1 <ko1@a...>
Date: Mon, 19 Nov 2012 15:07:20 +0900 (JST)
Subject: [ruby-changes:25659] ko1:r37716 (trunk): * thread.c: add `Thread#backtrace_locations' method.
ko1 2012-11-19 15:07:06 +0900 (Mon, 19 Nov 2012) New Revision: 37716 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37716 Log: * 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. Modified files: trunk/ChangeLog trunk/NEWS trunk/internal.h trunk/test/ruby/test_backtrace.rb trunk/thread.c trunk/vm_backtrace.c Index: ChangeLog =================================================================== --- ChangeLog (revision 37715) +++ ChangeLog (revision 37716) @@ -1,3 +1,22 @@ +Mon Nov 19 14:55:51 2012 Koichi Sasada <ko1@a...> + + * 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@r...> * Makefile.in, common.mk (probes.h): moved to common.mk and changed to Index: thread.c =================================================================== --- thread.c (revision 37715) +++ thread.c (revision 37716) @@ -4623,11 +4623,17 @@ */ 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); +} + /* * Document-class: ThreadError * @@ -4705,7 +4711,8 @@ 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); Index: vm_backtrace.c =================================================================== --- vm_backtrace.c (revision 37715) +++ vm_backtrace.c (revision 37716) @@ -697,9 +697,44 @@ 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,9 +748,21 @@ 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); +} + /* * call-seq: * caller(start=1) -> array or nil @@ -749,61 +796,13 @@ 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 */ Index: NEWS =================================================================== --- NEWS (revision 37715) +++ NEWS (revision 37716) @@ -56,6 +56,8 @@ * 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 @@ 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: Index: internal.h =================================================================== --- internal.h (revision 37715) +++ internal.h (revision 37716) @@ -310,7 +310,9 @@ /* 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); Index: test/ruby/test_backtrace.rb =================================================================== --- test/ruby/test_backtrace.rb (revision 37715) +++ test/ruby/test_backtrace.rb (revision 37716) @@ -1,5 +1,5 @@ - require 'test/unit' +require 'thread' class TestBacktrace < Test::Unit::TestCase def test_exception @@ -91,4 +91,39 @@ } 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/