GNU/Linux >> Znalost Linux >  >> Linux

Dostanou procesy na pozadí při odhlášení SIGHUP?

Řešení 1:

Odpověď nalezena.

U BASH to závisí na huponexit shell, kterou lze zobrazit a/nebo nastavit pomocí vestavěného shopt příkaz.

Zdá se, že tato možnost je ve výchozím nastavení vypnutá, alespoň na systémech založených na RedHat.

Více informací na manuálové stránce BASH:

Shell se standardně ukončí po přijetí SIGHUP. Před ukončením interaktivní shell znovu odešle SIGHUP všem úlohám, spuštěným i zastaveným. Zastavené úlohy jsou odeslány SIGCONT, aby bylo zajištěno, že obdrží SIGHUP. Aby shell neposílal signál konkrétní úloze, měl by být odstraněn z tabulky úloh s vestavěným disown (viz PŘÍKAZY SHELL BUILTIN níže) nebo označen, aby nepřijímal SIGHUP pomocí disown -h.

Pokud byla možnost huponexit shell nastavena pomocí shopt, bash odešle SIGHUP všem úlohám, když se interaktivní přihlašovací shell ukončí.

Řešení 2:

Bude odesláno SIGHUP v mých testech:

Shell1:

[[email protected]: ~] ssh localhost
[[email protected]: ~] perl -e sleep & 
[1] 1121
[[email protected]: ~] ps
  PID TTY          TIME CMD
 1034 pts/46   00:00:00 zsh
 1121 pts/46   00:00:00 perl
 1123 pts/46   00:00:00 ps

Shell2:

strace -e trace=signal -p1121

Shell1 Again:

[[email protected]: ~] exit
zsh: you have running jobs.
[[email protected]: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Znovu Shell2 :

strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause()                                 = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached

Proč stále běží?:
Pokročilé programování v prostředí Unix od Stevense to pokrývá v části 9.10:Orphaned Process Groups. Nejrelevantnější sekce je:

Vzhledem k tomu, že skupina procesů je osiřelá, když rodič skončí, POSIX.1 vyžaduje, aby každý proces v nově osiřelé skupině procesů, který je zastaven (stejně jako naše dítě), byl odeslán signál zavěšení (SIGHUP) následovaný signálem pokračování (SIGCONT).

To způsobí, že dítě bude pokračovat po zpracování signálu zavěšení. Výchozí akcí pro signál zavěšení je ukončit proces, takže musíme poskytnout obsluhu signálu, která signál zachytí. Proto očekáváme, že printf ve funkci sig_hup se objeví před printf ve funkci pr_ids.

Řešení 3:

Provedl jsem nějaké testy pomocí CentOS 7.1 a bash. Všimněte si, že to znamená huponexit je off ve výchozím nastavení a po většinu mých testů byl vypnutý.

Potřebujete nohup když zahájíte úlohu v terminálu, protože pokud tento terminál zavřete, aniž byste opustili prostředí shell , terminál odešle bash signál SIGHUP do shellu, který jej pak odešle všem dětem. Pokud opustíte shell čistě - to znamená, že úloha již musí být na pozadí, takže můžete zadat exit nebo stiskněte Control-D na příkazovém řádku – do úlohy na pozadí se z bash neposílají žádné signály.

Test:

Terminál 1

$ echo $$
16779

Terminál 2

$ strace -e signal -p16779
Process 16779 attached

(zavřete svorku 1, viz svorku 2):

--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16777, si_uid=3000090} ---
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_DFL, [], SA_RESTORER, 0x7f7ace3d9a00}, {0x456880, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], SA_RESTORER, 0x7f7ace3d9a00}, 8) = 0
kill(16779, SIGHUP)                     = 0
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16779, si_uid=3000090} ---
+++ killed by SIGHUP +++

Úloha doit.sh :

#!/bin/bash

imhupped() {
        echo "HUP" >> /tmp/outfile
}

trap imhupped SIGHUP

for i in $(seq 1 6); do echo out $i >> /tmp/outfile; sleep 5; done

Spusťte jej na pozadí v Terminálu 1:

Terminál 1

$ ./doit.sh &
[1] 22954

Vyhledejte to v Terminálu 2; zavřete terminál 1 po několika smyčkách:

Terminál 2

$ strace -e signal -p22954
Process 22954 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22980, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7a5d547a00}, {0x43e4b0, [], SA_RESTORER, 0x7f7a5d547a00}, 8) = 0
...
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=21685, si_uid=3000090} ---
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=23017, si_status=SIGHUP, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
...

Výstup na terminálu 3:

Terminál 3

out 1
out 2
out 3
HUP
out 4
out 5
out 6

Pokud však ukončíte bash , jednoduše odejde, aniž by dítěti vyslalo jakýkoli signál. Terminál se ukončí, protože již nemá potomka, ale samozřejmě není nikdo, kdo by HUP, protože podřízený shell je již pryč. SIGINT , SIG_BLOCK a SIG_SETMASK jak vidíte níže, jsou způsobeny sleep ve skořápce.

Terminál 1

$ ./doit.sh &
26275

Terminál 2

$ strace -e signal -p26275
Process 26275 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26280, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0


(..."exit" is typed in bash, notice no new signals sent...)


rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26303, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0

Terminál 3, výstup

out 1
out 2
out 3
out 4
out 5
out 6

Zajímavé je, že jsem nastavil huponexit být zapnutý s shopt -s huponexit; shopt (posledně jmenovaný nákup ke kontrole), poté provedl poslední test a znovu bash neodeslal procesu na pozadí žádný signál . Ještě zajímavější, jak jsme viděli bash udělal odeslat signál do procesu na pozadí poté, co jej přijal z terminálu, který se mu zavřel. Zdá se, že huponexit nesnášel ani jednu, ani druhou stranu.

Doufám, že to odstraní jakoukoli záhadu nebo zmatek týkající se alespoň bashova hupiness, kdy a jak je vysílán signál HUP. Alespoň pro mě byly mé testy zcela reprodukovatelné. Zajímalo by mě, jestli existují nějaká další nastavení, která mohou ovlivňovat chování bash.

A jako vždy YSMV (Your Shell May Vary).

Dodatek 1

Když spustím shell jako exec /bin/sh a poté spusťte skript jako /bin/sh ./doit.sh & , poté čistě opusťte shell, do úlohy na pozadí se neposílají žádné signály a úloha pokračuje až do dokončení.

Dodatek 2

Když spustím shell jako exec /bin/csh a poté spusťte skript jako /bin/sh ./doit.sh & , poté čistě opusťte shell, do úlohy na pozadí se neposílají žádné signály a úloha pokračuje až do dokončení.


Linux
  1. Proč mohu vidět výstup procesů na pozadí?

  2. Při přístupu k cPanelu se zobrazí chyba 404

  3. Příkazový řádek se přepíše, když jsou příkazy příliš dlouhé

  1. Co bych získal, když Sudo Program destruktivní jádra?

  2. Kdy vypnout TCP SACK?

  3. Jak Linux přiděluje šířku pásma mezi procesy?

  1. Zobrazuje se mi chyba, když se pokouším aktualizovat Youtube-dl v 18.04?

  2. Jak získat ID procesu na pozadí?

  3. Jak zabít všechny procesy na pozadí v zsh?