Ricerca…


Sintassi

  • allarme senza segno (secondi senza segno);
  • int kill (pid_t pid, int sig);

Parametri

Funzione, parametro (i), valore di ritorno Descrizione
alarm() nome della funzione
unsigned seconds Secondi per alzare un allarme o 0 per annullare qualsiasi allarme in sospeso
> = 0 0 se nessun altro allarme era in sospeso, altrimenti il ​​numero di secondi in cui l'allarme in attesa era ancora aperto. Questa funzione non fallirà.
- -
kill() nome della funzione
pid_t pid .
int sig 0 o ID segnale
0, -1 In caso di esito positivo 0 viene restituito, -1 in caso di errore con l'impostazione di errno su EINVAL , EPERM o ESRCH .

Aumentare SIGALARM con l'azione predefinita

Utilizzando l' alarm , l'utente può programmare il segnale SIGALARM da sollevare dopo l'intervallo specificato. Nel caso in cui l'utente non abbia bloccato, ignorato o specificato il gestore di segnale esplicito per questo segnale, l'azione predefinita per questo segnale verrà eseguita all'arrivo. L'azione predefinita di specifica per SIGALARM è terminare il processo:

#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;
}

Questo produce:

Hello!
1
2
3
4
5
[2]    35086 alarm      ./a.out

Impostare il gestore del segnale usando sigaction e alzando i segnali usando raise

Affinché un programma possa reagire a un determinato segnale, oltre all'azione predefinita, il gestore di segnale personalizzato può essere installato utilizzando sigaction . sigaction riceve tre argomenti - signal to act on, puntatore alla struttura sigaction_t che, se non NULL , sta descrivendo un nuovo comportamento e un puntatore a sigaction_t che, se non NULL sarà riempito con il vecchio comportamento (quindi è possibile ripristinarlo). Alzare i segnali nello stesso processo può essere fatto con il metodo raise . Se è necessario un maggiore controllo (per inviare il segnale ad un altro processo, è possibile utilizzare kill o pthread_kill , che accettano l'id del processo di destinazione o l'id del 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;
}

Questo produce:

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 processo che si suicida usando kill ()

Un processo può (provare a) inviare un segnale a qualsiasi altro processo usando la funzione kill() .

Per fare ciò, il processo di invio deve conoscere il PID del processo di ricezione. Come, senza introdurre una gara, un processo può essere sicuro solo del proprio PID (e dei PID dei suoi figli), l'esempio più semplice per dimostrare l'uso di kill() è che un processo invii un segnale a se stesso.

Di seguito un esempio di un processo che avvia la propria terminazione inviando un segnale di kill ( 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.");
}

Produzione:

Killed

(... o simili, a seconda dell'implementazione)

Gestisci SIGPIPE generato da write () in modo thread-safe

Quando write() viene chiamato per un pipe con named o senza nome o un socket di flusso la cui estremità di lettura è chiusa, accadono due cose:

POSIX.1-2001
  1. SIGPIPE segnale SIGPIPE viene inviato al processo che ha chiamato write()
POSIX.1-2004
  1. SIGPIPE segnale SIGPIPE viene inviato al thread che ha chiamato write()
  1. EPIPE errore EPIPE viene restituito da write()

Esistono diversi modi per gestire SIGPIPE :

  • Per i socket, SIGPIPE può essere disabilitato impostando opzioni specifiche della piattaforma come MSG_NOSIGNAL in Linux e SO_NOSIGPIPE in BSD (funziona solo per send , ma non per write ). Questo non è portatile.
  • Per FIFO (named pipe), SIGPIPE non verrà generato se writer usa O_RDWR invece di O_WRONLY , in modo che la fine della lettura sia sempre aperta. Tuttavia, ciò disabilita anche EPIPE .
  • Possiamo ignorare SIGPIPE o impostare il gestore globale. Questa è una buona soluzione, ma non è accettabile se non controlli l'intera applicazione (ad esempio stai scrivendo una biblioteca).
  • Con le versioni POSIX recenti, possiamo usare il fatto che SIGPIPE viene inviato al thread che ha chiamato write() e gestirlo utilizzando la tecnica di gestione del segnale sincrono.

Il codice seguente mostra la gestione SIGPIPE thread-safe per POSIX.1-2004 e successivi.

È ispirato da questo post :

  • Innanzitutto, aggiungi SIGPIPE per segnalare la maschera del thread corrente usando pthread_sigmask() .
  • Controlla se c'è già SIGPIPE sospeso usando sigpending() .
  • Chiama write() . Se la lettura della fine è chiusa, SIGPIPE verrà aggiunto alla maschera dei segnali in attesa e verrà restituito EPIPE .
  • Se write() restituito EPIPE e SIGPIPE non era già in sospeso prima di write() , rimuoverlo dalla maschera dei segnali in sospeso usando sigtimedwait() .
  • Ripristina la maschera del segnale originale usando pthread_sigmask() .

Codice sorgente:

#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;
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow