signal - Überblick über Signale (Software-Interrupts)
Linux unterstützt sowohl nach POSIX zuverlässige Signale (im
Folgenden: »Standard-Signale«) und POSIX-Echtzeit-Signale.
Jedes Signal hat eine aktuelle
Zuordnung. Sie legt fest, wie sich der
Prozess verhält, wenn er das Signal erhält.
Die Einträge in der »Aktion«-Spalte in der folgenden
Tabelle legen die Standardzuordnung für jedes Signal fest:
- Term
- Standardaktion ist der Abbruch des Prozesses.
- Ign
- Standardaktion ist, das Signal zu ignorieren.
- Core
- Die Standardaktion ist der Abbruch des Prozesses und das
Erstellen eines Speicherauszugs (siehe core(5)).
- Stop
- Die Standardaktion ist, den Prozess anzuhalten.
- Cont
- Die Standardaktion ist, einen angehaltenen Prozess
fortzusetzen.
Ein Prozess kann die Zuordnung eines Signals mit Hilfe von
sigaction(2)
oder
signal(2) ändern. (Letzteres ist schlechter portierbar bei
der Realisierung von Signal-Handlern; siehe
signal(2) für
Details.) Mit diesen Systemaufrufen kann ein Prozess eine der folgenden
Verhaltensweisen bei Erhalt eines Signals auswählen: die Standardaktion
ausführen, das Signal ignorieren oder das Signal mit einem
Signal-Handler abfangen. Ein Signal-Handler ist eine vom Programmierer
definierte Funktion. Sie wird automatisch aufgerufen, wenn das Signal
eintrifft.
Standardmäßig wird ein Signal-Handler auf dem normalen
Prozess-Stack aufgerufen. Man kann es einrichten, dass der Signal-Handler
einen alternativen Stack benutzt; vgl.
sigaltstack(2) für eine
Erörterung, wie das gemacht wird und wann es nützlich sein
könnte.
Die Signalzuordnung ist ein prozessbezogenes Attribut; in einer
Multithread-Anwendung ist die Zuordnung eines bestimmten Signales für
alle Threads gleich.
Ein mittels
fork(2) erstellter Kindprozess erbt eine Kopie der
Signalzuordnungen seines Elternprozesses. Während eines
execve(2) werden die Zuordnungen von verwalteten Signalen auf die
Vorgabe zurückgesetzt; die Zuordnung ignorierter Signale werden
unverändert gelassen.
Die folgenden Systemaufrufe und Bibliotheksfunktionen ermöglichen dem
aufrufenden Programm den Versand eines Signals:
-
raise(3)
- sendet dem aufrufenden Thread ein Signal
-
kill(2)
- sendet ein Signal an einen bestimmten Prozess, alle
Mitglieder einer bestimmten Prozessgruppe oder an alle Prozesse im
System
-
pidfd_send_signal(2)
- sendet ein Signal an einen Prozess, der durch einen
PID-Dateideskriptor identifiziert ist.
-
killpg(3)
- sendet ein Signal an alle Mitglieder einer bestimmten
Prozessgruppe
-
pthread_kill(3)
- sendet ein Signal an einen bestimmten POSIX-Thread im
gleichen Prozess wie die aufrufende Routine
-
tgkill(2)
- Es wird ein Signal an einen bestimmten Thread in einem
bestimmten Prozess gesendet. (Mit diesem Systemaufruf wird
pthread_kill(3) realisiert.)
-
sigqueue(3)
- sendet ein Echtzeit-Signal und zugehörige Daten an
einen bestimmten Prozess
Die folgenden Systemaufrufe setzen die Ausführung des aufrufenden Threads
aus, bis ein Signal abgefangen wird (oder ein nicht abgefangenes Signal den
Prozess beendet):
-
pause(2)
- setzt die Ausführung aus, bis irgendein Signal
abgefangen wird.
-
sigsuspend(2)
- ändert zeitweise die Signalmaske (siehe unten) und
setzt die Ausführung aus, bis eines der nicht maskierten Signale
abgefangen wird.
Anstatt ein Signal asynchron mit einem Signal-Handler abzufangen, kann ein
Signal auch synchron akzeptiert werden. Das heißt, die
Ausführung wird blockiert, bis das Signal gesendet wird. Dann liefert
der Kernel Informationen über das Signal an den Aufrufenden. Es gibt
zwei allgemeine Möglichkeiten, das zu tun:
- •
-
sigwaitinfo(2), sigtimedwait(2) und
sigwait(3) setzen die Ausführung aus, bis ein Signal
gesendet wird, dass zu einer festgelegen Gruppe von Signalen
gehört. Jeder dieser Aufrufe gibt Informationen über das
empfangene Signal zurück.
- •
-
signalfd(2) gibt einen Dateideskriptor
zurück. Mit ihm können Informationen über Signale
gelesen werden, die dem Aufrufenden übermittelt werden. Jeder
Aufruf von read(2) aus dieser Datei wird blockiert, bis eines der
Signale aus der im Aufruf von signalfd(2) festgelegten Menge an den
aufrufenden Prozess gesendet wird. Der von read(2)
zurückgegebene Puffer enthält eine Struktur, die das Signal
beschreibt.
Ein Signal kann
blockiert werden. Das bedeutet, dass es erst dann
gesendet wird, nachdem es (später/verzögert) freigegeben wurde.
Zwischen dem Zeitpunkt seiner Erzeugung und dem Zeitpunkt seines Versands wird
es
anstehend (pending) genannt.
Jeder Thread in einem Prozess hat eine unabhängige
Signalauswahl-Maske (signal mask). Sie legt den Satz von Signalen fest,
den der Thread derzeit blockiert. Ein Thread kann seine Signalauswahl-Maske
mit
pthread_sigmask(3) manipulieren. In einer traditionellen
Single-Threaded-Anwendung kann
sigprocmask(2) verwendet werden, um die
Signalmaske zu manipulieren.
Ein mittels
fork(2) erstellter Kindprozess erbt eine Kopie der
Signalmaske des Elternprozeses; die Signalmaske wird über
execve(2) hinweg erhalten.
Ein Signal kann Prozess-orientiert oder Thread-orientiert sein. Ein
Prozess-orientiertes Signal ist eines, das auf einen Prozess als gesamtes
zielt (und daher daran anhängig ist). Ein Signal kann
Prozess-orientiert sein, da es vom Kernel für einen Grund außer
einer Hardware-Ausnahmebehandlung erzeugt wurde oder da es mittels
kill(2) oder
sigqueue(3) gesandt wurde. Ein Thread-orientiertes
Signal ist eines, das auf einen bestimmten Thread abzielt. Ein Signal kann
Thread-orientiert sein, da es als Konsequenz einer Ausführung einer
bestimmten Anweisung in Maschinensprache erstellt wurde, die eine
Hardware-Ausnahmebehandlung auslöste (z.B.
SIGSEGV für
einen ungültigen Speicherzugriff oder
SIGFPE für einen
mathematischen Fehler) oder da es mit Schnittstellen wie
tgkill(2) oder
pthread_kill(3) auf einen bestimmten Thread zielte.
Ein Prozess-orientiertes Signal kann an jeden der Threads ausgeliefert werden,
der derzeit keine Signale blockiert. Falls mehr als ein Thread Signale nicht
blockiert, dann wählt der Kernel einen beliebigen Thread aus, an den er
das Signal ausliefert.
Ein Thread kann die aktuell für ihn anstehenden Gruppe von Signale mit
sigpending(2) ermitteln. Das sind einerseits die für diesen
Thread und andererseits die für seinen Prozess bestimmten Signale.
Ein mittels
fork(2) erstellter Kindprozess hat anfänglich eine
leere anhängende Signalgruppe; die anhängende Signalgruppe wird
über
execve(2) hinweg erhalten.
Immer wenn es einen Übergang von der Kernelmodus-Ausführung zu der
Anwendungsraum-Ausführung gibt (z.B bei der Rückkehr aus einem
Systemaufruf oder Einplanung eines Threads auf einer CPU), prüft der
Kernel, ob es ein anhängendes, nicht blockiertes Signal gibt,
für das der Prozess einen Signal-Handler etabliert hat. Falls es ein
solches anhängendes Signal gibt, passieren die folgenden Schritte:
- (1)
- Der Kernel führt die notwendigen
Vorbereitungsschritte zur Ausführung des Signal-Handlers
durch:
- (1.1)
- Das Signal wird aus der Menge der anhängenden
Signale entfernt.
- (1.2)
- Falls der Signal-Handler durch einen Aufruf von
sigaction(2) installiert wurde, der den Schalter SA_ONSTACK
festlegte, und der Thread über einen definierten alternativen
Signal-Stack verfügt (mittels sigaltstack(2)), dann wird der
Stack installiert.
- (1.3)
- Verschiedene Teile des Signal-bezogenen Kontextes werden in
ein besonderes Frame gespeichert, das auf dem Stack erstellt wird. Die
gespeicherten Informationen beinhalten:
- •
- das Programmzählregister (d.h. die Adresse der
nächsten Anweisung in dem Hauptprogramm, die ausgeführt
werden soll, wenn der Signal-Handler zurückkehrt);
- •
- architekturabhängige Registerzustände, die
zur Wiederaufnahme des unterbrochenen Programms benötigt
werden;
- •
- die aktuelle Signal-Maske des Threads;
- •
- die alternativen Signal-Stack-Einstellungen des
Threads.
- (Falls der Signal-Handler mittels des Schalters
SA_SIGINFO von sigaction(2) installiert wurde, dann kann auf
die obigen Informationen über das Objekt ucontext_t, auf das
durch das dritte Argument des Signal-Handlers gezeigt wird, zugegriffen
werden.)
- (1.4)
- Jedes bei der Registrierung des Handlers mit
sigprocmask(2) in act->sa_mask festgelegte Signal wird zu
der Signal-Maske des Threads hinzugefügt. Das auszuliefernde Signal
wird auch zu der Signal-Maske hinzugefügt, außer
SA_NODEFER wurde bei der Registrierung des Handlers festgelegt.
Diese Signale sind daher während der Ausführung des Handlers
blockiert.
- (2)
- Der Kernel konstruiert ein Frame für den
Signal-Handler auf dem Stack. Der Kernel setzt den Programmzähler
für den Thread, so dass er auf die erste Anweisung der
Signal-Handler-Funktion zeigt, und konfiguriert die
Rücksprungadresse für diese Funktion, so dass sie auf ein
Stück Code im Anwendungsraum zeigt, das als Signaltrampolin bekannt
ist (beschrieben in sigreturn(2)).
- (3)
- Der Kernel übergibt die Steuerung zurück an
den Anwendungsraum, wo mit der Ausführung beim Anfang der
Signal-Handler-Funktion fortgefahren wird.
- (4)
- Wenn der Signal-Handler zurückkehrt, wird die
Steuerung an den Signal-Trampolin-Code übergeben.
- (5)
- Das Signaltrampolin ruft den Systemaufruf
sigreturn(2) auf, der die Informationen auf dem in Schritt 1
erstellten Stack-Frame verwendet, um den Thread in dem Zustand
wiederherzustellen, in dem er vor dem Aufruf des Signal-Handlers war. Die
Signalmaske und die alternativen Signal-Stack-Einstellungen des Threads
werden als Teil dieser Prozedur wiederhergestellt. Nach Abschluss des
Aufrufs von sigreturn(2) übergibt der Kernel die Steuerung
wieder an den Anwendungsraum zurück und der Thread fährt mit
der Ausführung an dem Punkt fort, an dem er durch den
Signal-Handler unterbrochen wurde.
Beachten Sie, dass der abschließende Schritt nicht ausgeführt
wird, falls der Signal-Handler nicht zurückkehrt (z.B. weil die
Steuerung mittels
siglongjmp(3) aus dem Handler herausverlegt wurde
oder der Handler mittels
execve(2) ein neues Programm ausführt).
In solchen Szenarien ist es insbesondere die Verantwortung des Programmierers,
den Zustand der Signalmaske (mittels
sigprocmask(2))
wiederherzustellen, falls gewünscht wird, die Blockierung der Signale
aufzuheben, die beim Eintritt in den Signal-Handler blockiert wurden.
(Beachten Sie, dass
siglongjmp(3) die Signal-Maske wiederherstellen
könnte oder auch nicht, abhängig vom Wert
savesigs, der
beim entsprechenden Aufruf von
sigsetjmp(3) festgelegt wurde.)
Vom Standpunkt des Kernels aus ist die Ausführung des
Signal-Handler-Codes genau das gleiche wie die Ausführung jedes anderen
Codes im Anwendungsraum. Dies bedeutet, dass der Kernel keinerlei besondere
Zustandsinformationen aufzeichnet, die anzeigen, dass der Thread sich derzeit
in der Ausführung eines Signal-Handlers befindet. Alle notwendigen
Zustandsinformationen werden in Anwendungsraum-Registern und im
Anwendungsraum-Stack verwaltet. Die Tiefe, zu der verschachtelte
Signal-Handler aufgerufen werden können, wird daher durch den
Anwendungsraum-Stack begrenzt (und unterliegt daher dem Design der Software).
Linux untersützt die nachfolgend aufgeführten Standard-Signale.
Die zweite Spalte der Tabelle zeigt an, welcher Standard (falls vorhanden) das
Signal festlegt: »P1990« zeigt an, dass das Signal in dem
ursprünglichen Standard POSIX.1-1990 beschrieben wurde;
»P2001« zeigt an, dass das Signal in SUSv2 und POSIX.1-2001
hinzugefügt wurde.
Signal |
Standard |
Aktion |
Kommentar |
|
|
|
|
SIGABRT |
P1990 |
Core |
Abbruchsignal von abort(3) |
SIGALRM |
P1990 |
Term |
Timersignal von alarm(2) |
SIGBUS |
P2001 |
Core |
Bus-Fehler (Speicherzugriffsfehler) |
SIGCHLD |
P1990 |
Ign |
Kindprozess angehalten oder beendet |
SIGCLD |
- |
Ign |
ein Synonym für SIGCHLD
|
SIGCONT |
P1990 |
Cont |
fortsetzen, wenn angehalten |
SIGEMT |
- |
Term |
Emulator-Ausnahmebehandlung |
SIGFPE |
P1990 |
Core |
Fließkomma-Ausnahmefehler |
SIGHUP |
P1990 |
Term |
Verbindung am steuernden Terminal beendet |
|
|
|
(aufgehängt) oder der steuernde Prozess wurde beendet |
SIGILL |
P1990 |
Core |
ungültiger Befehl |
SIGINFO |
- |
|
ein Synonym für SIGPWR
|
SIGINT |
P1990 |
Term |
Unterbrechung von der Tastatur |
SIGIO |
- |
Term |
E/A jetzt möglich (4.2BSD) |
SIGIOT |
- |
Core |
IOT-Ausnahmebehandlung; ein Synonym für SIGABRT
|
SIGKILL |
P1990 |
Term |
Kill-Signal |
SIGLOST |
- |
Term |
Dateisperre verloren/aufgehoben (nicht verwandt) |
SIGPIPE |
P1990 |
Term |
defekte Pipe: Schreiben in eine Pipe ohne |
|
|
|
Leser; siehe pipe(7) |
SIGPOLL |
P2001 |
Term |
abfragbares Ereignis (Sys V) |
|
|
|
Synonym für SIGIO
|
SIGPROF |
P2001 |
Term |
Profiling-Timer abgelaufen |
SIGPWR |
- |
Term |
Stromausfall (System V) |
SIGQUIT |
P1990 |
Core |
Abbruch von der Tastatur |
SIGSEGV |
P1990 |
Core |
ungültige Speicherreferenz |
SIGSTKFLT |
- |
Term |
Stack-Ausnahmebehandlung am Koprozessor (nicht verwendet) |
SIGSTOP |
P1990 |
Stop |
Stop process |
SIGTSTP |
P1990 |
Stop |
Stop am Terminal eingegeben |
SIGSYS |
P2001 |
Core |
Ungültiger Systemaufruf (SVr4); |
|
|
|
siehe auch seccomp(2) |
SIGTERM |
P1990 |
Term |
Beendigungssignal (termination signal) |
SIGTRAP |
P2001 |
Core |
Trace-/Haltepunkt-Ausnahmebehandlung |
SIGTTIN |
P1990 |
Stop |
Terminal-Eingabe für Hintergrundprozess |
SIGTTOU |
P1990 |
Stop |
Terminal-Ausgabe für Hintergrundprozess |
SIGUNUSED |
- |
Core |
synonym mit SIGSYS
|
SIGURG |
P2001 |
Ign |
dringende Gegebenheit an Socket (4.2BSD) |
SIGUSR1 |
P1990 |
Term |
benutzerdefiniertes Signal 1 |
SIGUSR2 |
P1990 |
Term |
benutzerdefiniertes Signal 2 |
SIGVTALRM |
P2001 |
Term |
virtueller Wecker (4.2BSD) |
SIGXCPU |
P2001 |
Core |
CPU-Zeitbegrenzung überschritten (4.2BSD) |
|
|
|
siehe setrlimit(2) |
SIGXFSZ |
P2001 |
Core |
Dateigrößenbegrenzung überschritten (4.2BSD) |
|
|
|
siehe setrlimit(2) |
SIGWINCH |
- |
Ign |
Änderung der Fenstergröße (4.3BSD, Sun) |
Die Signale
SIGKILL und
SIGSTOP können nicht abgefangen,
blockiert oder ignoriert werden.
Bis einschließlich Linux 2.2 war das Standardverhalten für
SIGSYS,
SIGXCPU,
SIGXFSZ und (auf anderen Architekturen
als SPARC und MIPS)
SIGBUS den Prozess (ohne einen Speicherauszug zu
erzeugen) zu beenden. (Auf einigen anderen UNIX-Systemen ist die
Standardaktion für
SIGXCPUund
SIGXFSZ, den Prozess ohne
einen Speicherauszug zu beenden.) Linux 2.4 entspricht den Anforderungen von
POSIX.1-2001 an diese Signale und beendet den Prozess mit einem
Speicherauszug.
SIGEMT ist nicht in POSIX.1-2001 angegeben, erscheint aber trotzdem auf
den meisten anderen UNIX-Systemen. Dort ist die Standardaktion in der Regel
die Beendigung des Prozesses mit einem Speicherauszug.
SIGPWR (nicht in POSIX.1-2001 beschrieben) wird bei seinem Eintreten von
diesen anderen UNIX-Systemen ignoriert.
SIGIO (nicht in POSIX.1-2001 beschrieben) wird
standardmäßig auf verschiedenen anderen UNIX-Systemen ignoriert.
Falls für einen Prozess mehrere Standard-Signale anhängig sind,
ist die Reihenfolge, in der diese Signale ausgeliefert werden, nicht
spezifiziert.
Standard-Signale kennen keine Warteschlange. Falls mehrere Instanzen eines
Standard-Signals erstellt werden, während dieses Signal blockiert ist,
wird nur eine Instanz des Signals als anhängig markiert (und das Signal
wird ausgeliefert, genau wenn die Blockade aufgehoben wird). Im Fall, bei dem
ein Standard-Signal bereits anhängig ist, wird die dem Signal
zugehörige Struktur
siginfo_t (siehe
sigaction(2)) nicht
bei der Ankunft nachfolgender Instanzen des gleichen Signals
überschrieben. Daher wird der Prozess die Informationen, die zu der
ersten Instanz des Signals gehören, erhalten.
Der numerische Wert für jedes Signal wird in der nachfolgenden Tabelle
angegeben. Wie in der Tabelle gezeigt, haben viele Signale verschiedene
numerische Werte auf verschiedenen Architekturen. Der erste numerische Wert in
jeder Zeile zeigt die Signalnummer auf X86, ARM und den meisten anderen
Architekturen; der zweite Wert ist für Alpha und SPARC; der dritte
für MIPS und der letzte für PARISC. Ein Bindestrich (-) zeigt
an, dass ein Signal auf der entsprechenden Architektur nicht vorhanden ist.
Signal |
x86/ARM |
Alpha/ |
MIPS |
PARISC |
Hinweise |
|
die meisten anderen |
SPARC |
|
|
|
|
|
|
|
|
|
SIGHUP |
1 |
1 |
1 |
1 |
|
SIGINT |
2 |
2 |
2 |
2 |
|
SIGQUIT |
3 |
3 |
3 |
3 |
|
SIGILL |
4 |
4 |
4 |
4 |
|
SIGTRAP |
5 |
5 |
5 |
5 |
|
SIGABRT |
6 |
6 |
6 |
6 |
|
SIGIOT |
6 |
6 |
6 |
6 |
|
SIGBUS |
7 |
10 |
10 |
10 |
|
SIGEMT |
- |
7 |
7 |
- |
|
SIGFPE |
8 |
8 |
8 |
8 |
|
SIGKILL |
9 |
9 |
9 |
9 |
|
SIGUSR1 |
10 |
30 |
16 |
16 |
|
SIGSEGV |
11 |
11 |
11 |
11 |
|
SIGUSR2 |
12 |
31 |
17 |
17 |
|
SIGPIPE |
13 |
13 |
13 |
13 |
|
SIGALRM |
14 |
14 |
14 |
14 |
|
SIGTERM |
15 |
15 |
15 |
15 |
|
SIGSTKFLT |
16 |
- |
- |
7 |
|
SIGCHLD |
17 |
20 |
18 |
18 |
|
SIGCLD |
- |
- |
18 |
- |
|
SIGCONT |
18 |
19 |
25 |
26 |
|
SIGSTOP |
19 |
17 |
23 |
24 |
|
SIGTSTP |
20 |
18 |
24 |
25 |
|
SIGTTIN |
21 |
21 |
26 |
27 |
|
SIGTTOU |
22 |
22 |
27 |
28 |
|
SIGURG |
23 |
16 |
21 |
29 |
|
SIGXCPU |
24 |
24 |
30 |
12 |
|
SIGXFSZ |
25 |
25 |
31 |
30 |
|
SIGVTALRM |
26 |
26 |
28 |
20 |
|
SIGPROF |
27 |
27 |
29 |
21 |
|
SIGWINCH |
28 |
28 |
20 |
23 |
|
SIGIO |
29 |
23 |
22 |
22 |
|
SIGPOLL |
|
|
|
|
identisch zu SIGIO |
SIGPWR |
30 |
29/- |
19 |
19 |
|
SIGINFO |
- |
29/- |
- |
- |
|
SIGLOST |
- |
-/29 |
- |
- |
|
SIGSYS |
31 |
12 |
12 |
31 |
|
SIGUNUSED |
31 |
- |
- |
31 |
|
Beachten Sie Folgendes:
- •
- Wenn das Signal definiert ist, ist SIGUNUSED synonym
zu SIGSYS. Seit Glibc 2.26 ist SIGUNUSED auf keiner
Architektur mehr definiert.
- •
- Signal 29 ist SIGINFO / SIGPWR (synonym
für den gleichen Wert) auf einer Alpha-Maschine, aber
SIGLOST auf einer SPARC.
Beginnend mit Linux 2.2 unterstützt Linux Echtzeit-Signale, wie sie
ursprünglich in den POSIX.1b-Echtzeit-Erweiterungen definiert wurden
(und jetzt in POSIX.1-2001 enthalten sind). Die Bereich der
unterstützten Echtzeit-Signale wird von den Makros
SIGRTMIN und
SIGRTMAX definiert. POSIX.1-2001 verlangt, dass eine Umsetzung
mindestens
_POSIX_RTSIG_MAX (8) Echtzeit-Signale unterstützt.
Der Linux-Kernel unterstützt eine Reihe von 33 verschiedenen
Echtzeit-Signalen, nummeriert von 32 bis 64. Doch die Glibc-Umsetzung der
POSIX-Threads verwendet intern zwei (für NPTL) oder drei (für
LinuxThreads) Echtzeit-Signale (siehe
pthreads (7)) und stellt den Wert
von
SIGRTMIN passend (auf 34 oder 35 ein). Da die Zahl der
verfügbaren Echtzeit-Signale je nach Glibc-Threading-Implementierung
variiert und diese Variation (entsprechend dem verfügbaren Kernel und
der Glibc) zur Laufzeit auftreten kann und tatsächlich die
verfügbaren Echtzeitsignale je nach UNIX-System variieren, sollten
Programme
niemals mit eincodierten Zahlen auf Echtzeit-Signale
verweisen. Stattdessen sollte auf Echtzeit-Signale immer mit der Notation
SIGRTMIN+n verwiesen werden und zur Laufzeit überprüft
werden, ob (
SIGRTMIN+n)
SIGRTMAX nicht übersteigt.
Im Gegensatz zu Standard-Signalen haben Echtzeit-Signale keine vordefinierten
Bedeutungen: der gesamte Satz von Echtzeit-Signalen kann für
anwendungsspezifische Zwecke genutzt werden.
Die Standardaktion für ein nicht abgefangenes Echtzeit-Signal ist der
Abbruch des Prozesses.
Echtzeit-Signale zeichnen sich durch folgende Merkmale aus:
- •
- Von Echtzeit-Signalen können mehrere Instanzen
anstehen. Im Gegensatz dazu wird beim Versand mehrerer Instanzen eines
Standard-Signals, während das Signal aktuell blockiert ist, nur
eine Instanz weiter anstehen.
- •
- Wenn das Signal mit Hilfe von sigqueue(3) gesendet
wird, kann mit ihm ein begleitender Wert (entweder eine Ganzzahl (Integer)
oder ein Zeiger) gesendet werden. Wenn der empfangende Prozess mittels des
SA_SIGINFO-Schalters für sigaction(2) einen Handler
für dieses Signal implementiert, kann dieser Wert aus dem
si_value-Feld der siginfo_t-Struktur (das zweite Argument
des Handlers) bestimmt werden. Darüber hinaus können die
Felder si_uid und si_pid dieser Struktur verwendet werden,
um die PID und reale Benutzerkennung des Prozesses zu erhalten, der das
Signal erzeugt hat.
- •
- Echtzeit-Signale werden in einer garantierten Reihenfolge
zugestellt. Mehrere Echtzeit-Signale des gleichen Typs werden in der
Reihenfolge zugestellt, in der sie gesendet wurden. Wenn verschiedene
Echtzeit-Signale an einen Prozess geschickt werden, wird das Signal mit
der niedrigsten Signalnummer zuerst zugestellt. (D.h. niedrig nummerierte
Signale haben höchste Priorität.) Im Gegensatz dazu ist die
Reihenfolge der Zustellung mehrerer für einen Prozess anstehender
Standard-Signale nicht festgelegt.
Wenn sowohl Standard- als auch Echtzeit-Signale für einen Prozess
anstehen, macht POSIX keine Angabe dazu, welche Signale zuerst zugestellt
werden. Linux gibt wie auch viele andere Implementierungen den
Standard-Signalen den Vorzug.
Nach POSIX sollte eine Umsetzung mindestens
_POSIX_SIGQUEUE_MAX (32)
Echtzeit-Signale in der Warteschlange eines Prozesses ermöglichen.
Allerdings macht Linux das anders. Bis einschließlich Linux 2.6.7 legt
Linux eine systemweite Obergrenze für die Anzahl wartender
Echtzeit-Signale für alle Prozesse fest. Diese Grenze kann eingesehen
und (mit entsprechenden Rechten) durch die Datei
/proc/sys/kernel/rtsig-max geändert werden. Aus der verwandten
Datei
/proc/sys/kernel/rtsig-nr kann die Anzahl der aktuell anstehenden
Signale ermittelt werden. In Linux 2.6.8 wurden diese
/proc-Schnittstellen durch die Ressource
RLIMIT_SIGPENDING, die
einen benutzerspezifischen Grenzwert für anstehende Signale in der
Warteschlange festlegt, ersetzt (siehe
setrlimit(2)).
Die Ergänzung um Echtzeitsignale erforderte die Verbreiterung der
Signalmengenstruktur (
sigset_t) von 32 auf 64 Bit. Konsequenterweise
wurden viele Systemaufrufe durch neue Systemaufrufe abgelöst, die die
größeren Signalmengen unterstützten. Die alten und neuen
Systemaufrufe sind wie folgt:
Wenn ein Signal-Handler aufgerufen wird, während ein Systemaufruf oder
Bibliotheksfunktionsaufruf blockiert ist, wird entweder:
- •
- nach Abschluss des Signal-Handlers der Aufruf neu gestartet
oder
- •
- der Aufruf schlägt mit dem Fehler EINTR
fehl.
Welche dieser beiden Verhaltensweisen eintritt, hängt von der
Schnittstelle und der Verwendung oder Nichtverwendung des Schalters
SA_RESTART ab (siehe
sigaction(2)). Die Einzelheiten
unterscheiden sich zwischen UNIX-Systemen. Im Folgenden werden die
Linux-Spezifika erörtert.
Wenn ein blockierter Aufruf einer der folgenden Schnittstellen von einem
Signal-Handler unterbrochen wird, wird der Aufruf nach der Rückkehr aus
dem Signal-Handler erneut gestartet, wenn der Schalter
SA_RESTART
verwendet wurde; anderenfalls schlägt der Aufruf mit dem Fehler
EINTR fehl:
- •
- Aufrufe von read(2), readv(2),
write(2), writev(2) und ioctl(2) für
»langsame« Geräte. Bei »langsamen«
Geräten kann ein E-/A-Aufruf für eine unbestimmte Zeit zu
einer Blockade führen. Zu ihnen gehören beispielsweise
Terminals, Pipes und Sockets. Hat ein E-/A-Aufruf für ein langsames
Gerät schon Daten übertragen und wird durch einen
Signal-Handler unterbrochen, wird der Aufruf mit einem Erfolgs-Status
abgeschlossen (normalerweise ist das die Zahl übertragener Bytes).
Beachten Sie, dass eine (lokale) Festplatte nach dieser Definition kein
langsames Gerät ist. E/A-Aktionen auf Fesplattengeräten
werden durch Signale nicht unterbrochen.
- •
-
open(2), wenn er blockieren kann (z. B. beim
Öffnen eines FIFOs; siehe fifo(7)).
- •
-
wait(2), wait3(2), wait4(2),
waitid(2) und waitpid(2).
- •
- Socket-Schnittstellen: accept(2), connect(2),
recv(2), recvfrom(2), recvmmsg(2), recvmsg(2),
send(2), sendto(2) und sendmsg(2), es sei denn, es
wurde für den Socket eine Zeitbegrenzung (Timeout) festgelegt
(siehe unten).
- •
- Dateisperrende Schnittstellen: flock(2) und die
Aktionen F_SETLKW und F_OFD_SETLKW von fcntl(2).
- •
- POSIX-Schnittstellen für Nachrichten-Warteschlangen:
mq_receive(3), mq_timedreceive(3), mq_send(3), and
mq_timedsend(3).
- •
-
futex(2) FUTEX_WAIT (seit Linux 2.6.22;
vorher immer Fehlschlag mit EINTR).
- •
-
io_getevents(2)
- •
-
pthread_mutex_lock(3), pthread_cond_wait(3)
und verwandte APIs.
- •
-
futex(2) FUTEX_WAIT_BITSET.
- •
- POSIX-Semaphor-Schnittstellen: sem_wait(3) und
sem_timedwait(3) (seit Linux 2.6.22; vorher immer Fehlschlag mit
EINTR).
- •
-
read(2) von einem inotify(7)-Dateideskriptor
(seit Linux 3.8; vorher immer Fehlschlag mit EINTR).
Folgende Schnittstellen werden nach einer Unterbrechung durch einen
Signal-Handler, unabhängig von der Verwendung von
SA_RESTART nie
erneut gestartet; sie schlagen immer mit dem Fehler
EINTR fehl:
- •
- »Eingabe«-Socket-Schnittstellen, wenn
für den Socket mittels setsockopt(2) eine Zeitbegrenzung
(Timeout, SO_RCVTIMEO) festgelegt wurde: accept(2),
recv(2), recvfrom(2), recvmmsg(2) (auch mit einem von
NULL verschiedenen Argument timeout) und recvmsg(2).
- •
- »Ausgabe«-Socket-Schnittstellen, wenn
für den Socket mittels setsockopt(2) eine Zeitbegrenzung
(Timeout, SO_RCVTIMEO) festgelegt wurde: connect(2),
send(2), sendto(2) und sendmsg(2).
- •
- Schnittstellen, mit denen auf Signale gewartet wird:
pause(2), sigsuspend(2), sigtimedwait(2) und
sigwaitinfo(2).
- •
- Schnittstellen, die Dateideskriptoren mehrfach nutzen:
epoll_wait(2), epoll_pwait(2), poll(2),
ppoll(2), select(2) und pselect(2).
- •
- System-V-IPC-Schnittstellen: msgrcv(2),
msgsnd(2), semop(2), and semtimedop(2).
- •
- Schlaf-Systemaufrufe: clock_nanosleep(2),
nanosleep(2), and usleep(3).
- •
-
io_getevents(2)
Die Funktion
sleep(3) wird ebenfalls niemals neu gestartet, wenn sie
durch einen Handler unterbrochen wurde, wird aber erfolgreich verlassen: Der
Rückgabewert ist die Zeit, die noch geschlafen werden sollte.
Unter bestimmten Umständen kann die
Benachrichtigungsfunktionalität im Benutzerraum von
seccomp(2)
zum Neustart von Systemaufrufen führen, die andernfalls niemals durch
SA_RESTART neugestartet würden; für Details siehe
seccomp_unotify(2).
Auf Linux können sogar ohne Signal-Handler bestimmte sperrende
Systemaufrufe mit dem Fehler
EINTR fehlschlagen, nachdem der Prozess
von einem der Stop-Signale gestoppt wird und dann mittels
SIGCONT
wieder fortgesetzt. Dieses Verhalten wird von POSIX.1 nicht gebiligt und tritt
nicht auf anderen Systemen auf.
Die folgenden Linux-Schnittstellen zeigen dieses Verhalten:
- •
- »Eingabe«-Socket-Schnittstellen, wenn
für den Socket mittels setsockopt(2) eine Zeitbegrenzung
(Timeout, SO_RCVTIMEO) festgelegt wurde: accept(2),
recv(2), recvfrom(2), recvmmsg(2) (auch mit einem von
NULL verschiedenen Argument timeout) und recvmsg(2).
- •
- »Ausgabe«-Socket-Schnittstellen, wenn
für den Socket mittels setsockopt(2) eine Zeitbegrenzung
(Timeout, SO_RCVTIMEO) festgelegt wurde: connect(2),
send(2), sendto(2) und sendmsg(2), falls eine
Sendezeitüberschreitung ( SO_SNDTIMEO) gesetzt wurde.
- •
-
epoll_wait(2), epoll_pwait(2).
- •
-
semop(2), semtimedop(2).
- •
-
sigtimedwait(2), sigwaitinfo(2).
- •
- Linux 3.7 und älter: read(2) von einem
inotify(7)-Dateideskriptor
- •
- Linux 2.6.21 und früher: futex(2)
FUTEX_WAIT, sem_timedwait(3), sem_wait(3).
- •
- Linux 2.6.8 und früher: msgrcv(2),
msgsnd(2).
- •
- Linux 2.4 und früher: nanosleep(2).
POSIX.1, mit den beschriebenen Ausnahmen
Für eine Diskussion asynchron-Signal-sicherer Funktionen, siehe
signal-safety(7).
Die Datei
/proc/[pid]/task/[TID]/status enthält verschiedene
Felder, die die Signale, die ein Thread blockiert (
SigBlk),
abfängt (
SigCgt) oder ignoriert (
SigIgn) zeigt. (Die
Gruppe der abgefangenen oder ignorierten Signale wird für alle Threads
eines Prozesses identisch sein.) Andere Felder zeigen die Gruppe der
anhängenden Signale, die für den Thread bestimmt sind (
SigPnd) sowie die Gruppe der anhängenden Signale, die für
den Prozess als ganzes bestimmt sind (
ShdPnd). Die entsprechenden
Felder in
/proc/[PID]/status zeigen die Informationen für den
Haupt-Thread. Siehe
proc(5) für weitere Details.
Es gibt sechs Signale, die als Konsequenz aus einer Hardware-Ausnahmebehandlung
ausgeliefert werden können:
SIGBUS,
SIGEMT,
SIGFPE,
SIGILL,
SIGSEGV und
SIGTRAP. Welches
dieser Signale für eine bestimmte Hardware-Ausnahmebehandlung
ausgeliefert wird, ist nicht dokumentiert und ergibt nicht immer Sinn.
Zum Beispiel kann ein ungültiger Speicherzugriff, der die Auslieferung
von
SIGSEGV auf einer CPU-Architektur hervorruft, die Auslieferung von
SIGBUS auf einer anderen Architektur (oder andersherum) hervorrufen.
Als weiteres Beispiel löst die Verwendung der X86-
int-Anweisung
mit einem verbotenen Argument (jeder Zahl außer 3 und 128) die
Auslieferung von
SIGSEGV aus, obwohl
SIGILL mehr Sinn
ergäbe, aufgrund der Art, wie die CPU die verbotene Operation an den
Kernel berichtet.
kill(1),
clone(2),
getrlimit(2),
kill(2),
pidfd_send_signal(2),
restart_syscall(2),
rt_sigqueueinfo(2),
setitimer(2),
setrlimit(2),
sgetmask(2),
sigaction(2),
sigaltstack(2),
signal(2),
signalfd(2),
sigpending(2),
sigprocmask(2),
sigreturn(2),
sigsuspend(2),
sigwaitinfo(2),
abort(3),
bsd_signal(3),
killpg(3),
longjmp(3),
pthread_sigqueue(3),
raise(3),
sigqueue(3),
sigset(3),
sigsetops(3),
sigvec(3),
sigwait(3),
strsignal(3),
swapcontext(3),
sysv_signal(3),
core(5),
proc(5),
nptl(7),
pthreads(7),
sigevent(7)
Die deutsche Übersetzung dieser Handbuchseite wurde von Martin Eberhard
Schauer <
[email protected]>, Dr. Tobias Quathamer
<
[email protected]> und Helge Kreutzmann <
[email protected]>
erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die
GNU
General Public License Version 3 oder neuer bezüglich der
Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken
Sie bitte eine E-Mail an die
Mailingliste
der Übersetzer