首页 > 系统相关 >Linux APP查询驱动的方式归类总

Linux APP查询驱动的方式归类总

时间:2024-08-28 14:25:04浏览次数:10  
标签:struct 队列 APP 归类 queue Linux tasklet 等待 wait

Linux APP查询驱动的方式归类总


前言

一、具体方式是什么?

1、休眠与唤醒
2、阻塞与非阻塞
3、POLL机制
4、异步通知
tips:等待队列用于进程等待条件,工作队列用于异步任务处理。

二、使用步骤

休眠与唤醒

tips:
在中断处理函数中,不能休眠,也就不能调用会导致休眠的函数。
上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时的处理就可以放在上半部完成。
下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。
上半部和下半部使用参考点
①、如果要处理的内容不希望被其他中断打断,那么可以放到上半部。
②、如果要处理的任务对时间敏感,可以放到上半部。
③、如果要处理的任务与硬件有关,可以放到上半部
④、除了上述三点以外的其他任务,优先考虑放到下半部。
下半部机制类别`
1、软终端 softirq_action

struct softirq_action
 {
	 void (*action)(struct softirq_action *);
};
softirq_vec 数组
static struct softirq_action softirq_vec[NR_SOFTIRQS];  NR_SOFTIRQS = 10;
enum
{
	HI_SOFTIRQ=0, /* 高优先级软中断 */
	TIMER_SOFTIRQ, /* 定时器软中断 */
	NET_TX_SOFTIRQ, /* 网络数据发送软中断 */
	NET_RX_SOFTIRQ, /* 网络数据接收软中断 */
	BLOCK_SOFTIRQ,
	BLOCK_IOPOLL_SOFTIRQ,
	TASKLET_SOFTIRQ, /* tasklet 软中断 */
	SCHED_SOFTIRQ, /* 调度软中断 */
	HRTIMER_SOFTIRQ, /* 高精度定时器软中断 */
	RCU_SOFTIRQ, /* RCU 软中断 */
	NR_SOFTIRQS
};

2、TASKLET
tasklet 是利用软中断来实现的另外一种下半部机制,在软中断和 tasklet 之间,建议大家使用 tasklet。 Linux 内核使用 tasklet_struct 结构体来表示 tasklet:

struct tasklet_struct
{
	struct tasklet_struct *next; /* 下一个 tasklet */
	unsigned long state; /* tasklet 状态 */
	atomic_t count; /* 计数器,记录对 tasklet 的引用数 */
	void (*func)(unsigned long); /* tasklet 执行的函数 */
	unsigned long data; /* 函数 func 的参数 */
}`

使用 :
DECLARE_TASKLET(name, func, data); //name 为要定义的 tasklet 名字,这个名字就是一个 tasklet_struct 类型的时候变量, func就是 tasklet 的处理函数, data 是传递给 func 函数的参数
tasklet_init(&testtasklet, testtasklet_func, data); //初始化
3、工作队列
工作队列是另外一种下半部执行方式,工作队列在进程上下文执行,工作队列将要推后的工作交给一个内核线程去执行,因为工作队列工作在进程上下文,因此工作队列允许睡眠或重新调度。因此如果你要推后的工作可以睡眠那么就可以选择工作队列,否则的话就只能选择软终端和tasklet。
#define DECLARE_WORK(n, f) //创建 和 初始化n 表示定义的工作(work_struct), f 表示工作对应的处理函数。
bool schedule_work(struct work_struct *work) //调度

POLL机制

使用休眠-唤醒的方式等待某个事件发生时,有一个缺点: 等待的时间可能
很久。我们可以加上一个超时时间,这时就可以使用 poll 机制。
调用 poll 之后,进入内核态;致驱动程序的 drv_poll 被调用,drv_poll 还会判断一下有没有数据?返回这个状态,当前没有数据,则休眠一会要把自己这个线程挂入等待队列 wq 中,从休眠中被唤醒,继续执行 for 循环,唤醒可能是超时或者是poll队列唤醒。
eg:

static unsigned int xxx_drv_poll(struct file *fp, poll_table * wait)
{
	poll_wait(fp, &gpio_key_wait, wait);
	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}
阻塞与非阻塞
阻塞

谓阻塞,就是等待某件事情发生。比如调用 read 读取按键时,如果没有
按键数据则 read 函数不会返回,它会让线程休眠等待。
使用 poll 时,如果传入的超时时间不为 0,这种访问方法也是阻塞的。
使用 poll 时,可以设置超时时间为 0,这样即使没有数据它也会立刻返回,

非阻塞

非阻塞就是等待队列和poll select 和epoll的结合使用

等待队列

要在驱动中使用等待队列,必须创建并初始化一个等待队列头,等待队列头使用结构体wait_queue_head_t表示

struct __wait_queue_head {
	spinlock_t lock;
	struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

使用 init_waitqueue_head 函数初始化等待队列头
void init_waitqueue_head(wait_queue_head_t *q)
也可以使用宏 DECLARE_WAIT_QUEUE_HEAD 来一次性完成等待队列头的定义的初始化

结构体 wait_queue_t 表示等待队列项
等待队列头就是一个等待队列的头部,每个访问设备的进程都是一个队列项

struct __wait_queue {
	unsigned int flags;
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;

使用宏 DECLARE_WAITQUEUE 定义并初始化一个等待队列项,宏的内容如下:
DECLARE_WAITQUEUE(name, tsk)
name 就是等待队列项的名字, tsk 表示这个等待队列项属于哪个任务(进程),一般设置为current , Linux 内 核 中 current 相 当 于 一 个 全 局 变 量 , 表 示 当 前 进 程。

当设备不可访问的时候就需要将进程对应的等待队列项添加到前面创建的等待队列头中,当设备可以访问以后再将进程对应的等待队列项从等待队列头中移除即可

void add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait)
void remove_wait_queue(wait_queue_head_t *q,wait_queue_t *wait)

等待唤醒
void wake_up(wait_queue_head_t *q)
void wake_up_interruptible(wait_queue_head_t *q)
参数 q 就是要唤醒的等待队列头,这两个函数会将这个等待队列头中的所有进程都唤醒。wake_up 函数可以唤醒处于 TASK_INTERRUPTIBLE 和 TASK_UNINTERRUPTIBLE 状态的进程,而 wake_up_interruptible 函数只能唤醒处于 TASK_INTERRUPTIBLE 状态的进程

异步通知

对于APP:
注册signal函数和sigio挂钩, signal(SIGIO, sig_func);
打开驱动 fd = open(argv[1], O_RDWR);
将进程ID告诉驱动 fcntl(fd, F_SETOWN, getpid());
设置flags有 fasync标志位 flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);
对于驱动程序
调用 fasync_helper就行

static struct fasync_struct *button_async;
static int drv_fasync (int fd, struct file *filp, int on)
{
	return fasync_helper (fd, filp, on, &button_async);
}

fasync_helper 函 数 会 分 配 、 构 造 一 个 fasync_struct 结 构 体

驱动发送信号
kill_fasync (&button_async, SIGIO, POLL_IN);
button_async->fa_file 非空时,可以从中得到 PID,表示发给哪一个 APP;
第 2 个参数表示发什么信号: SIGIO;
第 3 个参数表示为什么发信号: POLL_IN,有数据可以读了

标签:struct,队列,APP,归类,queue,Linux,tasklet,等待,wait
From: https://blog.csdn.net/qq_43587089/article/details/141458502

相关文章

  • linux总线设备驱动模型
    linux总线设备驱动模型platform平台驱动模型linux自带I2C、SPI、USB等总线。但是在SOC中有些外设是没有总线这个概念的,但是又要使用总线、驱动和设备模型该怎么办呢?为了解决此问题,Linux提出了platform这个虚拟总线,相应的就有platform_driver和platform_devi......
  • uniapp js 数独小游戏 9*9 数独 2.0
    效果图: game.vue<template> <view> <viewclass="main"> <viewclass="foot"> <viewv-if="!isTip"class="sudoku_area"> <viewv-for="(row,index)ofrowList":key=&quo......
  • uniapp js 数独小游戏 n*n 看控制台的打印 数独 1.0
    uniappjs 数独小游戏n*n 看控制台的打印game.vue<template> <view>4567</view></template><scriptsetuplang="ts">import{ref}from'vue'import{onShow}from'@dcloudio/uni-app'constsdNum=ref(......
  • linux编程——认识GCC编译器
    目录一、引言二、GCC编译器简介三、GCC的主要特点四、GCC的使用方法五、GCC的高级功能六、总结一、引言  在Linux编程的广阔世界中,GCC(GNUCompilerCollection)编译器无疑是一个至关重要的工具。对于广大的开发者来说,熟练掌握GCC编译器的使用,能够极大地......
  • 【Linux入门】shell基础篇——if、case、与for循环
    文章目录if的条件分支基本`if`语句包含`else`的`if`语句包含`elseif`(或`elif`)的`if`语句注意示例if的嵌套使用case`case`语句的基本语法:示例使用if语句结合casefor循环for循环的基本格式1.基于列表的`for`循环2.C语言风格的`for`循环注意其他循环基于文件的for循环......
  • 【Linux入门】shell基础篇——while循环与until循环
    文章目录while循环与until循环while循环while循环的基本格式示例:打印0到5的数字死循环的几种实现方式注意退出循环until循环、与while循环的区别until循环示例while循环方式注意有趣的实例批量建立用户批量删除用户猜价格游戏密码输入验证说明while循环与until......
  • 109.微软邮箱强制要求使用MS Authenticator手机APP但中国没有GooglePlay的处理办法
    109.微软邮箱强制要求使用MSAuthenticator手机APP但中国没有GooglePlay的处理办法  背景: 微软邮箱强制用户使用它的Authenticator手机验证器APP(只能跳过3次), 而大部分中国用户手机上是没有谷歌框架和GooglePlay的,所以导致很多用户无法使用微软企业邮箱微软自己也发现了......
  • linux中,解决使用sudo时,自定义path路径不生效的问题
    问题当我们在非root用户下,需要使用root权限的时候,通常在前面加sudo就可以了但是,今天遇到了一个小问题,就是我明明已经配置了go的bin目录在PATH变量中,还是配置在/etc/profile中,在root用户下,是可以执行go命令的按理说,用sudogo应该也是没问题的但是,我发现,当我......
  • 安装python教程详解-(Linux和Windows11安装python)
    一、Linux编译安装Python3.12.5python官网地址:WelcometoPython.org1.1安装python环境1.1.1安装开发工具包和依赖#yum-ygroupinstall"DevelopmentTools" #yum-yinstallgcczlibzlib-devellibffilibffi-develreadline-developenssl-developenssl11ope......
  • Linux上网配置-CentOS7
    上网配置思路1.确认虚拟机的网络适配器为桥接模式2.网卡配置文件是否存在并启用网卡接口3.网卡配置文件详解:静态IP地址、子网掩码、默认网关、物理地址以及DNS4.局域网的其他物理机能远程该虚拟机5.虚拟机ping通外网一、确认虚拟机的网络适配器为桥接模式问题1.为什么......