กระบวนการพื้นหลังได้รับ SIGHUP เมื่อออกจากระบบหรือไม่


21

นี่คือการติดตามคำถามนี้

ฉันได้ทำการทดสอบเพิ่มเติม ดูเหมือนว่ามันจะไม่สำคัญว่าสิ่งนี้จะทำที่คอนโซลทางกายภาพหรือผ่านทาง SSH สิ่งนี้จะไม่เกิดขึ้นกับ SCP เท่านั้น cat /dev/zero > /dev/nullฉันยังทดสอบกับ พฤติกรรมเหมือนกันทุกประการ:

  • เริ่มต้นกระบวนการในพื้นหลังโดยใช้&(หรือวางไว้ในพื้นหลังหลังจากที่เริ่มใช้CTRL-Zและbg); นี้จะทำโดยไม่ต้องใช้nohup
  • ออกจากระบบ.
  • เข้าสู่ระบบอีกครั้ง
  • initกระบวนการนี้ยังคงมีการทำงานอย่างมีความสุขและตอนนี้เด็กโดยตรงของ

ฉันสามารถยืนยันได้ว่าทั้ง SCP และ CAT หยุดทำงานทันทีหากส่งSIGHUP; kill -HUPผมทดสอบนี้โดยใช้

ดังนั้นดูเหมือนว่า SIGHUP จะไม่ถูกส่งเมื่อออกจากระบบอย่างน้อยไปยังกระบวนการพื้นหลัง (ไม่สามารถทดสอบด้วยเบื้องหน้าด้วยเหตุผลที่ชัดเจน)

สิ่งนี้เกิดขึ้นกับฉันในตอนแรกด้วยคอนโซลบริการของ VMware ESX 3.5 (ซึ่งใช้ RedHat) แต่ฉันสามารถทำซ้ำได้บน CentOS 5.4

คำถามคืออีกครั้ง: ไม่ควรส่ง SIGHUP ไปยังกระบวนการแม้ว่าพวกเขาจะทำงานในพื้นหลังเมื่อออกจากระบบ? ทำไมสิ่งนี้ไม่เกิดขึ้น?


แก้ไข

ฉันตรวจสอบด้วยstraceตามคำตอบของ Kyle
ตามที่ฉันคาดไว้กระบวนการจะไม่ได้รับสัญญาณใด ๆเมื่อออกจากเชลล์ที่เปิดตัว สิ่งนี้เกิดขึ้นเมื่อใช้คอนโซลของเซิร์ฟเวอร์และผ่าน SSH


การใช้ Bash บน CentOS 7.1, shell script loop จะได้รับ SIGHUP ถ้ามันอยู่เบื้องหน้า แต่เทอร์มินัลฆ่า แสดงจากเทอร์มินัลอื่น: --- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=10676, si_uid=3000090} --- rt_sigreturn() = -1 EINTR (Interrupted system call) rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
— Mike S

ดังนั้นสคริปต์พื้นหลังจะ โปรดทราบว่าเทอร์มินัลปิดขณะที่ลูปกำลังรอการสลีป เชลล์ไม่ได้ออก:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
— Mike S

ดูคำตอบของฉันสำหรับการทดสอบ huponexitที่น่าสนใจที่ผมเห็นการเปลี่ยนแปลงในพฤติกรรมที่ไม่เนื่องจาก
— Mike S

คำตอบ:


26

พบคำตอบ

สำหรับ BASH นี้จะขึ้นอยู่กับhuponexitตัวเลือกของเชลล์ซึ่งสามารถดูและ / หรือตั้งค่าโดยใช้shoptคำสั่งในตัว

ดูเหมือนว่าตัวเลือกนี้จะปิดโดยปริยายอย่างน้อยในระบบที่ใช้ RedHat

ข้อมูลเพิ่มเติมเกี่ยวกับหน้าคน BASH :

เชลล์ออกโดยค่าเริ่มต้นเมื่อได้รับ SIGHUP ก่อนออกจากเชลล์แบบโต้ตอบจะส่ง SIGHUP ไปยังงานทั้งหมดไม่ว่าจะรันหรือหยุด งานที่หยุดทำงานจะถูกส่ง SIGCONT เพื่อให้แน่ใจว่าพวกเขาได้รับ SIGHUP เพื่อป้องกันไม่ให้เชลล์ส่งสัญญาณไปยังงานเฉพาะควรลบมันออกจากตารางงานโดยใช้ built-in ที่สร้างขึ้น (ดูคำสั่งจาก BUILTIN SHELL ด้านล่าง) หรือทำเครื่องหมายว่าไม่รับ SIGHUP โดยใช้ disown -h

หากตั้งค่าตัวเลือก huponexit shell ด้วย shopt แล้ว bash จะส่ง SIGHUP ไปยังงานทั้งหมดเมื่อเชลล์ล็อกอินแบบโต้ตอบออก


4
ตรวจสอบแล้ว เมื่อฉันทำ "exit", "logout" หรือ CTL-D child proc (job) จะไม่ได้รับการถอนหายใจ (ทั้งผู้ใช้ root และ reg) อย่างไรก็ตามเมื่อฉันทำ "kill -HUP $$" เพื่อฆ่าอินสแตนซ์ปัจจุบันของการทุบตีกระบวนการลูก DID ได้รับการถอนหายใจ ฉันตั้งค่า huponexit และกระบวนการลูกได้รับ SIGHUP เมื่อออก
— CarpeNoctem

3

มันจะส่ง SIGHUP ในการทดสอบของฉัน:

Shell1:

[kbrandt@kbrandt-opadmin: ~] ssh localhost
[kbrandt@kbrandt-opadmin: ~] perl -e sleep & 
[1] 1121
[kbrandt@kbrandt-opadmin: ~] 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 อีกครั้ง:

[kbrandt@kbrandt-opadmin: ~] exit
zsh: you have running jobs.
[kbrandt@kbrandt-opadmin: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Shell2 อีกครั้ง :

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

ทำไมมันยังทำงานอยู่:
การวางโปรแกรมขั้นสูงใน Unix Environment โดย Stevens ครอบคลุมหัวข้อนี้ในส่วนที่ 9.10: กลุ่มกระบวนการ Orphaned ส่วนที่เกี่ยวข้องมากที่สุดคือ:

เนื่องจากกลุ่มกระบวนการนั้นถูก orphaned เมื่อพาเรนต์สิ้นสุดลง POSIX.1 จึงต้องการให้ทุกกระบวนการในกลุ่มกระบวนการใหม่ที่ถูกกำพร้าที่หยุด (เนื่องจากลูกของเราเป็น) ถูกส่งสัญญาณวางสาย (SIGHUP) ตามด้วยสัญญาณต่อ (SIGCONT )

สิ่งนี้ทำให้เด็กยังคงดำเนินต่อไปหลังจากประมวลผลสัญญาณวางสาย การดำเนินการเริ่มต้นสำหรับสัญญาณวางสายคือการยุติกระบวนการดังนั้นเราจึงต้องจัดเตรียมเครื่องจัดการสัญญาณเพื่อจับสัญญาณ ดังนั้นเราจึงคาดว่า printf ในฟังก์ชัน sig_hup จะปรากฏก่อนหน้า printf ในฟังก์ชัน pr_ids


แต่คุณส่ง SIGHUP ไปที่นี่อย่างชัดเจน ฉันกำลังพูดถึงสิ่งที่เกิดขึ้นเมื่อคุณล็อกออฟจากเชลล์ที่คุณเริ่มกระบวนการ
— Massimo

ผลลัพธ์เดียวกันเมื่อฉันพิมพ์ exit แม้ว่าฉันจะได้รับคำเตือนเกี่ยวกับงาน แต่พิมพ์ exit อีกครั้ง ฉันทดสอบสิ่งนี้ด้วย ZSH
— Kyle Brandt

ฉันใช้ BASH และสิ่งนี้อาจขึ้นอยู่กับเปลือก แต่ทุบตีควรส่ง SIGHUP กระบวนการเด็กเมื่อเข้าสู่ระบบปิด ...
— Massimo

Bash ส่ง SIGCONT ถ้างานหยุดทำงาน แต่ฉันยืนยันว่ามันจะไม่ส่งอะไรเลยถ้างานไม่หยุด
— Kyle Brandt

การใช้ Bash บน CentOS 7.1 ฉันจะได้รับ SIGTERM ที่ส่งไปยังกระบวนการของฉันหยุดในหน้าต่างอื่น: 1. ) เริ่มเชลล์สคริปต์แบบง่าย ๆ (วนรอบด้วยเสียงก้องและสลีป), 2) ควบคุม -Z it, 3) strace กระบวนการใน หน้าต่างอื่น 4) ออกจากอาคารเดิม มันบ่นว่าฉันมีงานแล้วหลังจากออกจากรายการ strace ของฉัน: $ strace -e signal -p1705 Process 1705 attached --- stopped by SIGTSTP --- --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=791, si_uid=3000090} --- +++ killed by SIGTERM +++ แปลกไม่สอดคล้องกับส่วนที่ยกมาจากสตีเวนส์
— Mike S

2

ฉันรันการทดสอบบางอย่างโดยใช้ CentOS 7.1 และทุบตี โปรดทราบว่าวิธีการนี้huponexitเป็นoffค่าเริ่มต้นและปิดการทดสอบส่วนใหญ่ของฉัน

คุณต้องnohupเมื่อคุณเริ่มต้นงานในขั้วเพราะถ้าคุณใกล้ที่ขั้วโดยไม่ออกจากเปลือกเรียบร้อยที่สถานีส่งสัญญาณทุบตี SIGHUP กับเปลือกที่แล้วส่งไปให้เด็กทุกคน หากคุณออกจาก shell cleanly- หมายถึงงานต้องอยู่ในพื้นหลังอยู่แล้วดังนั้นคุณสามารถพิมพ์exitหรือกด Control-D ที่ command prompt - ไม่มีสัญญาณของการเรียงลำดับใด ๆ ที่ถูกส่งไปยังงานแบ็คกราวน์จาก bash

ทดสอบ:

อาคาร 1

$ echo $$
16779

อาคาร 2

$ strace -e signal -p16779
Process 16779 attached

(ปิดเทอร์มินัล 1 เห็นในเทอร์มินัล 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 +++

งาน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

เริ่มในพื้นหลังในเทอร์มินัล 1:

อาคาร 1

$ ./doit.sh &
[1] 22954

ใส่ไว้ในเทอร์มินัล 2; ปิดเทอร์มินัล 1 หลังจากลูปสองสามอัน:

อาคาร 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
...

เอาต์พุตในเทอร์มินัล 3:

อาคาร 3

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

อย่างไรก็ตามหากคุณออกbashมันก็จะออกโดยไม่ส่งสัญญาณใด ๆ ไปยังเด็กเลย เทอร์มินัลจะออกเพราะไม่มีลูกอีกต่อไป แต่แน่นอนว่าไม่มีใครที่จะ HUP เพราะเปลือกลูกหายไปแล้ว SIGINT, SIG_BLOCKและSIG_SETMASKคุณเห็นด้านล่างนี้เนื่องจากการsleepในเปลือก

อาคาร 1

$ ./doit.sh &
26275

อาคาร 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

เทอร์มินัล 3 เอาต์พุต

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

ที่น่าสนใจผมตั้งhuponexitให้เป็นด้วยshopt -s huponexit; shopt(คน shopt หลังตรวจสอบ) แล้วดำเนินการทดสอบที่ผ่านมาและอีกครั้งทุบตีส่งสัญญาณไปยังกระบวนการพื้นหลังไม่มี ยิ่งขัดจังหวะมากขึ้นเท่าที่เราเห็นทุบตีได้ส่งสัญญาณไปยังกระบวนการพื้นหลังหลังจากที่ได้รับมันจากสถานีที่ปิดในหน้าของมัน ดูเหมือนกับว่าhuponexitไม่มีการแบกทางเดียวหรืออื่น ๆ

ฉันหวังว่าสิ่งนี้จะลบความลึกลับหรือความสับสนใด ๆ ที่เกี่ยวกับ huppiness ของ bash อย่างน้อยประมาณเวลาและวิธีการที่ส่งสัญญาณ HUP อย่างน้อยการทดสอบของฉันก็ทำซ้ำได้อย่างสมบูรณ์สำหรับฉัน ฉันสนใจที่จะทราบว่ามีการตั้งค่าอื่น ๆ ที่อาจมีผลต่อพฤติกรรมของทุบตี

และเช่นเคย YSMV (Your Shell May Vary)

ภาคผนวก 1

เมื่อฉันเรียกใช้เชลล์เป็นexec /bin/shจากนั้นเรียกใช้สคริปต์เป็น/bin/sh ./doit.sh &แล้วออกจากเชลล์อย่างหมดจดไม่มีสัญญาณถูกส่งไปยังงานพื้นหลังและมันจะยังคงทำงานต่อไปจนเสร็จ

ภาคผนวก 2

เมื่อฉันเรียกใช้เชลล์เป็นexec /bin/cshจากนั้นเรียกใช้สคริปต์เป็น/bin/sh ./doit.sh &แล้วออกจากเชลล์อย่างหมดจดไม่มีสัญญาณถูกส่งไปยังงานพื้นหลังและมันจะยังคงทำงานต่อไปจนเสร็จ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.