【问题标题】:steps to terminate a shell终止 shell 的步骤
【发布时间】:2018-11-12 19:25:38
【问题描述】:

我已阅读 glibc 手册中有关作业控制的章节,但我想知道当 shell 终止时如何处理剩余的作业。

我认为以下步骤(遵循 posix 处理孤立进程组的约定,前两个步骤似乎很明显):

  • 使用 shell 的 sid 向作业发送 HUP 信号
  • 使用 shell 的 sid 向停止的作业发送 CONTINUE 信号
  • 释放分配给作业数据结构的资源

我的问题是,如果这些工作继续存在怎么办?

我认为有机会更改他们的会话 ID 以释放 sid 并解除进程组与终端的关联(不确定这是否有意义)

我应该ioctl(STDIN_FILENO, TIOCSCTTY) 使会话进程失去控制终端并发送信号吗?

如何处理tty?我应该启动登录并将其设置为 tty 的新控制终端进程组吗?

我仍然很困惑,希望提供线索。

【问题讨论】:

    标签: glibc job-control


    【解决方案1】:

    使用 shell 的 sid 向作业发送 HUP 信号

    没必要。当 shell(会话领导者)终止时,内核会自己发送一个 HUP 信号。

    使用 shell 的 sid 向已停止的作业发送 CONT 信号

    没必要。内核也会为你发送它;-)

    释放分配给作业数据结构的资源

    也不需要。当进程终止时,进程使用的所有资源都会被内核释放。

    我的问题是,如果这些工作继续存在怎么办?

    我猜你可以SIGKILL他们,如果这真的是个问题的话。在 unix 中,如果他们处理SIGHUP,他们应该 生存下来。

    “现代” systemd 采取了不同的方法,完全违背了这种精神,但我不会参与其中 ;-)

    注意事项:

    在 linux 中,来自kernel/exit.ckill_orphaned_pgrp() 负责将HUP+CONT 从会话中发送到所有停止的作业,以及来自drivers/tty/tty_jobctl.ctty_signal_session_leader(),通过tty_vhangup_session() 调用__tty_hangup() 负责将 HUP 从前台进程组发送到进程。

    【讨论】:

    • 嗨 mosvy,内核发送信号 HUP 和 CONT 但为谁处理?可能是根进程或负责发送信号的 shell 代码......我不认为它包含在内核代码中,但我可能是错的......我将深入研究 systemd 方法也,如果你有机会解释我真的很感兴趣..非常感谢你的帮助/时间
    • 不,内核将它发送到会话中的所有进程。我会给你一个内核源链接,但是在手机上编辑并不好玩。用 strace 检查它
    • 我在启动时检查了 bash 代码。虽然我对代码没有全面的理解,但我想涉及的代码应该在函数中: void exit_shell (s) @shell.c void hangup_all_jobs () @jobs.c 代码循环遍历作业表并发送带有以下指令的信号:killpg (jobs[i]->pgrp, SIGHUP); if (STOPPED (i)) killpg (jobs[i]->pgrp, SIGCONT);所以 bash 应该负责在退出时向其作业发送信号。今晚我将尝试追踪..
    • 这是非常特定于 bash 的,非标准 (shopt -s huponexit)。其他外壳(例如dash 没有实现)。您也不必复制它。如果您不相信我,请启动类似(trap '' HUP; exec sleep 10000) 的命令,然后使用 strace 从另一个窗口附加到sleep,然后使用 SIGKILL 杀死父 shell; sleep 仍然会收到 SIGHUP 和 SIGCONT。
    • 太棒了! Trap 使 HUP 信号无效, exec 用 sleep 替换 subshel​​l。 strace 输出显示信号是由内核发送的(si_code=SI_KERNEL)。请参见 sigaction(2) 联机帮助页。 Strace 日志如下:restart_syscall(<... resuming interrupted nanosleep ...>) = ? ERESTART_RESTARTBLOCK (Interrupted by signal) --- SIGHUP {si_signo=SIGHUP, si_code=SI_KERNEL} --- restart_syscall(<... resuming interrupted restart_syscall ...> 我将深入tty驱动代码中这些天来。这对我来说非常具有挑战性。再次感谢,你帮了我很多!
    【解决方案2】:
    • 我应该启动登录并将其设置为 tty 的新控制终端进程组吗?

    我读了一遍,我认为答案应该是否定的。

    对于基于字符的终端,根进程(initd/systemd/launchd 等)为预配置的终端或特定事件派生并执行 getty。 Getty打开终端文件进行读/写,并将std文件描述符关联到终端,从配置文件设置一个简单的环境并提示输入用户名,然后执行登录该用户名。 登录更改终端的所有权和权限,更改进程的角色(有效和真实的uid,gid,补充组),并执行登录shell 当 shell 终止时,它的父进程会收到 sigchd 的通知,然后重新启动 getty... 所以 tty 初始化/销毁不是 shell 的任务..

    还不确定如何处理幸存的进程组..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      相关资源
      最近更新 更多