Přeskočit na obsah

Signál (informatika)

Z Wikipedie, otevřené encyklopedie

Úvod

Signály jsou jednoduché zprávy, které se posílají procesům. Signály slouží v Unix- like 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).

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 program pokračuje 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
    (např. SIGILL- Illegal Instruction posílá jádro, jestliže se proces pokusí provést přednostní instrukci jádra)
  2. Signály, vznikající mimo proces při asynchronní události
    (např. 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, která jsou nadefinována v souboru.

Když proces dostane signál, pokaždé zareaguje nějakou akcí.
Tyto akce se dělí 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, tzv. neřekne nic jiného.
  2. Ignorování signálu- proces může na signály reagovat, tím pádem může jejich příchod ignorovat.
  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- zruší 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 realné UID. Ve FreeBSD se musí UID procesů shodovat.
Signál se může poslat v shellu voláním:

#kill [-s signal] pid

Signály původně vznikly kvůli ukončování procesů, proto kill.
Pokud se neuvede číslo signálu, posílá se implicitně 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ě procesu (podel hodnoty pid). Je-li sid==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í- často jen zaznamená, že přišel signál a program poté mimo handler kontroluje (periodicky), zda přišel signál a provádí nějakou 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 definovaná:

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- defaultní 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 (př. SA_RESTART- restartovat přerušená sytémová volání, SA_ONESHOT- po prvním obsloužení nastavit obsluhu na deaultní akci).
Podrobnější popis lze najít v manuálových stránkách- 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. Narozdí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().

Odkazy a zdroje

Programování v C
Časopis programátor
Jazyk C
Root.cz
abclinuxu