linux 内核 工作队列

来源:互联网 发布:路易十六知乎 编辑:程序博客网 时间:2024/04/30 11:45

工作队列是将操作延期执行的另一种手段。

每个工作队列都有一个数组,数组项的数目与系统中处理器的数目相同。 每个数组项都列出了将延期执行的任务。

对每个工作队列来说,内核都会创建一个新的内核守护进程,延期任务使用等待队列机制,在该守护进程的上下文中执行。


新的工作队列通过调用 create_workqueue 或 create_workqueue_singlethread 函数来创建。前一个函数在所有CPU 上都创建一个工作线程,

而后者只在系统第一个CPU 上创建一个线程。

kernel/workqueue.c

struct workqueue_struct *__create_workqueue(const char *name, int singlethread)

name 表示创建的守护进程在进程列表中显示的名称。

所有推送到工作队列上的任务,都必须打包为 workstruct 结构的实例, 从工作队列用户的角度来看,该结构的下述成员比较重要。


workqueue.h

struct work_struct;
typedef void (*work_func_t)(struct work_struct *work);

struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
};

内核提供了 INIT_WORK(work, func) 宏, 它向一个现存的work_struct 实例提供一个延期执行函数。

有两种方法可以向一个工作队列添加 work_struct 实例,分别是 queue_work 和 queue_work_delayed

/**
 * queue_work - queue work on a workqueue
 * @wq: workqueue to use
 * @work: work to queue
 *
 * Returns 0 if @work was already on a queue, non-zero otherwise.
 *
 * We queue the work to the CPU on which it was submitted, but if the CPU dies
 * it can be processed by another CPU.
 *
 * Especially no such guarantee on PREEMPT_RT.
 */
int queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
    int ret = 0, cpu = raw_smp_processor_id();

    ret = queue_work_on(cpu, wq, work);

    return ret;
}

它将work 添加到工作队列 wq, work 本身所指定的工作,其执行时间待定(在调度器选择该守护进程时执行)

为确保排队的工作项将在提交后一段时间内执行,需要扩展work_struct, 添加一个定时器。

struct delayed_work {
    struct work_struct work;
    struct timer_list timer;
};

queue_delayed_work() 用于向工作队列提交 delayed_work 实例。 它确保在延期工作执行之前,至少经过由delay 指定的一段时间(以jiffies 为单位。)

/**
 * queue_delayed_work - queue work on a workqueue after delay
 * @wq: workqueue to use
 * @dwork: delayable work to queue
 * @delay: number of jiffies to wait before queueing
 *
 * Returns 0 if @work was already on a queue, non-zero otherwise.
 */
int queue_delayed_work(struct workqueue_struct *wq,
            struct delayed_work *dwork, unsigned long delay)
{
    if (delay == 0)
        return queue_work(wq, &dwork->work);

    return queue_delayed_work_on(-1, wq, dwork, delay);
}

该函数首先创建一个内核定时器,它将在delayed jiffies 之内超时。 相关的处理程序接下来使用queue_work, 按通常的方式将工作添加到工作队列。


内核创建了一个标准的工作队列,成为events。 内核中凡是没有必要创建独立的工作队列,均可使用该队列。 内核提供了以下两个函数,可用于将新的工作添加到标准队列。

/**
 * schedule_work - put work task in global workqueue
 * @work: job to be done
 *
 * Returns zero if @work was already on the kernel-global workqueue and
 * non-zero otherwise.
 *
 * This puts a job in the kernel-global workqueue if it was not already
 * queued and leaves it in the same position on the kernel-global
 * workqueue otherwise.
 */
int schedule_work(struct work_struct *work)
{
    return queue_work(keventd_wq, work);
}


/**
 * schedule_delayed_work - put work task in global workqueue after delay
 * @dwork: job to be done
 * @delay: number of jiffies to wait or 0 for immediate execution
 *
 * After waiting for a given time this puts a job in the kernel-global
 * workqueue.
 */
int schedule_delayed_work(struct delayed_work *dwork,
                    unsigned long delay)
{
    return queue_delayed_work(keventd_wq, dwork, delay);
}