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);