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

 

 

posted @ 2017-03-22 20:39  bkycrmn  阅读(200)  评论(0)    收藏  举报