我最近对 Linux 内核的设计和历史产生了兴趣,所以我决定从头开始研究。没错,就是 0.01 版本。 :-) 当然,我意识到如此古老的代码可能有很多 bug 或不完整,但这正是它有趣的地方。 不管怎样,我注意到调度器函数 sleep_on_interruptible() 中一个奇怪之处。在内核 1.0 版本之前,两种形式的 sleep_on() 都只是等待一个 task_struct 指针变量,并将该变量设置为指向 sleep_on() 的最后一个调用者。因此,wake_up() 只会直接唤醒 sleep_on() 的最后一个调用者;该调用者负责唤醒之前的调用者(它保存了指向前一个调用者的指针),以此类推,形成一个链条。那时没有显式的等待队列,只有你可以称之为“隐式等待栈”的东西。 对于不可中断的等待,这样做还可以,但如果等待是可中断的,似乎就存在问题。假设等待指针变量的任务之一收到了信号。然后它会被调度器中的信号处理代码唤醒。这个任务会唤醒 *所有* 等待指针变量的任务,就像 wake_up() 一样。(如果任务位于“等待栈”的顶部,则行为就像调用 wake_up() 一样。如果任务位于等待栈的其他位置,它会唤醒顶部的任务,让自己重新进入睡眠状态,并等待被唤醒。然后事情就像 wake_up() 一样进行。) 当然,在这种实现方式下,你必须这样做,因为没有实际的方法可以从这样一个等待栈的中间取消链接一个任务。但这种行为仍然显得很奇怪。 也许我对 sleep_on_interruptible() 的预期行为理解有误,但我认为信号应该只唤醒接收信号的任务,而不是所有任务。我错了吗?在 1.0 及更高版本中,情况似乎确实如此,这些版本使用了传统的等待队列方法。 请注意,旧的内核代码仍然可以工作,因为被唤醒的任务在继续执行之前似乎总是会重新检查它们等待的条件;如果条件没有发生,它们会再次进入睡眠状态。但是,仅仅因为一个任务收到信号就唤醒所有任务似乎效率很低,因为它们都会再次调用 sleep_on_interruptible()。 有什么评论吗?这是一个有效的批评,也是内核被更改的原因吗?还是我对 sleep_on() 的理解有误? 并且,假设这个批评是有效的,他们为什么要等到 1.0 版本才做出改变呢? 附言:是否有关于内核设计的早期讨论的存档或记录? 我能找到的最早的东西是 linux-kernel 邮件列表的存档,但它只能追溯到 1995 年夏天,也就是项目启动四年后。
|