GNU/Linux >> Znalost Linux >  >> Linux

Linux Signals – příklad programu C pro zachycení signálů (SIGINT, SIGKILL, SIGSTOP atd.)

V 1. části série Linux Signals jsme se dozvěděli o základních konceptech linuxových signálů.

V návaznosti na předchozí část se v tomto článku naučíme, jak zachytit signály v procesu. Představíme praktický aspekt zpracování signálu pomocí fragmentů kódu programu C.

Zachycení signálu

Jak již bylo uvedeno v předchozím článku, pokud si proces přeje zpracovávat určité signály, pak v kódu musí tento proces zaregistrovat do jádra funkci zpracování signálů.

Následuje prototyp funkce zpracování signálu:

void <signal handler func name> (int sig)

Funkce zpracování signálu má typ návratu void a přijímá číslo signálu odpovídající signálu, který je třeba zpracovat.

Aby se funkce obsluhy signálu registrovala do jádra, je ukazatel funkce obslužného signálu předán jako druhý argument funkci ‚signál‘. Prototyp funkce signálu je :

void (*signal(int signo, void (*func )(int)))(int);

Může se to zdát jako složité prohlášení. Pokud se to pokusíme dekódovat:

  • Funkce vyžaduje dva argumenty.
  • Prvním argumentem je celé číslo (znak) znázorňující číslo signálu nebo hodnotu signálu.
  • Druhý argument je ukazatel na funkci zpracování signálu, která přijímá celé číslo jako argument a nevrací nic (void).
  • Zatímco samotná funkce „signál“ vrací ukazatel funkce, jehož návratový typ je neplatný.

Abychom to usnadnili, použijeme typedef :

typedef void sigfunc(int)

Takže zde jsme vytvořili nový typ „sigfunc“. Nyní pomocí tohoto typedef, pokud předěláme prototyp obsluhy signálu:

sigfunc *signal(int, sigfunc*);

Nyní vidíme, že je snazší pochopit, že funkce zpracování signálu přijímá celé číslo a ukazatel funkce typu sigfunc, zatímco vrací ukazatel funkce typu sigfunc.

Ukázkový program C pro zachycení signálu

Většina uživatelů Linuxu používá k ukončení procesů v Linuxu kombinaci kláves Ctr+C.

Přemýšleli jste někdy o tom, co se za tím skrývá? Kdykoli se stiskne ctrl+c, do procesu se odešle signál SIGINT. Výchozí akcí tohoto signálu je ukončení procesu. Ale i tento signál se dá zvládnout. Následující kód to ukazuje:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
  if (signo == SIGINT)
    printf("received SIGINT\n");
}

int main(void)
{
  if (signal(SIGINT, sig_handler) == SIG_ERR)
  printf("\ncan't catch SIGINT\n");
  // A long long wait so that we can easily issue a signal to this process
  while(1) 
    sleep(1);
  return 0;
}

Ve výše uvedeném kódu jsme simulovali dlouho běžící proces pomocí nekonečné smyčky while.

Funkce sig_handler se používá jako obsluha signálu. Tato funkce je zaregistrována do jádra předáním jako druhý argument systémového volání ‚signal‘ ve funkci main(). Prvním argumentem funkce ‚signal‘ je signál, který chceme obsluhovat signálem, což je v tomto případě SIGINT.

Na okraj, použití funkce sleep(1) má svůj důvod. Tato funkce byla použita ve smyčce while, takže smyčka while se spustí po nějaké době (tj. v tomto případě po jedné sekundě). To se stává důležitým, protože jinak by nekonečná smyčka při divokém běhu mohla spotřebovat většinu CPU, což by způsobilo, že počítač je velmi velmi pomalý.

Každopádně se vrátíme, až bude proces spuštěn a pokusíme se proces ukončit pomocí Ctrl+C:

$ ./sigfunc
^Creceived SIGINT
^Creceived SIGINT
^Creceived SIGINT
^Creceived SIGINT
^Creceived SIGINT
^Creceived SIGINT
^Creceived SIGINT

Ve výše uvedeném výstupu vidíme, že jsme několikrát zkusili kombinaci kláves ctrl+c, ale pokaždé se proces neukončil. Je to proto, že signál byl zpracován v kódu a to bylo potvrzeno z tisku, který jsme dostali na každém řádku.

SIGKILL, SIGSTOP a uživatelem definované signály

Kromě zpracování standardních signálů (jako INT, TERM atd.), které jsou k dispozici. Můžeme mít také uživatelem definované signály, které lze odesílat a zpracovávat. Následuje kód zpracovávající uživatelsky definovaný signál USR1:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
    if (signo == SIGUSR1)
        printf("received SIGUSR1\n");
    else if (signo == SIGKILL)
        printf("received SIGKILL\n");
    else if (signo == SIGSTOP)
        printf("received SIGSTOP\n");
}

int main(void)
{
    if (signal(SIGUSR1, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGUSR1\n");
    if (signal(SIGKILL, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGKILL\n");
    if (signal(SIGSTOP, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGSTOP\n");
    // A long long wait so that we can easily issue a signal to this process
    while(1) 
        sleep(1);
    return 0;
}

Vidíme, že ve výše uvedeném kódu jsme se pokusili zpracovat uživatelsky definovaný signál USR1. Také, jak víme, dva signály KILL a STOP nelze zvládnout. Pokusili jsme se tedy také zpracovat tyto dva signály, abychom viděli, jak v tomto případě reaguje systémové volání „signál“.

Když spustíme výše uvedený kód:

$ ./sigfunc

can't catch SIGKILL

can't catch SIGSTOP

Takže výše uvedený výstup jasně ukazuje, že jakmile se systémové volání „signal“ pokusí zaregistrovat handler pro signály KILL a STOP, signální funkce selže, což znamená, že tyto dva signály nelze zachytit.

Nyní se pokusíme předat signál USR1 tomuto procesu pomocí příkazu kill:

$ kill -USR1 2678

a na terminálu, kde běží výše uvedený program, vidíme :

$ ./sigfunc

can't catch SIGKILL

can't catch SIGSTOP
received SIGUSR1

Vidíme tedy, že uživatelsky definovaný signál USR1 byl během procesu přijat a byl správně zpracován.


Linux
  1. Co dělá program, když je odeslán signál Sigkill?

  2. Oprávnění souborů v Linuxu s příkladem

  3. Příklad Cobol Hello World:Jak psát, kompilovat a spouštět program Cobol na OS Linux

  1. 13 Základní systémová volání Linuxu vysvětlena pomocí zábavného virového programu Linux

  2. zavolejte funkci po dokončení programu pomocí ctrl c

  3. Ctrl + C přerušení zpracování událostí v Linuxu

  1. Linux – Jaké jsou různé způsoby nastavení oprávnění k souborům atd. na Gnu/linux?

  2. Linux – Může Ctrl+c odeslat signál Sigint více procesům?

  3. Co se stane, když pošlete SIGKILL do Zombie Process v Linuxu?