日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

kthread_work和kthread_worker机制

發(fā)布時間:2025/3/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 kthread_work和kthread_worker机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
Kernel中提供的kthread_work和kthread_worker機(jī)制和經(jīng)典的work_struct和workqueue_struct的關(guān)系有點(diǎn)類似.通過一個kthread_worker可以處理多個kthread_work,其實(shí)就是利用了工人在流水線上工作的形式.先來看看這兩個數(shù)據(jù)結(jié)構(gòu)的定義,它們定義在頭文件include/linux/kthread.h(3.1版本)

struct kthread_worker {
?? ?spinlock_t?? ??? ?lock;//保護(hù)work_list鏈表的自旋鎖
?? ?struct list_head?? ?work_list;//kthread_work鏈表,相當(dāng)于流水線
?? ?struct task_struct?? ?*task;//為該kthread_worker執(zhí)行任務(wù)的線程對應(yīng)的task_struct結(jié)構(gòu)
?? ?struct kthread_work?? ?*current_work;//當(dāng)前正在處理的kthread_work
};

struct kthread_work {
?? ?struct list_head?? ?node;//kthread_work鏈表的鏈表元素
?? ?kthread_work_func_t?? ?func;//執(zhí)行函數(shù),該kthread_work所要做的事情
?? ?wait_queue_head_t?? ?done;//沒有找到相關(guān)用法
?? ?struct kthread_worker?? ?*worker;//處理該kthread_work的kthread_worker
};

?? ?kthread_worker處理kthread_work是通過創(chuàng)建一個內(nèi)核線程來執(zhí)行kthread_worker_fn函數(shù)來實(shí)現(xiàn)的.下面給出一段例子代碼:
========================================================
struct kthread_worker worker;//聲明一個kthread_worker
init_kthread_worker(&worker);//初始化kthread_worker
struct task_struct *kworker_task = kthread_run(kthread_worker_fn, &worker, "nvme%d", dev->instance);//為kthread_worker創(chuàng)建一個內(nèi)核線程來處理work.

struct kthread_work work;//聲明一個kthread_work
init_kthread_work(&work, work_fn);初始化kthread_work,設(shè)置work執(zhí)行函數(shù).
queue_kthread_work(&worker, &work);//將kthread_work添加到kthread_worker的work_list.
========================================================

?? ?下面來依次介紹一下這些函數(shù)的實(shí)現(xiàn).
?? ?
?? ?init_kthread_worker和init_kthread_work其實(shí)是兩個宏.
#define init_kthread_worker(worker)?? ??? ??? ??? ??? ?\
?? ?do {?? ??? ??? ??? ??? ??? ??? ??? ?\
?? ??? ?static struct lock_class_key __key;?? ??? ??? ?\
?? ??? ?__init_kthread_worker((worker), "("#worker")->lock", &__key); \
?? ?} while (0)

?? ?該宏會調(diào)用函數(shù)__init_kthread_worker,該函數(shù)基本上就是初始化work_list鏈表
void __init_kthread_worker(struct kthread_worker *worker,
?? ??? ??? ??? ?const char *name,
?? ??? ??? ??? ?struct lock_class_key *key)
{
?? ?spin_lock_init(&worker->lock);
?? ?lockdep_set_class_and_name(&worker->lock, key, name);
?? ?INIT_LIST_HEAD(&worker->work_list);
?? ?worker->task = NULL;
}

?? ?宏init_kthread_work用來初始化kthread_work,主要任務(wù)是初始化鏈表元素,設(shè)置執(zhí)行函數(shù).
#define init_kthread_work(work, fn)?? ??? ??? ??? ??? ?\
?? ?do {?? ??? ??? ??? ??? ??? ??? ??? ?\
?? ??? ?memset((work), 0, sizeof(struct kthread_work));?? ??? ?\
?? ??? ?INIT_LIST_HEAD(&(work)->node);?? ??? ??? ??? ?\
?? ??? ?(work)->func = (fn);?? ??? ??? ??? ??? ?\
?? ??? ?init_waitqueue_head(&(work)->done);?? ??? ??? ?\
?? ?} while (0)

?? ?下面看下函數(shù)queue_kthread_work的實(shí)現(xiàn),該函數(shù)獲取了保護(hù)work_list的自旋鎖之后,將剩下的任務(wù)委托給函數(shù)insert_kthread_work去執(zhí)行.
bool queue_kthread_work(struct kthread_worker *worker,
?? ??? ??? ?struct kthread_work *work)
{
?? ?bool ret = false;
?? ?unsigned long flags;

?? ?spin_lock_irqsave(&worker->lock, flags);
?? ?if (list_empty(&work->node)) {
?? ??? ?insert_kthread_work(worker, work, &worker->work_list);
?? ??? ?ret = true;
?? ?}
?? ?spin_unlock_irqrestore(&worker->lock, flags);
?? ?return ret;
}

static void insert_kthread_work(struct kthread_worker *worker,
?? ??? ??? ??????? struct kthread_work *work,
?? ??? ??? ??????? struct list_head *pos)
{
?? ?lockdep_assert_held(&worker->lock);

?? ?list_add_tail(&work->node, pos);//pos = &worker->work_list,這里就是將kthread_work添加到kthread_worker的work_list鏈表末尾.
?? ?work->worker = worker;//設(shè)置處理該work的worker
?? ?
?? ?//如果此時指定了worker->task,將會喚醒worker->task表示的內(nèi)核線程.在初始化kthread_worker的時候worker->task = NULL,但是在上面創(chuàng)建內(nèi)核線程時所指定的線程的執(zhí)行函數(shù)kthread_worker_fn中會將worker->task賦值,詳情見下文kthread_worker_fn的介紹.
?? ?if (likely(worker->task))
?? ??? ?wake_up_process(worker->task);
}


?? ?kthread_worker_fn無疑是最重要的函數(shù),在該函數(shù)中將實(shí)現(xiàn)worker對work的處理.
?? ?
int kthread_worker_fn(void *worker_ptr)
{
?? ?struct kthread_worker *worker = worker_ptr;
?? ?struct kthread_work *work;

?? ?WARN_ON(worker->task);
?? ?worker->task = current;//將worker->task設(shè)置為當(dāng)前線程
repeat:
?? ?set_current_state(TASK_INTERRUPTIBLE);?? ?/* mb paired w/ kthread_stop */

?? ?if (kthread_should_stop()) {//如果該work處理線程在別的地方被停止了,則該線程會退出.
?? ??? ?__set_current_state(TASK_RUNNING);
?? ??? ?spin_lock_irq(&worker->lock);
?? ??? ?worker->task = NULL;
?? ??? ?spin_unlock_irq(&worker->lock);
?? ??? ?return 0;
?? ?}

?? ?work = NULL;
?? ?spin_lock_irq(&worker->lock);
?? ?if (!list_empty(&worker->work_list)) {
?? ??? ?//如果worker的work_list上有work,則獲取其上的第一個work,然后將其從鏈表中刪除.
?? ??? ?work = list_first_entry(&worker->work_list, struct kthread_work, node);
?? ??? ?list_del_init(&work->node);
?? ?}
?? ?worker->current_work = work;//將剛才獲取的work設(shè)置為worker當(dāng)前處理的work
?? ?spin_unlock_irq(&worker->lock);

?? ?if (work) {//如果剛才獲取到了work,則修改當(dāng)前線程的狀態(tài)為TASK_RUNNING,這樣在發(fā)生調(diào)度的時候,該線程就不會被從就緒隊(duì)列中移除.然后執(zhí)行該work的執(zhí)行函數(shù).
?? ??? ?__set_current_state(TASK_RUNNING);
?? ??? ?work->func(work);
?? ?} else if (!freezing(current))
?? ??? ?schedule();//如果沒有獲取到work,則說明該worker當(dāng)前無事可做,則調(diào)用schedule交出cpu,該線程會被從就緒隊(duì)列中移除,而進(jìn)入睡眠狀態(tài),直到有work被添加到worker的work_list時,被喚醒.

?? ?try_to_freeze();
?? ?goto repeat;//繼續(xù)處理work_list中的work或者剛被喚醒,去檢查work_list上是否有work可處理.
}

?? ?還有一個比較重要的函數(shù)是flush_kthread_worker,該函數(shù)會等待當(dāng)前work_list上的所有的work都被處理了,才會返回.可用來在最后要停止worker的處理線程之前,保證所有的work都已經(jīng)處理了.
void flush_kthread_worker(struct kthread_worker *worker)
{
?? ?struct kthread_flush_work fwork = {
?? ??? ?KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn),
?? ??? ?COMPLETION_INITIALIZER_ONSTACK(fwork.done),
?? ?};

?? ?queue_kthread_work(worker, &fwork.work);
?? ?wait_for_completion(&fwork.done);
}
?? ?該函數(shù)會首先創(chuàng)建并初始化一個kthread_flush_work,該結(jié)構(gòu)體包含了一個kthread_work和一個completion,然后將kthread_work添加到worker的work_list上,最后調(diào)用wait_for_completion等待該work被處理,這個最后一個提交的work被稱作flash_work,的執(zhí)行函數(shù)為kthread_flush_work_fn,如下所示,該函數(shù)僅僅是調(diào)用complete喚醒調(diào)用flush_kthread_worker的線程而已,該線程被喚醒之后,它就知道work_list上所有的work都已經(jīng)處理完了,flush函數(shù)也就返回了.
static void kthread_flush_work_fn(struct kthread_work *work)
{
?? ?struct kthread_flush_work *fwork =
?? ??? ?container_of(work, struct kthread_flush_work, work);
?? ?complete(&fwork->done);
}

總結(jié)

以上是生活随笔為你收集整理的kthread_work和kthread_worker机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。