什么是可重入内核?
4 回答
更简单的答案:
内核重入
如果内核不是可重入的,则只能在处于用户模式时暂停进程。尽管它可以在内核模式下挂起,但这仍然会阻止所有其他进程上的内核模式执行。这样做的原因是所有内核线程共享相同的内存。如果执行将在它们之间任意跳转,则可能会发生损坏。
可重入内核使进程(或者更准确地说,它们相应的内核线程)能够在内核模式下放弃 CPU。它们不会阻碍其他进程也进入内核模式。一个典型的用例是 IO 等待。进程想要读取一个文件。它为此调用了一个内核函数。在内核函数内部,磁盘控制器被要求提供数据。获取数据需要一些时间,并且在此期间功能被阻止。对于可重入内核,调度程序会将 CPU 分配给另一个进程(内核线程),直到来自磁盘控制器的中断指示数据可用并且我们的线程可以恢复。这个进程仍然可以访问 IO(需要内核函数),比如用户输入。系统保持响应并减少因 IO 等待而造成的 CPU 时间浪费。
这几乎是当今桌面操作系统的标准。
内核抢占
内核抢占对系统的整体吞吐量没有帮助。相反,它寻求更好的响应能力。
这里的想法是,通常内核函数只被硬件原因中断:外部中断或 IO 等待情况,它自愿将控制权交给调度程序。相反,抢占式内核也会中断和挂起内核功能,就像它会在用户模式下中断进程一样。系统响应速度更快,因为处理鼠标输入等进程即使在内核内部完成繁重的工作时也会被唤醒。
内核级别的抢占使内核开发人员的工作变得更加困难:内核函数不能仅由自愿或由中断处理程序(在某种程度上是受控环境)挂起,而且由于调度程序而由任何其他进程挂起。必须注意避免死锁,例如:一个线程锁定资源 A,但需要资源 B 被另一个线程中断,该线程锁定资源 B,但随后又需要资源 A。
拿我对先发制人的解释持保留态度。我很高兴有任何更正。
所有 Unix 内核都是可重入的。这意味着多个进程可能同时在内核模式下执行。当然,在单处理器系统上,只有一个进程可以进行,但在等待 CPU 或完成某些 I/O 操作时,许多进程可能会在内核模式下被阻塞。例如,在代表进程向磁盘发出读操作后,内核让磁盘控制器处理它并继续执行其他进程。当设备完成读取时,中断会通知内核,因此前一个进程可以恢复执行。
提供可重入性的一种方法是编写函数,以便它们只修改局部变量而不改变全局数据结构。这样的函数称为可重入函数。但是可重入内核不仅限于此类可重入函数(尽管这是一些实时内核的实现方式)。相反,内核可以包含不可重入函数并使用锁定机制来确保一次只有一个进程可以执行不可重入函数。
如果发生硬件中断,可重入内核能够挂起当前正在运行的进程,即使该进程处于内核模式。这种能力非常重要,因为它提高了发出中断的设备控制器的吞吐量。一旦设备发出中断,它会一直等待,直到 CPU 确认它。如果内核能够快速响应,设备控制器将能够在 CPU 处理中断时执行其他任务。
现在让我们看看内核可重入性及其对内核组织的影响。内核控制路径表示内核为处理系统调用、异常或中断而执行的指令序列。
在最简单的情况下,CPU 从第一条指令到最后一条指令顺序执行内核控制路径。但是,当以下事件之一发生时,CPU 会交错内核控制路径:
在用户态执行的进程调用系统调用,对应的内核控制路径验证请求不能立即得到满足;然后它调用调度程序来选择一个新的进程来运行。结果,发生了进程切换。第一个内核控制路径未完成,CPU 继续执行其他一些内核控制路径。在这种情况下,两条控制路径代表两个不同的进程执行。
CPU 在运行内核控制路径时检测到异常(例如,访问 RAM 中不存在的页面)。第一控制路径被挂起,CPU开始执行合适的程序。在我们的示例中,这种类型的过程可以为进程分配一个新页面并从磁盘读取其内容。当程序终止时,可以恢复第一控制路径。在这种情况下,两条控制路径代表同一个进程执行。
当 CPU 在启用中断的情况下运行内核控制路径时,会发生硬件中断。第一个内核控制路径未完成,CPU 开始处理另一个内核控制路径来处理中断。当中断处理程序终止时,第一个内核控制路径恢复。在这种情况下,两条内核控制路径运行在同一个进程的执行上下文中,系统 CPU 总时间也计算在内。但是,中断处理程序不一定代表进程进行操作。
当 CPU 在启用内核抢占的情况下运行时会发生中断,并且可以运行更高优先级的进程。在这种情况下,第一个内核控制路径未完成,CPU 代表更高优先级的进程继续执行另一个内核控制路径。仅当内核已使用内核抢占支持编译时才会发生这种情况。
这些信息可在http://jno.glas.net/data/prog_books/lin_kern_2.6/0596005652/understandlk-CHP-1-SECT-6.html获得
更多关于http://linux.omnipotent.net/article.php?article_id=12496&page=-1
可重入函数是一种可以由多个任务同时使用而不必担心数据损坏的函数。相反,不可重入函数是不能由多个任务共享的函数,除非通过使用信号量或通过在代码的关键部分禁用中断来确保函数的互斥。可重入函数可以随时中断并在以后恢复而不会丢失数据。可重入函数要么使用局部变量,要么在使用全局变量时保护它们的数据。
可重入函数:
Does not hold static data over successive calls
Does not return a pointer to static data; all data is provided by the caller of the function
Uses local data or ensures protection of global data by making a local copy of it
Must not call any non-reentrant functions