zl程序教程

您现在的位置是:首页 >  系统

当前栏目

linux workqueue实现原理

Linux原理 实现
2023-09-11 14:15:47 时间
  1. 如果在workqueue中添加dump_stack,打印信息中将会有一行workqueue信息,格式是:

Workqueue: $worqueue_name $work_function_name

比如,系统queue名为events,work函数为work_for_cpu_fn

模块自定义workqueue:kacpi_hotplug,函数为 acpi_hotplug_work_fn

driver自定义workqueue

系统workqueue:

默认的schedule_work_on,schedule_delayed_work_on,flush_scheduled_work,schedule_work都是在默认的系统workqueue events上执行的。

dump stack信息也是来源于dump_stack->__dump_stack->dump_stack_print_info->print_worker_info.

print_worker_info函数会对任务进行判断,如果不是worker线程,直接退出,worker线程的标志是任务的struct task_struct->flags成员设置了PF_WQ_WORKER标志。

内核中很多特殊线程有特殊标志(Per process flags),比如IDLE任务,kswapd任务,虚拟CPU任务,内核任务,SWAPWRITE任务, VCPU(KVM Virtualization) thread等等,在内核中要加以利用。


workqueue和CPU的绑定是如何操作的?

注意下面的kthread_bind_mask函数

实质上是通过kthreadd内核线程(PID为2,地位特殊)来创建内核woker线程,kthreadd是所有内核线程的父线程,具体可参考博客:https://blog.csdn.net/tugouxp/article/details/128064414?spm=1001.2014.3001.5501

系统启动的时候逐个创建每个CPU上的worker thread

优先级/affinity如何设置?

内核线程默认的调度测试是NORMAL(其实就是CFS,优先级为0)设置完优先级,继续使用用户传进来的参数cpu_all_mask来设置cpu affinity.

虽然创建会设置优先级,但这并不意味着内核线程不可以更改优先级和调度策略。在线程内部可以继续执行sched_setscheduler_nocheck函数来修改默认的调度策略和优先级。

比如中断线程化使用的内核线程,调度类型被设为FIFO,优先级也被提高。

创建内核线程的接口:

常用的kthead_run,kthread_create其实是有实现与被实现,调用与被调用,封装与被封装的关系的。不外乎几种:

workqueue的优先级

使用命令

$ ps -eo class,pid,ppid,args

查看进程的调度策略

所以基本上可以看到,所有的工作队列任务都是CFS调度方法

worker初始化过程

start_kernel->workqueue_init_early创建初始化system_wq等工作队列。

然后在workqueue_init中为此workqueue创建worker thread.

workqueue_init->wq_update_unbound_numa->alloc_unbound_pwq->get_unbound_pool->create_worker->worker->task = kthread_create_on_node(worker_thread,...);

新创建的worker线程加入到work pool的idle_list中

create_worker 后设置affinity, 优先级。每个pool一个优先级,一类affinity.归属于同一个POOL的worker有着相同的优先级和affinity属性。

结束!