zoukankan      html  css  js  c++  java
  • 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 

            

        

  • 相关阅读:
    19牛客暑期多校 round2 H 01矩阵内第二大矩形
    NOIP2017滚粗记
    Left 4 Dead 2(求生之路2) 游戏打不开 游戏闪退 的一种可能性以及解决方法
    Luogu P1156 垃圾陷阱
    Luogu P1376 机器工厂
    Luogu P1842 奶牛玩杂技
    Luogu P1880 石子合并
    Luogu P1441 砝码称重(fj省选)
    Luogu P1077 摆花
    Luogu P1282 多米诺骨牌
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4531512.html
Copyright © 2011-2022 走看看