由于AI的生态和工具链,目前有很大比例的ADAS系统基于rt linux 系统。而rt linux 也合入了主线。rt linux 相对于linux 可以参考 Linux 在自动驾驶中可靠吗。
什么是优先级反转(priority inversion)问题?
假设进程1的优先级低,进程2的优先级高。进程1持有互斥锁,进程2申请互斥锁,因为进程1已经占有互斥锁,所以进程2必须睡眠等待,导致优先级高的进程2等待优先级低的进程1。
如果存在进程3,优先级在进程1和进程2之间,那么情况更糟糕。假设进程1仍然持有互斥锁,进程2正在等待。进程3开始运行,因为它的优先级比进程1高,所以它可以抢占进程1,导致进程1持有互斥锁的时间延长,进程2等待的时间延长。

优先级继承(priority inheritance)
可以解决优先级反转问题。如果低优先级的进程持有互斥锁,高优先级的进程申请互斥锁,那么把持有互斥锁的进程的优先级临时提升到申请互斥锁的进程的优先级。在上面的例子中,把进程1的优先级临时提升到进程2的优先级,防止进程3抢占进程1,使进程1尽快执行完临界区,减少进程2的等待时间。

实时互斥锁(rt_mutex)实现了优先级继承。锁的等待者按优先级从高到低排序,如果优先级相等,那么先申请锁的进程的优先级高。持有锁的进程,如果它的优先级比优先级最高的等待者低,那么把它的优先级临时提升到优先级最高的等待者的优先级,代码如下。如果普通进程1持有锁,实时进程2等待锁,那么把普通进程1的优先级临时提升到实时进程2的优先级,普通进程1变成实时进程。
rt_mutex_lock() -> __rt_mutex_lock() -> rt_mutex_lock_state()
-> __rt_mutex_lock_state() -> rt_mutex_fastlock() -> rt_mutex_slowlock()
-> rt_mutex_slowlock_locked() -> task_blocks_on_rt_mutex()
实时内核使用实时互斥锁实现互斥锁(mutex)和伤害/等待互斥锁(ww_mutex),支持优先级继承。互斥锁的定义如下,可以看到在实时内核中互斥锁等同于实时互斥锁。
实时内核使用实时互斥锁实现读写信号量(rw_semaphore),支持优先级继承。
在实时内核中,自旋锁(spinlock_t)和读写锁(rwlock_t)是基于实时互斥锁实现的,临界区是可以抢占的,支持优先级继承。
自旋锁(spinlock_t)保护的临界区是不可抢占的,导致实时进程不能被及时调度。实时内核使用实时互斥锁实现自旋锁,临界区是可以抢占的,支持优先级继承,spin_lock_irq()和spin_lock_irqsave()不会禁止硬中断。
少数使用自旋锁保护的临界区不允许抢占,内核定义了原始自旋锁(raw_spinlock),提供传统的自旋锁。在非实时内核中,spinlock和raw_spinlock完全相同。
选择spinlock和raw_spinlock的时候,最好坚持3个原则。
读写锁(rwlock_t)保护的临界区是不可抢占的,导致实时进程不能被及时调度。实时内核使用实时互斥锁实现读写锁,临界区是可以抢占的,支持优先级继承,read_lock_irq()、read_lock_irqsave()、write_lock_irq()和write_lock_irqsave()不会禁止硬中断。为了降低实现的复杂性,只允许一个进程获取读锁,进程可以递归获取读锁。
少数使用读写锁保护的临界区不允许抢占,内核定义了原始读写锁(raw_rwlock),提供传统的读写锁。在非实时内核中,rwlock和raw_rwlock完全相同。
选择rwlock和raw_rwlock的原则,与选择spinlock和raw_spinlock的原则相同。
对于使用禁止硬中断保护的临界区,因为在实时内核中使用内核线程执行大多数中断处理函数,所以大多数临界区不需要禁止硬中断。
对于使用禁止内核抢占保护的临界区,在实时内核中大多数临界区可以修改为可以抢占的。
为了在实时内核中把这两种临界区修改为可以抢占的,实时内核从3.0版本开始引入local_irq_lock,在合并到内核主线5.8版本的时候把名称改为local_lock(本地锁)。local_lock为使用禁止内核抢占或硬中断保护的临界区提供了命名的作用域。
非实时内核把local_lock映射到禁止内核抢占和禁止硬中断,
实时内核把local_lock映射到一个每处理器自旋锁。函数local_lock()用来获取一个每处理器本地锁。
修改使用禁止软中断保护的临界区
在实时内核中,软中断由软中断线程执行,或者在进程开启软中断的时候执行,使用禁止软中断保护的临界区和软中断线程使用本地锁“softirq_ctrl.lock”互斥
rt_mutex_lock

rt_write_lock

rt_read_lock

rt_spin_lock

local_lock

rcu_read_unlock
