POSIX                
            Les signaux
        
        
            
    Recherche…
Syntaxe
- alarme non signée (secondes non signées);
- int kill (pid_t pid, int sig);
Paramètres
| Fonction, paramètre (s), valeur de retour | La description | 
|---|---|
| alarm() | nom de la fonction | 
| unsigned seconds | Secondes pour déclencher une alarme ou 0 pour annuler toute alarme en attente | 
| > = 0 | 0 si aucune autre alarme n'était en attente, sinon le nombre de secondes pendant lesquelles l'alarme en attente était encore ouverte. Cette fonction n'échouera pas. | 
| - | - | 
| kill() | nom de la fonction | 
| pid_t pid | . | 
| int sig | 0 ou ID du signal | 
| 0, -1 | En cas de succès, 0 est renvoyé, -1 en cas d'échec avec la définition d' errnosurEINVAL,EPERMouESRCH. | 
Relever SIGALARM avec l'action par défaut
 En utilisant l' alarm , l'utilisateur peut programmer le signal SIGALARM pour qu'il soit levé après l'intervalle spécifié. Si l'utilisateur n'a pas bloqué, ignoré ou spécifié un gestionnaire de signal explicite pour ce signal, l'action par défaut pour ce signal sera effectuée à l'arrivée. L'action par défaut par spécification pour SIGALARM consiste à terminer le processus: 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char** argv)
{
    printf("Hello!\n");
    // Set the alarm for five second
    alarm(5); // Per POSIX, this cannot fail
    // Now sleep for 15 seconds
    for (int i = 1; i <= 15; i++)
    {
        printf("%d\n", i);
        sleep(1);
    }
    // And print the message before successful exit
    printf("Goodbye!\n");
    return EXIT_SUCCESS;
}
Cela produit:
Hello!
1
2
3
4
5
[2]    35086 alarm      ./a.out
Réglage du gestionnaire de signaux à l'aide de sigaction et de signaux de relance à l'aide de raise
 Pour qu'un programme réagisse à un certain signal, autre qu'une action par défaut, un gestionnaire de signal personnalisé peut être installé à l'aide de sigaction . sigaction reçoit trois arguments - signal sur lequel agir, pointeur sur la structure sigaction_t qui, sinon NULL , décrit le nouveau comportement et le pointeur sur sigaction_t qui, si NULL ne sera pas rempli avec l'ancien comportement (on peut donc le restaurer). Augmenter les signaux dans le même processus peut être fait avec la méthode raise . Si plus de contrôle est nécessaire (pour envoyer le signal à un autre processus, kill ou pthread_kill peut être utilisé, qui accepte l'identifiant du processus de destination ou l'identifiant du thread). 
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Signals are numbered from 1, signal 0 doesn't exist
volatile sig_atomic_t last_received_signal = 0;
// Signal handler, will set the global variable
// to indicate what is the last signal received.
// There should be as less work as possible inside
// signal handler routine, and one must take care only
// to call reentrant functions (in case of signal arriving
// while program is already executing same function)
void signal_catcher(int signo, siginfo_t *info, void *context)
{
    last_received_signal = info->si_signo;
}
int main (int argc, char** argv)
{
    // Setup a signal handler for SIGUSR1 and SIGUSR2
    struct sigaction act;
    memset(&act, 0, sizeof act);
    // sigact structure holding old configuration
    // (will be filled by sigaction):
    struct sigaction old_1;
    memset(&old_1, 0, sizeof old_1);
    struct sigaction old_2;
    memset(&old_2, 0, sizeof old_2);
    act.sa_sigaction = signal_catcher;
    // When passing sa_sigaction, SA_SIGINFO flag
    // must be specified. Otherwise, function pointed
    // by act.sa_handler will be invoked
    act.sa_flags = SA_SIGINFO;
    if (0 != sigaction(SIGUSR1, &act, &old_1))
    {
        perror("sigaction () failed installing SIGUSR1 handler");
        return EXIT_FAILURE;
    }
    if (0 != sigaction(SIGUSR2, &act, &old_2))
    {
        perror("sigaction() failed installing SIGUSR2 handler");
        return EXIT_FAILURE;
    }
    // Main body of "work" during which two signals
    // will be raised, after 5 and 10 seconds, and which
    // will print last received signal
    for (int i = 1; i <= 15; i++)
    {
        if (i == 5)
        {
            if (0 != raise(SIGUSR1))
            {
                perror("Can't raise SIGUSR1");
                return EXIT_FAILURE;
            }
        }
        if (i == 10)
        {
            if (0 != raise(SIGUSR2))
            {
                perror("Can't raise SIGUSR2");
                return EXIT_FAILURE;
            }
        }
        printf("Tick #%d, last caught signal: %d\n",
            i, last_received_signal);
        sleep(1);
    }
    // Restore old signal handlers
    if (0 != sigaction(SIGUSR1, &old_1, NULL))
    {
        perror("sigaction() failed restoring SIGUSR1 handler");
        return EXIT_FAILURE;
    }
    if (0 != sigaction(SIGUSR2, &old_2, NULL))
    {
        perror("sigaction() failed restoring SIGUSR2 handler");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
Cela produit:
Tick #1, last caught signal: 0
Tick #2, last caught signal: 0
Tick #3, last caught signal: 0
Tick #4, last caught signal: 0
Tick #5, last caught signal: 30
Tick #6, last caught signal: 30
Tick #7, last caught signal: 30
Tick #8, last caught signal: 30
Tick #9, last caught signal: 30
Tick #10, last caught signal: 31
Tick #11, last caught signal: 31
Tick #12, last caught signal: 31
Tick #13, last caught signal: 31
Tick #14, last caught signal: 31
Tick #15, last caught signal: 31
Un processus qui se suicide en utilisant kill ()
 Un processus peut (essayer de) envoyer un signal à tout autre processus en utilisant la fonction kill() . 
 Pour ce faire, le processus d'envoi doit connaître le PID du processus de réception. Comme, sans introduire de race, un processus ne peut être sûr que de son propre PID (et des PID de ses enfants), l'exemple le plus simple pour démontrer l'utilisation de kill() consiste à envoyer un signal à lui-même. 
 Ci-dessous, un exemple de processus initiant sa propre terminaison en s'envoyant un kill-signal ( SIGKILL ): 
#define _POSIX_C_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main (void)
{
  pid_t pid = getpid(); /* Get my iown process ID. */
  kill(pid, SIGKILL); /* Send myself a KILL signal. */
  puts("Signal delivery initiated.");  /* Although not guaranteed, 
                                  practically the program never gets here. */
  pause(); /* Wait to die. */
  puts("This never gets printed.");
}
Sortie:
Killed
(... ou similaire, selon l'implémentation)
Gérer SIGPIPE généré par write () d'une manière thread-safe
 Lorsque write() est appelé pour un socket ou un socket de flux nommé ou non nommé dont la fin de lecture est fermée, deux choses se produisent: 
-  SIGPIPEsignalSIGPIPEest envoyé au processus appeléwrite()
-  SIGPIPEsignalSIGPIPEest envoyé au thread qui a appeléwrite()
-  EPIPEerreurEPIPEest renvoyée parwrite()
 Il y a plusieurs façons de traiter avec SIGPIPE : 
-  Pour les sockets, SIGPIPEpeut être désactivé en définissant des options spécifiques à la plate-forme telles queMSG_NOSIGNALsous Linux etSO_NOSIGPIPEdans BSD (fonctionne uniquement pour l'send, mais pas pour l'write). Ce n'est pas portable.
-  Pour les FIFO (canaux nommés), SIGPIPEne sera pas généré si writer utiliseO_RDWRau lieu deO_WRONLY, afin que la fin de la lecture soit toujours ouverte. Cependant, cela désactiveEPIPEaussi.
-  Nous pouvons ignorer SIGPIPEou définir le gestionnaire global. C'est une bonne solution, mais ce n'est pas acceptable si vous ne contrôlez pas toute l'application (par exemple, vous écrivez une bibliothèque).
-  Avec les versions récentes de POSIX, nous pouvons utiliser le fait que SIGPIPEest envoyé au thread qui a appeléwrite()et le gère en utilisant la technique de traitement du signal synchrone.
 Le code ci-dessous illustre la gestion SIGPIPE sans risque pour POSIX.1-2004 et les versions ultérieures. 
C'est inspiré par ce post :
-  Tout d'abord, ajoutez SIGPIPEau signal de masque du thread en cours en utilisantpthread_sigmask().
-  Vérifiez si SIGPIPEest déjà en attente à l'aide desigpending().
-  Appelez write(). Si la fin de la lecture est fermée,SIGPIPEsera ajouté au masque de signaux en attente etEPIPEsera renvoyé.
-  Si write()renvoyéEPIPEet queSIGPIPEn'était pas déjà en attente avantwrite(), supprimez-le du masque de signaux en attente à l'aide desigtimedwait().
-  Restaurer le masque de signal original en utilisant pthread_sigmask().
Code source:
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <sys/signal.h>
ssize_t safe_write(int fd, const void* buf, size_t bufsz)
{
    sigset_t sig_block, sig_restore, sig_pending;
    sigemptyset(&sig_block);
    sigaddset(&sig_block, SIGPIPE);
    /* Block SIGPIPE for this thread.
     *
     * This works since kernel sends SIGPIPE to the thread that called write(),
     * not to the whole process.
     */
    if (pthread_sigmask(SIG_BLOCK, &sig_block, &sig_restore) != 0) {
        return -1;
    }
    /* Check if SIGPIPE is already pending.
     */
    int sigpipe_pending = -1;
    if (sigpending(&sig_pending) != -1) {
        sigpipe_pending = sigismember(&sig_pending, SIGPIPE);
    }
    if (sigpipe_pending == -1) {
        pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
        return -1;
    }
    ssize_t ret;
    while ((ret = write(fd, buf, bufsz)) == -1) {
        if (errno != EINTR)
            break;
    }
    /* Fetch generated SIGPIPE if write() failed with EPIPE.
     *
     * However, if SIGPIPE was already pending before calling write(), it was
     * also generated and blocked by caller, and caller may expect that it can
     * fetch it later. Since signals are not queued, we don't fetch it in this
     * case.
     */
    if (ret == -1 && errno == EPIPE && sigpipe_pending == 0) {
        struct timespec ts;
        ts.tv_sec = 0;
        ts.tv_nsec = 0;
        int sig;
        while ((sig = sigtimedwait(&sig_block, 0, &ts)) == -1) {
            if (errno != EINTR)
                break;
        }
    }
    pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
    return ret;
}