在设计自己的驱动程序时,第一个要记住的规则是,只要可能,就应该避免资源的共享。
#include <asm/semaphore.h> //互斥、同步(少)
struct semaphore;
#include <linux/rwsema.h> //写者优先,适合写比较少的情况
struct rw_semaphore;
#include <completion> //完成
struct completion;
#include <linux/spinlock.h>
自旋锁 spinlock
核心规则:任何拥有自旋锁的代码都必须是原子的。它不能休眠,不能因为任何原因放弃处理器,除了服务中断以外。
(内核抢占的情况由自旋锁代码本身处理,任何时候,只要内核代码拥有自旋锁,在相关处理器上的抢占就会被禁止。(锁控制设备访问的情况)为了避免陷阱,需要在拥有自旋锁时禁止中断(仅在本地cpu上)。)
重要规则:自旋锁必须在可能的最短啊时间内拥有。
不明确规则:
不论是信号量还是自旋锁,都不允许锁拥有者第二次获得这个锁。
锁的顺序规则:
在必须获取多个锁时,应该始终以相同的顺序获得。
如果拥有信号量与自旋锁的组合,必须首先获得信号量。(先使用粗粒度的锁,lockmeter该补丁可以查看内核花费在锁上的时间)
驱动程序不能在拥有自旋锁、seqlock(写入少且快速)、或者RCU锁时休眠,如果禁止了中断也不能休眠。
免锁算法 原子操作、位操作 linux/kfifo.h
#include <linux/seqlock.h>
seqlock_t 保护的资源很小、很简单,会频繁访问且写入很少发生且必须快速,可以使用seqlock。通常不能用于保护包含指针的数据结构。
初始化:seqlock_t lock1 = SEQLOCK_UNLOCKED;
seqlock_t lock2;
seqlock_init(&lock2);
读取访问通过获得一个unsigned整数顺序值而进入临界区,在退出时,该顺序值和当前值比较,如果不相等,则必须重试读取访问。例如:
unsigned int seq;
do{
seq = read_seqbegin(&the_lock);
//完成所需工作
}while(read_seqretry(&the_lock,seq));
RCU(read-copy-update) 很少在驱动中使用,经常读取,很少写入的情况(网络路由表)