Linux Kernel workqueue 工作队列

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

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

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

 

1. 创建新的工作队列

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) 

INIT_DELAYED_WORK(work, func) 

它向一个现存的 work_struct 实例提供一个延期执行函数。

queue_work

queue_work_delayed

可以向一个工作队列添加 work_struct 实例

/**
 * 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, 按通常的方式将工作添加到工作队列。

 

2. 使用 Linux Kernel 创建的系统工作队列

内核创建了一个标准的工作队列 system_wq .

内核中凡是没有必要创建独立的工作队列,均可使用该队列。

schedule_work

schedule_delayed_work

可用于将新的工作添加到标准队列

/**
 * 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);
}

3. Linux Kernel Doc 介绍 workqueue

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/core-api/workqueue.rst

There are many cases where an asynchronous process execution context
is needed and the workqueue (wq) API is the most commonly used
mechanism for such cases.

When such an asynchronous execution context is needed, a work item
describing which function to execute is put on a queue.  An
independent thread serves as the asynchronous execution context.  The
queue is called workqueue and the thread is called worker.

While there are work items on the workqueue the worker executes the
functions associated with the work items one after the other.  When
there is no work item left on the workqueue the worker becomes idle.
When a new work item gets queued, the worker begins executing again.

4. Example

TP 中断响应程序下半部;
长按 power key 软关机 (delayed work)

5. workqueue 、waitqueue 及 tasklet

https://blog.csdn.net/ezimu/article/details/54851148

可以参考本文重点搞清楚:
workqueue 、waitqueue 及 tasklet (https://blog.csdn.net/fervor_heart/article/details/46964623) 三者的区别

https://computing.ece.vt.edu/~changwoo/ECE-LKP-2019F/l/lec11-int-bottom-half.pdf

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值