thread_backtrace 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +18 -0
- data/Rakefile +21 -0
- data/ext/thread_backtrace/extconf.rb +3 -0
- data/ext/thread_backtrace/thread_backtrace.c +73 -0
- data/lib/thread_backtrace.rb +11 -0
- metadata +59 -0
data/README.markdown
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
**THIS IS VERY-VERY EXPERIMENTAL AND HACKISH. USE ON YOUR OWN RISK.**
|
|
2
|
+
|
|
3
|
+
Thread Backtrace
|
|
4
|
+
================
|
|
5
|
+
|
|
6
|
+
It adds Thread#backtrace. Although I abuse private APIs of Ruby, no ruby patches are required. It **does not** work with 1.9.
|
|
7
|
+
|
|
8
|
+
Example
|
|
9
|
+
-------
|
|
10
|
+
|
|
11
|
+
>> require 'thread_backtrace'
|
|
12
|
+
=> true
|
|
13
|
+
>> def a; b; end; def b; c; end; def c; sleep 10; end
|
|
14
|
+
=> nil
|
|
15
|
+
>> Thread.fork { a }.backtrace
|
|
16
|
+
=> ["(irb):2:in `c'", "(irb):2:in `b'", "(irb):2:in `a'", "(irb):3:in `irb_binding'", "(irb):3:in `fork'", "(irb):3:in `irb_binding'", "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'", "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/workspace.rb:52"]
|
|
17
|
+
|
|
18
|
+
Also it adds caller_for_all_threads method to kernel. But it's not the same as output of REE (it doesn't skip the first entry for the current thread).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'rubygems' unless defined?(Gem)
|
|
2
|
+
require 'rake' unless defined?(Rake)
|
|
3
|
+
require 'rake/gempackagetask'
|
|
4
|
+
|
|
5
|
+
spec = Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'thread_backtrace'
|
|
7
|
+
s.version = '0.1'
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.has_rdoc = true
|
|
10
|
+
s.extra_rdoc_files = ["README.markdown"]
|
|
11
|
+
s.summary = "Adds Thread\#backtrace"
|
|
12
|
+
s.description = "Adds Thread\#backtrace for inspecting bactrace of a thread. Only works on 1.8"
|
|
13
|
+
s.files = PKG_FILES = %w(README.markdown Rakefile) + Dir.glob("{ext,lib}/**/*.{rb,c}")
|
|
14
|
+
s.extensions << 'ext/thread_backtrace/extconf.rb'
|
|
15
|
+
s.require_paths = ["lib"]
|
|
16
|
+
s.required_ruby_version = "~>1.8"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
20
|
+
pkg.gem_spec = spec
|
|
21
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include <node.h>
|
|
3
|
+
#include <env.h>
|
|
4
|
+
|
|
5
|
+
extern rb_thread_t rb_main_thread, rb_curr_thread;
|
|
6
|
+
extern struct FRAME * ruby_frame;
|
|
7
|
+
|
|
8
|
+
static rb_thread_t find_thread(VALUE thread)
|
|
9
|
+
{
|
|
10
|
+
rb_thread_t t = rb_main_thread;
|
|
11
|
+
do {
|
|
12
|
+
if (t->thread == thread) return t;
|
|
13
|
+
|
|
14
|
+
t = t->next;
|
|
15
|
+
} while (t != rb_main_thread);
|
|
16
|
+
|
|
17
|
+
// todo: raise exception
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static void * convert_pointer(rb_thread_t thread, void * ptr)
|
|
22
|
+
{
|
|
23
|
+
VALUE *p = (VALUE*)ptr;
|
|
24
|
+
|
|
25
|
+
if(thread == rb_curr_thread) return ptr;
|
|
26
|
+
|
|
27
|
+
if(p >= thread->stk_pos && p <= thread->stk_pos + thread->stk_len)
|
|
28
|
+
return (p - thread->stk_pos) + thread->stk_ptr;
|
|
29
|
+
|
|
30
|
+
return p;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static VALUE thread_backtrace(VALUE self)
|
|
34
|
+
{
|
|
35
|
+
rb_thread_t t = find_thread(self);
|
|
36
|
+
struct FRAME *frame, *prev_frame;
|
|
37
|
+
char buf[BUFSIZ];
|
|
38
|
+
VALUE ary;
|
|
39
|
+
NODE *n;
|
|
40
|
+
|
|
41
|
+
if (t == rb_curr_thread) {
|
|
42
|
+
frame = ruby_frame;
|
|
43
|
+
} else {
|
|
44
|
+
frame = convert_pointer(t, t->frame);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
ary = rb_ary_new();
|
|
48
|
+
if (frame->last_func == ID_ALLOCATOR) {
|
|
49
|
+
frame = convert_pointer(t, frame->prev);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (; frame && (n = frame->node); frame = prev_frame) {
|
|
53
|
+
prev_frame = convert_pointer(t, frame->prev);
|
|
54
|
+
|
|
55
|
+
if (prev_frame && prev_frame->last_func) {
|
|
56
|
+
if (prev_frame->node == n) {
|
|
57
|
+
if (prev_frame->last_func == frame->last_func) continue;
|
|
58
|
+
}
|
|
59
|
+
snprintf(buf, BUFSIZ, "%s:%d:in `%s'", n->nd_file, nd_line(n), rb_id2name(prev_frame->last_func));
|
|
60
|
+
} else {
|
|
61
|
+
snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n));
|
|
62
|
+
}
|
|
63
|
+
rb_ary_push(ary, rb_str_new2(buf));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return ary;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void Init_thread_backtrace()
|
|
70
|
+
{
|
|
71
|
+
VALUE cThread = rb_define_class("Thread", rb_cObject);
|
|
72
|
+
rb_define_method(cThread, "backtrace", thread_backtrace, 0);
|
|
73
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: thread_backtrace
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: "0.1"
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors: []
|
|
7
|
+
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2010-02-16 00:00:00 +03:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: Adds Thread#backtrace for inspecting bactrace of a thread. Only works on 1.8
|
|
17
|
+
email:
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions:
|
|
21
|
+
- ext/thread_backtrace/extconf.rb
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- README.markdown
|
|
24
|
+
files:
|
|
25
|
+
- README.markdown
|
|
26
|
+
- Rakefile
|
|
27
|
+
- ext/thread_backtrace/extconf.rb
|
|
28
|
+
- ext/thread_backtrace/thread_backtrace.c
|
|
29
|
+
- lib/thread_backtrace.rb
|
|
30
|
+
has_rdoc: true
|
|
31
|
+
homepage:
|
|
32
|
+
licenses: []
|
|
33
|
+
|
|
34
|
+
post_install_message:
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
|
|
37
|
+
require_paths:
|
|
38
|
+
- lib
|
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ~>
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: "1.8"
|
|
44
|
+
version:
|
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: "0"
|
|
50
|
+
version:
|
|
51
|
+
requirements: []
|
|
52
|
+
|
|
53
|
+
rubyforge_project:
|
|
54
|
+
rubygems_version: 1.3.5
|
|
55
|
+
signing_key:
|
|
56
|
+
specification_version: 3
|
|
57
|
+
summary: Adds Thread#backtrace
|
|
58
|
+
test_files: []
|
|
59
|
+
|