Scroll to navigation

SETJMP(3) Linux-Programmierhandbuch SETJMP(3)

BEZEICHNUNG

setjmp, sigsetjmp, longjmp, siglongjmp - Nichtlokalen Sprungbefehl durchführen

ÜBERSICHT

#include <setjmp.h>
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);
void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);

Mit Glibc erforderliche Makros (siehe feature_test_macros(7)):

setjmp(): siehe ANMERKUNGEN.

sigsetjmp(): _POSIX_C_SOURCE

BESCHREIBUNG

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 env für die spätere Verwendung durch longjmp(). In diesem Fall liefert setjmp() 0 zurück.

Die Funktion longjmp() verwendet die in env 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 val bereitgestellten Wert zurückliefert. Falls der Programmierer fehlerhafterweise den Wert 0 in val weitergibt, wird die »Schummel«-Rückkehr stattdessen 1 zurückliefern.

sigsetjmp() und siglongjmp()

sigsetjmp() und siglongjmp() führen auch nichtlokale Gotos durch, stellen aber eine vorhersehbare Behandlung der Prozesssignalmaske bereit.

Nur wenn das an sigsetjmp() übergebene Argument savesigs nicht Null ist, wird die aktuelle Signalmaske des Prozesses in env gespeichert und wiederhergestellt, wenn später mit diesem env ein siglongjmp durchgeführt wird.

RÜCKGABEWERT

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 val angegebene Nichtnull-Wert zurückgegeben.

Die Funktionen longjmp() oder siglongjmp() kehren nicht zurück.

ATTRIBUTE

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

KONFORM ZU

setjmp(), longjmp(): POSIX.1-2001, POSIX.1-2008, C89, C99.

sigsetjmp(), siglongjmp(): POSIX.1-2001, POSIX.1-2008.

ANMERKUNGEN

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. Unter Linux mit Glibc-Versionen vor 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 savesigs 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().

Nicht lokale GOTOs und Programmlesbarkeit

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.

Warnungen

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 env-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.

SIEHE AUCH

signal(7), signal-safety(7)

KOLOPHON

Diese Seite ist Teil der Veröffentlichung 5.10 des Projekts Linux-man-pages. Eine Beschreibung des Projekts, Informationen, wie Fehler gemeldet werden können sowie die aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.

ÜBERSETZUNG

Die deutsche Übersetzung dieser Handbuchseite wurde von Patrick Rother <krd@gulu.net>, Chris Leick <c.leick@vollbio.de>, Dr. Tobias Quathamer <toddy@debian.org> und Helge Kreutzmann <debian@helgefjell.de> 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 <debian-l10n-german@lists.debian.org>.

13. März 2017