阻塞 IO(BIO)

文章目录

  • 阻塞 IO(BIO)
    • 模型
    • 等待队列头
      • init_waitqueue_head
      • DECLARE_WAIT_QUEUE_HEAD
    • 等待队列项
    • 使用方法
    • 驱动程序
    • 应用程序
    • 模块使用
    • 参考

阻塞 IO(BIO)

模型

在这里插入图片描述

等待队列是内核实现阻塞和唤醒的内核机制。
等待队列以循环链表为基础结构,链表头和链表项分别为等待队列头等待队列元素
整个等待队列由等待队列头进行管理。

等待队列头

等待队列头使用结构体 wait_queue_head_t,定义在 linux/wait.h,结构体原型如下:

struct wait_queue_head {spinlock_t		lock;struct list_head	head;
};
typedef struct wait_queue_head wait_queue_head_t;

等待队列头的初始化有两种方法

init_waitqueue_head

  • 定义一个等待队列头 wait_queue_head_t read_wait
  • 等待 队列头初始化 init_waitqueue_head(&read_wait)

DECLARE_WAIT_QUEUE_HEAD

DECLARE_WAIT_QUEUE_HEAD 宏一次性完成等待队列头的定义和初始化

等待队列项

等待队列项使用结构体 struct wait_queue_entry,定义在 linux/wait.h,结构体原型如下:

struct wait_queue_entry {unsigned int		flags;void			*private;wait_queue_func_t	func;struct list_head	entry;
};

使用方法

  • 初始化等待队列头,并将条件设置为假的(condition=0)
  • 在需要阻塞的地方调用 wait_event 或者 wait_event_interruptible,使进程进入休眠
  • 当条件满足时,需要解除休眠,先将条件设置为真(condition=1),然后调用 wake_up 或者 wake_up_interruptible函数唤醒等待队列中的休眠进程。

驱动程序

#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/wait.h>#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
#define CHRDEVBASE_NUM 1             /* 设备数目 */static char *string_test = "kernel data this tyustli test";typedef struct {dev_t dev_id;          /* 设备号 */struct cdev c_dev;     /* cdev */struct class *class;   /* 类 */struct device *device; /* 设备 */int major;             /* 主设备号 */int minor;             /* 次设备号 */int flag;              /* read flag */char write_buf[100];char read_buf[100];wait_queue_head_t read_wait; /* 读等待队列头 */
} new_chrdev_t;static new_chrdev_t new_chrdev1;static int chrdevbase_open(struct inode *inode, struct file *file)
{file->private_data =container_of(inode->i_cdev, new_chrdev_t, c_dev); /* 设置私有数据 */printk("k: chrdevbase open\r\n");return 0;
}static ssize_t chrdevbase_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;new_chrdev_t *dev = (new_chrdev_t *)file->private_data;wait_event_interruptible(dev->read_wait, dev->flag);memcpy(dev->read_buf, string_test, strlen(string_test));ret = copy_to_user(buf, dev->read_buf, count);if (ret == 0) {printk("k: read data success\r\n");} else {printk("k: read data failed ret = %ld\r\n", ret);}return ret;
}static ssize_t chrdevbase_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;new_chrdev_t *dev = (new_chrdev_t *)file->private_data;ret = copy_from_user(dev->write_buf, buf, count);if (ret == 0) {printk("k: write data success write data is: %s\r\n", dev->write_buf);} else {printk("k: write data failed ret = %ld\r\n", ret);}dev->flag = 1;wake_up_interruptible(&dev->read_wait);return count;
}static int chrdevbase_release(struct inode *inode, struct file *file)
{printk("k: chrdevbase release\r\n");return 0;
}static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};static int __init chrdevbase_init(void)
{int err = 0;err = alloc_chrdev_region(&new_chrdev1.dev_id, 0, CHRDEVBASE_NUM,CHRDEVBASE_NAME);if (err < 0) {printk("k: alloc chrdev region failed err = %d\r\n", err);goto err_chrdev;}/* get major 1 and minor 1 */new_chrdev1.major = MAJOR(new_chrdev1.dev_id);new_chrdev1.minor = MINOR(new_chrdev1.dev_id);printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev1.major,new_chrdev1.minor);new_chrdev1.c_dev.owner = THIS_MODULE;cdev_init(&new_chrdev1.c_dev, &chrdevbase_fops);err = cdev_add(&new_chrdev1.c_dev, new_chrdev1.dev_id, 1);if (err < 0) {printk("k: cdev add failed err = %d\r\n", err);goto err_cdev_add;}new_chrdev1.class = class_create("chr_test1");if (IS_ERR(new_chrdev1.class)) {err = PTR_ERR(new_chrdev1.class);goto err_class_create;}new_chrdev1.device = device_create(new_chrdev1.class, NULL,new_chrdev1.dev_id, NULL, "chr_test1");if (IS_ERR(new_chrdev1.device)) {err = PTR_ERR(new_chrdev1.device);goto err_device_create;}/* 初始化等待队列头 */init_waitqueue_head(&new_chrdev1.read_wait);new_chrdev1.flag = 0;printk("k: base module init\r\n");return 0;err_device_create:class_destroy(new_chrdev1.class);
err_class_create:cdev_del(&new_chrdev1.c_dev);
err_cdev_add:unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);
err_chrdev:return err;
}static void __exit chrdevbase_exit(void)
{device_destroy(new_chrdev1.class, new_chrdev1.dev_id);class_destroy(new_chrdev1.class);cdev_del(&new_chrdev1.c_dev);unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);printk("k: base module exit!\r\n");
}module_init(chrdevbase_init);
module_exit(chrdevbase_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */

应用程序

应用程序使用 O_RDWR 默认以阻塞的方式打开

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"static char usrdata[] = { "user data!" };int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if (argc != 3) {printf("u: error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("u: can't open file %s\r\n", filename);return -1;}/* 从驱动文件读取数据 */if (atoi(argv[2]) == 1) {retvalue = read(fd, readbuf, 50);if (retvalue < 0) {printf("u: read file %s failed!\r\n", filename);} else {/*  读取成功,打印出读取成功的数据 */printf("u: read data:%s\r\n", readbuf);}}/* 向设备驱动写数据 */if (atoi(argv[2]) == 2) {memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if (retvalue < 0) {printf("u: write file %s failed!\r\n", filename);}}/* 关闭设备 */retvalue = close(fd);if (retvalue < 0) {printf("u: can't close file %s\r\n", filename);return -1;}return 0;
}

模块使用

模块安装

modprobe my_module

查看设备节点

ls /dev
~ # ls /dev/
chr_test1        ptypc            tty32            tty7
console          ptypd            tty33            tty8
cpu_dma_latency  ptype            tty34            tty9
full             ptypf            tty35            ttyAMA0
gpiochip0        random           tty36            ttyAMA1
gpiochip1        root             tty37            ttyAMA2
gpiochip2        rtc0             tty38            ttyAMA3
gpiochip3        snd              tty39            ttyp0
hwrng            tty              tty4             ttyp1
input            tty0             tty40            ttyp2
kmsg             tty1             tty41            ttyp3

模块使用

~ # /lib/modules/6.5.7+/my_app /dev/chr_test1 1 &
~ # k: chrdevbase open~ # /lib/modules/6.5.7+/my_app /dev/chr_test1 2
k: chrdevbase open
k: write data success write data is: user data!
k: read data success
k: chrdevbase release
~ # u: read data:kernel data this tyustli test
k: chrdevbase release[1]+  Done                       /lib/modules/6.5.7+/my_app /dev/chr_test1 1

参考

  • https://juejin.cn/post/7129070726249709599#heading-0

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

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

相关文章

深入了解UI标签栏设计细节:你不能错过的要点

UI 标签栏的作用有哪些&#xff1f; 导航是移动 UI 中最常见的组成部分&#xff0c;通常放置在 UI 标签栏上&#xff0c;以帮助我们在不同的页面之间切换。UI 标签栏可以保持界面的可控性&#xff0c;并提高可用性。简而言之&#xff0c;UI 标签栏可以加强交互&#xff0c;让用…

轻量Http客户端工具VSCode和IDEA

文章目录 前言Visual Studio Code 的插件 REST Client编写第一个案例进阶&#xff0c;设置变量进阶&#xff0c;设置Token 前言 作为一个WEB工程师&#xff0c;在日常的使用过程中&#xff0c;HTTP请求是必不可少的。我们采用的HTTP工具有如下&#xff1a; Postman Insomnia Ap…

CSS3多列分页属性

CSS3多列 Firefox浏览器支持该属性的形式是-moz-column-count&#xff0c;而基于Webkit的浏览器&#xff0c;例如Safari和Chrome&#xff0c;支持该属性的形式是-webkit-column-count column-count&#xff1a;该属性定义多列文本流中的栏数 语法&#xff1a;column-count:int…

YACS(上海计算机学会竞赛平台)三星级挑战——两数之和

题目描述 给定 n 个整数 a[1]​,a[2]​,⋯,a[n]​&#xff0c;并且保证 a[1​]≤a[2​]≤⋯≤a[n]​ 再给定一个目标值 t&#xff0c;请判断能否找到 a[i]​ 与 a[j]​&#xff0c;ai​aj​t 且 i≠j。 输入格式 第一行&#xff1a;单个整数n&#xff1b; 第二行&#xf…

智能优化算法应用:基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.卷尾猴算法4.实验参数设定5.算法结果6.参考文…

C++ 函数重载、操作符重载

依然是温故而知新&#xff0c;不过现在更多的是以此为乐的心态啦。本篇通过代码实例&#xff0c;展示c函数重载相关知识&#xff0c;包括构造函数的重载、操作符重载等。 在构造函数重载中&#xff0c;给大家带来点稍微提升的用法&#xff0c; 看了不吃亏&#xff0c;看了不上当…

如何快速实现地源热泵远程监控

地源热泵远程监控解决方案 一、项目背景 山东省潍坊市盛世花园小区地源热泵项目是一个先进的供暖与制冷系统&#xff0c;旨在为整个小区提供高效且节能的温控服务。该系统主要由地下管道网络、地源热泵单元以及室内分配系统组成。 针对现有的地源热泵系统的管理和监控问题&a…

110基于matlab的混合方法组合的极限学习机和稀疏表示进行分类

基于matlab的混合方法组合的极限学习机和稀疏表示进行分类。通过将极限学习机&#xff08;ELM&#xff09;和稀疏表示&#xff08;SRC&#xff09;结合到统一框架中&#xff0c;混合分类器具有快速测试&#xff08;ELM的优点&#xff09;的优点&#xff0c;且显示出显着的分类精…

【NAM】《NAM:Normalization-based Attention Module》

NeurIPS-2021 workshop 文章目录 1 Background and Motivation2 Related Work3 Advantages / Contributions4 Method5 Experiments5.1 Datasets and Metrics5.2 Experiments 6 Conclusion&#xff08;own&#xff09; 1 Background and Motivation 注意力机制是近些年视觉领域…

WPF组合控件TreeView+DataGrid之DataGrid封装

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; wpf的功能非常强大&#xff0c;很多控件都是原生的&#xff0c;但是要使用TreeViewDataGrid的组合&#xff0c;就需要我们自己去封装实现。 我们需要的效果如图所示&#x…

[python]python实现对jenkins 的任务触发

目录 关键词平台说明背景一、安装 python-jenkins 库二、code三、运行 Python 脚本四、注意事项 关键词 python、excel、DBC、jenkins 平台说明 项目Valuepython版本3.6 背景 用python实现对jenkins 的任务触发。 一、安装 python-jenkins 库 pip install python-jenkin…

论文解读:Informer-AAAI2021年最佳论文

论文背景 应用背景 训练的是历史数据&#xff0c;但预测的是未来的数据&#xff0c;但是历史数据和未来数据的分布不一定是一样的&#xff0c;所以时间序列应用于股票预测往往不太稳定 动作预测&#xff1a; 基于之前的视频中每一帧动作&#xff0c;预测下一帧这个人要做什么…

Ubuntu 常用命令之 echo 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 echo 是一个在 Ubuntu 系统下常用的命令&#xff0c;主要用于在终端输出字符串或者变量。 echo 的基本语法 echo [option] [string]echo 命令的参数包括 -n&#xff1a;不输出结尾的换行符。-e&#xff1a;启用反斜杠转义字符。…

超级逼真人脸生成,Stable Diffusion的3个关键技巧

大家好&#xff0c;你是否曾想过&#xff0c;为什么别人可以使用AI图像生成技术生成如此逼真的人脸&#xff0c;而自己的尝试却充满了错误和瑕疵&#xff0c;让人一眼看出是假的。尝试过调整提示和设置&#xff0c;但似乎仍无法与他人的质量相匹配。 本文将带大家了解使用Stab…

LeetCode-17 电话号码的字母组合

LeetCode-17 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;d…

硬件产品经理:硬件产品敏捷开发

目录 简介 敏捷 CSDN学院 作者简介 简介 之所以敏捷产品开发流程会越来越普遍。 主要得益于这个方法可以让企业使用更少的资源去开发出令客户满意的新产品。 敏捷开发强调的最重要的一点就是“快”。 也就是要求通过快速迭代来获取频繁的客户反馈。 这就特别适合应对市…

Python教你如何让代码摆脱死循环的困扰!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在编写Python代码时&#xff0c;无限循环是一个常见的问题&#xff0c;可能导致程序陷入死循环&#xff0c;使得代码无法正常执行。这篇博客将介绍一些方法&#xff0c;帮助大家防止和处理无限循环&#xff0c;确…

ansible变量的使用

本章主要介绍playbook中的变量 自定义变量使用变量文件字典变量列表变量facts变量内置变量变量的过滤器 为了能够写出更实用的playbook&#xff0c;需要在playbook中使用变量。下面来讲解playbook 中常见的变量。本章实验都在/home/lduan/demo2下操作&#xff0c;先把 demo2目…

百度网盘资源下载慢解决方法

1、使用百度网盘客户端&#xff0c;设置使用空闲带宽下载 亲测&#xff0c;可以一定程度上解决下载慢的问题&#xff0c;但是对于有些文件下载还是很慢就不清楚为什么了。 2、使用IDM进行下载 &#xff08;1&#xff09;、第一步下载和安装IDM 搜索后&#xff0c;普通下载后安…