Linux学习第25天:Linux 阻塞和非阻塞 IO 实验(二): 挂起

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


        为方便和上一节的衔接,在正式开始学习前,先把本节的思维导图引入:

二、阻塞IO实验

1.硬件原理图分析

2.实验程序

#define IMX6UIRQ_NAME "blockio" /* 名字 */
//修改设备文件名字为“blockio”,当驱动程序加载成功以后就会在根文件系统中出现一个名为“/dev/blockio”的文件。
wait_queue_head_t r_wait; /* 读等待队列头 */
//在设备结构体中添加一个等待队列头 r_wait,因为在 Linux 驱动中处理阻塞 IO需要用到等待队列。
/* 唤醒进程 */
if(atomic_read(&dev->releasekey)) { /* 完成一次按键过程 *//* wake_up(&dev->r_wait); */wake_up_interruptible(&dev->r_wait);}
//定时器中断处理函数执行,表示有按键按下,先在 107 行判断一下是否是一次有效的按键,如果是的话就通过 wake_up 或者 wake_up_interruptible 函数来唤醒等待队列r_wait。
/* 初始化等待队列头 */
init_waitqueue_head(&imx6uirq.r_wait);
//采用等待事件来处理 read 的阻塞访问, wait_event_interruptible 函数等待
//releasekey 有效,也就是有按键按下。如果按键没有按下的话进程就会进入休眠状态,因为采用
//了 wait_event_interruptible 函数,因此进入休眠态的进程可以被信号打断。200 #if 0
201 /* 加入等待队列,等待被唤醒,也就是有按键按下 */
202 ret = wait_event_interruptible(dev->r_wait,
atomic_read(&dev->releasekey));
203 if (ret) {
204 goto wait_error;
205 }
206 #endif
208 DECLARE_WAITQUEUE(wait, current); /* 定义一个等待队列 */
209 if(atomic_read(&dev->releasekey) == 0) { /* 没有按键按下 */
210 add_wait_queue(&dev->r_wait, &wait); /* 添加到等待队列头 */
211 __set_current_state(TASK_INTERRUPTIBLE);/* 设置任务状态 */
212 schedule(); /* 进行一次任务切换 */
213 if(signal_pending(current)) { /* 判断是否为信号引起的唤醒 */
214 ret = -ERESTARTSYS;
215 goto wait_error;
216 }
217 __set_current_state(TASK_RUNNING); /*设置为运行状态 */
218 remove_wait_queue(&dev->r_wait, &wait); /*将等待队列移除 */

        首先使用 DECLARE_WAITQUEUE 宏定义一个等待队列,如果没有按键按下的话就使用 add_wait_queue 函数将当前任务的等待队列添加到等待队列头 r_wait 中。随后调用__set_current_state 函数设置当前进程的状态为 TASK_INTERRUPTIBLE,也就是可以被信
号打断。接下来调用 schedule 函数进行一次任务切换,当前进程就会进入到休眠态。如果有按
键按下,那么进入休眠态的进程就会唤醒,然后接着从休眠点开始运行。在这里也就是从第 213
行开始运行,首先通过 signal_pending 函数判断一下进程是不是由信号唤醒的,如果是由信号
唤醒的话就直接返回-ERESTARTSYS 这个错误码。如果不是由信号唤醒的(也就是被按键唤醒
的)那么就在 217 行调用__set_current_state 函数将任务状态设置为 TASK_RUNNING,然后在
218 行调用 remove_wait_queue 函数将进程从等待队列中删除。

3.运行测试

1)、编译驱动程序和测试APP

①、编译驱动程序
1 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imxrel_imx_4.1.15_2.1.0_ga_alientek
......
4 obj-m := blockio.o//修改变量的值
......
11 clean:
12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

make -j32
编译成功以后就会生成一个名为“blockio.ko”的驱动模块文件。


②、编译测试APP
arm-linux-gnueabihf-gcc blockioApp.c -o blockioApp

2)、运行测试

depmod //第一次加载驱动的时候需要运行此命令
modprobe blockio.ko //加载驱动

驱动加载成功以后使用如下命令打开 blockioApp 这个测试 APP,并且以后台模式运行:
 

./blockioApp /dev/blockio &

        当按下 KEY0 按键以后 blockioApp 这个测试 APP 就会打印出按键值。输入“top”命令,查看 blockioAPP 这个应用 APP 的 CPU 使用率。

        使用“kill -9 PID”即可“杀死”指定 PID 的进程,例如杀死149进程命令为:kill -9 149

三、非阻塞IO实验

1.硬件原理图分析

2.实验程序

1)、驱动程序编写

#define IMX6UIRQ_NAME "noblockio" /* 名字 */
//修改设备文件名字为“noblockio”,当驱动程序加载成功以后就会在根文件系统
//中出现一个名为“/dev/noblockio”的文件。
 if (filp->f_flags & O_NONBLOCK) { /* 非阻塞访问 */if(atomic_read(&dev->releasekey) == 0) /* 没有按键按下 */return -EAGAIN;

        判断是否为非阻塞式读取访问,如果是的话就判断按键是否有效,也就是判断一下有没有按键按下,如果没有的话就返回-EAGAIN。

235 /*
236 * @description : poll 函数,用于处理非阻塞访问
237 * @param - filp : 要打开的设备文件(文件描述符)
238 * @param - wait : 等待列表(poll_table)
239 * @return : 设备或者资源状态,
240 */
241 unsigned int imx6uirq_poll(struct file *filp,
struct poll_table_struct *wait)
242 {
243 unsigned int mask = 0;
244 struct imx6uirq_dev *dev = (struct imx6uirq_dev *)
filp->private_data;
245
246 poll_wait(filp, &dev->r_wait, wait);
247
248 if(atomic_read(&dev->releasekey)) { /* 按键按下 */
249 mask = POLLIN | POLLRDNORM; /* 返回 PLLIN */
250 }
251 return mask;
252 }

        imx6uirq_poll 函数就是 file_operations 驱动操作集中的 poll 函数,当应用程序调用 select 或者 poll 函数的时候 imx6uirq_poll 函数就会执行。第 246 行调用 poll_wait 函数将等待队列头添加到 poll_table 中,第 248~250 行判断按键是否有效,如果按键有效的话就向应用程序返回 POLLIN 这个事件,表示有数据可以读取。

.poll = imx6uirq_poll,//设置 file_operations 的 poll 成员变量为 imx6uirq_poll。

2)、测试APP编写

52 #if 0
53 /* 构造结构体 */
54 fds.fd = fd;
55 fds.events = POLLIN;
56
57 while (1) {
58 ret = poll(&fds, 1, 500);
59 if (ret) { /* 数据有效 */
60 ret = read(fd, &data, sizeof(data));
61 if(ret < 0) {
62 /* 读取错误 */
63 } else {
64 if(data)
65 printf("key value = %d \r\n", data);
66 }
67 } else if (ret == 0) { /* 超时 */
68 /* 用户自定义超时处理 */
69 } else if (ret < 0) { /* 错误 */
70 /* 用户自定义错误处理 */
71 }
72 }
73 #endif

        使用 poll 函数来实现非阻塞访问。

75 while (1) {
76 FD_ZERO(&readfds);
77 FD_SET(fd, &readfds);
78 /* 构造超时时间 */
79 timeout.tv_sec = 0;
80 timeout.tv_usec = 500000; /* 500ms */
81 ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
82 switch (ret) {
83 case 0: /* 超时 */
84 /* 用户自定义超时处理 */
85 break;
86 case -1: /* 错误 */
87 /* 用户自定义错误处理 */
88 break;
89 default: /* 可以读取数据 */
90 if(FD_ISSET(fd, &readfds)) {
91 ret = read(fd, &data, sizeof(data));
92 if (ret < 0) {
93 /* 读取错误 */
94 } else {
95 if (data)
96 printf("key value=%d\r\n", data);
97 }
98 }
99 break;
100 }
101 }

        使用 select 函数来实现非阻塞访问。



3.运行测试

1)、编译驱动程序和测试APP

①、编译驱动程序
obj-m := noblockio.o

        make -j32编译成功以后就会生成一个名为“noblockio.ko”的驱动模块文件。

②、编译测试APP
arm-linux-gnueabihf-gcc noblockioApp.c -o noblockioApp

        编译成功以后就会生成 noblcokioApp 这个应用程序。

2)、运行测试

depmod //第一次加载驱动的时候需要运行此命令
modprobe noblockio.ko //加载驱动

驱动加载成功以后使用如下命令打开 noblockioApp 这个测试 APP,并且以后台模式运行:
 

./noblockioApp /dev/noblockio &

        当按下 KEY0 按键以后 noblockioApp 这个测试 APP 就会打印出按键值。输入“top”命令,
查看 noblockioAPP 这个应用 APP 的 CPU 使用率。

四、总结

        本篇笔记为本节的后半部分,主要内容为阻塞IO和非阻塞IO的驱动开发实现。


本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/154958.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rqt-robot-steering控制面板

目录 安装rqt-robot-steering控制面板&#xff08;已安装则跳过&#xff09;新建一个终端&#xff0c;先启动ros系统再新建一个终端&#xff0c;运行rqt-robot-steering再打开一个终端&#xff0c;验证使用控制面板控制小乌龟移动 安装rqt-robot-steering控制面板&#xff08;已…

多模态对比语言图像预训练CLIP:打破语言与视觉的界限

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

CSS3盒模型

CSS3盒模型规定了网页元素的显示方式&#xff0c;包括大小、边框、边界和补白等概念。2015年4月&#xff0c;W3C的CSS工作组发布了CSS3基本用户接口模块&#xff0c;该模块负责控制与用户接口界面相关效果的呈现方式。 1、盒模型基础 在网页设计中&#xff0c;经常会听到内容…

Android底层摸索改BUG(二):Android系统移除预置APP

首先我先提供以下博主博文&#xff0c;对相关知识点可以提供理解、解决、思考的 Android 系统如何预装第三方应用以及常见问题汇集android Android.mk属性说明及预置系统app操作说明系Android 中去除系统原生apk的方法 取消预置APK方法一&#xff1a; 其实就是上面的链接3&a…

qt-C++笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度

qt-C笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度 code review! 文章目录 qt-C笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度1.运行2.文件结构3.main.cc4.main.pro5.a.txt6.b.txt7.上述代码中QVBoxLayout&#xff0c…

SQL SERVER 表分区

1. 概要说明 SQL SERVER的表分区功能是为了将一个大表&#xff08;表中含有非常多条数据&#xff09;的数据根据某条件&#xff08;仅限该表的主键&#xff09;拆分成多个文件存放&#xff0c;以提高查询数据时的效率。创建表分区的主要步骤是 1、确定需要以哪一个字段作为分…

[云原生1. ] 使用Docker-compose一键部署Wordpress平台

文章目录 1. Docker-compose概述1.1 简介1.2 docker-compose 的三大概念1.3 docker-compose配置模板文件常用的字段1.4 docker-compose 常用命令及格式 2. YAML 文件的详细介绍及编写注意事项2.1 简介2.2 yaml的特性2.2.1 语法特点2.2.2 数据结构2.2.3 引号的区别2.2.4 内置类型…

我用好说 AI 做二次元人设

你有没有想过自己做一部原创作品&#xff1f; 就像开发《星露谷物语》那样&#xff0c;自己把控作品的 角色、故事、载体、宣传 等方方面面&#xff0c;让 idea 不再只是灵光一闪。 以前是 “万事开头难”&#xff0c;可能第一步都举步维艰。但现在有了 AI 就不同了&#xff…

品牌加盟商做信息展示预约小程序的效果如何

很多行业都有中部或头部品牌&#xff0c;对实体品牌企业来说想要快速高效发展&#xff0c;除了多地直营店外还需要招募加盟商进而提升生意营收。 因此线上渠道变得尤为重要&#xff0c;除了网站外&#xff0c;小程序是连接多平台生态很好的工具&#xff0c;随时打开、直接触达…

中国各城市土地利用类型(城市功能)矢量数据集(shp)

中国各城市土地利用类型(城市功能)数据集 时间:2018年 全国范围的城市用地类型数据(居住/商业/交通用地等共计11类) 分类:居住用地、商业用地、工业用地、医疗设施用地、体育文化设施用地、交通场站用地、绿地等用地类型 含城市编码、一级分类5个、二级分类11个 数据按…

LeetCode刷题:27.移除链表元素

文章目录 ⭐️27.移除链表元素⭐️&#x1f510;题目描述&#x1f4a1;解题思路&#x1f511;代码 本题的题解代码是用C语言编写的。 &#x1f4d2;博客主页&#xff1a;2023Fighting的博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;…

灯串上亚马逊加拿大合规标准CSA认证如何办理?

灯串 灯串和配件都是插头连接的便携式、临时性商品&#xff0c;最大额定输入电压为 120 伏。 本政策适用于季节性照明、装饰性灯具以及灯串。 亚马逊灯串政策 根据亚马逊的要求&#xff0c;所有季节性和装饰性灯串均应经过检测&#xff0c;并且遵守下列法规、标准和要求&…