2013-02-27 2 views
6

Ich versuche zu verstehen, ob getcontext/setcontext in einem bestimmten Szenario korrekt funktioniert.den Stack mit getcontext/setcontext hoch/runter schalten

Ich kann sehen, wie Setcontext() verwendet werden kann, um den Stapel zu einem bestimmten Ort in der Geschichte zurück zu wickeln.

Aber ich fragte mich, ob Sie nach einer Pause wieder zu einem Ort zurückkehren können, der in der Zukunft war? Ich nehme an, das hängt davon ab, getcontext() Aufruf erfasst eine Kopie des Stapels und ich kann nicht die genauen Details in der Dokumentation finden.

#include <stdio.h> 
#include <ucontext.h> 

int rollback  = 0; 
int backToFuture = 0; 
ucontext_t context; 
ucontext_t futureContext; 

void func(void) 
{ 
    // Some complex calc 
    if (some-condition) 
    { 
     getcontext(&futureContext); // After returning I want to come back 
            // here to carry on with my work. 
     if (backToFuture == 0) 
     { 
      setcontext(&context); // rewind to get stuff-done 
     } 
    } 
    // Finishe work 
} 

int main(void) 
{ 
    getcontext(&context); 
    if (rollback == 0) 
    { 
     printf("getcontext has been called\n"); 
     rollback++; 
     func(); 

     // eventually always return here. 
    } 
    else 
    { 
     printf("setcontext has been called\n"); 
     // Do specialized work that needed to be done 
     // May involve function calls. 
     // 
     // I worry that anything the adds new stack frames 
     // will disrupt the saved state of futureContext 
     // 
     // But without detailed information I can not be sure 
     // if this is an allowed senario. 
     backToFuture = 1; 
     setcontext(&futureContext); 
    } 
} 

Antwort

4

getcontext kopiert nicht Stapel, es Dumps nur Register (einschließlich Stapelzeiger) und ein wenig Kontextdaten wie Signalmaske usw.

Wenn Sie den Stapel den oberen Kontext ungültig abspringen. Selbst wenn Sie keine Funktion ausführen, denken Sie an den Signal-Handler, der dort ausgeführt werden kann. Wenn Sie zwischen zwei Stapeln springen wollen, müssen Sie makecontext.

Ich habe Variable, die zeigt, dass der Code ungültig ist:

void func(void) 
{ 
    // Some complex calc 
    if (1) 
    { 
     volatile int neverChange = 1; 
     getcontext(&futureContext); // After returning I want to come back 
            // here to carry on with my work. 
     printf("neverchange = %d\n", neverChange); 
     if (backToFuture == 0) 
     { 
      setcontext(&context); // rewind to get stuff-done 
     } 
    } 
    // Finishe work 
} 

Auf meinem Rechner es in Ergebnisse:

getcontext has been called 
neverchange = 1 
setcontext has been called 
neverchange = 32767 
+0

Können Sie die richtige Version des Codes in Ihrem Beitrag liefern mit 'makecontext '? Um genau zu sein, würde ich gerne einen Funktionsaufruf in einem Signal-Handler erstellen (der ausgeführt werden sollte, nachdem der Handler zurückkehrt). Ich möchte auch, dass der Stapel abrollt (werfen/fangen), um richtig zu funktionieren, wenn ich diese neu erstellte Funktion einwerfe und versuche, den äußeren ursprünglichen Kontext zu erfassen. Dies erfordert das Erstellen eines dynamischen Funktionsaufrufs (Stapelrahmenerstellung), nehme ich an. Ich bin mir nicht sicher, ob das mit setcontext möglich ist oder nicht (uc_link in ucontext_t?). – Etherealone

+0

Ich habe es geschafft, macekontext für diesen neu erstellten Funktionsaufruf zu verwenden, aber das Setzen von uc_link auf den letzten Parameter von signal_handler (ucontext_t) kehrt nicht korrekt zum alten Kontext zurück, nachdem der neue Funktionsaufruf ausgeführt wurde. (P.S. Das Ziel des Stackabwickelns in meinem vorherigen Kommentar ist, dass ich einen beleidigenden Vorgang sauber abbrechen möchte, der ein Signal erzeugt, das nicht katastrophal ist). – Etherealone

+0

@Etherealone, ich denke, das ist zu kompliziert für diesen Kommentar-Thread, aber fühlen Sie sich frei, mich mit einer Frage zu verknüpfen, sollten Sie eine erstellen. – zch