GNU/Linux >> Znalost Linux >  >> Linux

Kdy je signál zpracován a proč některé informace zamrznou?

termA nezamrzne. Pouze zobrazuje zpětné volání ve vstupním poli. Jednoduše stiskněte Enter pokračujte v zadávání.


Než vysvětlíte svůj problém, trochu kontextu o tom, jak read příkaz funguje. Načítá vstupní data z stdin do EOF se narazí. Je bezpečné vyslovit volání na read příkaz je neblokující, pokud jde o čtení ze souborů na disku. Ale když stdin je připojen k terminálu, příkaz se zablokuje, dokud uživatel něco nenapíše.

Jak obslužné programy signálů fungují?

Jednoduché vysvětlení, jak funguje zpracování signálu. Viz níže uvedený úryvek v C který funguje pouze na SIGINT (také znám jako CTRL+C )

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

/* signal handler definition */
void signal_handler(int signum){
  printf("Hello World!\n");
}

int main(){
  //Handle SIGINT with a signal handler
  signal(SIGINT, signal_handler);
  //loop forever!
  while(1);
}

Zaregistruje obsluhu signálu a poté vstoupí do nekonečné smyčky. Když narazíme na Ctrl-C , všichni se shodneme na tom, že obsluha signálu signal_handler() by se měl spustit a "Hello World!" vytiskne na obrazovku, ale program byl v nekonečné smyčce. Chcete-li vytisknout "Hello World!" muselo to být tak, že to přerušilo smyčku pro spuštění obsluhy signálu, že? Mělo by tedy opustit smyčku i program. Podívejme se:

gcc -Wall -o sighdl.o signal.c
./sighdl.o 
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!

Jak ukazuje výstup, pokaždé jsme vydali Ctrl-C , "Hello World!" vytiskne, ale program se vrátí do nekonečné smyčky. Je to až po vydání SIGQUIT signál s Ctrl-\ program skutečně skončil. V závislosti na vašem ulimit nastavení, vypíše jádro nebo vytiskne číslo přijatého signálu.

Zatímco interpretace, že smyčka skončí, je rozumná, nezohledňuje primární důvod pro zpracování signálu, tedy asynchronní zpracování událostí. To znamená, že obsluha signálu jedná mimo standardní tok ovládání programu; ve skutečnosti je celý program uložen v kontextu a nový kontext je vytvořen pouze pro zpracování signálu. Jakmile obslužný program signálu dokončí své akce, kontext se přepne zpět a spustí se normální tok provádění (tj. while(1) ).

Chcete-li odpovědět na vaše otázky,

Závěr potvrdil, že když bash provádí externí příkaz v popředí, nezpracovává žádné přijaté signály, dokud se proces na popředí neskončí

Klíčová věc, kterou je zde třeba poznamenat, je externí velitelská část. V prvním případě, kde sleep je externí proces, ale ve druhém případě read je vestavěný ze samotného shellu. Takže šíření signálu do těchto dvou se v obou těchto případech liší

type read
read is a shell builtin
type sleep
sleep is /usr/bin/sleep

1. Otevřete terminál s názvem termA a spusťte vytvořený soubor callback.sh s /bin/bash callback.sh poprvé, informace se okamžitě objeví.

Ano, toto chování se očekává. Protože v tuto chvíli je definována pouze funkce a handler pasti je registrován k funkci myCallback a signál ještě není přijat ve skriptu. Jak postupuje provádění, zpráva z read výzva je vyvolána poprvé.

2. Otevřete nový terminál s názvem termB a spusťte pkill -USR1 -f callback.sh poprvé se informace okamžitě objeví v termA

Ano, zatímco read příkaz čeká na řetězec následovaný Enter stisknutí klávesy, které signalizuje EOF , přijme signál SIGUSR1 z druhého terminálu se uloží aktuální kontext provádění a řízení se přepne na obsluhu signálu, která vytiskne řetězec s aktuálním datem.

Jakmile obslužná rutina dokončí provádění, kontext se vrátí na while smyčka, ve které je read příkaz stále čeká na vstupní řetězec. Až do read příkaz je úspěšný, všechny následující depeše signálu by pouze vytiskly řetězec uvnitř obslužného programu signálu.

Pokračujte v termB, spusťte pkill -USR1 -f callback.sh podruhé.

Stejně jako dříve, read příkaz není ve vaší smyčce while dokončen pro jednou, pouze pokud úspěšně načte řetězec, spustí se další iterace smyčky a vyvolá se nová výzva.

Zdroj obrázku:The Linux Programming Interface od Michaela KerrisK


Závěr potvrdil, že když bash provádí externí příkaz v popředí, nezpracovává žádné přijaté signály, dokud proces na popředí neskončí.

bash dělá zpracovávat signály na C / úroveň implementace, ale nespustí obslužné rutiny nastavené s trap dokud proces popředí neskončí. To je vyžadováno standardem:

When a signal for which a trap has been set is received while the shell is waiting for the completion of a utility executing a foreground command, the trap associated with that signal shall not be executed until after the foreground command has completed.

Všimněte si, že standard nerozlišuje mezi vestavěnými a externími příkazy; v případě "utility" jako read , který není spouštěn v samostatném procesu, není zřejmé, zda se signál vyskytuje v jeho "kontextu" nebo v kontextu hlavního shellu a zda je handler nastaven na trap by měl být spuštěn před nebo za read vrátí.

problém 1:callback.sh obsahuje nekonečnou smyčku while, jak vysvětlit, že nezpracovává žádné přijaté signály, dokud proces na popředí neskončí., v tomto případě proces na popředí nikdy neskončí.

To je špatně. bash neprovádí while smyčka v samostatném procesu. Protože zde není žádný proces na popředí bash čeká, může spustit jakýkoli obslužný program nastavený s trap ihned. Pokud read byly externím příkazem, nikoli while by byl proces v popředí.

problém 2:Ne please input something for foo: shown v termínu A;

přejděte na termB, spusťte pkill -USR1 -f callback.sh potřetí.

V termA se znovu zobrazí následující informace:callback function called at Mon Nov 19 09:07:24 HKT 2018

Stále žádné please input something for foo: zobrazeno v termA. Proč informace please input something for foo: zmrznout?

Nezamrzá. Stačí stisknout Enter a znovu se zobrazí.

Je to prostě tak

a) bash restartuje read zabudované na místě když je přerušen signálem -- nevrátí se a neprojde znovu přes while smyčka

b) nebude znovu zobrazovat výzvu nastavenou na -p v tom případě.

Všimněte si, že bash ani znovu nezobrazí výzvu v případě SIGINT z klávesnice bylo zpracováno, i když zahodí řetězec přečtený tak daleko od uživatele:

$ cat goo
trap 'echo INT' INT
echo $$
read -p 'enter something: ' var
echo "you entered '$var'"

$ bash goo
24035
enter something: foo<Ctrl-C>^CINT
<Ctrl-C>^CINT
<Ctrl-C>^CINT
bar<Enter>
you entered 'bar'

Tím se vytiskne you entered 'foobar' pokud byl signál odeslán z jiného okna s kill -INT <pid> místo pomocí Ctrl-C z terminálu.

Všechny věci v této poslední části (jak read je přerušeno atd.) je velmi bash charakteristický. V jiných shellech jako ksh nebo dash a dokonce i v bash při spuštění v režimu POSIX (bash --posix ), jakýkoli obsluhovaný signál ve skutečnosti přeruší read vestavěný. Ve výše uvedeném příkladu shell vypíše you entered '' a ukončete po prvním ^C, a pokud read je volána ze smyčky, smyčka bude restartována.


Linux
  1. Proč tento plášťový ropovod vystupuje?

  2. Proč malloc() volá mmap() a brk() zaměnitelně?

  3. Kdy systém odešle SIGTERM procesu?

  1. Proč debian a ubuntu výchozí runlevel 2?

  2. Co dělá 'set -e' a proč by mohlo být považováno za nebezpečné?

  3. IP Forwarding =kdy a proč je to vyžadováno?

  1. Co je to linuxový server a proč jej vaše firma potřebuje?

  2. Co znamená Env X=() { :;}; Command‘ Bash dělat a proč je to nejisté?

  3. Kdy a proč bych měl používat Apt-get Update?