/**
*
* @File : SaveSig.cxx
*
* @Authors : D. Mathieu
*
* @Date : 20/11/2001
*
* @Version : V1.0
*
* @Synopsis :
*
**/
#include <csignal> // sigemptyset(), sigaddset(), sigset_t
// SIG_BLOCK, SIG_UNBLOCK
// struct sigaction, _NSIG, SIGKILL, SIGSTOP
#include "CException.h"
#include "CExcFctSyst.h"
#include "nsSysteme.h"
#include "CstCodErr.h"
#include "SaveSig.h"
using namespace std;
using namespace nsUtil; // CExcFct
using namespace nsSysteme;
// Ces deux constantes devraient être ajoutées au fichier CstCodErr.h
const int CstNumSigFaux = 151;
const int CstSigNotDerout = 152;
namespace
{
// La version actuelle ne supporte pas les imbrications de blocs
// SaveSig() .... RestaureSig(), et lève une exception
// CExcFct pour toute utilisation illégale de ce couple de
// fonctions.
struct std::sigaction TabAction [_NSIG];
bool ASauvegarder = true;
struct std::sigaction TabActionIndivid [_NSIG];
// Une variable globale (statique) est obligatoirement initialisée
// à 0, donc le vecteur est initialisé à faux (d'où son nom)
bool DejaSauvegardeIndivid [_NSIG];
void SauverUnSignal (const sighandler_t NewHandler, int NumSig,
struct std::sigaction & OldAction) throw ()
{
struct std::sigaction Action;
Action.sa_flags = 0;
Action.sa_handler = NewHandler;
sigemptyset (& Action.sa_mask);
Sigaction (NumSig, & Action, & OldAction);
if (SIG_IGN == OldAction.sa_handler)
Sigaction (NumSig, & OldAction, 0);
} // SauverUnSignal()
void RestaurerUnSignal (int NumSig,
const struct std::sigaction & OldAction)
throw ()
{
Sigaction (NumSig, & OldAction, 0);
} // RestaurerUnSignal()
void BlockAllSig (const sigset_t & Masque) throw (CExcFctSyst)
{
// Boucle jusqu'à ce que Sigprocmask() ne soit plus interrompu
for (; ;)
try { Sigprocmask (SIG_BLOCK, & Masque, 0); break; }
catch (...) {}
} // BlockAllSig()
} // namespace anonyme
void nsSysteme::SaveSig (const sighandler_t NewHandler,
int NumSig /* = 0 */) throw (CExcFct)
{
// Une solution beaucoup plus belle, mais non demandée, consisterait
// à déclarer une structure dans l'espace anonyme, dont la donnée
// membre serait un masque de type sigset_t, et dont le
// constructeur initialiserait le masque à tous les signaux
// bloquables.
// Il suffirait ensuite de dééfinir dans l'espace anonyme un objet
// de ce type, global, qui serait donc construit une seule fois,
// avant l'appel de la fonction main()
sigset_t Masque;
sigemptyset (& Masque);
for (int i = _NSIG; --i; )
if (SIGKILL != i && SIGSTOP != i) sigaddset (& Masque, i);
if (NumSig)
{
// Sauvegarde d'un signal unique
if (NumSig <= 0 || NumSig >= _NSIG)
throw CExcFct ("SaveSig : signal inexistant",
CstNumSigFaux);
if (SIGKILL == NumSig || SIGSTOP == NumSig)
throw CExcFct ("SaveSig : signal non déroutable",
CstSigNotDerout);
if (DejaSauvegardeIndivid [NumSig])
throw CExcFct ("SaveSig : signal déjà sauvegardé",
CstSigSaved);
BlockAllSig (Masque);
SauverUnSignal (NewHandler, NumSig, TabActionIndivid [NumSig]);
DejaSauvegardeIndivid [NumSig] = true;
Sigprocmask (SIG_UNBLOCK, & Masque, 0);
}
else
{
if (! ASauvegarder)
throw CExcFct ("SaveSig : signaux deja sauvegardes",
CstSigSaved);
// Boucle jusqu'à ce que Sigprocmask() ne soit plus interrompu
BlockAllSig (Masque);
for (int i = _NSIG; --i; )
if (SIGKILL != i && SIGSTOP != i)
SauverUnSignal (NewHandler, i, TabAction [NumSig]);
ASauvegarder = false;
Sigprocmask (SIG_UNBLOCK, & Masque, 0);
}
} // SaveSig()
void nsSysteme::RestaureSig (int NumSig /* = 0 */) throw (CExcFct)
{
sigset_t Masque;
sigemptyset (& Masque);
for (int i = _NSIG; --i; )
if (SIGKILL != i && SIGSTOP != i) sigaddset (& Masque, i);
if (NumSig)
{
// Restauration d'un signal unique
if (NumSig <= 0 || NumSig >= _NSIG)
throw CExcFct ("ReataureSig : signal inexistant",
CstNumSigFaux);
if (SIGKILL == NumSig || SIGSTOP == NumSig)
throw CExcFct ("RestaureSig : signal non déroutable",
CstSigNotDerout);
if (!DejaSauvegardeIndivid [NumSig])
throw CExcFct ("RestaureSig : signal non sauvegardé",
CstSigSaved);
BlockAllSig (Masque);
RestaurerUnSignal (NumSig, TabActionIndivid [NumSig]);
DejaSauvegardeIndivid [NumSig] = false;
Sigprocmask (SIG_UNBLOCK, & Masque, 0);
}
else
{
if (ASauvegarder)
throw CExcFct ("RestaureSig : signaux non sauvegardes",
CstSigNotSaved);
BlockAllSig (Masque);
for (int i = _NSIG; --i; )
if (SIGKILL != i && SIGSTOP != i)
RestaurerUnSignal (NumSig, TabAction [i]);
ASauvegarder = true;
Sigprocmask (SIG_UNBLOCK, & Masque, 0);
}
} // RestaureSig()