Segnale (IPC) - Signal (IPC)

I segnali sono messaggi standardizzati inviati a un programma in esecuzione per attivare comportamenti specifici, come l'uscita o la gestione degli errori. Sono una forma limitata di comunicazione interprocesso (IPC), tipicamente utilizzata in Unix , Unix-like e altri sistemi operativi conformi a POSIX .

Un segnale è una notifica asincrona inviata a un processo oa un thread specifico all'interno dello stesso processo per notificargli un evento. Gli usi comuni di segnali sono di interrompere, sospendere, interrompere o uccidere un processo. I segnali hanno avuto origine negli anni '70 Bell Labs Unix e sono stati successivamente specificati nello standard POSIX .

Quando viene inviato un segnale, il sistema operativo interrompe il normale flusso di esecuzione del processo di destinazione per fornire il segnale. L'esecuzione può essere interrotta durante qualsiasi istruzione non atomica . Se il processo ha precedentemente registrato un gestore di segnale , quella routine viene eseguita. In caso contrario, viene eseguito il gestore del segnale predefinito.

I programmi incorporati possono trovare segnali utili per le comunicazioni tra processi, poiché i segnali sono notevoli per la loro efficienza algoritmica .

I segnali sono simili agli interrupt , con la differenza che gli interrupt sono mediati dalla CPU e gestiti dal kernel mentre i segnali sono mediati dal kernel (possibilmente tramite chiamate di sistema) e gestiti dai singoli processi . Il kernel può passare un interrupt come un segnale al processo che ha causato (tipici esempi sono SIGSEGV , SIGBUS , SIGILL e SIGFPE ).

Storia

La versione 1 Unix aveva chiamate di sistema separate per catturare interruzioni, chiusure e trap della macchina. La versione 4 combinava tutte le trap in un'unica chiamata, segnale e ogni trap numerata riceveva un nome simbolico nella versione 7 . kill è apparso nella versione 2 e nella versione 5 poteva inviare segnali arbitrari. Il piano 9 dei Bell Labs ha sostituito i segnali con note , che consentono l'invio di stringhe brevi e arbitrarie.

Invio di segnali

La chiamata di sistema kill (2) invia un segnale specificato a un processo specificato, se le autorizzazioni lo consentono. Allo stesso modo, il comando kill(1) consente a un utente di inviare segnali ai processi. La funzione di libreria raise(3) invia il segnale specificato al processo corrente.

Eccezioni come la divisione per zero o una violazione della segmentazione genereranno segnali (qui, rispettivamente, SIGFPE "floating point exception" e SIGSEGV "segmentation violazione", che entrambi per impostazione predefinita causano un core dump e un'uscita dal programma).

Il kernel può generare segnali per notificare i processi di eventi. Ad esempio, SIGPIPE verrà generato quando un processo scrive su una pipe che è stata chiusa dal lettore; per impostazione predefinita, ciò causa la terminazione del processo, il che è utile quando si costruiscono pipeline di shell .

La digitazione di determinate combinazioni di tasti sul terminale di controllo di un processo in esecuzione fa sì che il sistema invii determinati segnali:

  • Ctrl-C (nei vecchi Unix, DEL) invia un segnale INT ("interrupt", SIGINT ); per impostazione predefinita, ciò causa l'interruzione del processo.
  • Ctrl-Z invia un segnale TSTP ("terminal stop", SIGTSTP ); per impostazione predefinita, questo fa sì che il processo sospenda l'esecuzione.
  • Ctrl-\ invia un segnale QUIT ( SIGQUIT ); per impostazione predefinita, questo provoca la chiusura del processo e il dump del core.
  • Ctrl-T (non supportato su tutti gli UNIX) invia un segnale INFO ( SIGINFO ); per impostazione predefinita e, se supportato dal comando, questo fa sì che il sistema operativo mostri informazioni sul comando in esecuzione.

Queste combinazioni di tasti predefinite con i moderni sistemi operativi possono essere modificate con il comando stty .

Gestione dei segnali

I gestori di segnale possono essere installati con la chiamata di sistema signal(2) o sigaction(2) . Se non è installato un gestore di segnale per un segnale particolare, viene utilizzato il gestore predefinito. Altrimenti il ​​segnale viene intercettato e viene richiamato il gestore del segnale. Il processo può anche specificare due comportamenti predefiniti, senza creare un gestore: ignorare il segnale (SIG_IGN) e utilizzare il gestore di segnale predefinito (SIG_DFL). Ci sono due segnali che non possono essere intercettati e gestiti: SIGKILL e SIGSTOP .

Rischi

La gestione del segnale è vulnerabile alle condizioni di gara . Poiché i segnali sono asincroni, è possibile fornire un altro segnale (anche dello stesso tipo) al processo durante l'esecuzione della routine di gestione del segnale.

La chiamata sigprocmask(2) può essere utilizzata per bloccare e sbloccare la consegna dei segnali. I segnali bloccati non vengono consegnati al processo fino a quando non vengono sbloccati. I segnali che non possono essere ignorati (SIGKILL e SIGSTOP) non possono essere bloccati.

I segnali possono causare l'interruzione di una chiamata di sistema in corso, lasciando all'applicazione la gestione di un riavvio non trasparente .

I gestori del segnale devono essere scritti in modo tale da non provocare effetti collaterali indesiderati, ad es. alterazione dell'errno , alterazione della maschera del segnale, modifica della disposizione del segnale e altre modifiche agli attributi del processo globale . Anche l'uso di funzioni non rientranti , ad esempio malloc o printf , all'interno di gestori di segnale è pericoloso. In particolare, la specifica POSIX e il segnale della pagina man di Linux (7) richiedono che tutte le funzioni di sistema chiamate direttamente o indirettamente da una funzione di segnale siano sicure per il segnale asincrono . La pagina man di signal-safety(7) fornisce un elenco di tali funzioni di sistema sicure per il segnale asincrono (praticamente le chiamate di sistema ), altrimenti è un comportamento indefinito . Si suggerisce di impostare semplicemente qualche volatile sig_atomic_tvariabile in un gestore di segnale e di testarla altrove.

I gestori del segnale possono invece mettere il segnale in una coda e tornare immediatamente. Il thread principale continuerà quindi "ininterrotto" fino a quando i segnali non vengono presi dalla coda, come in un ciclo di eventi . "Ininterrotto" qui significa che le operazioni che si bloccano possono tornare prematuramente e devono essere riprese , come accennato in precedenza. I segnali dovrebbero essere elaborati dalla coda sul thread principale e non dai pool di lavoratori , poiché ciò reintroduce il problema dell'asincronicità. Tuttavia, la gestione di una coda non è possibile in modo sicuro dal segnale asincrono con solo sig_atomic_t , poiché solo le singole letture e scritture su tali variabili sono garantite come atomiche, non incrementi o (fetch-and)-decrementi, come sarebbe richiesto per una coda. Quindi, effettivamente, solo un segnale per gestore può essere accodato in modo sicuro con sig_atomic_t fino a quando non è stato elaborato.

Relazione con le eccezioni hardware

L' esecuzione di un processo può comportare la generazione di un'eccezione hardware , ad esempio, se il processo tenta di dividere per zero o incorre in un errore di pagina .

Nei sistemi operativi simili a Unix , questo evento modifica automaticamente il contesto del processore per avviare l'esecuzione di un gestore di eccezioni del kernel . In caso di alcune eccezioni, come un errore di pagina , il kernel dispone di informazioni sufficienti per gestire completamente l'evento stesso e riprendere l'esecuzione del processo.

Altre eccezioni, tuttavia, il kernel non può elaborare in modo intelligente e deve invece rinviare l'operazione di gestione delle eccezioni al processo di errore. Questo differimento è ottenuto tramite il meccanismo del segnale, in cui il kernel invia al processo un segnale corrispondente all'eccezione corrente. Ad esempio, se un processo tentasse una divisione intera per zero su una CPU x86 , verrebbe generata un'eccezione di errore di divisione e il kernel invierà il segnale SIGFPE al processo.

Allo stesso modo, se il processo tentasse di accedere a un indirizzo di memoria al di fuori del suo spazio di indirizzi virtuale , il kernel notificherebbe al processo questa violazione tramite un segnale SIGSEGV . L'esatta mappatura tra i nomi dei segnali e le eccezioni dipende ovviamente dalla CPU, poiché i tipi di eccezione differiscono tra le architetture.

Segnali POSIX

L'elenco seguente documenta i segnali specificati nella Single Unix Specification . Tutti i segnali sono definiti come macro costanti nel <signal.h>file di intestazione. Il nome della macro costante è costituito da un prefisso "SIG" seguito da un nome mnemonico per il segnale.

SIGABRT eSIGIOT
Il segnale SIGABRT e SIGIOT viene inviato a un processo per dirgli di abortire , cioè di terminare. Il segnale viene solitamente avviato dal processo stesso quando richiama la abort()funzione della libreria standard C , ma può essere inviato al processo dall'esterno come qualsiasi altro segnale.
SIGALRM ,SIGVTALRM eSIGPROF
Il segnale SIGALRM, SIGVTALRM e SIGPROF viene inviato a un processo quando scade il limite di tempo specificato in una chiamata a una precedente funzione di impostazione dell'allarme (come setitimer). SIGALRM viene inviato allo scadere del tempo reale o dell'orologio. SIGVTALRM viene inviato allo scadere del tempo CPU utilizzato dal processo. SIGPROF viene inviato allo scadere del tempo CPU utilizzato dal processo e dal sistema per conto del processo.
SIGBUS
Il segnale SIGBUS viene inviato a un processo quando provoca un errore del bus . Le condizioni che portano all'invio del segnale sono, ad esempio, un errato allineamento dell'accesso alla memoria o un indirizzo fisico inesistente.
SIGCHLD
Il segnale SIGCHLD viene inviato a un processo quando un processo figlio termina , viene interrotto o riprende dopo essere stato interrotto. Un uso comune del segnale consiste nell'istruire il sistema operativo a ripulire le risorse utilizzate da un processo figlio dopo la sua terminazione senza una chiamata esplicita alla chiamata di waitsistema.
SIGCONT
Il segnale SIGCONT indica al sistema operativo di continuare (riavviare) un processo precedentemente sospeso dal segnale SIGSTOP o SIGTSTP. Un uso importante di questo segnale è nel controllo del lavoro nella shell Unix .
SIGFPE
Il segnale SIGFPE viene inviato a un processo quando è stata rilevata una condizione eccezionale (ma non necessariamente errata) nell'hardware aritmetico in virgola mobile o intero. Ciò può includere la divisione per zero , underflow o overflow in virgola mobile, overflow di numeri interi, un'operazione non valida o un calcolo inesatto. Il comportamento può variare a seconda dell'hardware.
SIGHUP
Il segnale SIGHUP viene inviato a un processo quando il suo terminale di controllo è chiuso. È stato originariamente progettato per notificare il processo di una caduta della linea seriale (un hangup ). Nei sistemi moderni, questo segnale di solito significa che lo pseudo terminale o virtuale di controllo è stato chiuso. Molti demoni (che non hanno un terminale di controllo) interpretano la ricezione di questo segnale come una richiesta di ricaricare i loro file di configurazione e svuotare/riaprire i loro file di log invece di uscire. nohup è un comando per fare in modo che un comando ignori il segnale.
SIGILL
Il segnale SIGILL viene inviato a un processo quando si tenta di eseguire illegale , composto correttamente, sconosciuto, o privilegiato istruzione .
SIGINT
Il segnale SIGINT viene inviato a un processo dal suo terminale di controllo quando un utente desidera interrompere il processo. Questo viene in genere avviato premendo Ctrl+C , ma su alcuni sistemi è possibile utilizzare il carattere " cancella " o il tasto " interruzione ".
SIGKILL
Il segnale SIGKILL viene inviato a un processo per farlo terminare immediatamente ( kill ). A differenza di SIGTERM e SIGINT, questo segnale non può essere catturato o ignorato e il processo di ricezione non può eseguire alcuna pulizia dopo aver ricevuto questo segnale. Si applicano le seguenti eccezioni:
  • I processi zombi non possono essere uccisi poiché sono già morti e aspettano che i loro processi genitori li raccolgano.
  • I processi che si trovano nello stato bloccato non moriranno finché non si riattiveranno.
  • Il processo init è speciale: non riceve segnali che non vuole gestire e quindi può ignorare SIGKILL. Un'eccezione a questa regola è mentre init viene tracciato su Linux.
  • Un processo ininterrotto di sospensione non può terminare (e liberare le sue risorse) anche quando viene inviato SIGKILL. Questo è uno dei pochi casi in cui potrebbe essere necessario riavviare un sistema UNIX per risolvere un problema software temporaneo.
SIGKILL viene utilizzato come ultima risorsa quando si terminano i processi nella maggior parte delle procedure di arresto del sistema se non si chiude volontariamente in risposta a SIGTERM. Per velocizzare la procedura di spegnimento del computer, Mac OS X 10.6, noto anche come Snow Leopard , invierà SIGKILL alle applicazioni che si sono contrassegnate come "pulite" con conseguente tempi di spegnimento più rapidi senza, presumibilmente, effetti negativi. Il comando killall -9ha un effetto simile, sebbene pericoloso, quando viene eseguito ad esempio in Linux; non consente ai programmi di salvare i dati non salvati. Ha altre opzioni e, con nessuna, utilizza il segnale SIGTERM più sicuro.
SIGPIPE
Il segnale SIGPIPE viene inviato a un processo quando tenta di scrivere su una pipe senza un processo connesso all'altra estremità.
SIGPOLL
Il segnale SIGPOLL viene inviato quando si verifica un evento su un descrittore di file controllato in modo esplicito. Il suo utilizzo porta effettivamente a effettuare richieste di I/O asincrone poiché il kernel eseguirà il polling del descrittore al posto del chiamante. Fornisce un'alternativa al polling attivo .
SIGRTMIN aSIGRTMAX
I segnali da SIGRTMIN a SIGRTMAX sono destinati ad essere utilizzati per scopi definiti dall'utente. Sono segnali in tempo reale .
SIGQUIT
Il segnale SIGQUIT viene inviato a un processo dal suo terminale di controllo quando l'utente richiede che il processo esca ed esegua un core dump .
SIGSEGV
Il SIGSEGV segnale viene inviato a un processo quando si fa un riferimento non valido memoria virtuale, o segmentazione guasto , cioè quando si esegue una seg mentazione v iolation .
SIGSTOP
Il segnale SIGSTOP indica al sistema operativo di interrompere un processo per una successiva ripresa.
SIGSYS
Il segnale SIGSYS viene inviato a un processo quando passa un argomento errato a una chiamata di sistema . In pratica, questo tipo di segnale si incontra raramente poiché le applicazioni si affidano a librerie (ad esempio libc ) per effettuare la chiamata. SIGSYS può essere ricevuto da applicazioni che violano le regole di sicurezza di Linux Seccomp configurate per limitarle. SIGSYS può essere utilizzato anche per emulare chiamate di sistema esterne, ad esempio emulare chiamate di sistema Windows su Linux.
SIGTERM
Il segnale SIGTERM viene inviato a un processo per richiederne la terminazione . A differenza del segnale SIGKILL, può essere catturato e interpretato o ignorato dal processo. Ciò consente al processo di eseguire una buona terminazione rilasciando risorse e salvando lo stato se appropriato. SIGINT è quasi identico a SIGTERM.
SIGTSTP
Il SIGTSTP segnale viene inviato ad un processo per la sua controllando terminale richiedere a fermata ( t erminal st o p ). Viene comunemente avviato dall'utente premendo Ctrl+Z . A differenza di SIGSTOP, il processo può registrare un gestore di segnale per o ignorare il segnale.
SIGTTIN eSIGTTOU
I SIGTTIN e SIGTTOU segnali sono inviati ad un processo quando si tenta di leggere in o scrivere fuori rispettivamente ricavati tty mentre in fondo . Tipicamente, questi segnali vengono ricevuti solo dai processi sotto il controllo del lavoro ; i demoni non hanno terminali di controllo e, quindi, non dovrebbero mai ricevere questi segnali.
SIGTRAP
Il segnale SIGTRAP viene inviato a un processo quando si verifica un'eccezione (o trap ): una condizione di cui un debugger ha richiesto di essere informato, ad esempio quando viene eseguita una particolare funzione o quando una particolare variabile cambia valore.
SIGURG
Il segnale SIGURG viene inviato a un processo quando un socket dispone di dati urgenti o fuori banda disponibili per la lettura.
SIGUSR1 eSIGUSR2
I segnali SIGUSR1 e SIGUSR2 vengono inviati a un processo per indicare condizioni definite dall'utente .
SIGXCPU
Il segnale SIGXCPU viene inviato ad un processo quando ha esaurito la CPU per una durata che supera un certo valore predeterminato impostabile dall'utente. L'arrivo di un segnale SIGXCPU fornisce al processo di ricezione la possibilità di salvare rapidamente eventuali risultati intermedi e di uscire con garbo, prima che venga terminato dal sistema operativo utilizzando il segnale SIGKILL.
SIGXFSZ
Il segnale SIGXFSZ viene inviato a un processo quando cresce un file che supera la dimensione massima consentita .
SIGWINCH
Il segnale SIGWINCH viene inviato a un processo quando il terminale di controllo cambia la sua dimensione (una win dow ch ange).

Azione predefinita

Un processo può definire come gestire i segnali POSIX in ingresso . Se un processo non definisce un comportamento per un segnale, viene utilizzato il gestore predefinito per quel segnale. La tabella seguente elenca alcune azioni predefinite per i sistemi UNIX compatibili con POSIX, come FreeBSD , OpenBSD e Linux .

Segnale
Numero portatile
Azione predefinita Descrizione
SIGABRT 6 Termina (core dump) Segnale di interruzione del processo
SIGALRM 14 Terminare Sveglia
SIGBUS N / A Termina (core dump) Accesso a una porzione indefinita di un oggetto di memoria
SIGCHLD N / A Ignorare Processo figlio terminato, interrotto o continuato
SIGCONT N / A Continua Continua l'esecuzione, se interrotto
SIGFPE 8 Termina (core dump) Operazione aritmetica errata
SIGHUP 1 Terminare Appendere
SIGILL 4 Termina (core dump) Istruzione illegale
SIGINT 2 Terminare Segnale di interruzione del terminale
SIGKILL 9 Terminare Uccidi (non può essere catturato o ignorato)
SIGPIPE 13 Terminare Scrivi su una pipa senza che nessuno lo legga
SIGPOLL N / A Terminare Evento sondabile
SIGPROF N / A Terminare Timer di profilazione scaduto
SIGQUIT 3 Termina (core dump) Segnale di chiusura del terminale
SIGSEGV 11 Termina (core dump) Riferimento di memoria non valido
SIGSTOP N / A Fermare Interrompi l'esecuzione (non può essere catturato o ignorato)
SIGSYS N / A Termina (core dump) Cattiva chiamata di sistema
SIGTERM 15 Terminare Segnale di terminazione
SIGTRAP 5 Termina (core dump) Traccia/trappola punto di interruzione
SIGTSTP N / A Fermare Segnale di arresto del terminale
SIGTTIN N / A Fermare Processo in background durante il tentativo di lettura
SIGTTOU N / A Fermare Processo in background che tenta di scrivere
SIGUSR1 N / A Terminare Segnale definito dall'utente 1
SIGUSR2 N / A Terminare Segnale definito dall'utente 2
SIGURG N / A Ignorare I dati fuori banda sono disponibili su una presa
SIGVTALRM N / A Terminare Timer virtuale scaduto
SIGXCPU N / A Termina (core dump) Limite di tempo della CPU superato
SIGXFSZ N / A Termina (core dump) Limite dimensione file superato
SIGWINCH N / A Ignorare La dimensione della finestra del terminale è cambiata
Numero portatile:
Per la maggior parte dei segnali il numero di segnale corrispondente è definito dall'implementazione. Questa colonna elenca i numeri specificati nello standard POSIX.
Azioni spiegate:
Terminate  – Interruzione anomala del processo. Il processo viene terminato con tutte le conseguenze di _exit() eccetto che lo stato reso disponibile per wait() e waitpid() indica una terminazione anomala da parte del segnale specificato.
Terminate (core dump)  – Terminazione anomala del processo. Inoltre, possono verificarsi azioni di terminazione anomale definite dall'implementazione, come la creazione di un file principale.
Ignora  – Ignora il segnale.
Stop  – Arresta (non termina) il processo.
Continua  – Continua il processo, se è stato interrotto; in caso contrario ignorare il segnale.

Segnali vari

I seguenti segnali non sono specificati nella specifica POSIX . Tuttavia, a volte vengono utilizzati su vari sistemi.

SIGEMT
Il segnale SIGEMT viene inviato a un processo quando si verifica un trap dell'emulatore .
SIGNINFO
Il segnale SIGINFO viene inviato a un processo quando viene ricevuta una richiesta di stato ( info ) dal terminale di controllo.
SIGPWR
Il segnale SIGPWR viene inviato a un processo quando il sistema subisce un'interruzione di corrente .
SIGLOST
Il segnale SIGLOST viene inviato a un processo quando un file lock viene perso .
SIGSTKFLT
Il segnale SIGSTKFLT viene inviato a un processo quando il coprocessore sperimenta una v ac k f au lt (cioè popping quando la pila è vuota o spingendo quando è pieno). È definito da, ma non utilizzato su Linux, dove un errore dello stack del coprocessore x87 genererà invece SIGFPE.
SIGUNUSED
Il segnale SIGUNUSED viene inviato a un processo quando viene effettuata una chiamata di sistema con un numero di chiamata di sistema inutilizzato . È sinonimo di SIGSYS sulla maggior parte delle architetture.
SIGCLD
Il segnale SIGCLD è sinonimo di SIGCHLD.

Guarda anche

Riferimenti

link esterno