In che modo SIGINT si relaziona agli altri segnali di terminazione come SIGTERM, SIGQUIT e SIGKILL?


103

Sui sistemi POSIX, i segnali di terminazione di solito hanno il seguente ordine (in base a molte pagine MAN e alle specifiche POSIX):

  1. SIGTERM: chiedi cortesemente di terminare un processo. Terminerà correttamente, ripulendo tutte le risorse (file, socket, processi figli, ecc.), Eliminando i file temporanei e così via.

  2. SIGQUIT - richiesta più forte. Terminerà sgradevole, ripulendo ancora le risorse che hanno assolutamente bisogno di essere ripulite, ma forse non cancellerà i file temporanei, forse scriverà le informazioni di debug da qualche parte; su alcuni sistemi verrà scritto anche un core dump (indipendentemente dal fatto che il segnale venga catturato dall'app o meno).

  3. SIGKILL - richiesta più forte. Al processo non viene nemmeno chiesto di fare nulla, ma il sistema ripulirà il processo, che sia così o meno. Molto probabilmente viene scritto un core dump.

Come si inserisce SIGINT in quell'immagine? Un processo CLI viene solitamente terminato da SIGINT quando l'utente preme CRTL + C, tuttavia un processo in background può anche essere terminato da SIGINT utilizzando l'utility KILL. Quello che non riesco a vedere nelle specifiche o nei file di intestazione è se SIGINT è più o meno forte di SIGTERM o se c'è qualche differenza tra SIGINT e SIGTERM.

AGGIORNARE:

La migliore descrizione dei segnali di terminazione che ho trovato finora è nella documentazione GNU LibC . Spiega molto bene che c'è una differenza intenzionale tra SIGTERM e SIGQUIT.

Dice di SIGTERM:

È il modo normale per chiedere cortesemente di terminare un programma.

E dice di SIGQUIT:

[...] e produce un core dump quando termina il processo, proprio come un segnale di errore del programma. Si può pensare a questa come una condizione di errore del programma "rilevata" dall'utente. [...] Alcuni tipi di pulizie sono meglio omessi nella gestione di SIGQUIT. Ad esempio, se il programma crea file temporanei, dovrebbe gestire le altre richieste di terminazione eliminando i file temporanei. Ma è meglio che SIGQUIT non li elimini, in modo che l'utente possa esaminarli insieme al core dump.

E anche SIGHUP è spiegato abbastanza bene. SIGHUP non è realmente un segnale di terminazione, significa semplicemente che la "connessione" con l'utente è stata persa, quindi l'app non può aspettarsi che l'utente legga ulteriori output (es. Stdout / stderr output) e non ci sono input da aspettarsi dal utente più a lungo. Per la maggior parte delle app, ciò significa che è meglio chiudere. In teoria un'app potrebbe anche decidere di entrare in modalità daemon quando viene ricevuto un SIGHUP e ora viene eseguita come processo in background, scrivendo l'output in un file di registro configurato. Per la maggior parte dei demoni già in esecuzione in background, SIGHUP di solito significa che devono riesaminare i propri file di configurazione, quindi lo si invia ai processi in background dopo aver modificato i file di configurazione.

Tuttavia non c'è alcuna spiegazione utile di SIGINT in questa pagina, a parte quella che viene inviata da CRTL + C. C'è qualche motivo per gestire SIGINT in un modo diverso da SIGTERM? In caso affermativo, quale sarebbe questo motivo e come sarebbe diverso il trattamento?


1
Buona domanda. Sospetto che alcuni dei cruft storici di Unix sarebbero coinvolti nella risposta.
Alex B

So che questa domanda è vecchia, ma nel caso qualcuno venisse qui per un ampio elenco di segnali per il tuo sistema operativo (Linux), puoi trovarli digitando sudo fuser -lsul prompt dei comandi. Per me questo fa apparire:HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED
Nick Bull

3
Prova anche kill -lper un elenco di segnali.
AAAfarmclub

Risposte:


88

SIGTERM e SIGKILL sono destinati a richieste generiche di "terminazione di questo processo". SIGTERM (per impostazione predefinita) e SIGKILL (sempre) causeranno la chiusura del processo. SIGTERM può essere catturato dal processo (ad es. In modo che possa eseguire la propria pulizia se lo desidera), o addirittura ignorato completamente; ma SIGKILL non può essere catturato o ignorato.

SIGINT e SIGQUIT sono destinati specificamente alle richieste dal terminale: è possibile assegnare caratteri di ingresso particolari per generare questi segnali (a seconda delle impostazioni di controllo del terminale). L'azione predefinita per SIGINT è lo stesso tipo di terminazione del processo dell'azione predefinita per SIGTERM e dell'azione non modificabile per SIGKILL; anche l'azione predefinita per SIGQUIT è la terminazione del processo, ma possono verificarsi ulteriori azioni definite dall'implementazione, come la generazione di un core dump. O può essere intercettato o ignorato dal processo, se necessario.

SIGHUP, come dici tu, ha lo scopo di indicare che la connessione del terminale è stata persa, piuttosto che essere un segnale di terminazione in quanto tale. Ma, ancora una volta, l'azione predefinita per SIGHUP (se il processo non lo cattura o lo ignora) è terminare il processo allo stesso modo di SIGTERM ecc.

C'è una tabella nelle definizioni POSIX per la signal.hquale elenca i vari segnali e le loro azioni e scopi predefiniti, e il capitolo Interfaccia generale del terminale include molti più dettagli sui segnali relativi al terminale.


10
Questo è il punto chiave: SIGINT e SIGQUIT possono essere generati da terminale utilizzando singoli caratteri, mentre il programma è in esecuzione. Gli altri segnali devono essere generati da un altro programma, in qualche modo (ad es. Dal comando kill). SIGINT è meno violento di SIGQUIT; quest'ultimo produce un core dump. SIGKILL non può essere intrappolato. SIGHUP viene generato se la tua connessione si blocca (la finestra si chiude, ecc.). Quindi, hanno tutti significati diversi.
Jonathan Leffler

TTY Demystified ha alcune informazioni facilmente digeribili su come i segnali interagiscono con il sottosistema tty del kernel. Aggiunge un po 'di contesto alla tua risposta.
Daniel Näslund

2
Sembra che le specifiche non siano molto precise, ma la mia comprensione è che SIgint chiede al programma di interrompere l'azione corrente, non necessariamente di uscire. Per un programma progettato solo eseguire un'azione per esecuzione che implica la chiusura, ma per un programma interattivo che ha una sorta di ciclo di lettura-valutazione-stampa, può significare rinunciare all'eval corrente e tornare alla lettura dell'input dell'utente. Penso che lo faccia meno su Sigint.
bdsl

Quale segnale viene inviato durante il riavvio?
Dan Dascalescu

10

Come ha notato DarkDust, molti segnali hanno gli stessi risultati, ma i processi possono attribuire loro azioni diverse distinguendo come ogni segnale viene generato. Guardando il codice sorgente del kernel di FreeBSD (kern_sig.c) vedo che i due segnali sono gestiti allo stesso modo, terminano il processo e vengono consegnati a qualsiasi thread.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */

9

man 7 signal

Questa è la comoda pagina di manuale non normativa del progetto di pagine di manuale di Linux che spesso si desidera consultare per informazioni sui segnali di Linux.

La versione 3.22 menziona cose interessanti come:

I segnali SIGKILL e SIGSTOP non possono essere catturati, bloccati o ignorati.

e contiene la tabella:

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at tty
SIGTTIN   21,21,26    Stop    tty input for background process
SIGTTOU   22,22,27    Stop    tty output for background process

che riassume il segnale Actionche distingue ad esempio SIGQUIT da SIGQUIT, poiché SIGQUIT ha azione Coree SIGINT Term.

Le azioni sono documentate nello stesso documento:

The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.
Core   Default action is to terminate the process and dump core (see core(5)).
Stop   Default action is to stop the process.
Cont   Default action is to continue the process if it is currently stopped.

Non vedo alcuna differenza tra SIGTERM e SIGINT dal punto di vista del kernel poiché entrambi hanno azione Termed entrambi possono essere catturati. Sembra che sia solo una "distinzione di convenzione di utilizzo comune":

  • SIGINT è ciò che accade quando si esegue CTRL-C dal terminale
  • SIGTERM è il segnale predefinito inviato da kill

Alcuni segnali sono ANSI C e altri no

Una notevole differenza è che:

  • SIGINT e SIGTERM sono ANSI C, quindi più portabili
  • SIGQUIT e SIGKILL non lo sono

Sono descritti nella sezione "7.14 Gestione dei segnali" della bozza C99 N1256 :

  • SIGINT riceve un segnale di attenzione interattivo
  • SIGTERM una richiesta di terminazione inviata al programma

il che rende SIGINT un buon candidato per un Ctrl + C. interattivo

POSIX 7

POSIX 7 documenta i segnali con l' signal.hintestazione: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

Questa pagina ha anche la seguente tabella di interesse che menziona alcune delle cose che avevamo già visto in man 7 signal:

Signal    Default Action   Description
SIGABRT   A                Process abort signal.
SIGALRM   T                Alarm clock.
SIGBUS    A                Access to an undefined portion of a memory object.
SIGCHLD   I                Child process terminated, stopped,
SIGCONT   C                Continue executing, if stopped.
SIGFPE    A                Erroneous arithmetic operation.
SIGHUP    T                Hangup.
SIGILL    A                Illegal instruction.
SIGINT    T                Terminal interrupt signal.
SIGKILL   T                Kill (cannot be caught or ignored).
SIGPIPE   T                Write on a pipe with no one to read it.
SIGQUIT   A                Terminal quit signal.
SIGSEGV   A                Invalid memory reference.
SIGSTOP   S                Stop executing (cannot be caught or ignored).
SIGTERM   T                Termination signal.
SIGTSTP   S                Terminal stop signal.
SIGTTIN   S                Background process attempting read.
SIGTTOU   S                Background process attempting write.
SIGUSR1   T                User-defined signal 1.
SIGUSR2   T                User-defined signal 2.
SIGTRAP   A                Trace/breakpoint trap.
SIGURG    I                High bandwidth data is available at a socket.
SIGXCPU   A                CPU time limit exceeded.
SIGXFSZ   A                File size limit exceeded.

BusyBox init

Il rebootcomando predefinito 1.29.2 di BusyBox invia un SIGTERM ai processi, rimane inattivo per un secondo e quindi invia SIGKILL. Questa sembra essere una convenzione comune tra diverse distribuzioni.

Quando si arresta un sistema BusyBox con:

reboot

invia un segnale al processo di inizializzazione.

Quindi, il gestore del segnale init finisce per chiamare:

static void run_shutdown_and_kill_processes(void)
{
    /* Run everything to be run at "shutdown".  This is done _prior_
     * to killing everything, in case people wish to use scripts to
     * shut things down gracefully... */
    run_actions(SHUTDOWN);

    message(L_CONSOLE | L_LOG, "The system is going down NOW!");

    /* Send signals to every process _except_ pid 1 */
    kill(-1, SIGTERM);
    message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
    sync();
    sleep(1);

    kill(-1, SIGKILL);
    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    sync();
    /*sleep(1); - callers take care about making a pause */
}

che stampa sul terminale:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes

Ecco un minimo esempio concreto di ciò .

Segnali inviati dal kernel


8

Dopo una rapida ricerca su Google per sigint vs sigterm , sembra che l'unica differenza prevista tra i due sia se è stata avviata da una scorciatoia da tastiera o da una chiamata esplicita a kill.

Di conseguenza, potresti, ad esempio, intercettare sigint e fare qualcosa di speciale con esso, sapendo che probabilmente è stato inviato da una scorciatoia da tastiera. Forse aggiorna lo schermo o qualcosa del genere, invece di morire (non consigliato, poiché le persone si aspettano ^Cdi uccidere il programma, solo un esempio).

Ho anche imparato che ^\dovrebbe inviare sigquit, che potrei iniziare a usare da solo. Sembra molto utile.


3

Usando kill(sia la chiamata di sistema che l'utility` puoi inviare quasi qualsiasi segnale a qualsiasi processo, dato che hai il permesso. Un processo non può distinguere come un segnale ha preso vita e chi lo ha inviato.

Detto questo, SIGINT ha davvero lo scopo di cantare l'interruzione Ctrl-C, mentre SIGTERM è il segnale terminale generale. Non esiste il concetto di un segnale "più forte", con la sola eccezione che ci sono segnali che non possono essere bloccati o gestiti (SIGKILL e SIGSTOP, secondo la pagina man).

Un segnale può essere solo "più forte" di un altro segnale rispetto a come un processo di ricezione gestisce il segnale (e qual è l'azione predefinita per quel segnale). Ad esempio, per impostazione predefinita, sia SIGTERM che SIGINT portano alla risoluzione. Ma se ignori SIGTERM, non terminerà il tuo processo, mentre SIGINT lo fa ancora.


0

Con l'eccezione di pochi segnali, i gestori di segnali possono catturare i vari segnali, oppure il comportamento predefinito alla ricezione di un segnale può essere modificato. Vedere la signal(7)pagina man per i dettagli.


Sì, ma se non conosco "il significato" di un singolo, cogliere il segnale è inutile, perché non saprò cosa fare nella mia applicazione. GNU C ad esempio spiega la differenza tra SIGQUIT e SIGTERM. Ma fornisce poche informazioni su SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.html
Mecki

"Il SIGINTsegnale (" interruzione del programma ") viene inviato quando l'utente digita il carattere INTR (normalmente C-c)." "SIGINT 2 Term Interrupt from keyboard" Si preme Ctrl-C, SIGINTviene inviato. Il processo normalmente muore. Cos'altro dare?
Ignacio Vazquez-Abrams

Potenzialmente potrebbe esserci una descrizione dell'intenzione che il programmatore dovrebbe presumere che l'utente avrà quando premerà ctrl-c, ovvero la semantica del messaggio. Ad esempio, le specifiche HTTP chiariscono che quando un utente invia una richiesta GET, il server non deve presumere che desideri che faccia qualcosa tranne che inviare una risposta.
bdsl
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.