CONFIG_PREEMPT_RT的引入意味着linux内核拥有了实时性,虽然还远远达不到硬实时,可是基本的实时性还是挺不错的,这又一次说明了linux内核的灵活性,想加入什么新特性很简单而且很直接。
这个实时性补丁主要考虑了几个方面,一个是将自旋锁进行了改进,一个是将中断线程化了,还有一个就是又引入了几个内核线程专门处理一些不得不延后的操作。频繁的中断很影响实时性,因为它们是不确定的,对于中断的发生时刻是未知的,另外中断发生时无论cpu正在处理什么任务都要停下来来处理中断,即使一个无关紧要的中断也比最高优先级的进程的优先级别高,任何任务都无条件向中断让路,这大大影响了实时性,实时任务被中断压得不得不一会一停,这只是其一,还有一个影响实时性的因素就是内核的自旋锁,自旋锁在某种意义上就是抢占禁用,这样的话即使再高优先级的进程也无法抢占占有自旋锁的进程,在以前的rcu锁中,为了一个rcu读端加锁,整个系统的抢占被禁用,这些都影响了实时性。于是实时补丁就着手改变这个现状,具体就是:第一,将传统的自旋锁用mutex实现,这样的话,自旋锁就可以睡眠了,但是中断中不允许睡眠,而中断中运用了大量的自旋锁,因此引出了第二点,就是中断线程化,每个中断向量都有一个专门的线程负责处理,这些中断处理线程拥有全局的优先级,受到调度器的全局调度,因此,它们不一定能竞争得过优先级很高的实时进程,所有这一切还没有完,因为自旋锁可以睡眠了,那就意味着抢占禁用期间不能再利用自旋锁了,当然可以用传统的自旋锁,这就引出了第三点,也就是说专门单列出来一个机制,用来将抢占禁用期间的不得不用自旋锁的操作进行适当的延迟,这个也是一个作重要的机制,实际上有两种方式,一个就是使用原来的RCU机制,因为第一代rcu的一个“期限”到期就是所有的读端都释放了rcu读锁,而释放了rcu读锁意味着打开了抢占,开着抢占就可以睡眠了,也就是说可以用实时的mutex实现的自旋锁了,注意,第二代的可睡眠的rcu是不能用于这里的,因为在rcu读锁占有期间,抢占并不禁用,而释放了锁,也不会影响抢占位,因此第二代的可睡眠rcu和抢占是无关的,因此不能用,在抢占禁用期间调用延时的利用自旋锁函数的第二个机制就是单独开一些内核线程来负责这些工作,
内核线程拥有进程上下文,可以睡眠,因而可以随意调用可睡眠的自旋锁函数,从这里可以再次看出进程在linux中的意义,进程太伟大了,如果有什么事情,那么就让进程来做吧,这样限制会最少。

原来的自旋锁利用了禁用抢占这个内核特性活泼了很久很久,一直都不错,但是实际上,禁用抢占和锁其实是两个概念,非实时内核的自旋锁实现中由于自旋的要求 将抢占和锁耦合在一起,让它们一起实现一个功能,比如对于up上的抢占内核,自旋锁就是禁用抢占而已,对于up非抢占内核,自旋锁什么也不做,对于smp 上的抢占内核,不但要禁用抢占还要加锁,...如此一看,看似很奇妙,实际上很糟糕,因此才有了那么多的情况下的那么多的机制,一般初学者会发晕的,不统 一的操作杂糅在一起形成了拙劣的设计,不过linux就是这样,这也是linux的优点。现在的实时补丁下的内核看看情况会是怎样,在实时补丁下,自旋锁 已经不再自旋了,回归成了一个真正的锁,以往的spin_lock_irqsave要disable preemption,但是现在不用了,也就是说,现在的自旋锁不靠禁用抢占来保证锁不被抢走(其实是cpu不被抢走,也就是自旋锁保证进程不离开当前的 执行环境),而是用了一把真正的锁。这时,即使一个进程抢占了这个持有锁的进程,那么在它想获得这把锁的时候还是会被阻塞进而睡眠等锁的。我们来看一下这个补丁的部分代码:
static int desched_thread(void * __bind_cpu)