I'm trying to update a tool we've developed here at Rapleaf for observing what the threads in your app are up to (thread-dump). One of the limitations of thread-dump is that it can only produce the file, function and line for each thread, rather than the entire stack trace. It would be extremely handy in a lot of circumstances to know not just where the thread ended up but how it got there.
I have attempted to traverse each thread's frame list. It seems like this should be the ticket. However, I've found that in practice the process is ridiculously unstable when I try this approach. Almost immediately, I see bus errors or segmentation faults.
Is there some reason that it is impossible to traverse another thread's frames (and nodes, etc)? I've really been banging my head against this one. Admittedly, I'm not a C ninja, so I could use any pointers you've got. If there's an alternate approach that would make this easier, I'm all ears.
code (forgive the printf debugging statements):
static VALUE backtrace(rb_thread_t th)
{
char buf[BUFSIZ];
char buf2[BUFSIZ];
char otherbuf[BUFSIZ];
VALUE ary;
NODE *n;
struct FRAME *frame;
n = th->node;
frame = th->frame;
ary = rb_ary_new();
rb_ary_push(ary, rb_obj_id(th->thread));
if (n) {
snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n));
printf("Actual line: %s:%d\n", n->nd_file, nd_line(n));
rb_ary_push(ary, rb_str_new2(buf));
}
while(frame->prev){
if(frame->prev->last_func){
if(strcmp(rb_id2name(frame->prev->last_func), "(null)") == 0){
printf("func name was (null)\n");
}
else{
printf("parent: %s\n", rb_id2name(frame->prev->last_func));
}
}
else{
printf("parent had no last func\n");
}
if(frame->prev->node){
if(nd_line(frame->prev->node)){
printf("parent line: %d\n", nd_line(frame->prev->node));
if(frame->prev->node->nd_file){
strcpy(frame->prev->node->nd_file, otherbuf);
printf("parent file: %s\n", otherbuf);
snprintf(buf2, BUFSIZ, "from %s:%d in %s", otherbuf, nd_line(frame->prev->node), rb_id2name(frame->prev->last_func));
rb_ary_push(ary, rb_str_new2(buf2));
}
}
else{
printf("parent has no line\n");
}
}
else{
printf("parent has no node\n");
}
frame = frame->prev;
}
return ary;
}