กระบวนการพื้นหลังได้รับ 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.