Linux設備驅動器之一 工作線程
- 數據結構
- Linux APIs
- 產生工作線程 kthread_create_worker
- 初始化工作 kthread_init_work
- 排隊工作 kthread_queue_work
- 在Linux中的應用實列
- SPI 驅動器與imx SPI
- 任務工作線程代碼
- 啟動任務工作線程
- 工作線程(worker)
- Linux管理線程
數據結構
struct kthread_worker {unsigned int flags;raw_spinlock_t lock;struct list_head work_list;struct list_head delayed_work_list;struct task_struct *task;struct kthread_work *current_work;
};struct kthread_work {struct list_head node;kthread_work_func_t func;struct kthread_worker *worker;/* Number of canceling calls that are running at the moment. */int canceling;
};struct kthread_delayed_work {struct kthread_work work;struct timer_list timer;
};
Linux APIs
產生工作線程 kthread_create_worker
struct kthread_worker *kthread_create_worker(unsigned int flags, const char namefmt[], …)
- unsigned int flags : 指定任務工作線程默認行為
- const char namefmt[] : kthread 任務工作線程的printf樣式名稱。
- … : 變量參數
如果成功,則返回一個指針, 它指向已產生的任務工作線程;
如果無法分配所需的結構,則返回 ERR_PTR(-ENOMEM);
如果調用者收到一個致命信號,則返回 ERR_PTR(-EINTR)。
初始化工作 kthread_init_work
kthread_init_work(work, fn)
這是一個宏定義,它初始化struct kthread_work結構變量work, 并設置fn為完成該工作的程序代碼。就是調用fn去完成需要的工作。
排隊工作 kthread_queue_work
bool kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work)
功能: 排隊一個kthread_work
參數:
- struct kthread_worker *worker : 任務工作線程
- struct kthread_work *work: 需要排隊的工作
將工作排隊到工作處理器任務以進行異步執行。任務必須已使用 kthread_worker_create() 創建。如果工作已成功排隊,則返回 true;如果工作已處于掛起狀態,則返回 false。
如果工作需要由其他任務工作線程使用,請重新初始化該工作。例如,當任務工作線程停止并再次啟動時。
在Linux中的應用實列
SPI 驅動器與imx SPI
spi_init_queue調用kthread_create_worker,kthread_init_work, 去產生SPI任務工作線程,細節見下面的代碼段。
static int spi_init_queue(struct spi_controller *ctlr)
{ctlr->running = false;ctlr->busy = false;ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev));if (IS_ERR(ctlr->kworker)) {dev_err(&ctlr->dev, "failed to create message pump kworker\n");return PTR_ERR(ctlr->kworker);}kthread_init_work(&ctlr->pump_messages, spi_pump_messages);/** Controller config will indicate if this controller should run the* message pump with high (realtime) priority to reduce the transfer* latency on the bus by minimising the delay between a transfer* request and the scheduling of the message pump thread. Without this* setting the message pump thread will remain at default priority.*/if (ctlr->rt)spi_set_thread_rt(ctlr);return 0;
}
imx SPI 驅動器支持NXP i.MX 8M Nano。
下列的流程圖描繪了imx SPI 驅動器如何調用spi_init_queue去初始化任務工作線程。
spi_register_master 由下列的宏定義
#define spi_register_master(_ctlr) spi_register_controller(_ctlr)
任務工作線程代碼
static void spi_pump_messages(struct kthread_work *work)
如果SPI任務工作線程忙,則調用kthread_queue_work,將任務工作加入到等待隊列。
啟動任務工作線程
工作線程(worker)
int kthread_worker_fn(void *worker_ptr)
{struct kthread_worker *worker = worker_ptr;struct kthread_work *work;/** FIXME: Update the check and remove the assignment when all kthread* worker users are created using kthread_create_worker*() functions.*/WARN_ON(worker->task && worker->task != current);worker->task = current;if (worker->flags & KTW_FREEZABLE)set_freezable();repeat:set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */if (kthread_should_stop()) {__set_current_state(TASK_RUNNING);raw_spin_lock_irq(&worker->lock);worker->task = NULL;raw_spin_unlock_irq(&worker->lock);return 0;}work = NULL;raw_spin_lock_irq(&worker->lock);if (!list_empty(&worker->work_list)) {work = list_first_entry(&worker->work_list,struct kthread_work, node);list_del_init(&work->node);}worker->current_work = work;raw_spin_unlock_irq(&worker->lock);if (work) {kthread_work_func_t func = work->func;__set_current_state(TASK_RUNNING);trace_sched_kthread_work_execute_start(work);work->func(work);/** Avoid dereferencing work after this point. The trace* event only cares about the address.*/trace_sched_kthread_work_execute_end(work, func);} else if (!freezing(current))schedule();try_to_freeze();cond_resched();goto repeat;
}
這個線程的流程圖如下
它檢查這個任務線程的任務工作鏈表,如果非空,那么就從任務工作鏈表上取下一個任務工作 并運行它的回調函數。這個回調函數在任務工作初始化是設置。
從這個程序段看出,任務工作一定要初始化。
Linux管理線程
Linux系統初始時,產生了一個工作線程的管理線程,這里稱其為任務線程產生的監視線程。
kthread_create_worker產生一個struct kthread_create_info變量,并將這個變量加入到一個待產生線程鏈表中,這個鏈表的表頭是kthread_create_list
監視線程監視這個待產生線程鏈表,一旦新的變量加入這個鏈表,這個監視線程就產生一個新的任務工作(worker)線程。