148 kthread_worker:怎么把内核线程当工人?

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

一、前言

可以通过此结构体让内核为我们创建一个线程,在线程里面完成一件事情

驱动传输数据的两种方式

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>

#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值