内核实验(八):实现O-NONBLOCK非阻塞读写
创始人
2025-05-30 13:21:56
0

一、篇头

继续使用qemu调试内核的实验。本章复习阻塞与非阻塞IO的概念和机制,然后对之前实验(七)的代码做少许修改,来实现非阻塞的IO读写。

二、系列文章

略……

三、实验环境

  • 编译服务器+NFS:ubuntu 22.04
  • Qemu 虚拟机:Linux version 5.15.102 + Buysbox 1.3.36 + ARM_32bit

Qemu 启动命令:qemu-system-arm -nographic -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -initrd …/busybox/rootfs.ext4.img.gz -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb

四、源码

4.1 非阻塞IO与阻塞IO

非阻塞:进程发起I/O系统调用后,如果设备驱动的缓冲区没有数据,那么进程返回一个错误而不会被阻塞。如果驱动缓冲区中有数据,那么设备驱动把数据直接返回给用户进程。

阻塞:进程发起I/O系统调用后,如果设备的缓冲区没有数据,那么需要到硬件I/O中重新获取新数据,进程会被阻塞,也就是睡眠等待。直到数据准备好,进程才会被唤醒,并重新把数据返回给用户空间。

4.2 驱动源码

  • 文件名:linux-stable\my_kmodules\test_7.c
#include 
#include 
#include 
#include 
#include 
#include #define MY_DEV_NAME "my_dev"DEFINE_KFIFO(my_kfifo, char, 128);static int test_6_open(struct inode *inode, struct file *file)
{int major = MAJOR(inode->i_rdev);int minor = MINOR(inode->i_rdev);pr_info("%s: major=%d, minor=%d\n", __func__, major, minor);return 0;
}static int test_6_release(struct inode *inode, struct file *file)
{pr_info("%s \n", __func__);return 0;
}static ssize_t test_6_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{int ret;unsigned int copied_count=0;pr_info("%s \n", __func__);/** (1)add for O_NONBLOCK reading*/if(kfifo_is_empty(&my_kfifo)){if(file->f_flags & O_NONBLOCK){return  -EAGAIN;}}ret = kfifo_to_user(&my_kfifo, buf,  count, &copied_count);if(ret != 0) {return -EFAULT;}//pr_info("%s :%s, count=%d, copied_count=%d\n", __func__, my_kfifo.buf,  count, copied_count);return copied_count;
}static ssize_t test_6_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{int ret;unsigned int copied_count=0;pr_info("%s \n", __func__);/** (1)add for O_NONBLOCK writing*/if(kfifo_is_full(&my_kfifo)){if(file->f_flags & O_NONBLOCK){return  -EAGAIN;}}ret = kfifo_from_user(&my_kfifo, buf, count, &copied_count);if(ret != 0) {return -EFAULT;}//pr_info("%s , my_kfifo.buf=%s\n", __func__, my_kfifo.buf);	return copied_count;}static const struct file_operations test_fops = {.owner = THIS_MODULE,.open = test_6_open,.release = test_6_release,.read = test_6_read,.write = test_6_write
};static struct miscdevice test_6_misc_device ={.minor = MISC_DYNAMIC_MINOR,.name = MY_DEV_NAME,.fops = &test_fops,
};static int __init test_6_init(void)
{int ret;pr_info("test_6_init\n");ret = misc_register(&test_6_misc_device);if (ret != 0 ) {pr_err("failed to misc_register");return ret;}pr_err("Minor number = %d\n", test_6_misc_device.minor);return 0;
}static void __exit test_6_exit(void)
{pr_info("test_6_exit\n");misc_deregister(&test_6_misc_device);
}module_init(test_6_init);
module_exit(test_6_exit);MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("szhou <66176468@qq.com>");
MODULE_DESCRIPTION("test_7, 使用misc、KFIFO开发设备驱动非阻塞设备驱动。");

4.3 APP源码

  • 文件名:linux-stable\my_kmodules\app_test_7.c
#include 
#include 
#include 
#include  //消除 warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
#include  //消除 warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]#define MY_DEV_NAME "/dev/my_dev"int main(int argc, void * argv[])
{int fd;int ret;size_t len;char message[80] = "To test reading and writing FIFO device with O_NONBLOCK.";char *read_buffer;len = sizeof(message);read_buffer = (char *)malloc((size_t)2*len);memset((void *)read_buffer, 0, 2*len);fd = open(MY_DEV_NAME, O_RDWR | O_NONBLOCK);if (fd < 0) {printf("open device %s failded\n", MY_DEV_NAME);return -1;}/*1: 先读一次,但这个时候KFIFO为空,所以会直接返回 */ret = read(fd, read_buffer, (size_t)2*len);printf("read %d bytes\n", ret);printf("read buffer=%s\n", read_buffer);/*2. 写一次数据 */ret = write(fd, message, len);if (ret != len)printf("have write %d bytes\n", ret);/*3. 再写一次数据 */ret = write(fd, message, len);if (ret != len)printf("have write %d bytes\n", ret);/*4. 读取数据,这次因为KFIFO非空,所以可以获得数据 */ret = read(fd, read_buffer, 2*len);printf("read %d bytes\n", ret);printf("read buffer=%s\n", read_buffer);close(fd);
}

4.4 Makefile

  • 文件名:linux-stable\my_kmodules\Makefile
  • 如下,继续追加 test_7.o 即可编译出test_7.ko
KDIR := /home/szhou/works/qemu_linux/linux-stableobj-m := test_1.o test_2.o test_3.o test_4.o  test_5.o test_6.o test_7.o
all :$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) cleanrm -f *.ko

五、编译及部署

(1)执行驱动KO编译
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ make
make -C /home/szhou/works/qemu_linux/linux-stable M=/home/szhou/works/qemu_linux/linux-stable/my_kmodules modules
make[1]: Entering directory '/home/szhou/works/qemu_linux/linux-stable'CC [M]  /home/szhou/works/qemu_linux/linux-stable/my_kmodules/test_7.oMODPOST /home/szhou/works/qemu_linux/linux-stable/my_kmodules/Module.symversCC [M]  /home/szhou/works/qemu_linux/linux-stable/my_kmodules/test_7.mod.oLD [M]  /home/szhou/works/qemu_linux/linux-stable/my_kmodules/test_7.ko
make[1]: Leaving directory '/home/szhou/works/qemu_linux/linux-stable'(2)执行app编译
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ arm-linux-gnueabi-gcc app_test_7.c -o app_test_7 --static(3)将KO和APP存放到NFS共享目录
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ cp test_7.ko app_test_7  ~/works/nfs_share/
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ 

六、运行及测试

(1)启动之前编译组建的QEMU虚拟机
----------------------------------------
Welcome to szhou's tiny Linux
----------------------------------------Please press Enter to activate this console. (2)挂载NFS共享目录
~ #  mount -t nfs -o nolock 192.168.3.67:/home/szhou/works/nfs_share /mnt(3) 加载ko
~ # cd /mnt/
/mnt # insmod test_7.ko 
test_7: loading out-of-tree module taints kernel.
test_6_init
Minor number = 125
/mnt # mdev  -s(4) 运行app测试
/mnt # ./app_test_7 
test_6_open: major=10, minor=125
test_6_read 
read -1 bytes
read buffer=
test_6_write 
test_6_write 
have write 48 bytes
test_6_read 
read 128 bytes
read buffer=To test reading and writing FIFO device with O_NONBLOCK.
test_6_release 
/mnt # 

操作画面如下图:

在这里插入图片描述

相关内容

热门资讯

服装厂管理制度 服装厂管理制度(通用5篇)  在社会发展不断提速的今天,接触到制度的地方越来越多,制度是指要求大家共...
三讲五心征文 三讲五心征文  导语:征文,没有题目、题材、格式的限定,与作文大体上一样,但更好写,因为局限少了很多...
施工队管理规章制度 施工队管理规章制度  在不断进步的社会中,我们都跟制度有着直接或间接的联系,制度泛指以规则或运作模式...
保安班长工作职责 保安班长工作职责篇一:保安队长工作职责一,对所有保安的管理,督导训练及考核。二,每日检查保安值班日记...
数位dp题目总结 数位dp 题目知识点难度2376. 统计特殊整数数位dp模板困难600. 不含连续1的非负整数数位d...
技术实力与社区贡献的双重认可!... 社区成员又添喜讯!近日,经过 Apache IoTDB 项目管理委员会的...
市民文明公约 市民文明公约  建设文明城市,提高市民素质是关键。文明公约的推行,能使市民自觉遵守公民基本道德规范和...
公司会议纪要经典范文 公司会议纪要经典范文  公司会议纪要经典范文(精选12篇)  在平日的学习、工作或生活中,在处理事务...
LIO-SAM实现地面分割思路 本人最近在研究lio-sam,不得不感叹作者Tixiao Shan的实力,...
店长工作职责 店长工作职责店长工作职责1店长是店面的核心人物,店长必须服从公司总部的统一指挥,积极配合总部的各项营...
个人工作履历表格 个人工作履历表格个人工作履历表格照片性别 男 出生日期 1980年9月4日民族 汉 婚姻状况 未 政...
Java注解怎么用 什么是注解 Java的注解(Annotation)是一种元数据ÿ...
脱不下孔乙己的长衫,现代的年轻... “如果我没读过书,我还可以做别的工作,可我偏偏读过书”“学历本该是我的敲...
Python3处理手写笔记 导语利用Python实现手写笔记的压缩与增强。至于起因大概是:这个内容很有趣。。。——...
单位员工工作守则 单位员工工作守则范本(通用10篇)  单位员工工作守则是怎样的?应该怎么去写呢?以下是小编帮大家整理...
公司安全管理规章制度 公司安全管理规章制度(通用10篇)  在社会一步步向前发展的今天,制度在生活中的使用越来越广泛,制度...
师范专业自荐信 师范专业自荐信模板锦集六篇  在当下的社会中,自荐信在我们的生活愈发常见,在写作上,自荐信也具有一定...
企业管理的规章制度 关于企业管理的规章制度(精选5篇)  随着社会一步步向前发展,制度的使用频率呈上升趋势,制度是指一定...
编程题]组队竞赛(Java实现... 🎉🎉🎉点进来你就是我的人了 博主主页:...
用JS+CSS打造你自己的弹幕... 文章目录前言主要内容实现方法DOM方法显现效果代码CANVAS方法显现效果代码总结更多宝藏 前言 ...