• 底半部之工作队列和tasklet,内核定时器。


    1、软中断机制
      不能以模块形式出现
      使用起来不够灵活
    2、tasklet
      核心数据结构
          struct tasklet_struct
          {
              function
              data
              ....
          }  
      1)定义tasklet变量
      2)初始化tasklet变量
         DECLARE_TASKLET //定义并初始化tasklet变量
     
      3)使用tasklet变量登记底半部
     
      注意事项:
          tasklet登记的底半部函数也是运行中断上下文中的
          也就意味着在底半部函数中不能调用引起阻塞或者
          睡眠的函数
      如果底半部函数中 必须调用引起阻塞或者睡眠的函数
      可以考虑使用工作队列的方式登记底半部

    3、工作队列
      核心数据结构
         struct work_struct
         {
            //保存底半部函数的地址
            work_func_t func;
            ...
         }
      步骤:
         1)定义work变量
            struct work_struct btn_work;
         2)初始化work变量
            INIT_WORK(&btn_work, btn_work_func)
            
            以上两个步骤可以使用
            DECLARE_WORK(btn_work, btn_work_func)
                
         3)使用work变量登记底半部
            schedule_work(&btn_work);
         4)flush或者cancel
            bool flush_work(struct work_struct *work)
            cancel_work_sync(struct work_struct *work)   
            
       
       tasklet和work登记底半部的对比
         1)通过工作队列去登记底半部
            底半部函数工作于进程上下文中 不受限制
         2)如果同时使用了tasklet和工作队列登记了底半部
            一定是taklet登记的底半部函数最先被执行到          
         详细对比  tasklet_work.png          
     
      如果希望底半部函数登记后隔10s再去执行 实现方式
     
      核心数据结构:
          struct delayed_work {
        struct work_struct work;
        struct timer_list timer;
          };
      使用步骤:
          1)定义delayed_work变量
             struct delayed_work btn_dwork;
          2) 初始化delayed_work变量
             INIT_DELAYED_WORK(&btn_dwork, func)
          3) 使用delayed_work登记底半部
             schedule_delayed_work(&btn_dwork, 延时时间)  
          4)当卸载模块时 对已经登记并未得到执行的
             底半部做处理?
             a)flush 阻塞到指定dwork被执行到才返回
               flush_delayed_work(struct delayed_work *dwork)
             b)cancel 取消约定
               cancel_delayed_work(struct delayed_work *work)
                 
       1)连续两次登记底半部 几次有效?哪次有效?
          
          只有1次有效
          第一次有效
       2)登记底半部后 ,直接卸载模块 内核崩溃 为什么?
         
    4、内核定时器
      软件意义上的定时器
     
      系统时钟中断:CPU会周期性 不停地收到系统时钟中断信号
                    执行系统时钟中断处理函数
                    timer_event_init()
                    {
                       setup_irq(info->irqno, &timer_event_irqaction);
                    }
                    timer_event_irqaction.timer_event_handler()
                    {
                        /*硬件相关的事*/
                        
                        /*硬件无关动作*/
                        tick_periodic()
                        {
                            更新墙上时间
                            jiffies++;
                            给当前正在执行的线程时间片做--操作
                            判断当前线程的时间片是否耗尽
                            一旦耗尽重新做任务调度
                            选出新的线程放入CPU中运行
                        }
                    }
       HZ:决定了1s产生的系统时钟中断的次数
          当前系统中HZ=1000
       tick, 系统时钟滴答
             tick = 1/HZ;
       jiffies, 记录自开机以来产生的系统时钟中断次数      
                unsigned int 类型
                
                例如HZ=1000
                在某个时间点1读取jiffies 为10000
                在某个时间点2读取jiffies 为20000
       
       内核定时器(软件意义上的)
          struct timer_list
          {
              //超时时间
              unsigned long expires;
              //定时时间到后执行的动作
              void (*function)(unsigned long);
              //指定调用function时传递的参数值
              unsigned long data;
              ...
          }
       定时器的使用步骤:
          1)定义一个timer_list变量
             struct timer_list led_timer;
          2) 初始化timer_list变量
             init_timer(&led_timer)
             
             led_timer.function=xxx
             led_timer.expires = xxx
             led_timer.data = xxx
         3) 启动定时器  
            
            void add_timer(struct timer_list *timer)
            
            int mod_timer(struct timer_list *timer, unsigned long expires)
         4) 修改定时器超时时间
            int mod_timer(struct timer_list *timer, unsigned long expires)
         5)取消定时器
            int del_timer(struct timer_list *timer)

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/interrupt.h>
    #include <mach/platform.h>
    #include <linux/delay.h>
    
    typedef struct btn_desc
    {
        int irq;//中断号
        char *name;//名称
    }btn_desc_t;
    
    btn_desc_t buttons[]=
    {
        {IRQ_GPIO_A_START+28, "up"},
        {IRQ_GPIO_B_START+30, "down"},
        {IRQ_GPIO_B_START+31, "left"},
        {IRQ_GPIO_B_START+9,  "right"},
    
    };
    /*1 定义变量*/
    //struct tasklet_struct btn_tasklet;
    
    int mydata = 0x100;
    
    void btn_tasklet_func(unsigned long data)
    {
        int *pdata = (int *)data;
        
        printk("<1>" "enter %s: do no emergent things ...
    ",__func__);
        printk("<1>"  "mydata=%#x
    ", *pdata);
        (*pdata)++;
        msleep(1);
    }
    DECLARE_TASKLET(btn_tasklet, btn_tasklet_func, (unsigned long)&mydata);
    irqreturn_t btn_isr(int irq, void *dev)
    {
        btn_desc_t *pdata = dev;
        printk("<1>" "enter %s: do emergent things ...
    ",__func__);
        printk("<1>" "%s key is pressed!
    ", pdata->name);
    
        /*登记底半部*/
        printk("<1>" "register bottom half
    ");
        tasklet_schedule(&btn_tasklet);
        printk("<1>" "exit from top half
    ");
        return IRQ_HANDLED;
    }
    int __init btn_drv_init(void)
    {
        /*2 初始化变量*/
        //tasklet_init(&btn_tasklet, btn_tasklet_func, 
          //           (unsigned long)(&mydata));
        int ret = 0;
        int i =0;
        for(; i<ARRAY_SIZE(buttons); i++)
        {
            ret = request_irq(buttons[i].irq, btn_isr,
                              IRQF_TRIGGER_FALLING,
                              buttons[i].name, 
                              &(buttons[i]));
            if(ret)
            {
                printk("<1>"  "request_irq failed!
    ");
                while(i)
                {
                    i--;
                    free_irq(buttons[i].irq, buttons+i);
                }
                return ret;
            }
        }
        return 0;
    }
    void __exit btn_drv_exit(void)
    {
        int i = 0;
        for(i=0; i<ARRAY_SIZE(buttons); i++)
        {
            free_irq(buttons[i].irq, buttons+i);
        }
    }
    module_init(btn_drv_init);
    module_exit(btn_drv_exit);
    MODULE_LICENSE("GPL");
    #include <linux/init.h> 
    #include <linux/module.h>

    #include <linux/interrupt.h> #include <mach/platform.h> #include <linux/delay.h> typedef struct btn_desc { int irq;//中断号 char *name;//名称 }btn_desc_t; btn_desc_t buttons[]= { {IRQ_GPIO_A_START+28, "up"}, {IRQ_GPIO_B_START+30, "down"}, {IRQ_GPIO_B_START+31, "left"}, {IRQ_GPIO_B_START+9, "right"}, }; /*1 定义一个work变量*/ struct work_struct btn_work; irqreturn_t btn_isr(int irq, void *dev) { btn_desc_t *pdata = dev; printk("<1>" "enter %s: do emergent things ... ",__func__); printk("<1>" "%s key is pressed! ", pdata->name); /*登记底半部*/ printk("<1>" "register bottom half "); schedule_work(&btn_work); printk("<1>" "exit from top half "); return IRQ_HANDLED; } void btn_work_func(struct work_struct *work) { printk("<1>" "enter %s: do no emergent things.... ", __func__); } int __init btn_drv_init(void) { int ret = 0; int i =0; for(; i<ARRAY_SIZE(buttons); i++) { ret = request_irq(buttons[i].irq, btn_isr, IRQF_TRIGGER_FALLING, buttons[i].name, &(buttons[i])); if(ret) { printk("<1>" "request_irq failed! "); while(i) { i--; free_irq(buttons[i].irq, buttons+i); } return ret; } } /*2 初始化work变量*/ INIT_WORK(&btn_work, btn_work_func); return 0; } void __exit btn_drv_exit(void) { int i = 0; for(i=0; i<ARRAY_SIZE(buttons); i++) { free_irq(buttons[i].irq, buttons+i); } } module_init(btn_drv_init); module_exit(btn_drv_exit);
    MODULE_LICENSE("GPL");
     
    #include "../../global.h"
    
    #include <linux/interrupt.h>
    #include <mach/platform.h>
    #include <linux/delay.h>
    
    typedef struct btn_desc
    {
        int irq;//中断号
        char *name;//名称
    }btn_desc_t;
    
    btn_desc_t buttons[]=
    {
        {IRQ_GPIO_A_START+28, "up"},
        {IRQ_GPIO_B_START+30, "down"},
        {IRQ_GPIO_B_START+31, "left"},
        {IRQ_GPIO_B_START+9,  "right"},
    
    };
    /*1 定义一个work变量*/
    struct work_struct btn_work;
    struct delayed_work btn_dwork;
    
    irqreturn_t btn_isr(int irq, void *dev)
    {
        btn_desc_t *pdata = dev;
        printk("<1>" "enter %s: do emergent things ...
    ",__func__);
        printk("<1>" "%s key is pressed!
    ", pdata->name);
    
        /*登记底半部*/
        printk("<1>" "register bottom half
    ");
        //schedule_work(&btn_work);
        schedule_delayed_work(&btn_dwork, 10*HZ);
        printk("<1>" "exit from top half
    ");
        return IRQ_HANDLED;
    }
    void btn_work_func(struct work_struct *work)
    {
        printk("<1>" "enter %s: do no emergent things....
    ", __func__);
        msleep(1);
    }
    void btn_dwork_func(struct work_struct *work)
    {
        printk("<1>" "enter %s: do no emergent things....
    ", __func__);
    }
    int __init btn_drv_init(void)
    {
        int ret = 0;
        int i =0;
        for(; i<ARRAY_SIZE(buttons); i++)
        {
            ret = request_irq(buttons[i].irq, btn_isr,
                              IRQF_TRIGGER_FALLING,
                              buttons[i].name, 
                              &(buttons[i]));
            if(ret)
            {
                printk("<1>"  "request_irq failed!
    ");
                while(i)
                {
                    i--;
                    free_irq(buttons[i].irq, buttons+i);
                }
                return ret;
            }
        }
        /*2 初始化work变量*/
        INIT_WORK(&btn_work, btn_work_func);
        INIT_DELAYED_WORK(&btn_dwork,btn_dwork_func);
        return 0;
    }
    void __exit btn_drv_exit(void)
    {
        int i = 0;
        for(i=0; i<ARRAY_SIZE(buttons); i++)
        {
            free_irq(buttons[i].irq, buttons+i);
        }
    }
    module_init(btn_drv_init);
    module_exit(btn_drv_exit);
    #include "../../global.h"
    #include <linux/gpio.h>
    #include <mach/platform.h>
    
    #define LED1    (PAD_GPIO_C+12)
    
    /*定义timer变量*/
    struct timer_list led_timer;
    
    void led_timer_func(unsigned long data)
    {
        gpio_set_value(LED1, data);
        
        led_timer.data = !data;
        mod_timer(&led_timer, jiffies+1*HZ);
    }
    int __init led_drv_init(void)
    {
        /*申请GPIO管脚*/
        gpio_request(LED1, "led1");
        /*使用管脚*/
        gpio_direction_output(LED1, 0);
        /*初始化定时器*/
        init_timer(&led_timer);
        led_timer.function = led_timer_func;
        led_timer.expires = jiffies + 1*HZ;
        /*要设置为的管脚电平状态*/
        led_timer.data = 1;
        /*启动定时器*/
        add_timer(&led_timer);
        //mod_timer(&led_timer, led_timer.expires);
        return 0;
    }
    void __exit led_drv_exit(void)
    {
        gpio_free(LED1);
    }
    module_init(led_drv_init);
    module_exit(led_drv_exit);
  • 相关阅读:
    easyui好例子,值得借鉴
    DDL 和DML 区别
    兼容IE的文字提示
    搭代理
    美国服务器
    跟随滚动条滚动
    JS Array对象
    JS 内置对象 String对象
    JS 对象
    JS 二维数组
  • 原文地址:https://www.cnblogs.com/DXGG-Bond/p/11859049.html
Copyright © 2020-2023  润新知