概念
优先级: 硬件中断->软件中断->内核->用户线程
# 概念
优先级: 硬件中断->软件中断->内核->用户线程
理想中的中断函数应该精简,耗时最短;但现实中的事物偏偏是复杂耗时的。
这样复杂耗时的操作我们想不用中断能不能实现,但我们又无法预知他什么时候到来,所以还是必须用中断。
中庸之道,在上面两种方案中糅合折中,就得出了“上半部分”与“下半部分”的概念。
中断嘛,还是要用滴,只不过现在我们只把他当“引子”,告诉说:“有个这样的中断产生了,'工作队列'你去处理下,我先撤啦!”。这就是“上半部分”
剩余的复杂耗时的工作就在“工作队列”中去做。这就属于“下半部分”
下半部分:
耗时,不太紧急,但又要优先于普通进程的部分
软中断
Tasklet
工作队列
定义:
<include/linux/workqueue.h>
struct work_struct {
atomic_long_t data; //
struct list_head entry; //队头
work_func_t func; //回调函数
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
typedef void (*work_func_t)(struct work_struct *work);
初始化
/*
* 功能:初始化工作队列,将回电函数加到工作队列中
* 输入参数:struct work_struct *work:工作队列
* int onstack: 回调函数指针
* 返回值:none
*/
void __init_work(struct work_struct *work, int onstack);
调度函数
/*
* 功能:调度工作队列,实质并不是去调回调函数,而是标记他为运行态(即唤醒它)。
* 故几篇快速多次按键,任务函数也不一定调很多次,只是在它休眠时调用该调度函数会唤醒他
* 输入参数:struct work_struct *work:工作队列
* 返回值:boll
*/
bool schedule_work(struct work_struct *work)
上半部分
紧急,不耗时的任务,优先级最高的。
硬件中断
# 工程实例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
static int irq;
static int gpio;
static struct work_struct ws;//定义一个工作队列
static irqreturn_t handler_t(int irq, void *dev)//自定义的中断服务函数
{
printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
schedule_work(&ws); //调度,使工作队列中的任务变为可运行态,就是改变一个标志位的事,标志一下马上返回
//,并不是要等工作队列中的任务运行完才返回
return IRQ_HANDLED;
}
void work_func(struct work_struct *work)//自定义的工作队列的回调函数
{
printk(KERN_INFO "%s : %s : %d - entry.\n", __FILE__, __func__, __LINE__);
ssleep(3);
printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);
}
static int __init demo_init(void)
{
struct device_node *np = NULL;
int ret;
printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
INIT_WORK(&ws, work_func);//初始化工作队列,绑定回调函数
np = of_find_node_by_name(NULL, "key");//从设备树中找到key这个设备
if(NULL == np){
return -EINVAL;
}
gpio = of_get_named_gpio(np, "key-intr", 0);//从np这个设备中找出属性名为key-intr的第0项gpio引脚
if(gpio_is_valid(gpio)){
ret = gpio_request_one(gpio, GPIOF_IN, "key-intr");//将引脚复用功能设为外部中断
if(ret){
printk(KERN_INFO "%s : %s : %d - gpio_request_one fail.\n",
__FILE__, __func__, __LINE__);
return ret;
}
irq = gpio_to_irq(gpio);//为gpio引脚申请一个软中断号
if(0 > irq){
printk(KERN_INFO "%s : %s : %d - gpio_to_irq fail.\n",
__FILE__, __func__, __LINE__);
return irq;
}
ret = request_irq(irq, handler_t, IRQF_TRIGGER_RISING, "demo", NULL);//绑定回调函数并将软中断号注册进内核
if(ret){
printk(KERN_INFO "%s : %s : %d - request_irq fail.\n",
__FILE__, __func__, __LINE__);
return ret;
}
}else{
printk(KERN_INFO "%s : %s : %d - of_get_named_gpio fail.\n",
__FILE__, __func__, __LINE__);
return gpio;
}
return 0;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
free_irq(irq, NULL);//释放中断号
gpio_free(gpio);//释放gpio,即引脚复用功能还原
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");