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);