博客
关于我
工作队列浅析
阅读量: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/

你可能感兴趣的文章
MySQL 数据类型和属性
查看>>
mysql 敲错命令 想取消怎么办?
查看>>
Mysql 整形列的字节与存储范围
查看>>
mysql 断电数据损坏,无法启动
查看>>
MySQL 日期时间类型的选择
查看>>
Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
查看>>
MySQL 是如何加锁的?
查看>>
MySQL 是怎样运行的 - InnoDB数据页结构
查看>>
mysql 更新子表_mysql 在update中实现子查询的方式
查看>>
MySQL 有什么优点?
查看>>
mysql 权限整理记录
查看>>
mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
查看>>
MYSQL 查看最大连接数和修改最大连接数
查看>>
MySQL 查看有哪些表
查看>>
mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
查看>>
MySql 查询以逗号分隔的字符串的方法(正则)
查看>>
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
查看>>
mysql 查询数据库所有表的字段信息
查看>>
【Java基础】什么是面向对象?
查看>>
mysql 查询,正数降序排序,负数升序排序
查看>>