2009-08-21 1 views
6

En C sur Solaris 10, je voudrais obtenir la pile d'appels à partir d'un thread arbitraire dans un processus.Récupérer la pile d'appel de n'importe quel thread à l'intérieur de C

J'ai beaucoup de threads de travail et un thread qui les surveille tous pour détecter les boucles serrées et les blocages. La fonction que je voudrais implémenter consiste à ce que le thread de surveillance imprime la pile d'appels à partir du thread «bloqué» plusieurs fois avant de le tuer.

Je sais implémenter cela en faisant exécuter par le thread de surveillance pstack (avec system() ou en forking). Mais j'aimerais pouvoir implémenter cette fonction en C. Y at-il un moyen de le faire? Je sais comment faire un thread imprimer sa propre pile d'appels, en marchant la pile, ce qui est utile si elle frappe un assert, mais pas comment le faire pour un autre thread dans le même processus.

Merci pour toute aide. NickB

Répondre

3

Si vous utilisez gcc, vous pouvez utiliser la fonction intégrée __builtin_return_address. void * __builtin_return_address (niveau int non signé)

La fonction renvoie l'adresse de la fonction à partir de laquelle la fonction est appelée. c'est l'appelant de la fonction.

Le niveau spécifie le nombre de niveaux. 0 signifie que la fonction actuelle 1 signifie appelant, 2 signifie appelant appelant. L'exemple suivant fournira l'utilisation. En imprimant les adresses de la fonction, la pile d'appels peut être déterminée.

int calla() 
{ 
    printf("Inside calla\n"); 
    printf("A1=%x\n",__builtin_return_address (0)); 
    printf("A2=%x\n",__builtin_return_address (1)); 
    printf("A3=%x\n",__builtin_return_address (2)); 
} 
int callb() 
{ 
    printf("Inside callb\n"); 
    calle(); 
    printf("B1=%x\n",__builtin_return_address (0)); 
    printf("B2=%x\n",__builtin_return_address (1)); 
    printf("B3=%x\n",__builtin_return_address (2)); 
} 
int callc() 
{ 
    printf("Inside callc\n"); 
    printf("C1=%x\n",__builtin_return_address (0)); 
    printf("C2=%x\n",__builtin_return_address (1)); 
    printf("C3=%x\n",__builtin_return_address (2)); 
} 
int calld() 
{ 
    printf("Inside calld\n"); 
    printf("D1=%x\n",__builtin_return_address (0)); 
    printf("D2=%x\n",__builtin_return_address (1)); 
    printf("D3=%x\n",__builtin_return_address (2)); 
} 
int calle() 
{ 
    printf("Inside calle\n"); 
    printf("E1=%x\n",__builtin_return_address (0)); 
    printf("E2=%x\n",__builtin_return_address (1)); 
    printf("E3=%x\n",__builtin_return_address (2)); 
} 
main() 
{ 
    printf("Address of main=%x calla=%x callb=%x callc=%x calld=%x calle=%x\n",main,calla,callb,callc,calld,calle); 
    calla(); 
    callb(); 
    calld(); 
} 
+0

Mais comment cela permet-il à un thread d'obtenir la pile d'appels d'un autre thread? – NickB

4

Vous pouvez utiliser walkcontext() marcher la pile, en utilisant dladdr()/dladdr1() pour convertir les adresses noms de fonctions. walkcontext() prend un ucontext pour le fil. Si vous n'avez pas la coopération de ce thread alors vous pouvez obtenir un ucontext pour cela en arrêtant le thread (par exemple avec PCTWSTOP) puis en lisant son adresse du champ pr_oldcontext de la structure lwpstatus pour ce thread, obtenu à partir de /proc/self/lstatus.

Questions connexes