spin_lock概述
spin_lock 自旋锁如果获取不了,进程一直处于忙等待的状态占用着cpu,不会被其他的task打断,不会进入sleep状态,除了自旋锁以外的其他任何形式的锁都有可能导致睡眠或者进程切换
- spin_lock
防止内核抢占死锁,关闭其他进程/中断的抢占,假如进程和中断运行在同一个cpu上,进程设置成TASK_INTERRUPT,进程没解锁,中断就得不到锁一直忙等待 - spin_lock_irq 无论之前中断是打开还是关闭,获得锁解锁后都是开启中断,防止内核和中断抢占死锁
- spin_lock_irqsave 保存当前中断的状态,关闭中断进入临界区,退出临界区后将保存的中断状态写回寄存器,防止自旋状态丢掉之前的中断状态
tasklet(中断下半部处理机制)
Tasklet是Linux内核中一种延迟执行机制,基于软中断实现,软中断的使用只在那些执行频率很高和连续性要求很高的情况下才需要。tasklet是利用软中断实现的一种下半部机制;
tasklet有两类中断代表,HI_SOFTIRQ和TASKLET_SOFTIRQ,两者之间的区别是在于 HI_SOFTIRQ软件中断先于 TASKLET_SOFTIRQ类型的软中断执行。
tasklet定义
struct tasklet_struct
{
struct tasklet_struct *next; //链表中下一个tasklet
unsigned long state; //tasklet的状态, TASKLET_STATE_SCHED Tasklet is scheduled for execution, TASKLET_STATE_RUN Tasklet is running (SMP only)
atomic_t count; //tasklet 引用计数,不为0,禁止tasklet,为0时tasklet才被激活设置为等待执行状态 TASKLET_STATE_SCHED
bool use_callback;
union {
void (*func)(unsigned long data); //func/ callback 成员是tasklet的处理程序,data是参数
void (*callback)(struct tasklet_struct *t);
};
unsigned long data;
};
tasklet 使用流程
tasklet_init(&stream->buf_done_tasklet, rkisp_buf_done_task,(unsigned long)stream);//注册task要执行的程序,stream是他的参数
tasklet_disable(&stream->buf_done_tasklet);
tasklet_kill(&stream->buf_done_tasklet);
tasklet调度
static inline void tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) //检查tasklet的状态,若为TASKLET_STATE_SCHED,表示已经被调度在list中等待被执行,否则继续执行__tasklet_schedule
__tasklet_schedule(t);
}
void __tasklet_schedule(struct tasklet_struct *t)
{
unsigned long flags;
local_irq_save(flags); //保存IF标志的状态,并禁用本地中断
t->next = NULL;
*__get_cpu_var(tasklet_vec).tail = t; //下面的这两行代码就是给tasklet分配per_cpu变量
__get_cpu_var(tasklet_vec).tail = &(t->next);
raise_softirq_irqoff(TASKLET_SOFTIRQ); //触发软中断,让其在下一次do_softirq()的时候,有机会被执行
local_irq_restore(flags); //恢复前面保存的标志
}