赞
踩
linux实现中断下文的机制主要有4种:
1.软中断 2.tasklet 3.工作队列 4.线程化irq
本文主要介绍中断下文机制中的工作队列,工作队列与tasklet最大的区别就是tasklet不能休眠,工作队列可以休眠,所以tasklet多用来处理比较耗时间的任务,而工作队列可以处理非常复杂并且更耗时间的事情。
**实现原理:**工作队列的实现机制非常复杂,简单的来说就是,Linux系统在启动期间会创建内核线程,该线程创建以后就处于sleep状态,然后这个线程会一直去队列里面读,看看有没有任务,如果有就执行,没有就休眠。
**共享工作队列:**多个不同的程序共用,不需要自己创建,但如果前面的工作比较耗时的话,就会影响到后面的工作。
**自定义工作队列:**共享工作队列无法满足需要时,需要我们自己创建,其系统的开销大,优点是不会受到其他工作的影响。
内核源码路径:/include/linux/workqueue.h 定义了工作队列的结构体。
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
};
#dedfine DECLARE_WORK(n,f);
功能:静态定义并且初始化工作队列。
#define INIT_WORK (_work,_func);
功能:动态定义并且初始化工作队列。
参数介绍:
work:工作队列地址;
func:工作函数;
int schedule_work(struct work_struct *work);
功能:调度工作,把work_struct挂到cpu相关的工作队列链表上,等待工作者线程处理。
参数介绍:
work:工作队列地址。
在此,调度完工作,并不会马上执行,只是加到了共享队列里面去,等轮到时才会执行。
如果多次调用相同的任务,假如上一次的任务还没有完成,那么多次调度相同的任务是无效的。
#include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/of_irq.h> #include <linux/workqueue.h> struct device_node *test_device_node; struct property *test_node_property; struct work_struct key_test; int gpio_num; int irq; //中断上文函数 irq_handler_t test_key(int irq, void *args) { printk("Start!\n"); //唤醒工作队列 schedule_work(&key_test); printk("End!\n"); return IRQ_HANDLED;//接收到了准确的中断信号,并且做了相应正确的处理 } //中断下文函数 void work_queue_test(unsigned long data) { int i = 0; while(i<50){ i++; printk("test_key is %d.\n",i); } } //探针函数,用于设备的初始化 int dts_probe(struct platform_device *pdev) { int ret = 0; printk("dts_probe matching ok!\n"); //test_device_node = of_find_node_by_name(NULL,"test_key");//根据节点名字索引设备树节点 test_device_node = of_find_node_by_path("/test_key");//根据据对路径索引设备树节点 if(test_device_node == NULL){ printk("Failture to find device node %s","test_key"); return -1; } //获取gpio的编号 gpio_num = of_get_named_gpio(test_device_node,"key-gpio",0); if(gpio_num < 0){ printk("Failture to get gpio %s","key-gpio"); return -1; } //设置gpio的方向 gpio_direction_input(gpio_num); //irq = irq_of_parse_and_map(test_device_node,0); irq = gpio_to_irq(gpio_num);//同上一句代码,为gpio申请中断号 printk("irq is %d\n",irq); //申请并注册中断资源 ret = request_irq(irq,test_key,IRQF_TRIGGER_RISINNG,"test_key",NULL); if(ret < 0){ printk("Failed to requst irq\n") return -1; } //初始化key_test这个工作队列,并且将work_queue_test添加进工作队列 INIT_WORK(&key_test,work_queue_test); return 0; } int dts_remove(struct platform_device *pdev) { printk("dts_remove!\n"); return 0; } //根据设备名字匹配 const struct platform_device_id dts_idtable = { .name = "dts_test1" } //根据compatible匹配 const struct of_device_id of_match_table_test[] = { {.compatible = "led_keys"}, {} } //初始化dts_driver结构体 struct platform_driver dts_driver = { .probe = dts_probe, .remove = dts_remove, .driver = { .ower = THIS_MODULE, .name = "dts_test2", .of_match_table = of_match_table_test }, .id_table = &dts_idtable }; //驱动初始化函数 static int dts_driver_init(void) { int ret = 0; ret = platform_driver_register(&dts_driver); if(ret < 0){ printk("platform driver register error\n"); return ret; } printk("platform driver register of!\n"); return 0; } //驱动卸载函数 static int dts_driver_exit(void) { printk("dts_driver_exit!\n"); free_irq(irq,NULL); platform_driver_unregister(&dts_driver); } //模块加载 module_init(dts_driver_init); //模块卸载 module_exit(dts_driver_exit); /*模块许可证声明,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时, *会收到内核被污染“kernel tainted” 的警告 */ MODULE_LICENSE("GPL");
obj-m += work_queue.o
KDIR:=/linux/linux-4.1.15
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
当系统启动完成之后执行:
insmod work_queue
加载该模块
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。