文章目录
一、前言
可以通过此结构体让内核为我们创建一个线程,在线程里面完成一件事情
驱动传输数据的两种方式
1、同步传输
低速数据:驱动同步传输
优点:简单直接
缺点:传输效率低,同步传输会造成当前线程阻塞,影响用户空间应用程序执行的效率
2、异步传输
高速数据:驱动交给内核来异步传输
优点:无阻塞
缺点:机制复杂、内核里面的相关代码很多
二、kthread_worker结构体
include/linux/kthread.h
把内核线程抽象为流水线工人,按序处理其他线程/进程交付的批量工作
内核里面的流水线工人可能有多个
struct kthread_worker {
unsigned int flags;
// 自旋锁
spinlock_t lock;
// 不需要延时的工作串联,即串联下面的kthread_work结构体
struct list_head work_list;
// 需要延时完成的工作串联
struct list_head delayed_work_list;
// 表示一个具体的进程或者线程
struct task_struct *task;
// 指向正在处理的某一个具体的工作,详见下
struct kthread_work *current_work;
};

三、kthread_work结构体
include/linux/kthread.h
表示等待内核线程处理的具体工作
struct kthread_work {
// 此链表节点将串联在kthread_worker->work_list
struct list_head node;
// 为每一个具体工作指定一个具体的函数,真正负责完成具体的工作,自定义
kthread_work_func_t func;
// 这个具体工作属于哪个工人,内核里面可能有多个工人,指向上面node成员指向的kthread_worker
struct kthread_worker *worker;
/* Number of canceling calls that are running at the moment. */
int canceling;
};
- node:链表节点
- func:函数指针
- worker:处理该工作的内核线程工人
kthread_work_func_t 数据类型定义
typedef void (*kthread_work_func_t)(struct kthread_work *work);
四、kthread_flush_work 结构体
kernel/kthread.c
用于等待某个内核线程工人处理完所有工作
struct kthread_flush_work {
struct kthread_work work;
struct completion done;
};
- work:具体内核线程工作
- done:完成量,等待所有工作处理完毕
五、如何使用上面的数据结构
1、初始化 kthread_worker结构体
init_kthread_worker 函数
先定义,后初始化
// 定义一个工人
struct kthread_worker hi_worker;
// 初始化一个工人
init_kthread_worker(&hi_worker);
2、为kthread_worker创建内核线程
先定义,后初始化
struct task_struct *kworker_task;
// kworker_task 要被hi_worker中的task成员所指向
kworker_task = kthread_run(kthread_worker_fn, &hi_worker, "nvme%d", 1);
- kthread_worker_fn:内核线程一直运行的函数,具体的工作就在这个函数指针里面完成。这是内核提供给我们的
- hi_worker:已初始化的kthread_worker结构体变量
- “nvme%d”:为内核线程设置名字
3、初始化kthread_work
先定义,后初始化
// 定义一个具体的工作变量
struct kthread_work hi_work;
// 为此工作变量指定一个具体的工作函数
init_kthread_work(&hi_work, xxx_work_fn);
- xxx_work_fn:处理该工作的具体函数,自定义实现,负责完成具体的工作
4、启动工作
交付工作给内核线程工人
// hi_worker:具体内核线程工人,struct kthread_worker
// hi_work:具体工作,struct kthread_work
kthread_queue_work(&hi_worker, &hi_work);
注意工人手里可能有多个具体工作
5、FLUSH工作队列
刷新指定 kthread_worker上所有 work
// 等待此流水线工个人手里的工作完成
kthread_flush_worker(&hi_worker);
- hi_worker:具体内核线程工人
6、停止内核线程
停止创建的内核线程
// struct task_struct 指针
kthread_stop(kworker_task);
六、例程
1、驱动源文件
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include <linux/fs.h>
#include<linux/slab.h>
#include<linux/io.h>
#include<linux/uaccess.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/of.h>
#include<linux/of_address.h>
#include<linux/of_irq.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include<linux/atomic.h>
#include<linux/timer.h>
#include<linux/jiffies.h>
#include<linux/interrupt.h>
#include<linux/completion.h>
#include<linux/ide.h>
#include<linux/kthread.h>
#include<linux/sched.h>
#

本文详细介绍了Linux内核中的kthread_worker和kthread_work结构体,以及它们在驱动程序中如何用于实现同步传输和异步传输。通过kthread_work_func_t定义的工作函数,驱动可以创建内核线程来处理特定任务,如LED控制。工作队列的初始化、启动、刷新和停止过程也进行了说明,展示了如何在驱动中优雅地管理内核线程和工作队列。
最低0.47元/天 解锁文章
2913

被折叠的 条评论
为什么被折叠?



