Linux中Workqueue机制分析

636阅读 0评论2012-02-17 378333581
分类:

走入 Linux 的殿堂已经有一年有余了,在这里我想将 Linux 的各种实现机制分析一遍,一方面对自己来说也是温故而知新,另一方面,促进大家的交流,最好能够给大家一些抛砖引玉的启迪。我是硬件出身,搞硬件已经好多年了,从是专门软件开发也接近两年了,在这一段时间内我越发认为软硬件协同设计是未来发展的主流,软硬件的界限越来越模糊,软硬件的设计思想是相通的,实现方法是各异的,实现的结果上当然也存在较大差别,因此,很有必要做好软硬件的协同设计。本着这样的想法,我想将我所认识的 Linux 分析一遍,特别是一些我认为精华和重要的机制,另外在讨论过程中,我会插入一些其他的 OS 实现机制,进行对比分析,我把这一类 blog 文章划归为“ Linux 机制分析”,希望大家支持。

    什么是 workqueue ?

    Linux 中的 Workqueue 机制就是为了简化内核线程的创建。通过调用 workqueue 的接口就能创建内核线程。并且可以根据当前系统 CPU 的个数创建线程的数量,使得线程处理的事务能够并行化。

    workqueue 是内核中实现简单而有效的机制,他显然简化了内核 daemon 的创建,方便了用户的编程,

    Workqueue 机制的实现

    Workqueue 机制中定义了两个重要的数据结构,分析如下:

    1、cpu_workqueue_struct 结构。该结构将 CPU 和内核线程进行了绑定。在创建 workqueue 的过程中, Linux 根据当前系统 CPU 的个数创建 cpu_workqueue_struct 。在该结构主要维护了一个任务队列,以及内核线程需要睡眠的等待队列,另外还维护了一个任务上下文,即 task_struct 。

    2、work_struct 结构是对任务的抽象。在该结构中需要维护具体的任务方法,需要处理的数据,以及任务处理的时间。该结构定义如下:

    struct work_struct {

    unsigned long pending;

    struct list_head entry;                  /* 将任务挂载到 queue 的挂载点 */

    void (*func)(void *);                   /* 任务方法 */

    void *data;                                  /* 任务处理的数据 */

    void *wq_data;                           /* work 的属主 */

    strut timer_list timer;                   /* 任务延时处理定时器 */

    };

    当用户调用 workqueue 的初始化接口 create_workqueue 或者 create_singlethread_workqueue 对 workqueue 队列进行初始化时,内核就开始为用户分配一个 workqueue 对象,并且将其链到一个全局的 workqueue 队列中。然后 Linux 根据当前 CPU 的情况,为 workqueue 对象分配与 CPU 个数相同的 cpu_workqueue_struct 对象,每个 cpu_workqueue_struct 对象都会存在一条任务队列。紧接着, Linux 为每个 cpu_workqueue_struct 对象分配一个内核 thread ,即内核 daemon 去处理每个队列中的任务。至此,用户调用初始化接口将 workqueue 初始化完毕,返回 workqueue 的指针。

    在初始化 workqueue 过程中,内核需要初始化内核线程,注册的内核线程工作比较简单,就是不断的扫描对应 cpu_workqueue_struct 中的任务队列,从中获取一个有效任务,然后执行该任务。所以如果任务队列为空,那么内核 daemon 就在 cpu_workqueue_struct 中的等待队列上睡眠,直到有人唤醒 daemon 去处理任务队列。

    Workqueue 初始化完毕之后,将任务运行的上下文环境构建起来了,但是具体还没有可执行的任务,所以,需要定义具体的 work_struct 对象。然后将 work_struct 加入到任务队列中, Linux 会唤醒 daemon 去处理任务。

    上述描述的 workqueue 内核实现原理可以描述如下:


    在 Workqueue 机制中,提供了一个系统默认的 workqueue 队列—— keventd_wq ,这个队列是 Linux 系统在初始化的时候就创建的。用户可以直接初始化一个 work_struct 对象,然后在该队列中进行调度,使用更加方便。

Workqueue 编程接口

序号

接口函数

说明

1

create_workqueue

用于创建一个 workqueue 队列,为系统中的每个 CPU 都创建一个内核线程。输入参数:

@name workqueue 的名称

2

create_singlethread_workqueue

用于创建 workqueue ,只创建一个内核线程。输入参数:

@name workqueue 名称

3

destroy_workqueue

释放 workqueue 队列。输入参数:

@ workqueue_struct :需要释放的 workqueue 队列指针

4

schedule_work

调度执行一个具体的任务,执行的任务将会被挂入 Linux 系统提供的 workqueue —— keventd_wq 输入参数:

@ work_struct :具体任务对象指针

5

schedule_delayed_work

延迟一定时间去执行一个具体的任务,功能与 schedule_work 类似,多了一个延迟时间,输入参数:

@work_struct :具体任务对象指针

@delay :延迟时间

上一篇:JIRA介绍
下一篇:mini2440启动代码分析之第七篇(ResetHandler和存储控制寄存器初始化)