免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1248 | 回复: 0
打印 上一主题 下一主题

linux驱动模块--工作队列分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-24 14:25 |只看该作者 |倒序浏览

工作队列(work queue)是另外一种将工作推后执行的形式 ,它和我们前面讨论的所有其他形式都有不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。
那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就选择tasklet。另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,它都会非常有用。如果不需要用一个内核线程来推后执行工作,那么就考虑使用tasklet。

1.      工作、工作队列和工作者线程
如前所述,我们把推后执行的任务叫做工作(work),描述它的数据结构为work_struct,这些工作以队列结构组织成工作队列(workqueue),其数据结构为workqueue_struct,而工作线程就是负责执行工作队列中的工作。系统默认的工作者线程为events,自己也可以创建自己的工作者线程。
2.      表示工作的数据结构
   工作用中定义的work_struct结构表示:
struct  work_struct{
    unsigned long pending;          /* 这个工作正在等待处理吗?*/
    struct list_head entry;         /* 连接所有工作的链表 */  
    void (*func) (void *);          /* 要执行的函数 */
    void *data;                     /* 传递给函数的参数 */
    void *wq_data;                  /* 内部使用 */
    struct timer_list timer;        /* 延迟的工作队列所用到的定时器 */
};
这些结构被连接成链表。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作被执行完毕,它就将相应的work_struct对象从链表上移去。当链表上不再有对象的时候,它就会继续休眠。
3. 创建推后的工作
要使用工作队列,首先要做的是创建一些需要推后完成的工作。可以通过DECLARE_WORK在编译时静态地建该结构:
DECLARE_WORK(name, void (*func) (void *), void *data);
这样就会静态地创建一个名为name,待执行函数为func,参数为data的work_struct结构。
同样,也可以在运行时通过指针创建一个工作:
INIT_WORK(struct work_struct *work, woid(*func) (void *), void *data);
这会动态地初始化一个由work指向的工作。
4. 工作队列中待执行的函数
工作队列待执行的函数原型是:
void work_handler(void *data)
这个函数会由一个工作者线程执行,因此,函数会运行在进程上下文中。默认情况下,允许响应中断,并且不持有任何锁。如果需要,函数可以睡眠。需要注意的是,尽管该函数运行在进程上下文中,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射。通常在系统调用发生时,内核会代表用户空间的进程运行,此时它才能访问用户空间,也只有在此时它才会映射用户空间的内存。
5. 对工作进行调度
现在工作已经被创建,我们可以调度它了。想要把给定工作的待处理函数提交给缺省的events工作线程,只需调用
schedule_work(&work);
work马上就会被调度,一旦其所在的处理器上的工作者线程被唤醒,它就会被执行。
有时候并不希望工作马上就被执行,而是希望它经过一段延迟以后再执行。在这种情况下,可以调度它在指定的时间执行:
schedule_delayed_work(&work, delay);
这时,&work指向的work_struct直到delay指定的时钟节拍用完以后才会执行。
6. 工作队列的简单应用
#include linux/module.h>
#include linux/init.h>
#include linux/workqueue.h>
static struct workqueue_struct *queue = NULL;
static struct work_struct work;
static void work_handler(struct work_struct *data)
{
        printk(KERN_ALERT “work handler function.\n”);
}
static int __init test_init(void)
{
        queue = create_singlethread_workqueue(“helloworld”); /*创建一个单线程的工作队列*/
        if (!queue)
                goto err;
        INIT_WORK(&work, work_handler);
        schedule_work(&work);
        return 0;
err:
        return -1;
}
static void __exit test_exit(void)
{
        destroy_workqueue(queue);
}
MODULE_LICENSE(“GPL”);
module_init(test_init);
module_exit(test_exit);


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/90876/showart_1909592.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP