Segnali

Uno dei meccanismi di Inter Process Communication sono i segnali.

Un segnale è un messaggio semplice con semantica predefinita a seconda del suo identificativo (come le bandiere di segnalazione marittima). Il segnale può essere inviato ad un processo

  • dal kernel - segnale di sistema - per indicare anomalie; p.es. Segment Violation è un segnale
  • da un altro processo - segnale utente - usando ilkernel come intermediario

Delivery

NB: i segnali sono, per forza di cose, asincroni. Quando il processo inviante è attivo, non necessariamente lo è anche il processo ricevente, specie con una sola CPU. E' il kernel che 'recapita' il segnale quando il ricevente diventa attivo nella CPU.

Un processo non aspetta un segnale, lo riceve come 'evento'.

Linux ha una ricca collezione di segnali, più di 40. Alcuni di rilievo sono:

num nome significato
1 hangup il terminale di controllo non è più connesso
2 interrupt l'utente ha premuto Ctrl-C
3 quit l'utente ha premuto Ctrl-\
4 illegal operation il processo ha tentato una divisione per zero o altra operazione impossibile
9 kill il processo è stato 'ucciso'
10 usr1 a disposizione dei programmatori
11 segment violation il processo ha tentato un accesso fuori mappa
15 terminate il processo riceve una richiesta di terminazione

Per avere una lista completa dei segnali, linux fornisce il comando kill -l.

Quando un processo riceve un segnale ha a disposizione tre comportamenti:

  • default - morire
  • ignorarlo - un processo setta una maschera dei segnali che intende ricevere, (quasi) tutti gli altri sono ignorati
  • gestirlo - un processo ha registrato una funzione di callback per ogni segnale che non ignora, e viene invocata alla ricezione del segnale

Tutti i segnali si possono ignorare o gestire, tranne il 9 (kill), alla ricezione del quale si può solo morire.

Ogni (bravo) programmatore Linux deve fornire una procedura di gestione per il segnale 15 (terminate), che gli dia modo di chiudere eventuali file aperti o connessioni, rilasciare risorse, salvare lo stato se necessario, e poi terminare di propria iniziativa.

Quanto sopra è tanto più vero quando un processo è in un Cgroup, che condivide le risorse. In tal caso il processo corrente che termina, deve anche indicarlo al capogruppo.

I processi di un Cgroup che terminano, non vengono immediatamente rimossi dalla memoria, ma rimangono in stato detto Zombie, in attesa che anche tutti gli altri membri del gruppo abbiano terminato. Solo allora il capogruppo rilascia effettivamente le risorse, e tutti gli zombies vengono 'mietuti'.

Il Comando 'kill'

Sintassi:

kill [-segnale] PID

invia il segnale al processo indicato.

Il segnale di default è il 15 (terminate). Questo è il modo in cui si devono terminare i processi.

Solo quando, per motivi runtime, il processo è 'appeso', si può a malincuore inviare kill -9 PID, correndo i rischi inerenti a questo metodo.

Si può inviare un kill -9 solo ai propri processi. Tranne evidentemente che l'amministratore può inviarlo a qualsiasi processo.

Kill1

Attenzione

I servizi di sistema, organizzati in Cgroups hanno procedure di terminazione corretta del servizio, che vengono invocate dal comando systemctl, o service in versioni più vecchie.

Non ammazzare mai processi a caso, componenti di un servizio, o l'intero servizio può trovarsi in uno stato inconsistente.

Il Segnale 'quit'

Se un nostro bellissimo programma è 'appeso', forse in loop infinito, e lo terminiamo con Ctrl-C (segnale di interrupt), il processo termina e noi non sapremo mai perchè era appeso.

C'è la possibilità di terminare il processo in foreground con i tasti `Ctrl-\? (segnale di quit) e, con oppurtuna previa disposizione, verrà prodotto un file di Core Dump, contenente lo stato della memoria virtuale del processo all'istante della sua terminazione. (Viene detto anche il cadavere del processo).

Se il programma era stato compilato col supporto al debugger è quindi possibile ispezionare il file di core.

Lasciare i cadaveri a giro è deprecato di default, però.

Quit1

Limiti di utilizzo risorse

Il comando ulimit -a mostra i limiti di utilizzo risorse per l'utente corrente:

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7385
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7385
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
$

Per ciascun parametro viene anche indicata l'opzione per cambiarlo.

Un tempo l'amministratore di sistema in un file di configurazione globale, imponeva limiti diversi per utenti diversi, ma questo ambiente è scomparso.

Non vi sono effettivamente limiti: se un parametro non è esplicitamente marcato unlimited, ha comunque un valore di default che è il massimo supportato dal sistema.

Tranne che il 'core file size' che di default è zero. Per cambiarlo:

ulimit -c unlimited

Ora si può provare l'esercizio:

$ ulimit -c unlimited
$ sleep 2000
^\Quit (core dumped)
$ ls -l
total 384
-rw------- 1 mich mich 393216 mar 16 18:29 core
$

Con eventualmente:

$ gdb core
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
"/tmp/xx/core": not in executable format: File format not recognized
(gdb) backtrace
No stack.
(gdb) quit
$

Il debugger è gdb, ma non riconosce il file poichè l'eseguibile non era stato compilato col supporto al debugger.

results matching ""

    No results matching ""