博客
关于我
工作队列浅析
阅读量:798 次
发布时间:2023-04-17

本文共 3564 字,大约阅读时间需要 11 分钟。

内核工作队列与event线程创建

在内核开发中,工作队列(workqueue)是一种非常重要的机制,用于异步处理任务。通过工作队列,可以将任务提交给特定的内核线程进行处理,这在内核模块开发中尤为常见。以下将详细讲解如何在内核中创建事件线程,并将work_struct添加到工作队列中。

1. work_struct的提交

在内核中,提交一个work_struct到工作队列,可以通过调用queue_work函数实现。queue_work函数接受两个参数:workqueue_struct *wqwork_struct *workwq是工作队列的实例,而work则是待处理的任务。

int queue_work(struct workqueue_struct *wq, struct work_struct *work){    int ret;    ret = queue_work_on(get_cpu(), wq, work);    put_cpu();    return ret;}

queue_work_on函数是queue_work的核心部分,它负责将work_struct添加到指定的工作队列中。get_cpu()put_cpu()函数用于获取和释放当前处理CPU,这在多核环境中非常重要。

2. 工作队列的创建

在内核中,默认会创建一个名为keventd_wq的工作队列,这个队列用于处理事件相关的任务。keventd_wq是通过create_workqueue函数创建的。

void __init init_workqueues(void){    alloc_cpumask_var(&cpu_populated_map, GFP_KERNEL);    cpumask_copy(cpu_populated_map, cpu_online_mask);    singlethread_cpu = cpumask_first(cpu_possible_mask);    cpu_singlethread_map = cpumask_of(singlethread_cpu);    hotcpu_notifier(workqueue_cpu_callback, 0);    keventd_wq = create_workqueue("events");    BUG_ON(!keventd_wq);}

create_workqueue函数通过__create_workqueue_key来创建工作队列实例。工作队列的创建涉及到CPU的初始化和线程的创建。singlethread标志决定了是否为每个CPU创建一个独立的线程。

#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)#define __create_workqueue(name, singlethread, freezeable, rt) \    __create_workqueue_key((name), (singlethread), (freezeable), (rt), NULL, NULL)struct workqueue_struct *__create_workqueue_key(const char *name,    int singlethread, int freezeable, int rt,    struct lock_class_key *key, const char *lock_name){    // ... 代码省略 ...    if (singlethread) {        cwq = init_cpu_workqueue(wq, singlethread_cpu);        err = create_workqueue_thread(cwq, singlethread_cpu);        start_workqueue_thread(cwq, -1);    } else {        // ... 代码省略 ...    }    return cwq;}

init_cpu_workqueue函数初始化CPU的工作队列,create_workqueue_thread函数创建线程,并将线程绑定到指定的CPU上。start_workqueue_thread函数则启动线程,开始处理任务。

3. 工作队列的处理

queue_work函数将work_struct添加到工作队列后,insert_work函数会将任务添加到队列中,并触发相关的处理流程。

static void insert_work(struct cpu_workqueue_struct *cwq,    struct work_struct *work, struct list_head *head){    trace_workqueue_insertion(cwq->thread, work);    set_wq_data(work, cwq);    smp_wmb();    list_add_tail(&work->entry, head);    wake_up(&cwq->more_work);}

set_wq_data函数将work_struct的数据与工作队列关联起来,smp_wmb函数用于保证内核的可见性,这在多核环境中非常重要。list_add_tail函数将任务添加到工作队列的末尾,wake_up函数则通知相关的等待队列,确保任务能够被处理。

4. work_pending的实现

work_pending是一个内核标志位,用于检查是否有任务需要处理。它通过检查TIF_NEED_RESCHED标志位来判断。

#define _TIF_NEED_RESCHED       (1 << TIF_NEED_RESCHED)#define TIF_NEED_RESCHED        3       /* rescheduling necessary */work_pending:    testb $_TIF_NEED_RESCHED, %cl    jz work_notifysig    work_resched:        call schedule    LOCKDEP_SYS_EXIT    DISABLE_INTERRUPTS(CLBR_ANY)    TRACE_IRQS_OFF    movl TI_flags(%ebp), %ecx    andl $_TIF_WORK_MASK, %ecx    jz restore_all    testb $_TIF_NEED_RESCHED, %cl    jnz work_reschedwork_notifysig:    movl %esp, %eax    xorl %edx, %edx    call do_notify_resume    jmp resume_userspace_sigEND(work_pending)

work_resched函数会调用schedule函数重新调度当前进程,确保任务能够按时处理。

5. do_notify_resume的作用

do_notify_resume函数负责通知用户空间,确保用户线程能够继续执行。这通过TI_flags来实现,检查是否有需要重新调度的任务。

#define resume_userspace_sig    resume_userspaceENTRY(resume_userspace)    LOCKDEP_SYS_EXIT    DISABLE_INTERRUPTS(CLBR_ANY)    TRACE_IRQS_OFF    movl TI_flags(%ebp), %ecx    andl $_TIF_WORK_MASK, %ecx    jne work_pending    jmp restore_all

do_notify_resume函数通过resume_userspace返回,用户线程可以继续执行任务。

6. 总结

在内核中,通过queue_work函数将work_struct提交到工作队列keventd_wq,可以创建并处理事件线程。默认的工作队列keventd_wq为每个CPU创建一个独立的线程,处理任务。了解工作队列的实现机制,有助于更好地开发和优化内核模块。

转载地址:http://ymgfk.baihongyu.com/

你可能感兴趣的文章
MongoDB可视化客户端管理工具之NoSQLbooster4mongo
查看>>
Mongodb学习总结(1)——常用NoSql数据库比较
查看>>
MongoDB学习笔记(8)--索引及优化索引
查看>>
mongodb定时备份数据库
查看>>
mppt算法详解-ChatGPT4o作答
查看>>
mpvue的使用(一)必要的开发环境
查看>>
MQ 重复消费如何解决?
查看>>
mqtt broker服务端
查看>>
MQTT 保留消息
查看>>
MQTT 持久会话与 Clean Session 详解
查看>>
MQTT工作笔记0007---剩余长度
查看>>
MQTT工作笔记0009---订阅主题和订阅确认
查看>>
Mqtt搭建代理服务器进行通信-浅析
查看>>
MS Edge浏览器“STATUS_INVALID_IMAGE_HASH“兼容性问题
查看>>
ms sql server 2008 sp2更新异常
查看>>
MS UC 2013-0-Prepare Tool
查看>>
MSBuild 教程(2)
查看>>
msbuild发布web应用程序
查看>>
MSB与LSB
查看>>
MSCRM调用外部JS文件
查看>>