GNU/Linux >> Znalost Linux >  >> Linux

Základy signálů Linuxu – část I

Co je to signál? Signály jsou softwarová přerušení.

Robustní program potřebuje zvládnout signály. Je to proto, že signály představují způsob, jak aplikaci doručit asynchronní události.

Uživatel, který stiskne ctrl+c, proces vysílá signál k ukončení jiného procesu atd., to vše jsou případy, kdy proces musí provést zpracování signálu.

Linuxové signály

V Linuxu má každý signál jméno, které začíná znaky SIG. Například:

  • Signál SIGINT, který je generován, když uživatel stiskne ctrl+c. Toto je způsob ukončení programů z terminálu.
  • SIGALRM  se generuje, když se vypne časovač nastavený funkcí budíku.
  • Signál SIGABRT je generován, když proces volá funkci přerušení.
  • atd

Když se signál objeví, proces musí říct jádru, co s ním má dělat. Mohou existovat tři možnosti, pomocí kterých lze signál zlikvidovat:

  1. Signál lze ignorovat. Ignorováním máme na mysli, že se při výskytu signálu nic neudělá. Většinu signálů lze ignorovat, ale signály generované hardwarovými výjimkami, jako je dělení nulou, pokud jsou ignorovány, mohou mít podivné důsledky. Také nelze ignorovat několik signálů jako SIGKILL a SIGSTOP.
  2. Signál lze zachytit. Když je vybrána tato možnost, proces zaregistruje funkci s jádrem. Tato funkce je volána jádrem, když se objeví tento signál. Pokud signál není pro proces fatální, pak v této funkci může proces zpracovat signál správně nebo se může rozhodnout ukončit ladně.
  3. Nechte použít výchozí akci. Každý signál má výchozí akci. Může to být ukončení procesu, ignorování atd.

Jak jsme již uvedli, dva signály SIGKILL a SIGSTOP nelze ignorovat. Je to proto, že tyto dva signály poskytují uživateli root nebo jádru způsob, jak zabít nebo zastavit jakýkoli proces v jakékoli situaci. Výchozí akcí těchto signálů je ukončení procesu. Tyto signály nelze zachytit ani ignorovat.

Co se stane při spuštění programu?

Vše závisí na procesu, který volá exec. Když je proces spuštěn, stav všech signálů je buď ignorován, nebo je výchozí. Je to pozdější možnost, která se pravděpodobně stane, pokud proces, který volá exec, ignoruje signály.

Vlastností funkcí exec je změnit akci na libovolném signálu na výchozí akci. Jednodušeji řečeno, pokud má rodič funkci zachycování signálu, která je volána při výskytu signálu, pak pokud tento rodič vykonává nový podřízený proces, pak tato funkce nemá v novém procesu žádný význam, a proto je dispozice stejného signálu nastavena na výchozí hodnotu. v novém procesu.

Také, protože obvykle máme procesy běžící na pozadí, takže shell pouze nastaví dispozice signálu ukončení jako ignorovaný, protože nechceme, aby byly procesy na pozadí ukončeny uživatelem stisknutím klávesy ctrl+c, protože to maří účel vytvoření procesu. běžet na pozadí.

Proč by funkce zachycení signálu měly být reentrantní?

Jak jsme již probrali, jednou z možností dispozice signálu je zachycení signálu. V procesním kódu se to provádí registrací funkce do jádra, kterou jádro volá, když se objeví signál. Jedna věc, kterou je třeba mít na paměti, je, že funkce, kterou proces registruje, by měla být reentrantní.

Než vysvětlíme důvod, nejprve pochopíme, co jsou reentrantní funkce? Reentrantní funkce je funkce, jejíž provádění může být mezi tím z jakéhokoli důvodu zastaveno (například kvůli přerušení nebo signálu) a poté může být znovu bezpečně spuštěno předtím, než její předchozí vyvolání dokončí provádění.

Nyní se vrátíme k problému:Předpokládejme, že funkce func() je registrována pro zpětné volání při výskytu signálu. Nyní předpokládejme, že tato funkce func() již byla spuštěna, když se signál objevil. Protože tato funkce je zpětným voláním pro tento signál, aktuální provádění tohoto signálu bude plánovačem zastaveno a tato funkce bude volána znovu (kvůli signálu).

Problém může být, pokud funkce func() pracuje na některých globálních hodnotách nebo datových strukturách, které jsou ponechány v nekonzistentním stavu, když bylo provádění této funkce uprostřed zastaveno, pak druhé volání stejné funkce (kvůli signálu) může způsobit nežádoucí výsledky.

Takže říkáme, že funkce zachycování signálu by měly být reentrantní.

V našich článcích send-signal-to-process a Linux fuser command naleznete praktické příklady, jak posílat signály procesu.

Vlákna a signály

Již jsme viděli v jedné z předchozích sekcí, že manipulace se signálem má svou vlastní složitost (jako je použití reentrantních funkcí). Ke složitosti máme obvykle vícevláknové aplikace, kde se manipulace se signálem stává opravdu komplikovanou.

Každé vlákno má svou vlastní masku soukromého signálu (masku, která definuje, které signály jsou doručitelné), ale způsob, jakým se provádí dispozice signálu, je sdílen všemi vlákny v aplikaci. To znamená, že dispozice pro určitý signál nastavený vláknem může být snadno přepsána nějakým jiným vláknem. V tomto případě se mechanismus uspořádání změní pro všechna vlákna.

Například vlákno A se může rozhodnout ignorovat určitý signál, ale vlákno B ve stejném procesu se může rozhodnout zachytit stejný signál registrací funkce zpětného volání do jádra. V tomto případě je požadavek vlákna A přepsán požadavkem vlákna B.

Signály jsou v jakémkoli procesu dodávány pouze do jednoho vlákna. Kromě hardwarových výjimek nebo vypršení časovače (které jsou doručeny vláknu, které událost způsobilo), jsou všechny signály předávány procesu libovolně.

K odstranění tohoto nedostatku existuje několik POSIX API, jako je pthread_sigmask() atd., které lze použít.

V dalším článku (část 2) této série probereme, jak zachytit signály v procesu, a vysvětlíme praktický aspekt zpracování signálů pomocí úryvků kódu.


Linux
  1. Proces spouštění Linuxu

  2. Stavy procesu Linuxu

  3. Linux CreateProcess?

  1. Jak mohu v Linuxu zjistit, který proces poslal mému procesu signál

  2. Kdy je setsid() užitečné nebo proč potřebujeme seskupovat procesy v Linuxu?

  3. Vytvoření démona v Linuxu

  1. UNIX / Linux:3 způsoby odesílání signálu do procesů

  2. Úvod do Linuxových vláken – část I

  3. Linux:proces do služby