setjmp, sigsetjmp, longjmp, siglongjmp - Nichtlokalen Sprungbefehl
durchführen
Standard-C-Bibliothek (
libc,
-lc)
#include <setjmp.h>
int setjmp(jmp_buf Umg);
int sigsetjmp(sigjmp_buf Umg, int speicherSig);
[[noreturn]] void longjmp(jmp_buf Umg, int Wert);
[[noreturn]] void siglongjmp(sigjmp_buf Umg, int Wert);
setjmp(): siehe ANMERKUNGEN.
sigsetjmp():
_POSIX_C_SOURCE
Die auf dieser Seite beschriebenen Funktionen werden für
»nichtlokale Gotos« verwandt: Übergabe der
Ausführung von einer Funktion zu einer vorbestimmten Stelle in einer
anderen Funktion. Die Funktion
setjmp() etabliert dynamisch das Ziel,
zu dem die Steuerung später übergeben wird und
longjmp()
führt den Ausführungstransfer aus.
Die Funktion
setjmp() speichert verschiedene Informationen über
die aufrufende Umgebung (typischerweise den Stack-Zeiger, den
Anweisungszeiger, möglicherweise die Werte von anderen Registern und
die Signalmaske) im Puffer
Umg für die spätere Verwendung
durch
longjmp(). In diesem Fall liefert
setjmp() 0
zurück.
Die Funktion
longjmp() verwendet die in
Umg gespeicherten
Informationen, um die Steuerung zu dem Punkt zurückzuübergeben,
an dem
setjmp() aufgerufen worden war und den Stack auf seinem Zustand
zum Zeitpunkt des Aufrufs von
setjmp() wiederherzustellen
(»zurückzuspulen«). Zusätzlich und abhängig
von der Implementierung (siehe ANMERKUNGEN) können die Werte einiger
anderer Register und der Prozesssignalmaske auf den Wert zum Zeitpunkt des
Aufrufs von
setjmp() wiederhergestellt werden.
Nach einem erfolgreichen
longjmp() fährt die Ausführung so
fort, als ob
setjmp() ein zweites Mal zurückgekehrt wäre.
Diese »Schummel«-Rückkehr kann von einem echten Aufruf
von
setjmp() unterschieden werden, da die
»Schummel«-Rückkehr den in
Wert bereitgestellten
Wert zurückliefert. Falls der Programmierer fehlerhafterweise den Wert
0 in
Wert weitergibt, wird die »Schummel«-Rückkehr
stattdessen 1 zurückliefern.
sigsetjmp() und
siglongjmp() führen auch nichtlokale Gotos
durch, stellen aber eine vorhersehbare Behandlung der Prozesssignalmaske
bereit.
Nur wenn das an
sigsetjmp() übergebene Argument
speicherSig
nicht Null ist, wird die aktuelle Signalmaske des Prozesses in
Umg
gespeichert und wiederhergestellt, wenn später mit diesem
Umg
ein
siglongjmp durchgeführt wird.
setjmp() und
sigsetjmp() geben 0 zurück, wenn sie direkt
aufgerufen wurden; bei dem »nachgeahmten« Zurückkehren,
das nach
longjmp() und
siglongjmp() auftritt, wird der in
Wert angegebene Nichtnull-Wert zurückgegeben.
Die Funktionen
longjmp() oder
siglongjmp() kehren nicht
zurück.
Siehe
attributes(7) für eine Erläuterung der in diesem
Abschnitt verwandten Ausdrücke.
Schnittstelle |
Attribut |
Wert |
setjmp(), sigsetjmp() |
Multithread-Fähigkeit |
MT-Safe |
longjmp(), siglongjmp() |
Multithread-Fähigkeit |
MT-Safe |
setjmp(),
longjmp(): POSIX.1-2001, POSIX.1-2008, C99.
sigsetjmp(),
siglongjmp(): POSIX.1-2001, POSIX.1-2008.
POSIX spezifiziert nicht, ob
setjmp() die Signalmaske sichern wird (um
sie später während
longjmp() wieder herzustellen). In
System-V wird es dies nicht tun. In 4.3BSD wird es dies tun und dort gibt es
eine Funktion
_setjmp(), die es nicht tut. Das Verhalten unter Linux
hängt von der Glibc-Version und den Einstellungen der
Feature-Test-Makros ab. Vor Glibc 2.19 folgte
setjmp()
standardmäßig dem Verhalten von System V, aber das BSD-Verhalten
wird bereitgestellt, wenn das
_BSD_SOURCE-Feature-Test-Macro explizit
definiert ist und weder
_POSIX_SOURCE,
_POSIX_C_SOURCE,
_XOPEN_SOURCE,
_GNU_SOURCE noch
_SVID_SOURCE definiert
ist. Seit Glibc 2.19 stellt
<setjmp.h> nur die System-V-Version
von
setjmp() bereit. Programme, die die BSD-Semantik benötigen,
sollten Aufrufe von
setjmp() durch Aufrufe von
sigsetjmp(), bei
denen das Argument
speicherSig ungleich numerisch Null ist, ersetzen.
setjmp() und
longjmp() können zum Umgang mit Fehlern
innerhalb tiefverschachtelter Funktionsaufrufe nützlich sein oder um
einem Signal-Handler zu ermöglichen, die Steuerung an einen bestimmten
Punkt in dem Programm zu übergeben, statt zu dem Punkt
zurückzukehren, in dem der Handler das Hauptprogramm unterbrochen hat.
In letzterem Falle verwenden Sie
sigsetjmp() und
siglongjmp(),
falls Sie die Signalmaske portabel speichern und wiederherstellen
möchten. Lesen Sie auch die Diskussion zur Programmlesbarkeit weiter
unten.
Der Compiler kann Variablen in Register optimieren und
longjmp() kann die
Werte anderer Register zusätzlich zum Stack- und Programmzeiger
wiederherstellen. Daher ist der Wert von automatischen Variablen nach einem
Aufruf von
longjmp() undefiniert, falls alle folgenden Kriterien
zutreffen:
- •
- sie sind für die Funktion, die den entsprechenden
Aufruf setjmp() durchführte, lokal,
- •
- ihre Werte sind zwischen Aufrufen von setjmp() und
longjmp() geändert, und
- •
- sie sind nicht als volatile deklariert.
Entsprechende Anmerkungen gelten für
siglongjmp().
Auch wenn er missbraucht werden kann, hat der traditionelle
»goto«-Ausdruck von C zumindest den Vorteil, dass lexikalische
Hinweise (der Goto-Ausdruck und die Zielmarkierung) dem Programmierer
erlauben, leicht den Ablauf zu verstehen. Nichtlokale Gotos stellen keine
solchen Hinweise bereit: Mehrere Aufrufe von
setjmp() können die
gleiche Variable
jmp_buf einsetzen, so dass der Inhalt der Variablen
sich über die Lebensdauer des Programmes verändern kann.
Konsequenterweise kann der Programmierer dazu gezwungen sein, den Code
detailliert zu lesen, um das dynamische Ziel eines bestimmten Aufrufs von
longjmp() zu ermitteln. (Um das Leben der Programmierer zu erleichtern,
sollte jeder Aufruf von
setjmp() eine eineindeutige Variable
jmp_buf einsetzen.)
Weitere Schwierigkeiten kommen hinzu, da die Aufrufe von
setjmp() und
longjmp() nicht zwingend im gleichen Quellcodemodul sein müssen.
Zusammenfassend erschweren nicht lokale GOTOs das Verständnis und die
Verwaltung von Programmen. Falls möglich, sollte eine Alternative
benutzt werden.
Falls die Funktion, die
setjmp() aufruft, zurückkehrt, bevor
longjmp() aufgerufen wird, ist das Verhalten undefiniert. Irgendwelches
subtiles oder nicht so subtiles Chaos entsteht bestimmt dadurch.
Falls ein
longjmp()-Aufruf in einem Programm mit mehreren Threads einen
Umg-Puffer einsetzt, der durch einen Aufruf von
setjmp() in
einem anderen Thread initialisiert wurde, ist sein Verhalten nicht definiert.
POSIX.1-2008 Technische Berichtigung 2 fügt
longjmp() und
siglongjmp() zur Liste der asynchronsignalsicheren Funktionen hinzu.
Der Standard empfiehlt jedoch den Gebrauch dieser Funktionen aus
Signal-Handlern zu vermeiden. Sie fährt damit fort, zu betonen, dass,
falls diese Funktionen von einem Signal-Handler aufgerufen werden, der einen
Aufruf einer nicht asynchronsignalsicheren Funktion unterbrochen hatte (oder
etwas gleichbedeutendem, wie den Schritten, die
exit(3) entsprechen,
die über eine Rückkehr vom initialen Aufruf zu
main()
auftreten), das Verhalten nicht definiert ist, falls das Programm nachfolgend
einen Aufruf einer nicht asynchronsignalsicheren Funktion durchführt.
Der einzige Weg, nicht definiertes Verhalten zu vermeiden, ist, eines des
Nachfolgenden sicherzustellen:
- •
- Nach langen Sprüngen vom Signal-Handler ruft das
Programm keine asynchronsignalsicheren Funktionen auf und kehrt nicht vom
initialen Aufruf von main() zurück.
- •
- Jedes Signal, dessen Handler einen langen Sprung
durchführt, muss während jedes Aufrufs einer nicht
asynchronsignalsicheren Funktion blockiert werden und keine nicht
asynchronsignalsicheren Funktionen werden nach der Rückkehr vom
initialen Aufruf von main() aufgerufen.
signal(7),
signal-safety(7)
Die deutsche Übersetzung dieser Handbuchseite wurde von Patrick Rother
<
[email protected]>, Chris Leick <
[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