1. 锁的种类
Name | 函数api | 特点 | |
原子操作 | atomic_read atomic_set | 只能针对单变量 | |
信号量/互斥锁 | down down_interruptible down_uninterruptible up | 一般当获取不到当前的锁变量时会进入睡眠,不能在中断上下文中使用 | |
自旋锁 | spin_lock spin_unlock | 捕获不到当前锁变量时,会一直死等,不会睡眠,需要保证获取锁当中的代码不耗时,不睡眠 | |
读写锁 | read_lock/read_unlock write_lock/write_unlock | 支持多个读进程并存,但是读和写进程是互斥的 | |
RCU | rcu_read_lock/rcu_dereference/rcu_read_unlock rcu_assign_pointer | 读写操作可以并存 |
2. 自旋锁
自旋锁可以使用在中断上下文中,但是使用时候需要一些技巧。
场景1: 进程和中断互斥的情况
//进程
int process_func()
{
spin_lock(xx)
a++
spin_unlock(xx)
}
//中断
int interrupt_handler()
{
spin_lock(xx)
a++
spin_unlock(xx)
}
问题:当process_func已经获取锁,这时候发生了中断(中断是可以打断进程的),这时候就会进入interrupt_handler,但这时候无法获取锁,因为锁已经被进程process_func获取,这时候就会导致中断处理函数无法返回,系统死锁。
解决办法:就是需要在进程上下文中,关中断,然后获取spin_lock
//进程
int process_func()
{
//先关中断,再获取锁
spin_lock_irq(xx)
a++
//释放锁,开中断
spin_unlock_irq()
}
//中断
int interrupt_handler()
{
spin_lock(xx)
a++
spin_unlock(xx)
}
场景2: 函数嵌套调用
//进程A
int process_funcA()
{
//先关中断,再获取锁
spin_lock_irq(xxA)
process_funcB()
a++
//释放锁,开中断
spin_unlock_irq(xxA)
}
//进程B
int process_funcB()
{
//先关中断,再获取锁
spin_lock_irq(xxB)
a++
//释放锁,开中断
spin_unlock_irq(xxB)
}
//中断
int interrupt_handler()
{
spin_lock(xxA)
a++
spin_unlock(xxA)
}
问题: 进程A虽然已经关掉了中断,但是调用B之后,又开了中断,执行a++之前,如果被中断interrupt_handler打断,那么又会死锁。
解决方法:
//进程A
int process_funcA()
{
//先保存中断标志,再关中断,再获取锁
spin_lock_irqsave(xxA)
process_funcB()
a++
//释放锁,回复保存的中断标志
spin_unlock_irqrestore(xxA)
}
//进程B
int process_funcB()
{
//先保存中断标志,再关中断,再获取锁
spin_lock_irqsave(xxB)
a++
//释放锁,回复保存的中断标志
spin_unlock_irqrestore(xxB)
}
//中断
int interrupt_handler()
{
spin_lock(xxA)
a++
spin_unlock(xxA)
}
others
todo...