Signál je v informatice jednoduchá zpráva, která se posílá procesům. Signály slouží v unixových systémech k informování procesu o výskytu události. Pomocí signálů lze meziprocesově komunikovat a manipulovat s procesy (ukončovat, pozastavovat, atd.).
Příjemcem/odesílatelem signálu může být jen proces (v Unixech může být odesílatelem i jádro operačního systému).
Jestliže proces obdrží signál, začne se ihned provádět příslušná akce, i když nebyla dokončena právě zpracovávaná funkce. Mluvíme tzv. o asynchronních signálech. Po dokončení akce pokračuje program od místa přerušení (pokud nebyl ukončen).
Dělení signálů
Signály se dělí do dvou skupin:
- Signály, které se posílají při chybové události
- SIGILL (Illegal Instruction) – posílá jádro, jestliže se proces pokusí provést neplatnou, neznámou nebo privilegovanou instrukci
- Signály vznikající mimo proces při asynchronní události
- SIGINT (Interrupt) posílá se procesu po stisknutí
CTRL-c
Druhy akcí
Signál je jen obyčejné celé číslo. Jestliže však o nich mluvíme, odvoláváme se na ně jmény.
Když proces dostane signál, zareaguje nějakou akcí, které dělíme do tří skupin:
- Implicitní akce – každý signál má za následek provedení nějaké implicitní akce, která je provedena, pokud proces, pro který je signál určen, nevyžaduje jinou akci
- Ignorování signálu – proces nemusí na signály reagovat
- Obsluha signálu – příchozí signál se obslouží pomocí uživatelsky definované funkce (handler). Jakmile se provede, proces pokračuje od místa, kde byl signálem přerušen.
Seznam implicitních akcí
- exit – zrušení procesu
- core – zrušení procesu a uložení obsahu jeho paměti do souboru core- ten se využívá pro analyzování chyb
- ignore – ignorování signálu
- stop – pozastavení procesu
- continue – pokračování pozastaveného procesu
Dva signály provedou implicitní akci vždy. Je to SIGKILL (ukončí proces) a SIGSTOP (pozastaví proces).
Posílání signálů
Proces s UID (User ID) rovným nule může poslat signál libovolnému procesu. Proces, který má UID různé od nuly, může v Linuxu poslat signál těm procesům, které mají stejné reálné nebo saved UID jako má on reálné UID. Ve FreeBSD se musí UID procesů shodovat.
Signál pošleme z příkazového řádku (shellu) příkazem:
# kill [-s signal] PID
PID je číslo procesu (Process ID). Příkaz se jmenuje kill (česky zabít), protože původně vznikl kvůli ukončování procesů. Pokud není uvedeno číslo signálu, posílá se implicitně signál TERM.
Programově se signál posílá voláním funkce:
int kill(pid_t pid, int sig); // (viz man 2 kill)
Funkce pošle signál sig jednomu nebo skupině procesů (podle hodnoty PID). Je-li sig==O, tak se pouze zjistí, má-li proces oprávnění poslat signál. Jakým procesům se signál pošle, záleží jen pid:
- pid > 0 – pošle se procesu s pid
- pid == 0 – pošle se procesům ve stejné skupině
- pid == -1 – pošle se všem procesům kromě systémových
- pid < -1 – pošle se procesům ve skupině s číslem -pid
Obsluha signálů
Jak je psáno výše, jsou signály asynchronní. Při obsluze tedy není zřejmé, v jakém se proces nachází stavu. Kvůli tomu by se měly v handlerech provádět jen bezpečné funkce (man sigaction). Výkon handleru pro obsluhu může být přerušen příchodem jiného signálu. Handler by měl vykonávat co nejméně operací, proto často jen zaznamená, že přišel signál. Program mimo handler periodicky kontroluje, zda přišel signál a eventuálně provádí požadovanou akci.
K nastavení obsluhy signálu slouží funkce:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
Funkce nastaví obsluhu signálu sig podle act a do oldact uloží předchozí nastavení obsluhy. Struktura sigaction je definována takto:
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
kde void (*sa_handler)(int)
specifikuje akci svázanou se signálem – buď adresa handleru nebo SIG_DFL (výchozí akce), SIG_IGN (ignorování signálu). Díky sigset_t sa_mask
můžeme nastavit masku signálu, které budou blokovány v handleru. int sa_flags
přetvářejí chování handleru (např. SA_RESTART – restartovat přerušená systémová volání, SA_ONESHOT – po prvním obsloužení nastavit obsluhu na výchozí akci). Podrobnější popis lze najít v manuálových stránkách, viz man sigaction
.
Někdy je těžké zajistit, aby program správně obsloužil signál, který může kdykoliv přijít a přerušit běh programu. Jestliže se tomuto chceme vyhnout, použijeme mechanismus blokování signálu. Blokované signály jsou ignorovány až do jejich odblokování, poté jsou procesu doručeny. Na rozdíl od ignorovaných, které jádro zahazuje a tak nejsou nikdy doručeny. K nastavování blokovaných signálů se používá funkce:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
Funkce nastaví masku blokovaných signálů a vrátí starou masku. Chování se nastaví hodnotou how
– SIG_BLOCK (blokují se stejné signály jako doposud a navíc ty definované argumentem set
), SIG_UNBLOCK (signály v set
jsou vyjmuty z blokovaných), SIG_SETMASK (blokovány signály definované v set
).
Maska signálu se nastavuje funkcemi:
int sigemptyset(sigset_t *set)
– inicializuje množinu signálů danou set na prázdnou
int sigfillset(sigset_t *set)
– inicializuje množinu signálů danou set na všechny definované signály
int sigaddset(sigset_t *set, int signum)
– přidá do množiny signálu signál signum
int sigdelset(sigset_t *set, int signum)
– vymaže z množiny signálů signál signum
int sigismember(const sigset_t *set, int signum)
– zjistí, zda je signál v dané množině signálů
Pro získání signálů, které čekají na odblokování, se používá funkce int sigpending(sigset_t *set);
. Pokud je potřeba proces pozastavit, dokud nepřijde nějaký signál, využívá se funkce int pause()
nebo funkce int sigsuspend(const sigset_t *sigmask)
, která dále mění masku blokovaných signálů danou pointrem *sigmask
.
Seznam signálů
Rodina standardů Single UNIX Specification definuje následující signály v hlavičkovém souboru signal.h
:
Název signálu
|
Kód signálu
|
Popis
|
SIGABRT
|
6
|
Ukončení procesu
|
SIGALRM
|
14
|
Vygenerován signál alarm
|
SIGBUS
|
10
|
Chyba sběrnice: „přístup do nedefinované oblasti paměti“
|
SIGCHLD
|
18
|
Potomek ukončen, pozastaven nebo znovu pokračuje*
|
SIGCONT
|
25
|
Pokračování, je-li pozastaven
|
SIGFPE
|
8
|
Chyba při zpracování čísla v plovoucí řádové čárce: „chybná aritmetická operace“
|
SIGHUP
|
1
|
Signál zavěšení
|
SIGILL
|
4
|
Neplatná strojová instrukce
|
SIGINT
|
2
|
Přerušení
|
SIGKILL
|
9
|
Kill (okamžité ukončení)
|
SIGPIPE
|
13
|
Zápis do roury, ze které nikdo nečte
|
SIGQUIT
|
3
|
Ukončit a vygenerovat core
|
SIGSEGV
|
11
|
Porušení ochrany paměti (segmentation fault, segmentation violation)
|
SIGSTOP
|
23
|
Dočasné pozastavení procesu
|
SIGTERM
|
15
|
Ukončení (žádost o ukončení)
|
SIGTSTP
|
23
|
Ukončující stop signál
|
SIGTTIN
|
26
|
Proces na pozadí se pokouší číst z TTY ("vstup")
|
SIGTTOU
|
27
|
Proces na pozadí se pokouší zapisovat na TTY ("výstup")
|
SIGUSR1
|
16
|
Uživatelsky definovaný 1
|
SIGUSR2
|
17
|
Uživatelsky definovaný 2
|
SIGPOLL
|
22
|
Událost pro polling
|
SIGPROF
|
29
|
Expirace profilovacího časovače
|
SIGSYS
|
12
|
Neplatné systémové volání
|
SIGTRAP
|
5
|
Krokování nebo bod přerušení (trap, vnitřní přerušení)
|
SIGURG
|
21
|
Na soketu jsou připravena urgentní data
|
SIGVTALRM
|
28
|
Signalizace od časovače virtuálního času: "vypršel virtuální časovač"
|
SIGXCPU
|
30
|
Překročen limit času CPU
|
SIGXFSZ
|
31
|
Překročen limit velikosti souboru
|
Poznámka: Hvězdička označuje rozšíření X/Open System Interfaces (XSI). Popis v uvozovkách přidán podle SUS.[1]
Reference
Externí odkazy