B
Bryan Duxbury
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;
}
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;
}