什么是不间断的过程?


156

有时,每当我在Linux上编写程序并由于某种错误而崩溃时,它将变成不间断的进程,并永远运行直到我重新启动计算机(即使注销)。我的问题是:

  • 是什么导致流程不可中断?
  • 我如何阻止这种情况发生?
  • 这可能是一个愚蠢的问题,但是有什么方法可以在不重新启动计算机的情况下中断它?

TASK_UNINTERUPTIBLE每当系统不处于空闲状态时,是否可以编写程序来启动进入该状态的进程,从而强行收集数据,并在超级用户退出后等待发送?这将是黑客检索信息,返回僵尸状态并在空闲时通过网络传输信息的金矿。有人可能会争辩说,这是一种创建Blackdoor权力的方法,可以根据需要进入和退出任何系统。我坚信,通过消除`TASK_UNINTERUPTIB
Nuuwski '16

2
请分享代码?
再次

Answers:


198

不间断进程是恰好在系统调用(内核函数)中的进程,无法被信号打断。

要了解这意味着什么,您需要了解可中断系统调用的概念。典型的例子是read()。这是一个系统调用,可能需要很长时间(几秒钟),因为它可能涉及旋转硬盘驱动器或移动磁头。在这段时间的大部分时间内,该进程将处于睡眠状态,从而阻塞硬件。

当进程在系统调用中处于睡眠状态时,它可以接收Unix异步信号(例如SIGTERM),然后发生以下情况:

  • 系统调用过早退出,并设置为将-EINTR返回给用户空间。
  • 信号处理程序被执行。
  • 如果该进程仍在运行,它将从系统调用中获取返回值,并且可以再次进行相同的调用。

从系统调用中尽早返回使用户空间代码可以响应信号而立即更改其行为。例如,对SIGINT或SIGTERM的反应干净终止。

另一方面,不允许以这种方式中断某些系统调用。如果系统由于某种原因而导致停顿,则该过程可能会无限期保持这种不可杀灭的状态。

LWN 在7月发表了一篇不错的文章,触及了这个话题。

要回答原始问题:

  • 如何防止这种情况的发生:找出造成您麻烦的驱动程序,然后停止使用或成为内核黑客并对其进行修复。

  • 如何在不重新启动的情况下终止不间断进程:以某种方式使系统调用终止。通常,最有效的方法是不拉电源线就拉电源线。您还可以成为内核黑客,并使驱动程序使用TASK_KILLABLE,如LWN文章中所述。


31
不幸的是,我拔掉了笔记本电脑上的电源线,但它无法正常工作。;-)
thecarpy 2014年

1
是不是EINTR而不是EAGAIN?同样,read()返回-1并将errno设置为错误。
lethalman

2
@Dexter:您确实错过了重点。阅读LWN文章:lwn.net/Articles/288056。这些问题是由懒惰的设备驱动程序程序员引起的,因此需要在设备驱动程序代码中进行修复。
ddaa 2015年

4
@ddaa“ Unix传统(以及几乎所有应用程序)都认为文件存储写入是不可中断的信号。更改该保证是不安全或不实际的。” ->这恰恰是所有IMO中最错误的部分。只需中断驱动程序的读/写请求,然后在实际设备(硬盘/网卡等)传送数据时,将其忽略。OS内核的制作方式应使开发人员无法破坏它。
德克斯特(Dexter)

2
@ddaa我确实知道Linux不是微内核,尽管我不确定我的评论的哪一部分与之相关...然后,您的评论是否意味着微内核OS不会对那些“不间断”的进程产生问题?因为如果没有,也许是时候让我成为微内核粉丝了……:D
Dexter

49

当进程处于用户模式时,可以随时中断它(切换到内核模式)。当内核返回用户模式时,它会检查是否有任何待处理的信号(包括用于终止进程的信号,例如SIGTERMSIGKILL)。这意味着只能在返回用户模式后才能杀死进程。

无法在内核模式下杀死进程的原因是,它可能破坏同一台计算机上所有其他进程使用的内核结构(杀死线程的潜在方式可能破坏同一进程中其他线程使用的数据结构) 。

当内核需要做一些可能花费很长时间的事情(例如,等待另一个进程编写的管道或等待硬件做某事)时,它会通过将自身标记为睡眠并调用调度程序以切换到另一个而进入睡眠状态。进程(如果没有非睡眠进程,则切换到“虚拟”进程,该进程告诉CPU放慢速度并处于一个循环-空闲循环)。

如果将信号发送到睡眠过程,则必须先唤醒它,然后才能返回用户空间,从而处理未决的信号。这里我们有两种主要的睡眠类型之间的区别:

  • TASK_INTERRUPTIBLE,可中断的睡眠。如果任务标记有此标志,则表明该任务正在休眠,但是可以通过信号唤醒。这意味着将任务标记为休眠的代码正在等待可能的信号,并且在唤醒后将对其进行检查并从系统调用中返回。处理完信号后,系统调用可能会自动重新启动(我不会详细介绍其工作原理)。
  • TASK_UNINTERRUPTIBLE,不间断的睡眠。如果一个任务标有该标志,那么它就不会被等待中的任何事物唤醒,要么是因为它不容易重新启动,要么是因为程序期望系统调用是原子的。这也可用于已知非常短的睡眠。

TASK_KILLABLE (在ddaa的答案链接到的LWN文章中提到)是一个新的变体。

这回答了您的第一个问题。关于第二个问题:您无法避免不间断的睡眠,这是正常现象(例如,每次进程从磁盘读/写磁盘时都会发生);但是,它们只能持续一秒钟的时间。如果它们持续更长的时间,通常意味着出现硬件问题(或设备驱动程序问题,在内核看来也是如此),其中设备驱动程序正在等待硬件执行永远不会发生的事情。这也可能意味着您正在使用NFS,并且NFS服务器已关闭(正在等待服务器恢复;也可以使用“ intr”选项来避免该问题)。

最后,您无法恢复的原因与内核等待直到返回用户模式以传递信号或终止进程的原因相同:它可能破坏内核的数据结构(等待可中断睡眠的代码可能会收到错误消息,告诉它返回到可以杀死进程的用户空间;等待不间断睡眠的代码不会出现任何错误)。


1
文件系统锁定错误也是可能的原因,IME。
东武

3
我不明白所有这些。“您无法避免不间断的睡眠”-操作系统的制作方式是否不能使不间断的睡眠根本不存在为一种状态?然后是有关损坏的部分-进程本身的内核模式部分(或任何可能导致损坏的部分)是否不能终止,或者仅修改其代码在内存中才可以返回?请解释为什么这样做是如此困难/不可能,甚至Linux都没有做到。(我认为此问题仅在Windows上存在)
Dexter

我能想到的唯一情况是,如果硬件本身可能导致损坏,那么真的不可能(安全地)杀死那些进程(而不仅仅是,很难说)。硬件无法控制;内核可以。但这是内核从硬件获取数据并修改内存的原因(这就是为什么在进程返回用户模式之前一定不能释放它,以及为什么会发生损坏的原因)...更改内存中的内核代码,不会有更多问题。
德克斯特(Dexter)2015年

@Dexter认为内核就像一个单一的多线程进程,其中每个进程的内核模式部分是内核中的一个线程。您的建议就像杀死多线程程序中的单个线程一样糟糕:它可能会留下悬挂的锁,临时修改数据结构或在修改过程中等等。
CesarB

@CesarB好吧,关于杀死线程的说法是正确的……但是“主”线程(例如,将是OS内核,而其他线程将是驱动程序)不能以某种方式处理它吗?尽管这些结构“处于被修改的中间”似乎是一个非常棘手的问题……也许我们将永远不会真正看到一个操作系统,其中不会出现不间断的进程:(
Dexter

23

页面中断后,不间断的进程通常会等待I / O。

考虑一下:

  • 线程尝试访问不在核心中的页面(要么是按需加载的可执行文件,已换出的匿名内存页面,要么是按需加载的mmap()文件),一样)
  • 现在,内核正在(尝试)将其加载到
  • 该页面可用之前,该过程无法继续。

进程/任务在这种状态下不能被中断,因为它不能处理任何信号。如果确实如此,则将发生另一个页面错误,并且该错误将返回原位。

当我说“进程”时,我的意思是“任务”,在Linux(2.6)下,它大致翻译为“线程”,在/ proc中可能有也可能没有单独的“线程组”条目

在某些情况下,它可能等待很长时间。一个典型的例子是可执行文件或mmap文件位于服务器发生故障的网络文件系统上。如果I / O最终成功,则任务将继续。如果最终失败,则该任务通常会获得SIGBUS或类似内容。


1
如果最终失败,则该任务通常会获得SIGBUS或类似内容。等一下,难道不能制造内核,以便在杀死那些“不间断”的进程时,仅向它们发送I / O操作失败的消息吗?然后该过程将返回到用户模式并消失?有一种方法可以安全地杀死那些“ D”状态进程。我想这并不容易,这就是为什么Windows或Linux都没有这种可能性的原因。另一方面,我希望能够至少不安全地杀死那些进程。我不在乎可能的系统崩溃或其他任何事情……
Dexter 2015年

@Dexter嗯,我从未在Windows上遇到过此问题。有什么方法可以在那里复制它?至少根据这篇文章,所有I / O请求都可以在Windows中中断。
Ruslan

1

关于第三个问题:我认为您可以通过运行杀死不中断的进程 sudo kill -HUP 1。它会在不结束正在运行的进程的情况下重新启动init,并且在运行它之后,我的不间断进程消失了。


-3

如果您正在谈论“僵尸”进程(在ps输出中指定为“僵尸”),那么这是进程列表中的无害记录,等待有人收集其返回码,因此可以安全地忽略它。

您能否描述一下适合您的“不间断流程”?它能否在“ kill -9”中幸存下来并快乐地突突?如果是这种情况,则它会卡在某个系统调用中,该系统调用会卡在某个驱动程序中,并且您会一直坚持此过程,直到重新启动(有时最好尽快重新启动)或卸载相关驱动程序(这不太可能发生) 。您可以尝试使用“ strace”来找出进程卡住的位置,并在将来避免使用。


不能像杀死进程一样强制卸载驱动程序吗?我知道内核模式比用户模式具有更多的特权访问,但是它永远不会比操作系统本身具有更多的特权。在内核模式下执行的任何操作始终会篡改在内核模式下执行的其他任何操作-根本没有控制权。
德克斯特(Dexter)2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.