中断下班部有三种方法实现:
1:软中断
2:tasklet,tasklet软中断执行的一个链表,是由中断实现的
3:workqueue,工作队列是由内核线程实现的
总体来说,tasklet的效率比workqueue高,因为tasklet工作的中断上下文,但是不能有睡眠
而workqueue则是工作在进程上下文,可以存在睡眠操作。
1:软中断 一般不推荐使用
需要咋
文件里添加信息:
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
KEY_SOFTIRQ, //自己添加的
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};
在这个枚举类型里添加信息。枚举一般是用来做数组的。
然后通过open_softirq(KEY_SOFTIRQ, softirq_handler);通过open_softirq()函数注册对应软中断的处理函数
在中断处理函数中raise_softirq(KEY_SOFTIRQ);raise_softirq()函数给这个软中断设置标志,当中断执行结束
马上去执行中断下半部。
网卡的收发包是直接在软中断中实现的,其他的可以在软中的tasklet,或者workqueue中实现。
2:tasklet,是软中断中的一种,让某个中断到来时就会唤醒tasklet_softirq,然后tasklet链表上的任务都会被执行,
tasklet工作在中断上下文中,不能有睡眠。
static DECLARE_TASKLET(my_tasklet, tasklet_handler, 0); 申请一个tasklet,挂在链表上
tasklet_schedule(&my_tasklet); 在中断处理函数设置下次在tasklet的时候进行调度
3:workqueue,是一个内核线程,工作在进程上下文,允许代码进行休眠,但是效率没有tasklet高
static DECLARE_WORK(my_work, work_handler); 创建一个工作任务
queue = create_workqueue("my_queue"); 创建一个工作队列
在中断处理函数中设置这个队列中这个任务可以执行,queue_work(queue, &my_work);
然后对出中断后的某个时间就会去执行这个queue上的任务
linux中使用grep搜索文件中的内容: grep -rn '<\xxxxx' .
linux kernel 经典代码:
这里使用的是免锁链表,首先将整个链表加锁,取下,然后解锁,这样的话以最短的时间解决的冲突,此时别人还能对tasklet_vec进行操作。
然后取下来的链表操作的时候也不要加锁,当如果取下来的链表中还有一些处理不了的任务,则就加锁重新放入到tasklet_vec这个链表上。这样就打打减少得了锁的时间
-
static void tasklet_action(struct softirq_action *a)
-
{
-
struct tasklet_struct *list;
-
-
local_irq_disable();
-
list = __get_cpu_var(tasklet_vec).head;
-
__get_cpu_var(tasklet_vec).head = NULL;
-
__get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
-
local_irq_enable();
-
-
while (list) {
-
struct tasklet_struct *t = list;
-
-
list = list->next;
-
-
if (tasklet_trylock(t)) {
-
if (!atomic_read(&t->count)) {
-
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
-
BUG();
-
t->func(t->data);
-
tasklet_unlock(t);
-
continue;
-
}
-
tasklet_unlock(t);
-
}
-
-
local_irq_disable();
-
t->next = NULL;
-
*__get_cpu_var(tasklet_vec).tail = t;
-
__get_cpu_var(tasklet_vec).tail = &(t->next);
-
__raise_softirq_irqoff(TASKLET_SOFTIRQ);
-
local_irq_enable();
-
}
-
}
阅读(2127) | 评论(0) | 转发(0) |