AA_PO-21492-123RF-Hypermania2_123RF-Ampeln_resized.jpg

© Hypermania2, 123RF

Prozesse, hört die Signale!

Signale sind ein wichtiges Linux-Feature

09.10.2013
Programme können unter Linux kommunizieren, indem sie sich "Signale" schicken. Wie das geht und wofür man Signale braucht, verraten wir in diesem Basics-Artikel.

Wenn Sie aus einem Terminalprogramm heraus ein anderes Programm starten, dann schläft die Shell solange, bis dieses Programm beendet ist. Wie kriegt sie mit, dass das andere Programm fertig ist? Linux schickt der Shell ein Signal und macht sie damit darauf aufmerksam, dass ein so genannter Kindprozess beendet wurde.

Das ist nur eines von vielen Anwendungsgebieten für Signale. Aus Benutzersicht sind Ihnen vielleicht die TERM- und KILL-Signale bekannt: Die können Sie mit dem Kommando kill an ein Programm schicken, um es zu beenden. Das KILL-Signal ist dabei das härtere: Es beendet einen Prozess in jedem Fall, egal, in welchem Zustand dieser gerade ist. Im Vergleich ist das TERM-Signal friedlicher und lässt dem Prozess noch die Gelegenheit zum Aufräumen.

Nun war hier abwechselnd von Programmen und Prozessen die Rede – sind das nicht gleichwertige Ausdrücke? Nein, ein Programm ist eine Datei auf der Festplatte, z. B. die Programmdatei firefox des Browsers Firefox. Ein Prozess entsteht erst, wenn Sie dieses Programm in den Speicher laden und starten. Einige Programme darf man auch mehrfach starten, so dass dann mehrere Prozesse laufen, die dasselbe Programm ausführen. Beim Verschicken von Signalen ist es immer wichtig, den richtigen Prozess anzusprechen.

Signalbehandlung

Das Funktionsprinzip von Signalen ist bei allen Unix-artigen Betriebssystemen (also auch bei Linux) gleich: Prozesse (oder auch das Betriebssystem selbst) können Signale an andere Prozesse verschicken. Wenn das passiert, geschieht zunächst wenig: Linux verwaltet für jeden Prozess eine Liste der empfangenen Signale, und wenn Prozess A ein Signal an Prozess B schickt, wird dies im passenden Listeneintrag von Prozess B vermerkt. Wird dieser das nächste Mal aktiv, setzt er nicht seine eigentliche Aufgabe fort. Stattdessen prüft Linux, ob er einen so genannten Signal-Handler für das Signal eingetragen hat. Das ist eine Programmfunktion, die im Normalbetrieb nie aufgerufen wird, sondern nur dann, wenn das zugehörige Signal empfangen wurde. Der Signal-Handler erledigt dann seine Arbeit, z. B. kann ein Signal-Handler für das TERM-Signal (terminate, beenden) dafür sorgen, dass das Programm Inhalte aus dem Speicher noch in eine offene Datei schreibt und diese dann schließt. Bei manchen Programmen öffnet der TERM-Signal-Handler ein Fenster und fragt nach, ob der Anwender das Programm wirklich schließen möchte.

Alternativ zum Einrichten eines Signal-Handlers haben Programme noch zwei weitere Möglichkeiten:

  • Sie können das Signal ignorieren, dann hat (im Beispiel des TERM-Signals) ein empfangenes Signal keine Wirkung mehr. Allerdings lassen sich nicht alle Signale ignorieren, das KILL-Signal z. B. wird immer verarbeitet.
  • Sie können eine Standardaktion ausführen lassen (was auch die Vorgabe ist, wenn ein Programm keinen eigenen Signal-Handler registriert): Um wieder das TERM-Signal als populärstes Beispiel zu verwenden, wird hier ein Programm einfach abgebrochen. Darum kann man fast alle Programme erfolgreich beenden, indem man ihnen ein TERM-Signal schickt.

Signalübersicht

Je nach Linux-Version (bzw. Unix-Version) stehen unterschiedliche Signale zur Verfügung. Eine Liste der bekannten Signale erhalten Sie, indem Sie in einem Terminalfenster den Befehl kill -l eingeben (Abbildung 1). In der Liste beginnt jeder Signalname mit "SIG"; diesen Teil lässt man im Normalfall weg, wenn man von einem Signal spricht. Das Signal SIGTERM (Nummer 15) bezeichnen wir also nur als TERM.

Abbildung 1: Die Liste der bekannten Signale kann auf jedem Linux-System anders aussehen. Wichtig sind nur die Signale mit Nummern unter 32.

Die "interessanten" Signale haben meist eine Nummer unter 32; bei Linux haben alle Signalnummern ab 32 etwas mit Echtzeitverarbeitung zu tun. Die folgenden Signale können Sie auch als Anwender von der Konsole aus verschicken:

  • HUP (1): Das Hang-up-Signal ist klassisch dafür vorgesehen, Prozesse zu beenden, die von einem entfernten Rechner aus gestartet wurden, wobei die Verbindung zwischen den Rechnern nicht mehr besteht. Das passiert auch heute noch so, wenn Sie sich per ssh auf einem anderen Rechner einloggen, dort Programme starten und dann ohne vorherige Abmeldung die Verbindung zum Internet trennen. Nützlicher ist das HUP-Signal aber für Administratoren: Wenn Sie die Konfiguration eines Dienstes (wie z. B. des Apache-Webservers) verändern und dann dem laufenden Apache-Prozess ein HUP-Signal schicken, liest dieser die Konfigurationsdatei neu ein. Das ist besser, als den Serverdienst zu beenden und neu zu starten.
  • TERM (15): Das TERM-Signal ist das Standardsignal, welches das Shell-Programm kill an einen Prozess sendet, wenn Sie keine Signalnummer angeben. Wie schon weiter oben beschrieben, fordert es den Prozess auf, sich zu beenden, erzwingt den Abbruch aber nicht: Wenn der Prozess einen Signal-Handler für TERM eingetragen hat, kann er durchaus weiter arbeiten.
  • KILL (9): Das KILL-Signal ist die agressive Variante des TERM-Signals. Prozesse, die es empfangen, werden rabiat abgebrochen, und sie können dem auch nicht vorbeugen, indem sie einen Signal-Handler installieren: Das geht für das KILL-Signal nicht.
  • STOP (19): Schicken Sie einem Prozess das STOP-Signal, wird er unterbrochen. Vielleicht kennen Sie die Wirkung der Tastenkombination [Strg]+[Z] in einem laufenden Shell-Programm: Diese hat eine ähnliche Funktion. In der Shell können Sie einen mit [Strg]+[Z] unterbrochenen Prozess mit dem Kommando fg (foreground) im "Vordergrund" bzw. mit bg (background) im Hintergrund weiterlaufen lassen. (Hintergrundprozesse blockieren die Shell nicht, so dass dann wieder ein Shell-Prompt erscheint.) Analog können Sie auch einen über das STOP-Signal angehaltenen Prozess wieder weiter laufen lassen:
  • CONT (18): Das CONT-Signal setzt einen Prozess fort, der vorher mit dem STOP-Signal angehalten wurde. Anderenfalls hat es keine Wirkung: Schicken Sie einem laufenden Prozess das CONT-Signal, passiert nichts.

Benutzerdefinierte Signale

Die Signale USR1 und USR2 haben keine festgelegte Bedeutung; sie sind dafür gedacht, dass Programmentwickler eigene Signalmechanismen entwickeln können. So könnten z. B. zwei Prozesse gemeinsam an einer größeren Rechenaufgabe arbeiten und sich gegenseitig regelmäßig Signale zuschicken, wenn sie eine Teilaufgabe abgearbeitet haben.

Ein echter Inhalt (im Sinne einer angehängten Nachricht) lässt sich auf diese Weise aber nicht übermitteln. Jedes Signal (wie KILL, TERM, SIG1 oder SIG2) hat intern eine Signalnummer, und diese Nummer ist alles, was an den Prozess übermittelt wird, wenn ein anderer Prozess das Signal schickt.

Auch wer das Signal geschickt hat, kann der empfangende Prozess nicht herausfinden, damit ist die Signalübertragung fehleranfällig, wenn man sie als Kommunikationsweg zwischen zwei Prozessen einsetzt: Ein dritter Prozess könnte absichtlich oder versehentlich Signale an eines der beiden kommunizierenden Programme schicken und dieses damit durcheinander bringen. Für echte Nachrichten nutzen Anwendungen darum andere Mechanismen, z. B. Pipes oder lokale Netzwerkverbindungen.

Signale vom Kernel

Einige Signale schickt das Betriebssystem selbständig: Dann gibt es keinen anderen Prozess als Absender. Viele der Standardsignale verschickt der Kernel, weil er festgestellt hat, dass ein Fehler aufgetreten ist:

  • HUP (1): Wie schon weiter oben beschrieben, schickt der Kernel Prozessen, die ihr Terminal verloren haben, ein HUP-Signal (Hang-up). Das passiert nicht nur, wenn Sie remote auf einer anderen Maschine arbeiten und die Verbindung abbricht, sondern auch, wenn Sie z. B. ein Terminalfenster über die X-Schaltfläche im Fensterrahmen schließen.
  • SEGV (11): Die Abkürzung steht für den historischen Begriff "Segmentation Violation", auch "Segmentation Fault" oder kurz "Segfault" genannt. Ein solcher Fehler tritt auf, wenn ein Programm versucht, auf Bereiche des Hauptspeichers zuzugreifen, die es entweder nicht gibt und für welche die nötigen Zugriffsrechte fehlen. Theoretisch könnte ein Prozess z. B. versuchen, Teile des Kernel-Speichers zu lesen oder zu verändern – praktisch ist das durch eine entsprechende Konfiguration der Speicherverwaltung verboten, und beim Versuch löst der Kernel einen Segfault aus. Das Signal kann ein Prozess durch einen geeigneten Signal-Handler abfangen, allerdings nicht viel damit anfangen, außer eine Fehlermeldung auszugeben und das Programm dann doch zu beenden.
  • ALRM (14): Programme können einen Timer registrieren, der nach einer vorgegebenen Zeit automatisch ein Signal an den Prozess schickt. Damit lassen sich programminterne Abläufe präzise zeitlich steuern, ohne dass das Programm ständig prüfen muss, ob eine bestimmte Wartezeit bereits verstrichen ist. Damit das Alarmsignal sinnvoll ist, muss das Programm einen ALRM-Handler eintragen.
  • CHLD (17): Das war das Beispiel am Anfang des Artikels: Wenn ein Prozess Kindprozesse hat (z. B. ist jedes Programm, das Sie aus einer Shell heraus starten, ein Kindprozess dieser Shell), dann führt das Beenden eines dieser Kindprozesse dazu, dass der Kernel dem Vaterprozess das CHLD-Signal (Child, Kind) schickt. Der Vater hat dann die Möglichkeit, den Programmende-Status des beendeten Prozesses abzufragen. Auf die Weise findet die Shell z. B. heraus, dass ein gestartetes Programm beendet wurde, und sie erfährt auch, ob es fehlerfrei oder nicht gelaufen ist.

Gut zu wissen

Die meisten Signale sind nur für Programmierer von Interesse, einige wenige (wie HUP, TERM, KILL) können Sie aber auch praktisch einsetzen. Um einem Prozess ein Signal zu schicken, benötigen Sie dessen Prozess-ID: Die können Sie über pidof Programmname herausfinden und dann mit kill -Signalname PID (z. B. kill -KILL 123) das Signal an den Prozess schicken. Läuft nur ein einziger Prozess mit einem bestimmten Namen, geht es auch schneller mit killall -Signalname Progname, z. B. killall -TERM firefox. Mehr dazu finden Sie in einem älteren Artikel im EasyLinux-Archiv [1].

Infos

[1] Praxisartikel zu "kill": Hans-Georg Eßer, "Prozesse im Griff", EasyLinux 04/2008, S. 122 ff., http://www.easylinux.de/2008/04/122-guru/

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 

Ähnliche Artikel

Kommentare