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+, "up"},
{IRQ_GPIO_B_START+, "down"},
{IRQ_GPIO_B_START+, "left"},
{IRQ_GPIO_B_START+, "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 ...\n",__func__);
printk("<1>" "mydata=%#x\n", *pdata);
(*pdata)++;
msleep();
}
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 ...\n",__func__);
printk("<1>" "%s key is pressed!\n", pdata->name); /*登记底半部*/
printk("<1>" "register bottom half\n");
tasklet_schedule(&btn_tasklet);
printk("<1>" "exit from top half\n");
return IRQ_HANDLED;
}
int __init btn_drv_init(void)
{
/*2 初始化变量*/
//tasklet_init(&btn_tasklet, btn_tasklet_func,
// (unsigned long)(&mydata));
int ret = ;
int i =;
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!\n");
while(i)
{
i--;
free_irq(buttons[i].irq, buttons+i);
}
return ret;
}
}
return ;
}
void __exit btn_drv_exit(void)
{
int i = ;
for(i=; 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+, "up"},
{IRQ_GPIO_B_START+, "down"},
{IRQ_GPIO_B_START+, "left"},
{IRQ_GPIO_B_START+, "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 ...\n",__func__);
printk("<1>" "%s key is pressed!\n", pdata->name); /*登记底半部*/
printk("<1>" "register bottom half\n");
schedule_work(&btn_work);
printk("<1>" "exit from top half\n");
return IRQ_HANDLED;
}
void btn_work_func(struct work_struct *work)
{
printk("<1>" "enter %s: do no emergent things....\n", __func__);
}
int __init btn_drv_init(void)
{
int ret = ;
int i =;
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!\n");
while(i)
{
i--;
free_irq(buttons[i].irq, buttons+i);
}
return ret;
}
}
/*2 初始化work变量*/
INIT_WORK(&btn_work, btn_work_func);
return ;
}
void __exit btn_drv_exit(void)
{
int i = ;
for(i=; 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+, "up"},
{IRQ_GPIO_B_START+, "down"},
{IRQ_GPIO_B_START+, "left"},
{IRQ_GPIO_B_START+, "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 ...\n",__func__);
printk("<1>" "%s key is pressed!\n", pdata->name); /*登记底半部*/
printk("<1>" "register bottom half\n");
//schedule_work(&btn_work);
schedule_delayed_work(&btn_dwork, *HZ);
printk("<1>" "exit from top half\n");
return IRQ_HANDLED;
}
void btn_work_func(struct work_struct *work)
{
printk("<1>" "enter %s: do no emergent things....\n", __func__);
msleep();
}
void btn_dwork_func(struct work_struct *work)
{
printk("<1>" "enter %s: do no emergent things....\n", __func__);
}
int __init btn_drv_init(void)
{
int ret = ;
int i =;
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!\n");
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 ;
}
void __exit btn_drv_exit(void)
{
int i = ;
for(i=; 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+*HZ);
}
int __init led_drv_init(void)
{
/*申请GPIO管脚*/
gpio_request(LED1, "led1");
/*使用管脚*/
gpio_direction_output(LED1, );
/*初始化定时器*/
init_timer(&led_timer);
led_timer.function = led_timer_func;
led_timer.expires = jiffies + *HZ;
/*要设置为的管脚电平状态*/
led_timer.data = ;
/*启动定时器*/
add_timer(&led_timer);
//mod_timer(&led_timer, led_timer.expires);
return ;
}
void __exit led_drv_exit(void)
{
gpio_free(LED1);
}
module_init(led_drv_init);
module_exit(led_drv_exit);

底半部之工作队列和tasklet,内核定时器。的更多相关文章

  1. 裸板中中断异常处理,linux中断异常处理 ,linux系统中断处理的API,中断处理函数的要求,内核中登记底半部的方式

    1.linux系统中的中断处理  1.0裸板中中断异常是如何处理的?     以s5p6818+按键为例          1)按键中断的触发        中断源级配置            管脚功 ...

  2. linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】

    转自:http://blog.chinaunix.net/uid-20768928-id-5077401.html 在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方 ...

  3. Linux内核中断顶半部和底半部的理解

    文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...

  4. Linux设备驱动程序:中断处理之顶半部和底半部

    http://blog.csdn.net/yuesichiu/article/details/8286469 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可 ...

  5. linux中断处理-顶半部(top half)和底半部(bottom half) -转

    原文:http://rensanshi.blog.163.com/blog/static/21395510820136282224877/ 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率 ...

  6. linux底半部机制在视频采集驱动中的应用

    最近在做一个arm+linux平台的视频驱动.本来这个驱动应该是做板子的第三方提供的,结果对方软件实力很差,自己做不了这个东西,外包给了一个暑期兼职的在读博士.学生嘛,只做过实验,没做过产品,给出的东 ...

  7. Linux驱动技术(七) _内核定时器与延迟工作

    内核定时器 软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行.实际上,时钟中断处理程 ...

  8. Linux中断底半部机制

    参考: Linux下半部处理之软中断 linux中断底半部机制 <深入理解Linux内核>软中断/tasklet/工作队列 软中断和tasklet介绍 详解操作系统中断 Linux内核:中 ...

  9. 内核定时器timer_list

    内核在时钟中断发生后执行检测各个定时器是否到期,到期后的定时器处理函数将作为软中断在底半部执行.实质上,时钟中断处理程序会唤起TIMER_SOFTIRQ软中断,运行当前处理器上到期的所有定时器.lin ...

随机推荐

  1. Java线程状态和关闭线程的正确姿势

    1.线程状态及切换 Java中的线程有六种状态,使用线程Thread内的枚举类来实现,如下,我对每个状态都进行了一定的解释. public enum State { /** 表示一个线程还没启用(即未 ...

  2. navicat for mysql ;连接数据库报错1251,解决办法。

    转载 改密码方式:用管理员身份打开cmd mysql -uroot -p(输入密码)            进入mysql执行下面三个命令 use mysql: ALTER USER 'root'@' ...

  3. Orecle基本概述(1)

    Orecle1.什么是orecle及体系结构?* 全局数据库,指物理磁盘数据库,一个真实存在的磁盘目录.*用户: 用户在oracle里面是用来隔离数据的*表空间: 逻辑结构,不可视的,虚拟的,用户的数 ...

  4. 从.NET CORE2.2升级到3.0过程及遇到的一些问题

    RoadFlow工作流引擎从.NET Core2.2升级到3.0遇到了一些问题及解决方式这里记录一下. 1.DLL项目框架从2.2选择到3.0,这个没什么好说的,没有问题.重点的WEB层的一些变化. ...

  5. idea 添加 注释 配置

    为类添加自动注释模版 File-->Settings-->Editor-->File and Code Templates 启用该模板才有效一定要勾上 /** * @author : ...

  6. linux下python相关命令

    若本机已安装python2,尽量不要动现有的python2,额外安装python3即可. 1.安装python3.6(centos下安装python3自带pip和setuptools) python3 ...

  7. Solidity语言系列教程

    Solidity 是一门面向合约的.为实现智能合约而创建的高级编程语言.这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在 以太坊虚拟机(EVM) 上运行. ...

  8. java架构之路-(MQ专题)RabbitMQ安装和基本使用

    RabbitMQ安装 我这里安装是使用阿里云的CentOS7.5来安装的,使用CentOS版本低于7的可能会报错. 1.安装rabbitmq所需要的依赖包 输入$ yum install build- ...

  9. 百万年薪python之路 -- MySQL数据库之 存储引擎

    MySQL之存储引擎 一. 存储引擎概述 定义: 存储引擎是mysql数据库独有的存储数据.为数据建立索引.更新数据.查询数据等技术的实现方法 ​ 首先声明一点: 存储引擎这个概念只有MySQL才有. ...

  10. (day27)subprocess模块+粘包问题+struct模块+ UDP协议+socketserver

    目录 昨日回顾 软件开发架构 C/S架构 B/S架构 网络编程 互联网协议 socket套接字 今日内容 一.subprocess模块 二.粘包问题 三.struct模块 四.UDP 五.QQ聊天室 ...