setjmp, sigsetjmp, longjmp, siglongjmp - Effectuer un saut non local
Bibliothèque C standard (
libc,
-lc)
#include <setjmp.h>
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int sauvsigs);
[[noreturn]] void longjmp(jmp_buf env, int val);
[[noreturn]] void siglongjmp(sigjmp_buf env, int val);
setjmp() : consultez la section NOTES.
sigsetjmp():
_POSIX_C_SOURCE
Les fonctions décrites dans cette page sont utilisées pour
effectuer des « sauts non locaux » :
transfert de l'exécution d'une fonction à un emplacement
prédéterminé d'une autre fonction. La fonction
setjmp() établit de façon dynamique l'emplacement vers
lequel le contrôle sera transféré ultérieurement
et
longjmp() se charge de transférer l'exécution.
La fonction
setjmp() sauvegarde diverses informations concernant
l'environnement de l'appelant (typiquement le pointeur de pile, le pointeur
d'instruction, potentiellement les valeurs d'autres registres ainsi que le
masque de signaux) dans le tampon
env pour son utilisation
ultérieure par
longjmp(). Dans ce cas,
setjmp() renvoie
0.
La fonction
longjmp() utilise les informations stockées dans
env pour transférer le contrôle à l'endroit
où
setjmp() fut appelé et restaurer
(« rewind ») la pile à son état lors
de l'appel à
setjmp(). De plus, et en fonction de
l'implémentation (voir NOTES), les valeurs d'autres registres et le
masque de signaux du processus peuvent également être
restaurées à leur état lors de l'appel à
setjmp().
Après un appel réussi à
longjmp(),
l'exécution continue comme si
setjmp() avait renvoyé une
deuxième fois. Ce renvoi « factice » peut
être distingué d'un vrai appel à
setjmp() car il
renvoie la valeur contenue dans
val. Si le programmeur passe la valeur
0 à
val par inadvertance, le renvoi
« factice » retourne
1 à la place.
sigsetjmp() et
siglongjmp() effectuent également des sauts
non locaux mais permettent une gestion prévisible du masque de signaux
du processus.
Si, et seulement si, l'argument
sauvsigs passé à
sigsetjmp() est non nul, le masque de signaux actuel du processus est
sauvegardé dans
env et sera rétabli lorsque
siglongjmp() sera invoquée avec ce contexte
env.
setjmp() et
sigsetjmp() renvoient
0 lorsqu'elles sont
appelées directement ; la valeur non nulle
spécifiée dans
val est renvoyée lors du renvoi
« factice » qui se produit après un appel
à
longjmp() ou
siglongjmp().
Les fonctions
longjmp() et
siglongjmp() ne renvoient pas.
Pour une explication des termes utilisés dans cette section, consulter
attributes(7).
Interface |
Attribut |
Valeur |
setjmp(), sigsetjmp() |
Sécurité des threads |
MT-Safe |
longjmp(), siglongjmp() |
Sécurité des threads |
MT-Safe |
setjmp(),
longjmp() : POSIX.1-2001, POSIX.1-2008, C99.
sigsetjmp(),
siglongjmp() : POSIX.1-2001, POSIX.1-2008.
POSIX ne spécifie pas si
setjmp() sauve le masque de signaux (pour
être ensuite restauré lors de
longjmp()). Sous
System V, ce n'est pas le cas. Sous 4.3BSD, le masque sera sauvé
et il y a une fonction
_setjmp qui ne fait pas la copie. Le
comportement sous Linux dépend de la version de la glibc ainsi que de
la configuration des macros de test de fonctionnalités. Avant la
glib 2.19,
setjmp() suit le comportement de System V par
défaut, mais le comportement BSD est fourni si la macro de test de
fonctionnalités
_BSD_SOURCE est définie et
qu’aucune des macros
_POSIX_SOURCE,
_POSIX_C_SOURCE,
_XOPEN_SOURCE,
_GNU_SOURCE ou
_SVID_SOURCE n'est
définie. Depuis la glibc 2.19,
<setjmp.h>
n’expose que la version System V de
setjmp(). Les
programmes ayant besoin de la sémantique BSD devraient remplacer les
appels de
setjmp() par des appels de
sigsetjmp() avec un
argument
sauvsigs non nul.
setjmp() et
longjmp() peuvent être utiles pour gérer
des erreurs dans des appels profondément imbriqués ou pour
permettre à un gestionnaire de signal de passer le contrôle
à un point précis du programme, plutôt que de renvoyer
là où le gestionnaire a interrompu le programme principal. Dans
ce dernier cas, si vous désirez sauvegarder et restaurer les masques de
signaux de manière portable, utilisez
sigsetjmp() et
siglongjmp(). Consultez également la sous-section sur la
lisibilité des programmes ci-dessous.
Le compilateur peut optimiser certaines variables dans des registres et
longjmp() peut restaurer les valeurs d'autres registres en plus des
pointeurs de pile et d'instruction. Par conséquent, les valeurs de
variables automatiques ne sont pas spécifiées après un
appel à
longjmp() si elles satisfont à tous les
critères suivants :
- •
- elles sont locales à la fonction qui a
effectué l'appel correspondant à
setjmp() ;
- •
- leur valeur est changée entre les appels à
setjmp() et longjmp() ;
- •
- elles ne sont pas déclarées comme
volatile.
Ces remarques s'appliquent aussi à
siglongjmp().
Bien que la déclaration C traditionnelle
« goto » puisse être exploitée, elle
a pour bénéfice que les repères lexicaux (la
déclaration de saut ainsi que l'étiquette cible) permettent au
programmeur de percevoir de façon claire le flux de contrôle.
Les sauts non locaux ne fournissent pas de tels repères :
plusieurs appels à
setjmp() peuvent utiliser la même
variable
jmp_buf de telle sorte que son contenu change au cours du
déroulement de l'application. Par conséquent, le programmeur
peut être astreint à une lecture détaillée du code
afin de déterminer la cible dynamique d'un appel
longjmp()
particulier (pour rendre la tâche du programmeur plus simple, chaque
appel à
setjmp() devrait utiliser une variable
jmp_buf
unique).
De façon encore plus compliquée, les appels à
setjmp() et
longjmp() peuvent même provenir de modules de
code source différents.
En résumé, les sauts non locaux peuvent rendre les programmes plus
difficiles à comprendre et à maintenir, et une alternative
devrait être utilisée lorsque c'est possible.
Si la fonction qui a appelé
setjmp() renvoie avant que
longjmp() ne soit appelée, le comportement n'est pas
défini. Une sorte de chaos plus ou moins subtil en résulterait
de façon certaine.
Si, dans un programme à plusieurs fils d'exécution, un appel
à
longjmp() utilise un tampon
env initialisé
préalablement par
setjmp() dans un fil d'exécution
différent, le comportement n'est pas défini.
Le Technical Corrigendum 2 de POSIX.1-2008 ajoute
longjmp() et
siglongjmp() à la liste des fonctions sûres
vis-à-vis des signaux asynchrones. Cependant, la norme recommande de ne
pas utiliser ces fonctions dans un gestionnaire de signal et indique ensuite
que si ces fonctions sont appelées depuis un gestionnaire de signal qui
a interrompu un appel à une fonction non sûre vis-à-vis
des signaux asynchrones (ou similaire tels que les étapes
équivalentes à
exit(3) se produisant après un
renvoi de l'appel initial
main()), le comportement n'est pas
défini si le programme fait par la suite un appel à une fonction
non sûre vis-à-vis des signaux asynchrones. La seule
façon d'éviter ce comportement non défini est de
s'assurer de la chose suivante :
- •
- Après un saut non local depuis un gestionnaire de
signal, le programme n'appelle pas de fonction non sûre
vis-à-vis des signaux asynchrones et ne renvoie pas depuis l'appel
initial à main().
- •
- Chaque signal dont le gestionnaire effectue un saut non
local doit être bloqué lors de chaque appel à
une fonction non sûre vis-à-vis des signaux asynchrones et
aucune fonction non sûre vis-à-vis des signaux asynchrones
n'est appelée après un renvoi depuis l'appel initial
à main().
signal(7),
signal-safety(7)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]> et
Grégoire Scano <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 concernant les conditions de copie
et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
[email protected]