毫无疑问,内核模式中的上下文切换是由硬件中断或软件中断引起的。众所周知,上下文切换应保持原子性,但如何实现原子性?众所周知,中断门禁用所有中断(我不知道是否包含NMI)。中断门本身是否可以自然地看作原子序列?
答案 0 :(得分:5)
原子操作在内核中实现如下。在高级别(例如,来自设备驱动程序开发人员的POV),内核提供与用户空间互斥体类似地获取和释放的locks。在较低级别,这些锁使用atomic operations的组合实现,并向preemption should not occur发送内核调度程序。
在调度程序本身中,masking interrupts保证原子性。这是使用单个指令(cli或sti)完成的,因此它本身就是原子的。 NMI确实可以在中断被清除时发生,但是,这是一种特殊情况。 NMI处理程序知道它可以在一个奇怪的上下文中调用,所以它确保它not change the context。
答案 1 :(得分:3)
上下文切换和互斥。 我假设通过上下文切换你的意思是任务切换。我必须注意,如果诚实的任务切换没有必要需要锁定。几乎在任何情况下,schedulling本身都需要互相排斥访问制定调度决策所需的一些数据,而不是上下文切换本身,这是遵循制定调度决策。
几乎所有现代操作系统都遵循设计,其中系统中的每个线程保留两个堆栈,一个在用户模式侧,另一个在内核模式侧。完成任务切换所需的全部操作是三步操作:
正如您所看到的,本质上下文切换操作时使用两组本地任务数据,但不是全局数据。 CPU寄存器的内容不是共享数据的示例。 注意!如果内核中只有一个代码实现上下文切换,则所有上下文切换都将通过相同的代码。并且在它中提供保证,如果任务被切换,该任务的内核堆栈的顶部将包含良好定义的格式的所有CPU状态。每次切换任务时,都可以在内核堆栈的顶部找到CPU状态数据!
存在两个注释:
内核中的Mutal排除。 一般来说,kenel可以分为两部分:硬件驱动和软件驱动。 fisrt one包括可由硬件设备(中断处理程序)分配的中断调用的代码,并且它不依赖于当前正在执行的线程,并且不依赖于以某种方式影响执行任务的上下文第二个包括当前正在执行的线程(系统调用和异常处理程序)显式或隐式调用的代码,并且通常需要访问任务描述符数据。
这两个内核部分为数据锁定提供了不同的要求。仅由内核的软件驱动部分使用的数据可以使用由内核环境提供的众所周知的同步原语。我的意思是遵循检查和等待方法的原语。例如互斥体。如果需要的数据被锁定,任务可以在等待队列中注册self并释放CPU以执行其他任务。
只能由硬件驱动的部分(仅由一个特定的中断处理程序)使用的数据可以依赖于如果处理相同时间的中断,则下一个中断无法传送到CPU的事实当处理程序通知中断控制器它完成中断处理(所谓的EOI(End Of Interrupt)通知)时。由于这个数据仅由一个中断处理程序使用,并且使用位于中断处理程序执行开始和发送EOI通知之间,以自然方式受到保护,并且不需要任何额外的锁定。
最后,软件和硬件驱动的内核部件之间或不同优先级中断处理程序之间共享的数据为mutal排除实现提供了最严格的要求。这样的数据既不受检查等待锁也不受同一优先级中断传递的串行性质的保护。对于此类数据的锁定要求有两个主要因素:
由于这种情况,在这种情况下使用下一个同步技术:
关于中断门。是的,你是对的。英特尔处理器在进入中断门期间自动禁用中断,并从处理程序重新启用它们。由于这个整个中断处理程序可以被认为是以原子方式执行。但!正如我在上面几行中所描述的那样,人们试图尽量减少以这种方式保护的代码量。因此,即使操作系统内核使用中断门而不是陷阱门,它也会尽可能快地在中断处理程序中手动重新启用中断。
NMI是一个非常特殊的案例。它的出现通常意味着整个世界都崩溃了。在所有系统都已经停机的那一刻,有人会关心同步吗?