2009-08-21 5 views
6

In C unter Solaris 10 möchte ich den Aufrufstapel von einem beliebigen Thread innerhalb eines Prozesses abrufen.Rufen Sie Aufrufstapel von beliebigem Thread innerhalb C

Ich habe viele Worker-Threads und einen Thread, der sie alle überwacht, um enge Schleifen und Deadlocks zu erkennen. Die Funktion, die ich implementieren möchte, besteht darin, dass der Überwachungs-Thread den Aufruf-Stack mehrere Male aus dem "aufgehängten" Thread druckt, bevor er ihn tötet.

Ich weiß, wie dies implementiert werden, indem der Überwachungsthread pstack ausführen (mit System() oder durch Gabelung). Aber ich würde gerne in der Lage sein, diese Funktion in C zu implementieren. Gibt es eine Möglichkeit, dies zu tun?

Ich weiß, wie man einen Thread seinen OWN Call Stack drucken lässt, indem er den Stack durchläuft, was nützlich ist, wenn er eine Assert trifft, aber nicht wie man dies für einen anderen Thread innerhalb desselben Prozesses tut.

Danke für jede Hilfe. NickB

Antwort

3

Wenn Sie gcc verwenden, können Sie die integrierte Funktion __builtin_return_address verwenden. void * __butintin_return_address (vorzeichenlose int-Ebene)

Die Funktion gibt die Adresse der Funktion zurück, von der die Funktion aufgerufen wird. d. h. der Aufrufer der Funktion.

Die Ebene gibt an, wie viele Ebenen. 0 bedeutet, aktuelle Funktion 1 bedeutet Anrufer, 2 bedeutet Anrufer Anrufer. Das folgende Beispiel bietet die Verwendung. Durch Drucken der Adressen der Funktion kann der Aufrufstapel bestimmt werden.

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

Aber wie ermöglicht das einem Thread, den Aufrufstapel von einem anderen Thread zu erhalten? – NickB

4

können Sie walkcontext() verwenden den Stapel zu gehen, dladdr()/dladdr1() mit den Adressen zu konvertieren Namen zu funktionieren. walkcontext() nimmt eine ucontext für den Thread. Wenn Sie nicht die Zusammenarbeit dieses Threads haben, können Sie einen Ucontext dafür erhalten, indem Sie den Thread (z. B. mit PCTWSTOP) stoppen und dann seine Adresse aus dem Feld der lwpstatus-Struktur für diesen Thread, erhalten von /proc/self/lstatus, lesen.