1、概述
工作队列是除软中断和tasklet以外最常用的下半部机制之一。工作队列的基本原理是把work(需要推迟执行的函数)交由一个内核线程来异步执行。关于工作队列的具体使用请读者参考其他资料,本文不再概述。
在创建工作队列时,可以通过flag参数指定创建的工作队列是否绑定到特殊的CPU。
内核创建的工作队列(作者使用的是一个6 core的虚拟机)如下,其中红色部分就是工作队列的命名。下面我们进描述下其命名规则。
2、命名规则
Linux内核创建的工作队列命名规则如下:kworker/%u:%d%s (cpu, id, priority) 。
对于未绑定CPU的工作队列,显示为kworker/u2:1。u:是unbound的缩写,代表没有绑定特定的CPU,cpu未绑定所以cpu字段为空,kworker /u2:0,2和0分别表示pool->id和id。
绑定特定cpu的工作队列,显示为kworker/0:13。0:cpu(绑定到cpu0),13:id。
优先级较高的工作队列(nice<0),显示为kworker/0:1H。0:cpu(绑定到cpu0),1:id,H:priority(高优先级)。
下面是内核在创建工作队列create_worker源码,其中对于工作队列的名称有详细描述:
/**
* create_worker - create a new workqueue worker
* @pool: pool the new worker will belong to
*
* Create and start a new worker which is attached to @pool.
*
* CONTEXT:
* Might sleep. Does GFP_KERNEL allocations.
*
* Return:
* Pointer to the newly created worker.
*/
static struct worker *create_worker(struct worker_pool *pool)
{
struct worker *worker = NULL;
int id = -1;
char id_buf[16];
/* ID is needed to determine kthread name */
id = ida_simple_get(&pool->worker_ida, 0, 0, GFP_KERNEL);
if (id < 0)
goto fail;
worker = alloc_worker(pool->node);
if (!worker)
goto fail;
worker->pool = pool;
worker->id = id;
if (pool->cpu >= 0)
snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,pool->attrs->nice < 0 ? "H" : "");
else
snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
worker->task = kthread_create_on_node(worker_thread, worker, pool->node, "kworker/%s", id_buf);
if (IS_ERR(worker->task))
goto fail;
set_user_nice(worker->task, pool->attrs->nice);
/* prevent userland from meddling with cpumask of workqueue workers */
worker->task->flags |= PF_NO_SETAFFINITY;
/* successful, attach the worker to the pool */
worker_attach_to_pool(worker, pool);
/* start the newly created worker */
spin_lock_irq(&pool->lock);
worker->pool->nr_workers++;
worker_enter_idle(worker);
wake_up_process(worker->task);
spin_unlock_irq(&pool->lock);
return worker;
fail:
if (id >= 0)
ida_simple_remove(&pool->worker_ida, id);
kfree(worker);
return NULL;
}