【问题标题】:Preemptive Kernel Design抢占式内核设计
【发布时间】:2014-08-25 05:23:40
【问题描述】:

我一直认为内核是不可抢占的。也就是说,内核代码运行完成,只有在返回用户空间时才会进行调度。我现在对设计可抢占内核时需要进行的更改感到好奇。

到目前为止我的思考过程:

  • 假设内核正在代表某个用户空间进程运行并突然被抢占。我们将当前处理器信息存储在进程的内核堆栈中。然后我们将该进程标记为可运行。当该进程被调度时,我们获取的信息不会将我们引导回用户空间,而是让我们继续运行内核任务(例如 syscall)。

  • 但是,有时内核不在进程上下文中运行。我们需要以某种方式使内核在这些点上不可抢占。能够停止调度程序的运行听起来很疯狂。

  • 我闻到了锁定的问题:假设我们正在运行一个获取某个锁定 A 的系统调用。如果它被抢占,如果调度程序之类的东西需要 A,我们可能会遇到问题。

我想知道我的推理是否有任何错误,或者我是否没有考虑到一些关键问题。

谢谢

【问题讨论】:

    标签: operating-system kernel preemption


    【解决方案1】:

    FreeBSD 有一些关于这个主题的精彩注释,可能是一个很好的案例研究。你可以在这里阅读更多:

    http://www.freebsd.org/doc/en/books/arch-handbook/smp-design.html

    在锁定的主题上,他们更小心地使用更细粒度的锁定,这样抢占可能只会在持有锁之外发生。

    在抢占锁持有线程会导致正确性问题的情况下,他们提到他们有一个 API 用于指示线程暂时处于不可中断区域:

    虽然锁可以在抢占的情况下保护大多数数据,但并非所有 内核是抢占安全的。例如,如果一个线程持有一个 自旋互斥锁被抢占,新线程尝试获取相同的自旋 互斥体,新线程可能会像被中断的线程一样永远旋转 永远没有机会执行。此外,一些代码,如代码 在 Alpha 上的 exec 期间为进程分配地址空间号 不需要被抢占,因为它支持实际的上下文切换 代码。通过使用 临界区。

    还有:

    临界区 API 的职责是防止上下文 在临界区内部切换。使用完全抢占式内核, 除了当前线程之外,线程的每个 setrunqueue 都是一个 抢占点。一种实现是为 critical_enter 设置一个 由其对应项清除的每个线程标志。如果 setrunqueue 是 用这个标志集调用,它不会抢占不管 新线程相对于当前线程的优先级。然而, 因为在自旋互斥锁中使用临界区来防止上下文 开关和多个自旋互斥锁可以获得,关键 section API 必须支持嵌套。为此,当前 实现使用嵌套计数而不是单个线程 标志。

    因此,在您的示例中,如果您有一个可抢占的线程持有对调度程序很重要的锁,您可能会将该线程标记为暂时不可抢占。

    即使在应用级软件中,您也可以找到这种方法的相似之处。 .Net 有一个称为约束执行区域[1][2][3] 的概念,虽然它们与调度无关,但用于向 VM 发出信号,表明某些即将执行的代码块必须'原子地'执行,并且 VM 应该推迟它可能执行的任何 Thread.Abort()s,以及确保代码可以完成(确保方法已经 JIT'd 并且有足够的堆栈空间)。不同的目的,但类似的粗略想法 - 告诉调度霸主“如果你以奇怪的方式打断我,你可能会破坏正确性”。

    当然,在内核抢占或 .Net CER 的情况下,开发人员有责任正确识别出现关键执行区域的所有区域,以确保强制执行某些锁定不变量。

    FreeBSD 有他们用来帮助​​调试这类问题的工具,以帮助识别例如死锁。一种特殊的技术是锁排序——每个锁都有一个特定的优先级;当你抓住锁时,你记录下当前的锁优先级。然后,如果您尝试获取低于当前优先级的锁,您就知道您违反了锁顺序,您应该通过记录操作系统故障来通知用户。

    对锁排序的需求可能不会立即显现出来,但考虑一下流行的死锁示例 - 2 个资源由两个锁保护:

    线程 A 想要获取锁 1 和 2。 线程 B 想要获取锁 1 和 2.. 但是:

    • 线程 A 获取锁 1
    • 线程 B 获取锁 2
    • 线程 A 试图抓住锁 2,但不能
    • 线程 B 尝试获取锁 1,但不能。
    • 已实现死锁。

    线程没有以一致的顺序获取锁。线程 B 实际上应该注意到他在尝试获取锁 1 时持有锁 2;从 1

    【讨论】:

      猜你喜欢
      • 2018-09-16
      • 2015-03-05
      • 1970-01-01
      • 1970-01-01
      • 2017-03-05
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多