LINUX内核 tasklet && work

    在内核中的中断机制中,为了防止解决中断嵌套(防止一个中断打断另一个中断)的问题,引进小任务机制:

    实际上,takslet经常运用在于:在中断处理中大量使用tasklet机制;tasklet用于减少硬中断处理的时间,将本来是在硬中断服务程序中完成的任务转化成软中断完成,即是将一些非紧急的任务留到tasklet中完成,而紧急的任务则在硬中断服务程序中完成。

      使用小任务机制需要三步:

        第一:定义一个struct tasklet_struct的类;

        第二步:初始化taskelet将处理任务的函数和takslet任务捆绑;

        第三步:调度tasklet :tasklet_schedule(&tasklet);

    

 12 #include <linux/delay.h>
 13 #include <linux/clk.h>
 14 #include <linux/miscdevice.h>
 15 #include <linux/io.h>
 16 #include <linux/ioport.h>
 17 #include <asm/uaccess.h>
 18 
 19 #include <linux/gpio.h>
 20 #include <mach/gpio.h>
 21 #include <plat/gpio-cfg.h>
 22 
 23 MODULE_LICENSE("GPL");
 24 MODULE_AUTHOR("bunfly");
 25 
 26 void my_tasklet_func(unsigned long data);
 27 struct tasklet_struct  my_tasklet;
 28 
 29 int test_init()
 30 {
 31     printk("hello kernel
");
 32     tasklet_init(&my_tasklet,my_tasklet_func, 0);
 33     tasklet_schedule(&my_tasklet);
 34     return 0;
 35 }
 36 
 37 void test_exit()
 38 {
 39     tasklet_kill(&my_tasklet);
 40     printk("exit
");
 41 }
 42 
 43 module_init(test_init);
 44 module_exit(test_exit);
 45 
 46 void my_tasklet_func(unsigned long data)
 47 {
 48     printk("wang wang wang
");
 49 }
 50 

     以下是在定时狗中断中使用tasklet的实例:

    

  1 #include <linux/init.h>
  2 #include <linux/thread_info.h>
  3 #include <linux/module.h>
  4 #include <linux/sched.h>
  5 #include <linux/errno.h>
  6 #include <linux/kernel.h>
  7 #include <linux/module.h>
  8 #include <linux/slab.h>
  9 #include <linux/input.h>
 10 #include <linux/init.h>
 11 #include <linux/serio.h>
 12 #include <linux/delay.h>
 13 #include <linux/clk.h>
 14 #include <linux/miscdevice.h>
 15 #include <linux/io.h>
 16 #include <linux/ioport.h>
 17 #include <asm/uaccess.h>
 18 
 19 #include <linux/gpio.h>
 20 #include <mach/gpio.h>
 21 #include <plat/gpio-cfg.h>
 22 
 23 MODULE_LICENSE("GPL");
 24 MODULE_AUTHOR("bunfly");
 25 
 26 irqreturn_t do_irq(int irq, void *data);
 27 unsigned long wdt_virt;
 28 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
 29 struct clk *k;
 30 
 31 void my_tasklet_func(unsigned long data) ;
 32 struct tasklet_struct  my_tasklet;
 33 //定义一个小任务
 34 
 35 int test_init()
 36 {
 37     int ret = 0;
 38     ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "bunflydog", 0x1111);
 39     if(ret < 0){
 40         printk("request_irq
");
 41         return 1;
 42     }
 43 
 44     k = clk_get(NULL, "watchdog");
 45     clk_enable(k);
 46 
 47     wdt_virt = ioremap(0x10060000, SZ_4K);
 48     wtcon = wdt_virt + 0x00;
 49     wtdat = wdt_virt + 0x04;
 50     wtcnt = wdt_virt + 0x08;
 51     wtclrint = wdt_virt + 0x0c;
 52 
 53     *wtcon = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (50 << 8);
 54     *wtdat = 0x8000;
 55     *wtcnt = 0x8000;
 56 
 57     tasklet_init(&my_tasklet, my_tasklet_func, 555);
 58     //小任务初始化
 59     return 0;
 60 }
 61 
 62 void test_exit()
 63 {
 64     printk("exit
");
 65 }
 66 
 67 module_init(test_init);
 68 module_exit(test_exit);
 69 
 70 void my_tasklet_func(unsigned long data)
 71 {
 72     if (in_interrupt()) {
 73         printk("KERNEL: my_tasklet_func in interrupt context.
");
 74     }
 75 
 76     printk("wang wang wang
");
 77 
 78     //msleep(1);
 79 }
 80 
 81 irqreturn_t do_irq(int irq, void *data)
 82 {
 83     if (in_interrupt()) {
 84         printk("KERNEL: do_irq in interrupt context.
");
 85     }
 86 
 87     tasklet_schedule(&my_tasklet);
 88 
 89     *wtclrint = 250;
 90     //清本次中断
 91     return IRQ_HANDLED;
 92 }

        运行结果:

      

      可以发现,my_taskelet_fun函数在do_irq函数调度之后才调用。

      需要注意的是:tasklet机制中不允许睡眠,如果将代码中my_tasklet_fun函数中的睡眠加上就会反发生错误;

      

      

  二.工作队列work

      但是,有时候中断处理需要花费很长时间来响应中断,这时候就需要用到工作队列了。

      类似于tasklet,work也需要三步:

      1,第一步声明一个work;     

                  work_struct my_work;

      2,  初始化work;        

                  INIT_WORK(my_work,my_mork_fun);                    

      3,将work加入调度;

                  schedule_work(my_work);

     以下是代码:

        

  1 #include <linux/init.h>
  2 #include <linux/thread_info.h>
  3 #include <linux/module.h>
  4 #include <linux/sched.h>
  5 #include <linux/errno.h>
  6 #include <linux/kernel.h>
  7 #include <linux/module.h>
  8 #include <linux/slab.h>
  9 #include <linux/input.h>
 10 #include <linux/init.h>
 11 #include <linux/serio.h>
 12 #include <linux/delay.h>
 13 #include <linux/clk.h>
 14 #include <linux/miscdevice.h>
 15 #include <linux/io.h>
 16 #include <linux/ioport.h>
 17 #include <asm/uaccess.h>
 18 
 19 #include <linux/gpio.h>
 20 #include <mach/gpio.h>
 21 #include <plat/gpio-cfg.h>
 22 
 23 MODULE_LICENSE("GPL");
 24 MODULE_AUTHOR("bunfly");
 25 
 26 irqreturn_t do_irq(int irq, void *data);
 27 unsigned long wdt_virt;
 28 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
 29 struct clk *k;
 30 
 31 void my_work_func(unsigned long data) ;
 32 struct work_struct  my_work;
 33 //1.定义工作队列
 34 
 35 int test_init()
 36 {
 37     int ret = 0;
 38     ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "bunflydog", 0x1111);
 39     if(ret < 0){
 40         printk("request_irq
");
 41         return 1;
 42     }
 43 
 44     k = clk_get(NULL, "watchdog");
 45     clk_enable(k);
 46 
 47     wdt_virt = ioremap(0x10060000, SZ_4K);
 48     wtcon = wdt_virt + 0x00;
 49     wtdat = wdt_virt + 0x04;
 50     wtcnt = wdt_virt + 0x08;
 51     wtclrint = wdt_virt + 0x0c;
 52 
 53     *wtcon = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (50 << 8);
 54     *wtdat = 0x8000;
 55     *wtcnt = 0x8000;
 56 
 57     INIT_WORK(&my_work, my_work_func);
 58     //2初始化工作队列
 59     return 0;
 60 }
 61 
 62 void test_exit()
 63 {
 64     printk("exit
");
 65 }
 66 
 67 module_init(test_init);
 68 module_exit(test_exit);
 69 
 70 void my_work_func(unsigned long data)
 71 {
 72     if (in_interrupt()) {
 73         printk("KERNEL: my_work_func in interrupt context.
");
 74     }
 75 
 76     printk("wang wang wang
");
 77 
 78     msleep(1);
 79 }
 80 
 81 irqreturn_t do_irq(int irq, void *data)
 82 {
 83     if (in_interrupt()) {
 84         printk("KERNEL: do_irq in interrupt context.
");
 85     }
 86     schedule_work(&my_work);
 87     //3.将工作队列假如调度策略
 88     *wtclrint = 250;
 89     return IRQ_HANDLED;
 90 }
 91 

        

    

原文地址:https://www.cnblogs.com/hongzhunzhun/p/4531512.html