有时,每当我在Linux上编写程序并由于某种错误而崩溃时,它将变成不间断的进程,并永远运行直到我重新启动计算机(即使注销)。我的问题是:
- 是什么导致流程不可中断?
- 我如何阻止这种情况发生?
- 这可能是一个愚蠢的问题,但是有什么方法可以在不重新启动计算机的情况下中断它?
有时,每当我在Linux上编写程序并由于某种错误而崩溃时,它将变成不间断的进程,并永远运行直到我重新启动计算机(即使注销)。我的问题是:
Answers:
不间断进程是恰好在系统调用(内核函数)中的进程,无法被信号打断。
要了解这意味着什么,您需要了解可中断系统调用的概念。典型的例子是read()
。这是一个系统调用,可能需要很长时间(几秒钟),因为它可能涉及旋转硬盘驱动器或移动磁头。在这段时间的大部分时间内,该进程将处于睡眠状态,从而阻塞硬件。
当进程在系统调用中处于睡眠状态时,它可以接收Unix异步信号(例如SIGTERM),然后发生以下情况:
从系统调用中尽早返回使用户空间代码可以响应信号而立即更改其行为。例如,对SIGINT或SIGTERM的反应干净终止。
另一方面,不允许以这种方式中断某些系统调用。如果系统由于某种原因而导致停顿,则该过程可能会无限期保持这种不可杀灭的状态。
LWN 在7月发表了一篇不错的文章,触及了这个话题。
要回答原始问题:
如何防止这种情况的发生:找出造成您麻烦的驱动程序,然后停止使用或成为内核黑客并对其进行修复。
如何在不重新启动的情况下终止不间断进程:以某种方式使系统调用终止。通常,最有效的方法是不拉电源线就拉电源线。您还可以成为内核黑客,并使驱动程序使用TASK_KILLABLE,如LWN文章中所述。
当进程处于用户模式时,可以随时中断它(切换到内核模式)。当内核返回用户模式时,它会检查是否有任何待处理的信号(包括用于终止进程的信号,例如SIGTERM
和SIGKILL
)。这意味着只能在返回用户模式后才能杀死进程。
无法在内核模式下杀死进程的原因是,它可能破坏同一台计算机上所有其他进程使用的内核结构(杀死线程的潜在方式可能破坏同一进程中其他线程使用的数据结构) 。
当内核需要做一些可能花费很长时间的事情(例如,等待另一个进程编写的管道或等待硬件做某事)时,它会通过将自身标记为睡眠并调用调度程序以切换到另一个而进入睡眠状态。进程(如果没有非睡眠进程,则切换到“虚拟”进程,该进程告诉CPU放慢速度并处于一个循环-空闲循环)。
如果将信号发送到睡眠过程,则必须先唤醒它,然后才能返回用户空间,从而处理未决的信号。这里我们有两种主要的睡眠类型之间的区别:
TASK_INTERRUPTIBLE
,可中断的睡眠。如果任务标记有此标志,则表明该任务正在休眠,但是可以通过信号唤醒。这意味着将任务标记为休眠的代码正在等待可能的信号,并且在唤醒后将对其进行检查并从系统调用中返回。处理完信号后,系统调用可能会自动重新启动(我不会详细介绍其工作原理)。TASK_UNINTERRUPTIBLE
,不间断的睡眠。如果一个任务标有该标志,那么它就不会被等待中的任何事物唤醒,要么是因为它不容易重新启动,要么是因为程序期望系统调用是原子的。这也可用于已知非常短的睡眠。TASK_KILLABLE
(在ddaa的答案链接到的LWN文章中提到)是一个新的变体。
这回答了您的第一个问题。关于第二个问题:您无法避免不间断的睡眠,这是正常现象(例如,每次进程从磁盘读/写磁盘时都会发生);但是,它们只能持续一秒钟的时间。如果它们持续更长的时间,通常意味着出现硬件问题(或设备驱动程序问题,在内核看来也是如此),其中设备驱动程序正在等待硬件执行永远不会发生的事情。这也可能意味着您正在使用NFS,并且NFS服务器已关闭(正在等待服务器恢复;也可以使用“ intr”选项来避免该问题)。
最后,您无法恢复的原因与内核等待直到返回用户模式以传递信号或终止进程的原因相同:它可能破坏内核的数据结构(等待可中断睡眠的代码可能会收到错误消息,告诉它返回到可以杀死进程的用户空间;等待不间断睡眠的代码不会出现任何错误)。
页面中断后,不间断的进程通常会等待I / O。
考虑一下:
进程/任务在这种状态下不能被中断,因为它不能处理任何信号。如果确实如此,则将发生另一个页面错误,并且该错误将返回原位。
当我说“进程”时,我的意思是“任务”,在Linux(2.6)下,它大致翻译为“线程”,在/ proc中可能有也可能没有单独的“线程组”条目
在某些情况下,它可能等待很长时间。一个典型的例子是可执行文件或mmap文件位于服务器发生故障的网络文件系统上。如果I / O最终成功,则任务将继续。如果最终失败,则该任务通常会获得SIGBUS或类似内容。
如果您正在谈论“僵尸”进程(在ps输出中指定为“僵尸”),那么这是进程列表中的无害记录,等待有人收集其返回码,因此可以安全地忽略它。
您能否描述一下适合您的“不间断流程”?它能否在“ kill -9”中幸存下来并快乐地突突?如果是这种情况,则它会卡在某个系统调用中,该系统调用会卡在某个驱动程序中,并且您会一直坚持此过程,直到重新启动(有时最好尽快重新启动)或卸载相关驱动程序(这不太可能发生) 。您可以尝试使用“ strace”来找出进程卡住的位置,并在将来避免使用。
TASK_UNINTERUPTIBLE
每当系统不处于空闲状态时,是否可以编写程序来启动进入该状态的进程,从而强行收集数据,并在超级用户退出后等待发送?这将是黑客检索信息,返回僵尸状态并在空闲时通过网络传输信息的金矿。有人可能会争辩说,这是一种创建Blackdoor
权力的方法,可以根据需要进入和退出任何系统。我坚信,通过消除`TASK_UNINTERUPTIB