1.工作队列概念:
a) 任务推后执行
b) 被推后的任务由“内核线程”执行
c) 允许重新调度和睡眠
d) 这些被推后的工作组成一个双向链表,既称为工作队列
2.运行机制
注释:
1.每个CPU都有独立的工作队列
2.每个工作队列形成一个双向链表
3.执行时由内核的一个线程去处理,执行的时机不确定;只有在线程觉得CPU有能 力处理时才去去工作队列的内容去执行
3.工作队列的相关结构
struct work_struct {
atomic_long_t data; /*原子类型数据*/
struct list_head entry; /*链表入口*/
work_func_t func; /*工作函数*/
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
struct workqueue_struct;/*好多成员*/
4.工作队列实现过程和相关函数:
法一:交给内核创建默认工作队列
a) 定义工作队列
struct work_struct xx_wq;
b) 定义工作函数
static work_func_t work_fun(unsingend int xxx)
c) 初始化工作队列,将工作队列与处理函数绑定
INIT_WORK(&xx_wq, work_fun);
d) 提交工作到默认队列;既工作的创建由内核自行处理
schedule_work(&xx_wq);
法二:手工创建工作队列
e) 定义工作队列
struct work_struct work; /*定义工作*/
workqueue_struct* wq; /*定义的队列*/
f) 定义工作函数
static work_func_t work_fun(unsingend int xxx)
g) 创建名字为 “mywork” 的工作队列
wq = create_workqueue(“mywork”);
h) 初始化工作队列
INIT_WORK(&xx_wq, work_fun);
i) 提交工作队列
int queue_work(wq, $work);
5.工作队列在中断分层技术的应用
/*1.定义结构体*/
struct work_struct xx_wq;
/*2.编写底半部函数,既工作函数*/
void xxx_do_work(unsigned long x)
{
...
}
/*4.中断处理顶半部*/
static irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
...
/*提交工作 并启动调度*/
schedule_work(&xx_wq);
...
}
/*5.模块加载*/
module_init(xxxx)
{
.....
/*申请中断*/
/*初始化工作队列,将工作队列与处理函数绑定,这个可以在open 函数初始化*/
INIT_WORK(&xx_wq,xxx_do_work);
......
}
/*6.模块卸载*/
module_exit(yyyy)
{
/*释放中断*/
}
/******************************************
author : hntea
date: 2016/3/14
function : key interrupt work test
******************************************/
#include<linux/module.h>
#include<linux/init.h>
#include<linux/miscdevice.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/io.h>
#include<linux/interrupt.h>
#define DEV_MINIR 11 /*自己随便取咯*/
#define DEV_NAME "key" /*自己随便取咯,该设备名会在 /dev目录下生成相应的设备文件*/
#define KEY_GPH0CON 0xE0200C00 /*key_1 /key_2 EXIT0/1*/
/*定义 work */
struct work_struct work1;
/******************************************
函数名: key_hardinit
函数功能:硬件初始化
******************************************/
void key_hardinit(void)
{
unsigned int *key_ioconfig = 0;
unsigned int *irq_mask = 0;
unsigned int *irq_enable = 0;
unsigned int temdata = 0;
/*GPIO初始化 32位寄存器*/
key_ioconfig = ioremap(KEY_GPH0CON,4); /*按键1和2设置成外部中断*/
temdata = ioread32(key_ioconfig);
temdata &= (~0xff);
temdata |= 0xff;
iowrite32(temdata,key_ioconfig);
/*中断控制初始化*/
}
/******************************************
中断底半部用工作队列实现
******************************************/
/*定义服务函数,任务提交后只执行一次*/
static void my_work1(struct work_struct *work)
{
printk("I am work1\n");
printk("I am work1,extern interrupt rase!\n");
}
/******************************************
函数名: key_interrupt
函数功能:中断服务函数入口
******************************************/
static irqreturn_t key_interrupt (int irq, void *dev_id)
{
/*1、顶部,硬件操作*/
/*2、底部,交个工作队列来处理*/
schedule_work(&work1);
return 0;
}
/******************************************
函数名: key_open
函数功能:文件操作
******************************************/
int key_open(struct inode *inode, struct file *filp)
{
key_hardinit();
return 0;
}
/******************************************
函数名:
函数功能:文件操作
******************************************/
struct file_operations key_fop =
{
.open = key_open,
};
struct miscdevice key=
{
.minor = DEV_MINIR ,
.name = DEV_NAME,
.fops = &key_fop,
};
static int keyInit(void)
{
int ret = 0;
/*1、注册设备文件*/
ret = misc_register(&key);
/*2、注册中断号,IRQF_TRIGGER_FALLING中断号在
: linux/arch/arm/mach-s5pv210/include/mach/irqs.h文件中有定义*/
ret = request_irq(IRQ_EINT0,key_interrupt,IRQF_TRIGGER_FALLING, DEV_NAME, 0);
/*3.初始化工作*/
INIT_WORK(&work1,my_work1);
printk("ret val is:%d\n",ret);
if(ret < 0)
{
printk("EXINT0 request fail!\n");
}else{
printk("EXINT0 request sucess!\n");
}
return 0;
}
static void keyExit(void)
{
int ret = 0;
/*注销中断*/
free_irq(IRQ_EINT0, 0);
/*注销混杂设备*/
ret = misc_deregister(&key);
/*注销设备*/
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hntea");
module_init(keyInit);
module_exit(keyExit);