Linux-Anwendungsentwicklung und Signalverarbeitung

Linux-Anwendungsentwicklung und Signalverarbeitung

Derzeit habe ich Probleme mit Benutzern, die sich über die Beendigung meiner Anwendung beschweren. Unter bestimmten (scheinbar willkürlichen) Bedingungen und Desktop-Umgebungen wird die App nicht beendet und die Einstellungen werden beim Neustart nicht gespeichert. Ich habe in den entsprechenden IRC-Kanälen nachgefragt und meistens wird mir gesagt, dass ich Signale richtig behandeln soll. Ich kenne SIGINT für Strg-C im Terminal und SIGTERM für die „normale“ Beendigung. Mir wurde aber gesagt, dass SIGHUP auch wichtig ist. Meine Frage lautet also:

Welche Signale muss ich verarbeiten, um eine gut funktionierende Anwendung zu erstellen?

Antwort1

https://en.wikipedia.org/wiki/Unix_signal

hat eine Liste mit Standardsignalen und deren Standardaktionen. Jeder Prozess mit ausreichenden Privilegien kann Ihnen jederzeit jedes Signal senden, aber Prozesse (oder Sie über Prozesse) sollten dies nicht tun.

Sie sollten nur killmit und erwarten, dass Ihre Prozesse killmitBEGRIFFund eine Reihe von Signalen, die von Ihrer Umgebung (der Shell, dem Terminaltreiber) generiert werden können, sofern Sie nicht wissen, dass das Ziel das spezielle Signal verarbeitet, das Sie senden möchten.

Sie können die Basissignale nach ihren Aktionen sortieren.

Die Coredumping-Signale

ABRT TRAP SYS BUS FPE ILL SEGV   XFSZ XCPU QUIT

werden entweder von Ihnen (TRAP, ABRT, SYS) unter Verwendung einiger spezieller Funktionen oder dadurch erzeugt, dass Sie in schwerwiegende Fehlerzustände geraten (BUS, FPE, ILL, SEGV). QUITwird von einem Benutzer an einem Terminal erzeugt, der einen Core Dump () wünscht C+\.

Möglicherweise möchten Sie die Standardeinstellungen beibehalten.

Aus demAbschlusssignale:

HUP INT PIPE TERM ALRM POLL PROF USR1 USR2

Sie sollten erwarten

HUP INT PIPE TERM

aus Ihrer Umgebung unter verschiedenen Umständen:

HUP -- when the terminal hungs up or you become a stopped orphaned process
INT -- when the user at the terminal interrupts you with C-c
PIPE -- when a PIPE or socket you write into closes, e.g. by
        exiting before you finished writing to it 
       (`yourprogram | (exit)` will give you a `PIPE` 
        if yourprogram attempts to write to its STDOUT) 
TERM -- when a process ends you a normal termination request

Die restlichen Abschlusssignale sollten Sie nur erhalten, wenn Sie diese selbst eingerichtet haben.

TÖTENUndSTOPPENSie können nichts dagegen tun.

Möglicherweise möchten Sie das vom Terminal generierteStoppsignale:

TTIN -- you read from the terminal and you're a backgrounded process
TTOU -- you write the terminal when you're a backgrounded process
        and the terminal is set to put you to sleep when you do
TSTP -- you're being put to sleep with `C-Z`

Im schlimmsten Fall stoppen diese jedoch nur Ihren Prozess, ohne Ihren Status zu beschädigen.

CHLDSofern Sie nicht sicher sind, dass Sie , CONT, oder verarbeiten müssen URG, tun Sie es nicht.

Kurz zusammengefasst:

Grundsätzlich denke ich, dass HUP, INT, PIPE und TERM behandelt (oder ignoriert) werden sollten, wenn Sie normalerweise vor dem Beenden eine Bereinigung durchführen möchten. Der Rest kann unverändert bleiben, es sei denn, Ihr Programm verwendet diese Signale oder Sie müssen unter allen Umständen unbedingt eine Bereinigung durchführen.

Im letzteren Fall können Sie alle nicht verarbeiteten Signale einfach blockieren. Beachten Sie jedoch, dass Signalblockierungsmasken über Forks und Execve-Aufrufe hinweg übernommen werden. Das Ignorieren oder Blockieren von Signalen wie ILL, die während der Ausführung Ihres Prozesses entstanden und Ihnen nicht per Kill oder Sigqueue gesendet wurden, führt zu undefiniertem Verhalten.

Wenn Sie tiefer in die Materie einsteigen möchten, sehen Sie sich die Manpages und Standards an. Signale sind ein ziemlich großes Thema unter Unix-Systemen und ihre Handhabung kann sehr knifflig sein.

Antwort2

Wenn Sie diesen Weg gehen, werden Sie wahrscheinlich eine ganze Reihe von Signalen ignorieren, einfach weil eines davon Ihr Programm beendet. Wie siblynx in einem Kommentar vorgeschlagen hat, wäre es am besten, diese Signale zu analysieren und herauszufinden, woher sie kommen. Schließlich könnte es einen guten Grund dafür geben, dass Ihr Programm beendet wird.

Nachdem Sie das gesagt haben, können Sie einen Blick darauf werfensignals(7)um eine Liste der Signale zu erhalten, die zu einer Prozessbeendigung führen können:

SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1 und SIGUSR2.

Wenn Ihre Anwendung einige Zeit an einem Terminal hängt, SIGINTist die Handhabung eine gute Idee ( Ctrl+ Cist schließlich ziemlich berühmt). SIGTERMist auch eine gute Idee, weil es das grundlegende Beendigungssignal bleibt und vom Kernel verwendet wird (beispielsweise beim Herunterfahren des Systems). SIGQUITist wahrscheinlich die „härtere“ Version der beiden vorherigen, da es einen Core Dump verursacht. Wenn Sie dieses erhalten, sollten Sie wahrscheinlich damit rechnen, dass Ihr Programm sofort abstürzt. Wenn Sie eines der anderen erhalten, sollten Sie von Ihrem Programm erwarten, dass es „sein Chaos aufräumt und geht“ (Einstellungen speichert, ordnungsgemäß beendet wird).

SIGILL, SIGFPE, SIGSEGVund SIGPIPEsind Signale, die auf Fehlverhalten des Programms hinweisen.Segmentierungsfehlerist wahrscheinlich die am häufigsten auftretende Situation, aber letztendlich können alle diese Fälle als Fehler behandelt werden, und ich glaube nicht, dass das Abfangen des Signals der beste Weg ist, diese Situationen zu beheben.

  • Meistens lassen Compiler das nicht SIGILLso einfach zu (mehr hier), also denke ich, dass Sie das beiseite legen können.
  • Achten Sie darauf, niemals durch Null zu dividieren, dann vermeiden Sie die meisten SIGFPEs. Ansonsten achten Sie nur darauf, dass Ihr Programm gut in Mathe ist und nicht mit den Zahlen übertreibt.
  • SIGSEGVkann verschiedene Ursachen haben (unzulässiger Speicherzugriff, unzulässige Derefencing). In diesem Fall würde ich vorschlagen, Ihr Programm während der Ausführung zu überwachen und den fehlerhaften Befehl mithilfe des Stacks gdbzurückzuverfolgen .gdb
  • Schließlich SIGPIPEbezieht sich hauptsächlich auf Datenströme (Lesen von Dateien, Verbindungen, ...). Wenn die Wahrscheinlichkeit besteht, dass einer Ihrer Programm-E/A-Streams während der Ausführung beendet wird, sollten Sie sicherstellen, dass Ihr Programm seine Deskriptoren vor der Verwendung überprüft und alle darin auftretenden E/A-Ereignisse verarbeitet ( beispielsweise bei der Verwendung von selectoder ). könnte hier ebenfalls nützlich sein.pollgdb

SIGABRT, SIGALRM, SIGUSR1und SIGUSR2sind im Grunde Benutzersignale. Wenn Sie sie empfangen, ist die Wahrscheinlichkeit groß, dass Sie dafür gesorgt haben.

Damit bleiben uns SIGHUPund übrig SIGKILL, die möglicherweise nicht abgefangen werden.

  • SIGHUPtritt beispielsweise auf, wenn Sie den Prozess von einem Terminal aus starten und dieses Terminal anschließend schließen, ohne den Prozess abzukoppeln ( disownoder mit nohup). Wenn Ihr Programm vom Terminal aus gestartet wird und als Daemon läuft, vergessen Sie nicht, es von der Shell abzukoppeln, beispielsweise durch Double-Forking. Dieses spezielle Signal ist weniger relevant, wenn Ihr Programm von einer GUI aus oder beim Booten gestartet werden kann, da das steuernde Terminal dann weniger wahrscheinlich „geschlossen“ wird.

  • SIGKILList, wie Sie wissen, das Allmächtige aller Signale. Es ist die Art und Weise des Kernels, „Scheiße!“ zu sagen. Wenn Sie das empfangen, sollten Sie Ihre Aufmerksamkeit auf das richten, was das Signal aussendet, und nicht darauf, wie Sie es in Ihrem Programm handhaben.

Letztendlich ist die Signalanalyse und die Verwendung von Debugging-Tools wahrscheinlich die einfachste Lösung für diese Probleme. Wenn der Kernel ein Signal auslöst, wenn sich Ihr Programm schlecht verhält, gdbsollte Ihnen dies dabei helfen, das Problem zu lokalisieren. Vergessen Sie in diesem Fall das Signal und konzentrieren Sie sich auf den Fehler, den es Ihnen meldet.

Wenn das Signal von „außen“ kommt, ist die Suche nach dem Sender wahrscheinlich die beste Vorgehensweise(wenn Sie es wirklich nicht finden können,RückverfolgungDiekill(2)Systemaufruf könnte ein guter letzter Ausweg sein). Dann können Sie entscheiden, ob Sie es ignorieren ( SIG_IGN) oder berücksichtigen möchten. Das Stummschalten des aussendenden Programms kann auch eine gute Alternative sein...

verwandte Informationen