8.3 tasklet 机制实现中断的下半部
涉及结构体类型:
******************* struct tasklet_struct ****************************8
485 /* Tasklets --- multithreaded analogue of BHs.
486
487 Main feature differing them of generic softirqs: tasklet
488 is running only on one CPU simultaneously.
489
490 Main feature differing them of BHs: different tasklets
491 may be run simultaneously on different CPUs.
492
493 Properties:
494 * If tasklet_schedule() is called, then tasklet is guaranteed
495 to be executed on some cpu at least once after this.
496 * If the tasklet is already scheduled, but its execution is still not
497 started, it will be executed only once.
498 * If this tasklet is already running on another CPU (or schedule is
called
499 from tasklet itself), it is rescheduled for later.
500 * Tasklet is strictly serialized wrt itself, but not
501 wrt another tasklets. If client needs some intertask synchronization,
502 he makes it with spinlocks.
503 */
504
505 struct tasklet_struct
506 {
507 struct tasklet_struct *next;//内核自动维护这三个参数
508 unsigned long state;
509 atomic_t count;
510 void (*func)(unsigned long);//下半部的处理函数/tasklet处理函数
511 unsigned long data; //下半部函数要接收的的点心/接收给tasklet处理函数传递的参数
512 };
struct tasklet_struct tsk //定义下半部任务对象
//下半部任务对象的初始化:
511 void tasklet_init(struct tasklet_struct *t,
512 void (*func)(unsigned long),
unsigned long data)
513 {
514 t->next = NULL;
515 t->state = 0;
516 atomic_set(&t->count, 0);
517 t->func = func;
518 t->data = data;
519 }
在中断的上半部,调用如下函数将下半部的任务交给调度器调度:
********************tasklet_schedule();***********************
551 static inline void tasklet_schedule(struct tasklet_struct *t)
552 {
553 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
554 __tasklet_schedule(t);
555 }
//下半部任务从内核移除:
523 void tasklet_kill(struct tasklet_struct *t)
524 {
525 if (in_interrupt())
526 printk("Attempt to kill tasklet from interrupt\n");
527
528 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
529 do {
530 yield();
531 } while (test_bit(TASKLET_STATE_SCHED, &t->state));
532 }
533 tasklet_unlock_wait(t);
534 clear_bit(TASKLET_STATE_SCHED, &t->state);
535 }
在中断的上半部,调用如下函数将下半部的任务交给调度器
调度。
void tasklet_schedule(struct tasklet_struct *t);
--------------------------------------------------------------------------------------------------------------------
Makefile
1 obj-m := demo.o
2
3 KERNEL := /linux-3.5
4
5 all:
6 make -C $(KERNEL) M=`pwd`
7 clean:
8 make -C $(KERNEL) M=`pwd` clean
9
demo.c
1 /* head file */
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <plat/irqs.h>
5
6 #include <linux/interrupt.h>
7
8 struct mill_key{
9 int irqnum;
10 char *name;
11 u32 cnt;
12 }millkeys[] = {
13 {IRQ_EINT(26), "key1", 0},
14 {IRQ_EINT(27), "key2", 0},
15 {IRQ_EINT(28), "key3", 0},
16 {IRQ_EINT(29), "key4", 0},
17 };
18
19 static struct tasklet_struct task;//定义下半部任务对象
20
21 static void mill_unregister_irqkey(void)
22 {
23 int i;
24
25 for (i = 0; i < ARRAY_SIZE(millkeys); ++i) {
26 free_irq(millkeys[i].irqnum, &millkeys[i]);
27 }
28
29 }
30
31 /*irq bootm half*/
32 static void do_bh_handler (unsigned long data)//该参数来接收中断上半部task.data传递的参数(点心)
33 {
34 struct mill_key *ptr = (void *)data;//结构体数组地址(点心)赋给定义的结构体数组指针
35
36 if (in_interrupt()) {//判断中断下半部发生在中断上下文还是进程上下文
37 printk("%s In interrupt ...\n", __func__);
38 } else {
39 printk("%s In process ...\n", __func__);
40 }
41
42 ptr->cnt++;//中断发生的次数
43 printk("%s is %s!\n", ptr->name, (ptr->cnt%2)?"down":"up");
44 }
45
46 /*irq top half*/
47 static irqreturn_t do_handler(int irqnum, void *dev)
48 {
49 task.data = (unsigned long)dev;//将结构体数组地址给task.data作为给tasklet函数传递的参数(给下半部函数的点心)
50
51 tasklet_schedule(&task);//在中断上半部将下半部的任务交给调度器调度
52
53 return IRQ_HANDLED;
54 }
55
56 static int mill_register_irqkey(void)
57 {
58 int i;
59 int ret;
60
61 for (i = 0; i < ARRAY_SIZE(millkeys); ++i) {
62 ret = request_irq(
63 millkeys[i].irqnum, do_handler,
64 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
65 millkeys[i].name, &millkeys[i]);//cookie中断注册函数的第五个参数在中断发生时会传递给中断处理函数do_handler的第二个参数
66 if (ret < 0) {
67 goto error0;
68 }
69 }
70
71 return 0;
72 error0:
73 while (i--) {
74 free_irq(millkeys[i].irqnum, &millkeys[i]);
75 }
76
77 return ret;
78 }
79
80 /* driver module entry */
81 static int __init demo_init(void)
82 {
83 tasklet_init(&task, do_bh_handler, 0);//下半部任务对象初始化
84
85 return mill_register_irqkey();
86 }
87
88 module_init(demo_init);
89
90
91 /* driver module exit */
92 static void __exit demo_exit(void)
93 {
94 tasklet_kill(&task);//下半部任务从内核移除
95
96 mill_unregister_irqkey();
97 }
98 module_exit(demo_exit);
99
100 /* driver module description */
101 MODULE_LICENSE("GPL");
102
103 MODULE_AUTHOR("millet9527");
104 MODULE_VERSION("millet plus 18");
105 MODULE_DESCRIPTION("example for driver module arch");



浙公网安备 33010602011771号