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号
浙公网安备 33010602011771号