linux将中断分为两部分:上部分和下半部(顶半部和底半部);上半部完成紧急但能很快完成的事情,下半部完成不紧急但比较耗时的操作;
1. struct tasklet_struct结构体
struct tasklet_struct
{
struct tasklet_struct *next; //构成链表的指针
unsigned long state; //该tasklet被调度的状态(被调度还是已经执行)
atomic_t count; //用于禁止tasklet执行(非0时)
void (*func)(unsigned long);//下半部函数
unsigned long data; //传递给下半部函数的参数
};
要实现tasklet中断下半部,就要构造一个struct tasklet_struct结构对象,并初始化里面的成员;然后放入对应的cpu的tasklet链表;最后设置软中断号TASKLET_SOFTIRQ所对应的比特位;
2. 初始化
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
#define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
上面DECLARE_TASKLET宏定义一个struct tasklet_struct对象,名字为name,下半部函数为func,传递的参数是data; 该tasklet可以被执行(因为count值被设置为0)
DECLARE_TASKLET_DISABLED宏与DECLARE_TASKLET仅仅是count被设置为1,故不能被执行; 需要调用tasklet_enable函数使能;
除了上面的宏,tasklet_init也可以实现对struct tasklet_struct结构体对象的初始化;
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
源码:
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
{
t->next = NULL;
t->state = 0;
atomic_set(&t->count, 0);
t->func = func;
t->data = data;
}
3. tasklet_schedule函数
将tasklet_struct对象加入到内核的tasklet链表中;
void tasklet_schedule(struct tasklet_struct *t);
源码:
static inline void tasklet_schedule(struct tasklet_struct *t)
{
//测试该tasklet_struct对象是否被调度状态,没有则设置并加入调度队列;
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
__tasklet_schedule(t);
}
4. 简单示例:
#if 1
static void jit_tasklet_fn(unsigned long arg); //前向声明
DECLARE_TASKLET(tlet,jit_tasklet_fn,(unsigned long)&xxx);
#else
static struct tasklet_struct tlet;
#endif
static void jit_tasklet_fn(unsigned long arg)
{
printk("in jit_tasklet_fn jiffies=%ld\n",jiffies);
}
//中断函数
static irqreturn_t my_handler(int irq, void *dev_id)
{
tasklet_schedule(&tlet);
return IRQ_HANDLED;
}
{
#if 0
tasklet_init(&tlet, jit_tasklet_fn, (unsigned long)&xxx);
#endif
...
}
上面两种不同的初始化方式:
static void jit_tasklet_fn(unsigned long arg); //前向声明
DECLARE_TASKLET(tlet,jit_tasklet_fn,(unsigned long)&xxx); 参数3为指针,大多指定某个结构体对象地址或NULL;
static struct tasklet_struct tlet;
tasklet_init(&tlet, jit_tasklet_fn, (unsigned long)&xxx);