【摘要】 在工作隊列里,我們把推后執(zhí)行的任務(wù)叫做工作(work),描述它的數(shù)據(jù)結(jié)構(gòu)為work_struct,這些工作以隊列結(jié)構(gòu)組織成工作隊列(workqueue),其數(shù)據(jù)結(jié)構(gòu)為workqueue_struct,而工作線程就是負責(zé)執(zhí)行工作隊列中的工作。系統(tǒng)有默認的工作者線程,自己也可以創(chuàng)建自己的工作者線程。
1. 內(nèi)核工作隊列
工作隊列常見的使用形式是配合中斷使用,在中斷的服務(wù)函數(shù)里無法調(diào)用會導(dǎo)致休眠的相關(guān)函數(shù)代碼,有了工作隊列機制以后,可以將需要執(zhí)行的邏輯代碼放在工作隊列里執(zhí)行,只需要在中斷服務(wù)函數(shù)里觸發(fā)即可,工作隊列是允許被重新調(diào)度、睡眠。
在工作隊列里,我們把推后執(zhí)行的任務(wù)叫做工作(work),描述它的數(shù)據(jù)結(jié)構(gòu)為work_struct,這些工作以隊列結(jié)構(gòu)組織成工作隊列(workqueue),其數(shù)據(jù)結(jié)構(gòu)為workqueue_struct,而工作線程就是負責(zé)執(zhí)行工作隊列中的工作。系統(tǒng)有默認的工作者線程,自己也可以創(chuàng)建自己的工作者線程。
2. 相關(guān)函數(shù)、結(jié)構(gòu)介紹
2.1 工作結(jié)構(gòu)
定義文件:
Workqueue.h (linux-3.5\include\Linux)
原型:
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func; /* 工作函數(shù)指針 */
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
在工作結(jié)構(gòu)體里,只需要關(guān)心一個成員函數(shù):work_func_t func;
這個成員函數(shù)是一個函數(shù)指針,指向工作函數(shù)的指針;內(nèi)核使用這個結(jié)構(gòu)來描述一個工作,一個工作簡單理解就是對應(yīng)于一個函數(shù),可以通過內(nèi)核調(diào)度函數(shù)來調(diào)用work_struct中func指針?biāo)赶虻暮瘮?shù)。
2.2 工作函數(shù)介紹
定義文件 Workqueue.h (linux-3.5\include\linux)
函數(shù)原型 typedef void (*work_func_t)(struct work_struct *work);
功能 這是指向工作函數(shù)地址的函數(shù)指針,編寫一個工作的函數(shù)。
參數(shù) struct work_struct *work,這個參數(shù),指向struct work_struct結(jié)構(gòu)變量本身。
示例:
struct work_struct work;
INIT_WORK(&work, work_func);
初始化一個work結(jié)構(gòu),work_func工作函數(shù)的參數(shù)就是指向work結(jié)構(gòu)。
2.3 初始化宏
1)初始化一個work結(jié)構(gòu):
INIT_WORK(_work, _func)
_work: struct work_struct work結(jié)構(gòu)指針。
_func:用來填充work_struct work結(jié)構(gòu)的fun成員,就是工作函數(shù)指針。
2)共享工作隊列調(diào)度宏:
schedule_work(_work)
它也是一個宏,作用是調(diào)度一個工作_work。
_work:要調(diào)度工作的結(jié)構(gòu)指針;
示例:
schedule_work(&work)
2.4 使用共享工作隊列的步驟
1)定義一個工作結(jié)構(gòu)變量
struct work_struct work;
2)初始化工作結(jié)構(gòu)(重點func成員)。
先編寫一個工作函數(shù):
void work_func(struct work_struct * dat)
{
printk(“%p:”,dat);
……
}
初始化work:
INIT_WORK(&work, work_func);
3)在適當(dāng)?shù)牡胤秸{(diào)度工作
如果工作用于中斷底部代碼,則在中斷頂部調(diào)度。
schedule_work(&work);
不是馬上執(zhí)行,而是等待CPU空閑才執(zhí)行work_func。
3. 案例代碼
3.1 共享工作隊列-按鍵驅(qū)動
下面這份代碼是在一個按鍵驅(qū)動代碼,在按鍵中斷服務(wù)函數(shù)里調(diào)度共享隊列,最終在工作函數(shù)里完成按鍵值的檢測打印。工作隊列采用的是共享工作隊列。
#include
#include
#include
#include
#include
#include
#include
#include
#include
static struct work_struct work;
static struct m_key_info *key_info_p=NULL;
/*存放按鍵的信息*/
struct m_key_info
{
int gpio;
char name[50];
int val;
int irq;
};
struct m_key_info key_info[]=
{
{EXYNOS4_GPX3(2),"key_irq_1",0x01},
{EXYNOS4_GPX3(3),"key_irq_2",0x02},
{EXYNOS4_GPX3(4),"key_irq_3",0x03},
{EXYNOS4_GPX3(5),"key_irq_4",0x04},
};
/*
工作函數(shù)
*/
static void key_work_func(struct work_struct *work)
{
msleep(50);
//udelay(n);
//mdelay(n);
//msleep(unsigned int msecs);
if(gpio_get_value(key_info_p->gpio)==0) //判斷按鍵是否按下
{
printk("按鍵值:%#x\n",key_info_p->val);
}
else
{
printk("按鍵值:%#x\n",key_info_p->val|0x80);
}
}
/*
中斷服務(wù)函數(shù)
*/
static irqreturn_t key_irq_handler(int irq, void *dev)
{
key_info_p=(struct m_key_info*)dev;
/*調(diào)度工作----工作結(jié)構(gòu)體添加到系統(tǒng)共享工作隊列里*/
schedule_work(&work);
return IRQ_HANDLED;
}
static int __init tiny4412_interrupt_drv_init(void)
{
/*初始化工作*/
INIT_WORK(&work,key_work_func);
int i;
for(i=0;i
3.2 自定義工作隊列-按鍵驅(qū)動
工作隊列除了可以使用內(nèi)核共享隊列以外,也可以自己創(chuàng)建隊列,下面這份代碼就演示如何自己創(chuàng)建隊列,并完成初始化、調(diào)用。代碼原型還是一份按鍵驅(qū)動代碼,與上面代碼相比,加了字符設(shè)備節(jié)點注冊,替換系統(tǒng)共享工作隊列為自定義的工作隊列。
#include
#include
#include /*雜項設(shè)備相關(guān)結(jié)構(gòu)體*/
#include /*文件操作集合頭文件*/
#include /*使用copy_to_user和copy_from_user*/
#include /*使用IO端口映射*/
#include
#include /*設(shè)備*/
#include /*標(biāo)準字符設(shè)備--分配設(shè)備號*/
#include /*ioctl操作*/
#include /*注冊中斷相關(guān)*/
#include /*中斷邊沿類型定義*/
#include /*中斷IO口定義*/
#include /*內(nèi)核定時器相關(guān)*/
#include /*等待隊列相關(guān)*/
#include /*等待隊列相關(guān)*/
#include /*POLL機制相關(guān)*/
#include /*自旋鎖相關(guān)*/
#include /*自旋鎖相關(guān)*/
#include /*原子操作相關(guān)*/
#include /*原子操作相關(guān)*/
#include /*延時函數(shù)*/
#include
#include /*信號相關(guān)頭文件*/
#include /*工作隊列相關(guān)*/
/*----------------------------------------------------
創(chuàng)建自己的工作隊列creator_workqueue測試
-----------------------------------------------------*/
/*定義ioctl的命令*/
#define Cmd_LEDON _IO('L',1) //無方向 --開燈
#define Cmd_LEDOFF _IO('L',0) //無方向 ---關(guān)燈
/*定義設(shè)備號注冊相關(guān)*/
static dev_t keydev; //存放設(shè)備號
static struct cdev *keyCdev; //定義cdev結(jié)構(gòu)體指針
static struct class *cls; //定義類結(jié)構(gòu)體指針
/*定義按鍵中斷相關(guān)*/
static unsigned int irq_buff[4]; /*存放中斷編號*/
static int key_value=0; /*存放按鍵按下的鍵值*/
/*定時器相關(guān)*/
struct timer_list my_timer;
/*全局標(biāo)志*/
static int poll_flag=0;
struct mutex ; /* 互斥鎖 */
/*等待隊列相關(guān)*/
static DECLARE_WAIT_QUEUE_HEAD(wait);/*初始化等待隊列頭*/
static int condition=0; /*喚醒隊列的條件-為假休眠-為真喚醒*/
/*異步通知助手相關(guān)*/
static struct fasync_struct *myfasync;
/*信號量*/
static DEFINE_SEMAPHORE(name_sem);
/*內(nèi)核工作隊列相關(guān)結(jié)構(gòu)體*/
static struct work_struct my_work;
/*延時工作隊列相關(guān)結(jié)構(gòu)體*/
static struct delayed_work my_delay_work;
/*創(chuàng)建自己的工作隊列相關(guān)*/
struct workqueue_struct *my_work_queue;
struct Buttons_data
{
char key_name[10]; /*按鍵的名字*/
char key; /*按鍵值*/
int GPIO; /*GPIO口編號*/
};
/*工作隊列的處理函數(shù)*/
static void my_work_func(struct work_struct *work)
{
static int count=0;
printk("\n\n用戶創(chuàng)建的系統(tǒng)共享工作隊列調(diào)度成功%d 次\n\n",count++);
}
/*結(jié)構(gòu)體整體賦值*/
static struct Buttons_data Key_interrupt[4]=
{
{"key1",0x01,EXYNOS4_GPX3(2)},
{"key2",0x02,EXYNOS4_GPX3(3)},
{"key3",0x03,EXYNOS4_GPX3(4)},
{"key4",0x04,EXYNOS4_GPX3(5)},
};
/*按鍵中斷服務(wù)函數(shù)*/
static irqreturn_t irq_handler_function(int irq,void * dat)
{
struct Buttons_data *p =(struct Buttons_data *)dat; /*強制轉(zhuǎn)換*/
if(!gpio_get_value(p->GPIO))
{
key_value=p->key; /*獲取按下按鍵值*/
}
else
{
key_value=p->key|0x80; /*獲取松開按鍵值*/
}
mod_timer(&my_timer,jiffies+1); /*修改超時時間*/
return IRQ_HANDLED;
}
/*定時器中斷服務(wù)函數(shù)*/
static void timer_function(unsigned long data)
{
printk("按鍵值讀取成功!!0x%x--->!\n",key_value);
/*添加延時工作到系統(tǒng)工作隊列中等待執(zhí)行*/
// schedule_delayed_work(&my_delay_work,HZ*5);
//queue_work(my_work_queue,&my_work); /*調(diào)度共享工作隊列*/
queue_delayed_work_on(-1,my_work_queue,&my_delay_work,HZ*5);
}
static int key_open(struct inode *my_inode, struct file *my_file)
{
unsigned char i;
for(i=0;i<4;i++)
{
//獲取中斷編號
irq_buff[i]=gpio_to_irq(EXYNOS4_GPX3(2+i));
request_irq(irq_buff[i],irq_handler_function,IRQ_TYPE_EDGE_BOTH,Key_interrupt[i].key_name,&Key_interrupt[i]);
}
/*定時器相關(guān)*/
my_timer.expires=0;/*1秒鐘*/
my_timer.function=timer_function;/*定時器中斷處理函數(shù)*/
my_timer.data=888; /*傳遞給定時器中斷服務(wù)函數(shù)的參數(shù)-用于共享定時器*/
init_timer(&my_timer); /*初始化定時器*/
add_timer(&my_timer); /*啟動定時器*/
printk("open ok !\n");
return 0;
}
static ssize_t key_read(struct file *my_file, char __user *buf, size_t my_conut, loff_t * my_loff)
{
int error=0;
error=copy_to_user(buf,&key_value,my_conut); /*向應(yīng)用層拷貝按鍵值*/
key_value=0;
if(!error)
{
return 0; /*沒有讀取成功*/
}
else
{
return my_conut; /*返回成功讀取的字節(jié)數(shù)*/
}
}
static ssize_t key_write(struct file *my_file, const char __user *buf, size_t my_conut, loff_t *my_loff)
{
int error;
printk("write ok !\n");
return 1;
}
static long key_unlocked_ioctl(struct file *my_file, unsigned int cmd, unsigned long argv)
{
int dat;
/*只有傳遞地址的時候才需要轉(zhuǎn)換-----*/
void __user *argv1=(void __user*)argv; //強制轉(zhuǎn)換地址
printk("argv1=%ld\n",*(unsigned long*)argv1); //取出數(shù)據(jù)
argv=(unsigned long*)argv; /*轉(zhuǎn)為指針形式*/
switch(cmd)
{
case Cmd_LEDON:
dat=100;
copy_to_user(argv,&dat,4);
printk("LEDON_----->OK\n");
break;
case Cmd_LEDOFF:
dat=200;
copy_to_user(argv,&dat,4);
printk("LEDOFF_----->OK\n");
break;
}
return 0;
}
/*poll--*/
unsigned int my_poll(struct file *my_file, struct poll_table_struct * p)
{
/*喚醒休眠的進程*/
poll_wait(my_file,&wait,p);/*添加等待隊列--不是立即休眠*/
printk("<1>""8888\n");
if(condition==1)
{
printk("drive----poll ----ok!\n");
condition=0; /*清除標(biāo)志*/
return POLLIN; /*返回事件*/
}
return 0; /*返回事件*/
}
/*異步通知助手*/
int key_fasync(int fd, struct file *my_file,int on) //異步通知
{
int error;
printk("驅(qū)動層收到的文件描述符:%d\n",fd);
error=fasync_helper(fd,my_file,on,&myfasync);
printk("驅(qū)動層異步通知結(jié)構(gòu)體文件描述符:%d\n",myfasync->fa_fd);
return error;
}
static int key_release(struct inode *my_inode, struct file *my_file)
{
int i;
//釋放中斷
for(i=0;i<4;i++)
{
free_irq(irq_buff[i],&Key_interrupt[i]);
}
return 0;
}
/*定義一個文件操作集合結(jié)構(gòu)體*/
static struct file_operations ops_key={
.owner = THIS_MODULE,
.read=key_read, /*讀函數(shù)-被應(yīng)用層read函數(shù)調(diào)用*/
.write=key_write, /*寫函數(shù)-被應(yīng)用層write函數(shù)調(diào)用*/
.open=key_open, /*打開函數(shù)-被應(yīng)用層open函數(shù)調(diào)用*/
.release=key_release, /*釋放函數(shù)*/
.unlocked_ioctl=key_unlocked_ioctl, /*ioctl操作*/
.poll=my_poll, /*poll機制*/
.fasync=key_fasync, /*異步通知助手*/
};
static int __init key_init1(void)
{
/*動態(tài)分配一個設(shè)備號*/
alloc_chrdev_region(&keydev,0,1,"mykey"); //我們可以讀取/proc/devices文件以獲得Linux內(nèi)核分配給設(shè)備的主設(shè)備號和設(shè)備名字
/*動態(tài)分配cdev結(jié)構(gòu)體,返個cdev結(jié)構(gòu);如果執(zhí)行失敗,將返回NULL。*/
keyCdev = cdev_alloc();
/*初始化Cdev結(jié)構(gòu)體*/
cdev_init(keyCdev,&ops_key);
/*注冊Cdev結(jié)構(gòu)體*/
cdev_add(keyCdev,keydev,1);
/*創(chuàng)建類*/
cls=class_create(THIS_MODULE,"my_key");
/*在類下面創(chuàng)建設(shè)備*/
device_create(cls,NULL,keydev,NULL,"my_delaywork");// /dev/
/*創(chuàng)建自己的工作隊列*/
my_work_queue =create_workqueue("my_workqueue");
/*初始化延時工作隊列*/
INIT_DELAYED_WORK(&my_delay_work,my_work_func);
/*初始化無延時的工作隊列*/
// INIT_WORK(&my_work,my_work_func);
printk("<1>""key drive init OK!!-->__FILE__=%s __LINE__=%d\n",__FILE__,__LINE__);
return 0;
}
//KERN_EMERG
static void __exit key_exit(void)
{
device_destroy(cls,keydev); //注銷設(shè)備節(jié)點
class_destroy(cls); //注銷分配的類
cdev_del(keyCdev); //注銷CDEV結(jié)構(gòu)體
unregister_chrdev_region(keydev,1); //注銷設(shè)備
kfree(keyCdev); //釋放結(jié)構(gòu)體
printk("<1>""key drive exit OK!! -->__FILE__=%s __LINE__=%d\n",__FILE__,__LINE__);
}
//EXPORT_SYMBOL(key_init);
module_init(key_init1); /*驅(qū)動入口*/
module_exit(key_exit); /*驅(qū)動出口*/
MODULE_LICENSE("GPL");
(key_info)>(key_info)/sizeof(key_info[0]);i++)> -
嵌入式
+關(guān)注
關(guān)注
5087文章
19152瀏覽量
306391 -
內(nèi)核
+關(guān)注
關(guān)注
3文章
1378瀏覽量
40338 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4341瀏覽量
62796
發(fā)布評論請先 登錄
相關(guān)推薦
評論