summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--NEWS4
-rw-r--r--internal.h4
-rw-r--r--test/ruby/test_backtrace.rb37
-rw-r--r--thread.c13
-rw-r--r--vm_backtrace.c105
6 files changed, 124 insertions, 58 deletions
diff --git a/ChangeLog b/ChangeLog
index 3fda33a98f..4a0d75a572 100644
--- a/ChangeLog
+++ b/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
diff --git a/NEWS b/NEWS
index 41e836fc44..77efc123ab 100644
--- a/NEWS
+++ b/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:
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
diff --git a/thread.c b/thread.c
index 4b1adc1334..4a3aeaa396 100644
--- a/thread.c
+++ b/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);
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 */