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)线程。