Kann ein C-Programm die Ausführung fortsetzen, nachdem ein Signal bearbeitet wurde?

8

Ich bin neu in der Signalverarbeitung in Unix durch C und habe mir (aus reinem Interesse) einige Tutorials angeschaut.

Meine Frage ist, ist es möglich, die Ausführung eines Programms nach dem Punkt fortzusetzen, an dem ein Signal bearbeitet wird?

Ich verstehe, dass die Signal-Handling-Funktion die Bereinigung durchführt, aber im Geiste der Ausnahmebehandlung (wie in C ++), ist es möglich, dass dieses Signal auf dieselbe Weise behandelt wird und das Programm normal weiterläuft?

Momentan geht catch in eine Endlosschleife (vermutlich wäre es eine Art zu beenden, exit(1) aufzurufen).

Meine Absicht wäre, dass b 1 zugewiesen wird und das Programm ordnungsgemäß beendet wird (wenn das natürlich möglich ist).

Hier ist mein Code:

%Vor%

Wie ist der prozedurale C-Prozess, wie wird der Signal-Handler, der vor der beanstandeten Anweisung deklariert wurde, tatsächlich aufgerufen, nachdem dieser ausgeführt wurde?

Und schließlich müssen alle Variablen, die im Falle einer Ausnahme bereinigt werden müssen, vor der Funktion deklariert werden, damit die Bereinigungsfunktion ordnungsgemäß aufgeräumt werden kann, oder?

Vielen Dank im Voraus für Ihre Antworten und Entschuldigungen, wenn einige der oben genannten sehr offensichtlich ist.

    
Nobilis 09.01.2013, 10:44
quelle

3 Antworten

9

Ja, dafür sind Signalhandler zuständig. Einige Signale müssen jedoch speziell behandelt werden, damit das Programm fortgesetzt werden kann (z. B. SIGSEGV, SIGFPE, ...).

Siehe Man Signaction:

  

Laut POSIX ist das Verhalten eines Prozesses nicht definiert, nachdem es ein SIGFPE-, SIGILL- oder SIGSEGV-Signal ignoriert hat   generiert durch Kill (2) oder Raise (3). Ganzzahlige Division durch Null hat ein undefiniertes Ergebnis. Auf einigen Architekturen erzeugt es ein   SIGFPE-Signal. (Auch die Division der negativsten ganzen Zahl durch -1 kann SIGFPE erzeugen.) Das Ignorieren dieses Signals könnte zu einem          Endlosschleife.

Im Moment ignorieren Sie das Signal, indem Sie nichts tun, um zu verhindern, dass es (wieder) passiert. Sie benötigen den Ausführungskontext im Signal-Handler und reparieren ihn manuell, indem Sie einige Register überschreiben.

  

Wenn SA_SIGINFO in sa_flags angegeben ist, wird sa_sigaction (statt   sa_handler) gibt die Signalverarbeitungsfunktion für signum an. Dies   Funktion empfängt die Signalnummer als erstes Argument, einen Zeiger   zu einem siginfo_t als zweites Argument und einem Zeiger zu einem ucontext_t   (cast to void *) als drittes Argument. (Allgemein, der Handler   Funktion verwendet das dritte Argument nicht. Sehen   getcontext (2) für weitere Informationen über ucontext_t.)

Der Kontext ermöglicht den Zugriff auf die Register zum Zeitpunkt des Fehlers und muss geändert werden, damit das Programm fortgesetzt werden kann. Siehe lkml-Post . Wie bereits erwähnt, könnte siglongjmp auch eine Option sein. Der Post bietet auch eine eher wiederverwendbare Lösung für die Behandlung des Fehlers, ohne Variablen global zu machen usw.:

  

Und weil Sie selbst damit umgehen, haben Sie jede Flexibilität, die Sie wollen   mit Fehlerbehandlung. Zum Beispiel können Sie den Fehlerbehandler erstellen   Springen Sie zu einem bestimmten Punkt in Ihrer Funktion mit etwas wie   das:

%Vor%
  

Dann muss Ihr Handler für SIGFPE nur etwas wie

tun      

context.eip = context.ecx;

    
Jonas Wielicki 09.01.2013, 11:10
quelle
5

Im Allgemeinen, ja, die Ausführung wird fortgesetzt, nachdem der Handler zurückkehrt. Wenn das Signal jedoch durch einen Hardwarefehler (wie eine Gleitkommaausnahme oder einen Segmentierungsfehler) verursacht wurde, haben Sie keine Möglichkeit, diesen Fehler rückgängig zu machen, und Ihr Programm wird unabhängig davon beendet.

Mit anderen Worten, Sie müssen zwischen Signalen und Dingen, die Signale verursachen, unterscheiden. Signale selbst sind vollkommen in Ordnung und handhabbar, aber sie können nicht immer Fehler beheben, die Signale verursachen .

(Einige Signale sind speziell, wie zB ABRT und STOP, in dem Sinne, dass man selbst wenn man ein solches Signal mit kill manuell anhebt, die Effekte nicht "verhindern" kann überhaupt behandelt werden.)

    
Kerrek SB 09.01.2013 10:50
quelle
4

Wenn Sie wissen, was Sie tun, können Sie den Anweisungszeiger so einstellen, dass er direkt nach der fehlerhaften Anweisung zeigt. Unten ist mein Beispiel für x86 (32bit und 64bit). Versuche nicht zu Hause oder in echten Produkten !!!

%Vor%     
Alexey Polonsky 11.05.2015 13:51
quelle

Tags und Links