中断处理:
进程和中断上下文的区别:
1. 内核栈不同(进程栈,中断栈)
2. 中断上下文中不允许睡眠(睡眠会触发调度,即引起进程切换)
查看系统中的中断源和中断次数: cat /proc/interrupts
使用request_irq()注册中断处理函数,使用的中断号是逻辑中断号
irqreturn_t irq_handler(int irq, void *arg)-------->irq_handler(指向中断处理函数的指针),irq(IRQ号),arg(对应的设备ID),该函数指针用于初始化struct irqaction对象中的handler成员
中断处理函数的返回值:处理完成返回IRQ_HANDLED(中断被正常处理),不是本设备产生的中断IRQ_NONE(用于共享中断)
中断处理分为2个部分:
上半部:中断处理函数
下半部(BH):处理复杂或不紧急的任务
实现下半部的方式:
1. SoftIRQ(软中断):不会直接使用
2. Tasklet(小任务,特定的软中断):回调函数,立即执行
3. 定时器,延后执行
4. 工作队列:内核线程
立即执行
延后执行
软中断的执行时机:
1. 在中断处理函数执行完成后,中断返回之前
2. 在ksoftirqd内核线程中执行
区别:***
软中断处理函数也在中断上下文中,因此不能调用睡眠函数
工作队列处于进程上下文,可以调用睡眠函数
工作队列传递参数
struct T {
struct work_struct work;------>工作队列节点
int arg;------>节点的ID
};
jiffies时钟中断触发的计数器,每秒钟增加CONFIG_HZ(中断次数)的值。
32无符号长整形 2^32,系统启动5分钟后翻转
同步和互斥机制:
1. 关中断
local_irq_save 保存当前中断状态,并且关中断
local_irq_restore 恢复之前中断状态,开中断
2. 原子操作(单CPU时使用) ***
仅执行一次,在执行过程中不会中断也不会休眠,是最小的执行单元
atomic.h(在这一结构体中,定义的变量为原子变量(整形变量))中的操作
设置标志位或计数时使用
3. 自旋锁 ***
使用循环判断锁的状态,如果已经加锁,一直执行循环操作等待,直到锁被释放
多CPU间互斥时使用
spin_lock_irqsave----->获取自旋锁并关中断,保存当前中断状态到flags(标志寄存器)
spin_unlock_irqrestore----->释放自旋锁并开中断,恢复之前中断状态
4. 读写自旋锁
读读并发,读写和写写互斥
read_lock_irqsave----->获取读锁并关中断,保存当前中断状态flags
read_unlock_irqrestore----->释放读锁并开中断,恢复之前中断状态
write_lock_irqsave----->获取写锁并关中断,保存当前中断状态flags
write_unlock_irqrestore----->释放写锁并开中断,恢复之前中断状态
5. 顺序锁
读读和读写并发,写写互斥
do {
read_seqbegin---->读之前获取顺序值,函数返回顺序值
while(read_seqretry)---->读完之后检查顺序值是否发生了变化,如果是,则要重读
write_seqlock---->写之前加锁
write_sequnlock----->写之后解锁
}
6. 信号量(睡眠,不能在中断上下文使用)***
down_interruptible------>获取信号量(信号量的值减1),当信号量的值不为0时,可以立即获取信号量,否则进程休眠,但是能够被信号唤醒
up------>释放信号量(信号量的值加1),如果有进程等待信号量,则唤醒这些进程
7. 读写信号量(睡眠)---->本质与信号量一样,这是将读和写分开
读读并发,读写和写写互斥
down_read
down_write
8. 互斥锁(睡眠)***
在进程上下文中给临界区加锁
mutex_lock----->访问共享资源之前获得互斥锁
mutex_unlock------>访问完共享资源后释放互斥锁
9. RCU(read copy update) ***
读读,读写,写写并发
rcu_read_lock----->读者(对共享资源发起读访问操作的代码)进入临界区
rcu_dereference----->读者用于获取共享资源的内存区指针
rcu_read_unlock----->读者退出临界区
10. 完成量(睡眠)***
用于同步,使用等待队列实现
wait_for_completion----->等待其他任务完成某个操作
complete------>某个操作完成后,唤醒等待的任务
11. 等待队列(睡眠)
wait_event(wq,condition)---->在条件condition不成立的情况下将当前进程放入到等待队列并休眠的基本操作
wake_up----->唤醒在等待队列中的进程
12.临界区的概念
每个进程中访问临界资源(共享资源)的那段代码称为临界区