Signál (informatika)

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:

  1. 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
  2. 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:

  1. 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
  2. Ignorování signálu – proces nemusí na signály reagovat
  3. 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áluKód signáluPopis
SIGABRT6Proces přerušen
SIGALRM14Vygenerován signál alarm
SIGBUS10Chyba sběrnice: „přístup do nedefinované oblasti paměti“
SIGCHLD18Potomek ukončen, pozastaven nebo znovu pokračuje*
SIGCONT25Pokračování, je-li pozastaven
SIGFPE8Chyba při zpracování čísla v plovoucí řádové čárce: „chybná aritmetická operace“
SIGHUP1Signál zavěšení
SIGILL4Neplatná strojová instrukce
SIGINT2Přerušení
SIGKILL9Kill (okamžité ukončení)
SIGPIPE13Zápis do roury, ze které nikdo nečte
SIGQUIT3Ukončit a vygenerovat core
SIGSEGV11Porušení ochrany paměti (segmentation fault, segmentation violation)
SIGSTOP23Dočasné pozastavení procesu
SIGTERM15Ukončení (žádost o ukončení)
SIGTSTP23Ukončující stop signál
SIGTTIN26Proces na pozadí se pokouší číst z TTY ("vstup")
SIGTTOU27Proces na pozadí se pokouší zapisovat na TTY ("výstup")
SIGUSR116Uživatelsky definovaný 1
SIGUSR217Uživatelsky definovaný 2
SIGPOLL22Událost pro pooling
SIGPROF29Expirace profilovacího časovače
SIGSYS12Neplatné systémové volání
SIGTRAP5Krokování nebo bod přerušení (trap, vnitřní přerušení)
SIGURG21Na soketu jsou připravena urgentní data
SIGVTALRM28Signalizace od časovače virtuálního času: "vypršel virtuální časovač"
SIGXCPU30Překročen limit času CPU
SIGXFSZ31Př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