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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

kthread_work和kthread_worker机制

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

struct kthread_worker {
?? ?spinlock_t?? ??? ?lock;//保護work_list鏈表的自旋鎖
?? ?struct list_head?? ?work_list;//kthread_work鏈表,相當于流水線
?? ?struct task_struct?? ?*task;//為該kthread_worker執行任務的線程對應的task_struct結構
?? ?struct kthread_work?? ?*current_work;//當前正在處理的kthread_work
};

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

?? ?kthread_worker處理kthread_work是通過創建一個內核線程來執行kthread_worker_fn函數來實現的.下面給出一段例子代碼:
========================================================
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創建一個內核線程來處理work.

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

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

?? ?該宏會調用函數__init_kthread_worker,該函數基本上就是初始化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,主要任務是初始化鏈表元素,設置執行函數.
#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)

?? ?下面看下函數queue_kthread_work的實現,該函數獲取了保護work_list的自旋鎖之后,將剩下的任務委托給函數insert_kthread_work去執行.
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;//設置處理該work的worker
?? ?
?? ?//如果此時指定了worker->task,將會喚醒worker->task表示的內核線程.在初始化kthread_worker的時候worker->task = NULL,但是在上面創建內核線程時所指定的線程的執行函數kthread_worker_fn中會將worker->task賦值,詳情見下文kthread_worker_fn的介紹.
?? ?if (likely(worker->task))
?? ??? ?wake_up_process(worker->task);
}


?? ?kthread_worker_fn無疑是最重要的函數,在該函數中將實現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設置為當前線程
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設置為worker當前處理的work
?? ?spin_unlock_irq(&worker->lock);

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

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

?? ?還有一個比較重要的函數是flush_kthread_worker,該函數會等待當前work_list上的所有的work都被處理了,才會返回.可用來在最后要停止worker的處理線程之前,保證所有的work都已經處理了.
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);
}
?? ?該函數會首先創建并初始化一個kthread_flush_work,該結構體包含了一個kthread_work和一個completion,然后將kthread_work添加到worker的work_list上,最后調用wait_for_completion等待該work被處理,這個最后一個提交的work被稱作flash_work,的執行函數為kthread_flush_work_fn,如下所示,該函數僅僅是調用complete喚醒調用flush_kthread_worker的線程而已,該線程被喚醒之后,它就知道work_list上所有的work都已經處理完了,flush函數也就返回了.
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);
}

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。