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

news2024/11/27 18:36:15

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.coloradmin.cn/o/1146369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux两条服务器实现相互免密登录

1.准备两台虚拟机&#xff0c;一台充当服务器端&#xff08;server&#xff09;&#xff0c;一台充当客户端&#xff08;client&#xff09; 服务器端&#xff08;server&#xff09;&#xff1a;192.168.75.139 客户端&#xff08;client&#xff09;&#xff1a;192.168.75…

腾讯云和阿里云双11优惠大战,服务器价格相差1块钱?

2023双十一优惠活动来了&#xff0c;同配置轻量应用服务器2核2G3M带宽&#xff0c;阿里云87元一年&#xff0c;腾讯云88元一年&#xff0c;阿里云不限制月流量&#xff0c;腾讯云限制200GB月流量&#xff0c;阿里云系统盘是50GB高效云盘&#xff0c;腾讯云是40GB SSD云硬盘&…

redis6.0源码分析:跳表skiplist

文章目录 前言什么是跳表跳表&#xff08;redis实现&#xff09;的空间复杂度相关定义 跳表&#xff08;redis实现&#xff09;相关操作创建跳表插入节点查找节点删除节点 前言 太长不看版 跳跃表是有序集合zset的底层实现之一&#xff0c; 除此之外它在 Redis 中没有其他应用。…

LED主流光源-高均匀条形光源

&#xff08;1&#xff09;产品特点&#xff1a; ① 高均匀条形照明光源&#xff0c;可制作长度最长为 2000mm 的光源&#xff1b; ② 可用 M3 螺纹孔安装&#xff0c;也可以在三个挤型槽内插入 M3 螺母安装。 &#xff08;2&#xff09;应用领域&#xff1a; ① 电子元件识别与…

掌握Python:开启未来的大门

Python&#xff0c;一门以其简洁性和多才多艺而著称的编程语言&#xff0c;正成为未来的关键技能之一。随着数字时代的到来&#xff0c;Python的发展前景愈发广泛&#xff0c;而且其易学性吸引着越来越多的学习者。 1.Python的发展前景&#xff1a; Python在数据科学、人工智能…

任正非说:我们要改善和媒体的关系,而不是要利用媒体,不要自以为聪明。

嗨&#xff0c;你好&#xff01;这是华研荟【任正非说】系列的第22篇文章&#xff0c;让我们继续聆听任正非先生的真知灼见&#xff0c;学习华为的管理思想和管理理念。 一、我曾经在与一个世界著名公司&#xff0c;也是我司全方位的竞争对手的合作时讲过&#xff0c;我是拉宾的…

【数学基础】【进制转换】十进制转其他进制、其他进制转十进制

十进制转其他进制 JavaScript实现 const convert (num,base2)>{return !num?0:convert(~~(num/base),base)*10(num%base); } convert(8,2) // 1000 convert(8,8) // 10 convert(8,16) // 8其他进制转十进制 JavaScript实现 const reconvert (num,base2,curr1)>{retu…

代码随想录算法训练营第4天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交 、142.环形链表II

JAVA语言编写 24. 两两交换链表中的节点 谷歌、亚马逊、字节、奥多比、百度 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。…

浙大网新:重视AI驱动,就是重视未来发展

【科技明说 &#xff5c; 重磅专题】 对于浙大网新在AI方面的发展情况&#xff0c;我是看到一个消息之后才开始有了关注&#xff0c;之前总感觉浙大网新在AI方面战略雷声大雨点小&#xff0c;然而当我看到这个消息后才发现&#xff0c;浙大网新其实也非常重视AI方面的发展。 …

【微信小程序】WXML的模板语法与WXSS模板样式

&#x1f5a5;️&#x1f5a5;️&#x1f5a5;️ 博主主页&#xff1a; &#x1f449;&#x1f3fb; &#x1f449;&#x1f3fb; &#x1f449;&#x1f3fb; 糖 &#xff0d;O&#xff0d; &#x1f6a9;&#x1f6a9;&#x1f6a9;微信小程序专栏&#xff1a;微信小程序 &…

聚量推客升级啦,加入了外卖cps、话费充值等

“聚量推客”升级啦&#xff0c;加入了生活cps模块&#xff0c;包含美团外卖cps、滴滴打车出行cps、电影票推广、话费充值等cps推广场景&#xff0c;聚量推客不止是app地推拉新和网推拉新平台&#xff0c;更是一个 综合性推广平台&#xff0c;未来会接入越来越多的推广场景&…

OpenCV官方教程中文版 —— Hough 直线变换

OpenCV官方教程中文版 —— Hough 直线变换 前言一、原理二、OpenCV 中的霍夫变换三、Probabilistic Hough Transform 前言 目标 • 理解霍夫变换的概念 • 学习如何在一张图片中检测直线 • 学习函数&#xff1a;cv2.HoughLines()&#xff0c;cv2.HoughLinesP() 一、原理…

基础课13——数据异常处理

数据异常是指数据不符合预期或不符合常识的情况。数据异常可能会导致数据分析结果不准确&#xff0c;甚至是错误&#xff0c;因此在进行数据分析之前需要对数据进行清洗和验证。 常见的数据异常包括缺失值、重复值、异常值等。 缺失值是指数据中存在未知值或未定义的值&#…

Winform 多语言化快速解析替换工具-1分钟一个界面

随着业务的扩展&#xff0c;有的软件有多语言化的需求。那么如果软件已经很多写死的文字内容如何快速进行语言化替换呢&#xff0c;一个一个去改工作量太大。 于是开发了个小工具用来替换现有内容并生成语音包&#xff0c;原理就是采用正则表达式进行匹配控件关键字以及中文进…

使用MLC-LLM将RWKV 3B模型跑在Android手机上

0x0. 前言 这篇文章主要是填一下 MLC-LLM 部署RWKV World系列模型实战&#xff08;3B模型Mac M2解码可达26tokens/s&#xff09; 这里留下来的坑&#xff0c;这篇文章里面介绍了如何使用 MLC-LLM 在A100/Mac M2上部署 RWKV 模型。但是探索在Android端部署一个RWKV对话模型的ap…

宇信科技:强势行业加速融入AIGC,同时做深做细

【科技明说 &#xff5c; 重磅专题】 大家可能没有想到&#xff0c;一向对外低调行事的宇信科技&#xff0c;在AIGC方面2023年就已经训练出了适配金融场景的垂直模型&#xff0c;并应用到了各产品线上&#xff0c;同时结合通用大模型预研了宇信金融系统编程大模型。宇信金融系…

IOC课程整理-15 Spring 类型转换

1. Spring 类型转换的实现 2. 使用场景 3. 基于 JavaBeans 接口的类型转换 4. Spring 內建 PropertyEditor 扩展 5. 自定义 PropertyEditor 扩展 6. Spring PropertyEditor 的设计缺陷 7. Spring 3 通用类型转换接口 8. Spring 內建类型转换器 9. Converter 接口的局限性 10. G…

Azure - 机器学习:使用 Apache Spark 进行交互式数据整理

目录 本文内容先决条件使用 Apache Spark 进行交互式数据整理Azure 机器学习笔记本中的无服务器 Spark 计算从 Azure Data Lake Storage (ADLS) Gen 2 导入和整理数据从 Azure Blob 存储导入和处理数据从 Azure 机器学习数据存储导入和整理数据 关注TechLead&#xff0c;分享AI…

深入理解Linux网络笔记(五):深度理解本机网络IO

本文为《深入理解Linux网络》学习笔记&#xff0c;使用的Linux源码版本是3.10&#xff0c;网卡驱动默认采用的都是Intel的igb网卡驱动 Linux源码在线阅读&#xff1a;https://elixir.bootlin.com/linux/v3.10/source 4、深度理解本机网络IO 1&#xff09;、跨机网络通信过程 …

快速排序——及其改进

hoare版本&#xff08;原始版本&#xff09;&#xff1a; 思想&#xff1a;树的遍历思想&#xff0c;先把数组第一个数作为KEY,然后left从左到右&#xff0c;right从右到左一起走&#xff0c;当left找到比key大的值时停下来&#xff0c;当right找到比key小的值时停下来&#xf…