linux环形缓冲区kfifo实践2:配合等待队列使用

news2024/11/26 0:38:57

基础

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

初始化等待队列:init_waitqueue_head

深挖init_waitqueue_head宏的定义可知,传递给它的参数q是一个wait_queue_head_t类型的指针。

init_waitqueue_head的参数q是一个指针

#define init_waitqueue_head(q)				\
	do {						\
		static struct lock_class_key __key;	\
							\
		__init_waitqueue_head((q), #q, &__key);	\
	} while (0)
extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *);

等待队列 

/**
 * wait_event_interruptible - sleep until a condition gets true
 * @wq: the waitqueue to wait on
 * @condition: a C expression for the event to wait for
 *
 * The process is put to sleep (TASK_INTERRUPTIBLE) until the
 * @condition evaluates to true or a signal is received.
 * The @condition is checked each time the waitqueue @wq is woken up.
 *
 * wake_up() has to be called after changing any variable that could
 * change the result of the wait condition.
 *
 * The function will return -ERESTARTSYS if it was interrupted by a
 * signal and 0 if @condition evaluated to true.
 */
#define wait_event_interruptible(wq, condition)				\
({									\
	int __ret = 0;							\
	might_sleep();							\
	if (!(condition))						\
		__ret = __wait_event_interruptible(wq, condition);	\
	__ret;								\
})
/*
 * The below macro ___wait_event() has an explicit shadow of the __ret
 * variable when used from the wait_event_*() macros.
 *
 * This is so that both can use the ___wait_cond_timeout() construct
 * to wrap the condition.
 *
 * The type inconsistency of the wait_event_*() __ret variable is also
 * on purpose; we use long where we can return timeout values and int
 * otherwise.
 */

#define ___wait_event(wq, condition, state, exclusive, ret, cmd)	\
({									\
	__label__ __out;						\
	wait_queue_t __wait;						\
	long __ret = ret;	/* explicit shadow */			\
									\
	INIT_LIST_HEAD(&__wait.task_list);				\
	if (exclusive)							\
		__wait.flags = WQ_FLAG_EXCLUSIVE;			\
	else								\
		__wait.flags = 0;					\
									\
	for (;;) {							\
		long __int = prepare_to_wait_event(&wq, &__wait, state);\
									\
		if (condition)						\
			break;						\
									\
		if (___wait_is_interruptible(state) && __int) {		\
			__ret = __int;					\
			if (exclusive) {				\
				abort_exclusive_wait(&wq, &__wait,	\
						     state, NULL);	\
				goto __out;				\
			}						\
			break;						\
		}							\
									\
		cmd;							\
	}								\
	finish_wait(&wq, &__wait);					\
__out:	__ret;								\
})

long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state);

从wait_event_interruptible(wq, condition)到prepare_to_wait_event(&wq, &__wait, state),注意这里是&wq,又知prepare_to_wait_event函数的第一个参数是指针,所以,

从wait_event_interruptible宏的定义深挖可知,wait_event_interruptible的第一个参数不是指针,是传递的结构体变量。

wait_event_interruptible的第一个参数不是指针,是传递的结构体变量

wait_event_interruptible的第一个参数不是指针,是传递的结构体变量

 唤醒队列

wake_up_interruptible宏的定义向下深挖可知,wake_up_interruptible的第一个参数是指针

wake_up_interruptible的第一个参数是指针。

wake_up_interruptible的第一个参数是指针。

#define wake_up_interruptible(x)	__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);

驱动代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/kfifo.h>
#include <linux/wait.h>

#define DEBUG_INFO(format, ...) printk("%s:%d -- "format"\n",\
__func__,__LINE__,##__VA_ARGS__)

struct ch5_kfifo_struct{
    struct miscdevice misc;
    struct file_operations fops;
    struct kfifo fifo;
    char buf[64];
    wait_queue_head_t read_queue;
    wait_queue_head_t write_queue;
};

static int ch5_open (struct inode *inode, struct file *file){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)container_of(file->f_op,struct ch5_kfifo_struct,fops);
    file->private_data = p;
    DEBUG_INFO("major = %d, minor = %d\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
    DEBUG_INFO("name = %s",p->misc.name);
    return 0;
}

static int ch5_release (struct inode *inode, struct file *file){
    DEBUG_INFO("close");
    return 0;
}

static ssize_t ch5_read (struct file *file, char __user *buf, size_t size, loff_t *pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int ret;
    int actual_readed = 0;

    if(kfifo_is_empty(&p->fifo)){
        if(file->f_flags & O_NONBLOCK){
            DEBUG_INFO("kfifo is null");
            return -EAGAIN;
        }
        ret = wait_event_interruptible(p->read_queue,kfifo_is_empty(&p->fifo) == 0);
        if(ret){
            DEBUG_INFO("wait_event_interruptible error");
            return ret;
        }
        DEBUG_INFO("");
    }
    
    ret = kfifo_to_user(&p->fifo, buf, size, &actual_readed);
    if (ret){
        DEBUG_INFO("kfifo_to_user error");
		return -EIO;
    }
    
    DEBUG_INFO("size = %d,actual_readed = %d\n",size,actual_readed);

    if (!kfifo_is_full(&p->fifo)){
        wake_up_interruptible(&p->write_queue);
    }

    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_readed);
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("read p->buf = %s\n",p->buf);
    }
    *pos = *pos + actual_readed;
    return actual_readed;
}
static ssize_t ch5_write (struct file *file, const char __user *buf, size_t size, loff_t* pos){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)file->private_data;
    int actual_writed = 0;
    int ret;
    if(kfifo_is_full(&p->fifo)){
        if(file->f_flags & O_NONBLOCK){
            DEBUG_INFO("kfifo is full");
            return -EAGAIN;
        }
        ret = wait_event_interruptible(p->write_queue, kfifo_is_full(&p->fifo) == 0);
        if(ret){
            DEBUG_INFO("wait_event_interruptible error");
            return ret;
        }
        DEBUG_INFO("");
    }
    ret = kfifo_from_user(&p->fifo, buf, size, &actual_writed);
    if (ret){
        DEBUG_INFO("kfifo_from_user error");
		return -EIO;
    }
    
    DEBUG_INFO("actual_writed = %d\n",actual_writed);

    if (!kfifo_is_empty(&p->fifo)){
        wake_up_interruptible(&p->read_queue);
    }
    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_writed);
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("write:p->buf = %s\n",p->buf);
    }
    *pos = *pos + actual_writed;
    return actual_writed;
}

struct ch5_kfifo_struct ch5_kfifo = {
    .misc = { 
        .name = "ch5-04-block",
        .minor = MISC_DYNAMIC_MINOR,
    },
    .fops = {
        .owner = THIS_MODULE,
        .read = ch5_read,
        .write = ch5_write,
        .open = ch5_open,
        .release = ch5_release,
    },
};

static int __init ch5_init(void){
    int ret = 0;
    DEBUG_INFO("start init\n");
    ch5_kfifo.misc.fops = &ch5_kfifo.fops;
    ret = kfifo_alloc(&ch5_kfifo.fifo,
				8,
				GFP_KERNEL);
    if (ret) {
        DEBUG_INFO("kfifo_alloc error: %d\n", ret);
        ret = -ENOMEM;
        return ret;
    }
    DEBUG_INFO("kfifo_alloc size = %d",kfifo_avail(&ch5_kfifo.fifo));

    init_waitqueue_head(&ch5_kfifo.read_queue);
    init_waitqueue_head(&ch5_kfifo.write_queue);

    ret = misc_register(&ch5_kfifo.misc);
    if(ret < 0){
        DEBUG_INFO("misc_register error: %d\n", ret);
        return ret;
    }
    DEBUG_INFO("misc_register ok");
    return 0;
}

static void __exit ch5_exit(void){
    DEBUG_INFO("exit\n");
    misc_deregister(&ch5_kfifo.misc);
    kfifo_free(&ch5_kfifo.fifo);
}

module_init(ch5_init);
module_exit(ch5_exit);

MODULE_LICENSE("GPL");

测试结果:

小结 

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

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

相关文章

pytest 编写规范

一、pytest 编写规范 1、介绍 pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要特点有以下几点&#xff1a; 1、简单灵活&#xff0c;容易上手&#xff0c;文档丰富&#xff1b;2、支持参数化&#xff0c;可以细粒度地控制要测试的测试用例&#xff1b;3、能够…

分享之python 协程

线程和进程的操作是由程序触发系统接口&#xff0c;最后的执行者是系统&#xff1b;协程的操作则是程序员。 协程存在的意义&#xff1a;对于多线程应用&#xff0c;CPU通过切片的方式来切换线程间的执行&#xff0c;线程切换时需要耗时&#xff08;保存状态&#xff0c;下次继…

Redux中reducer 中为什么每次都要返回新的state!!!

Redux中reducer 中为什么每次都要返回新的state&#xff01;&#xff01;&#xff01; 最近在学习react相关的知识&#xff0c;学习redux的时候遇到看到一个面试题&#xff1a; 如果Redux没返回新的数据会怎样&#xff1f; 这就是要去纠结为什么编写reducer得时候为什么不允许直…

LT8711HE 是一款高性能的Type-C/DP1.2到HDMI2.0转换器

LT8711HE 1.描述 LT8711HE是一种高性能的Type-C/DP1.2到HDMI2.0转换器&#xff0c;设计用于连接USB Type-C源或DP1.2源到HDMI2.0接收器。LT8711HE集成了一个DP1.2兼容的接收器&#xff0c;和一个HDMI2.0兼容的发射机。此外&#xff0c;还包括两个CC控制器&#xff0c;用于CC通…

Linux Maven 安装与配置

目录 Maven 下载 解压缩下载的文件 移动Maven文件夹 配置环境变量 验证安装 注意 Maven 下载 官方地址 Maven – Download Apache Maven&#xff0c;下载完成后&#xff0c;解压到合适的位置即可&#xff1b; 解压缩下载的文件 解压缩下载的文件&#xff1a; 使用以下命…

Malloc动态内存分配

在C语言中我们会使用malloc来动态地分配内存&#xff0c;这样做的一个主要理由是有些数据结构的大小只有在运行时才能确定。例如&#xff0c;如果你正在编写一个程序&#xff0c;需要用户输入一些数据&#xff0c;但你不知道用户会输入多少数据&#xff0c;那么你就需要使用动态…

VGPU理解与实践包含虚拟机显卡直通,k8s安装,GPU-manager使用与实践测试

提示&#xff1a;文章分为三部分&#xff1a;物理GPU绑定虚拟机、k8s安装、gpu-manager虚拟化实现与测试 文章目录 前言一、什么是VGPU&#xff1f;二、此文件会拆分成三部分&#xff1a;1.物理机显卡直通虚拟机2.安装K8S3.安装GPU-manager、测试全流程 总结 前言 用户角度GPU…

【Linux】HTTPS协议——应用层

1 HTTPS是什么&#xff1f; HTTPS也是⼀个应⽤层协议.是在 HTTP 协议的基础上引⼊了⼀个加密层. HTTP 协议内容都是按照⽂本的⽅式明⽂传输的. 这就导致在传输过程中出现⼀些被篡改的情况. HTTP VS HTTPS 早期很多公司刚起步的时候&#xff0c;使用的应用层协议都是HTTP&am…

7.7 通俗易懂详解稠密连接网络DenseNet 手撕稠密连接网络DenseNet

一.思想 与ResNet的区别 DenseNet这样拼接有什么好处&#xff1f;DenseNet优点 对于每一层&#xff0c;使用前面所有层的特征映射作为输入&#xff0c;并且其自身的特征映射作为所有后续层的输入。 DenseNet的优点: 缓解了消失梯度问题&#xff0c;加强了特征传播&#xff0c…

在java集合HashMap中如何替换某一个键值

replace() 方法替换 hashMap 中是指定的 key 对应的 value。 replace() 方法的语法为&#xff1a; hashmap.replace(K key, V newValue) 或 hashmap.replace(K key, V oldValue, V newValue)示例代码如下&#xff08;把hashmap集合中的值为USA 的记录替换 成“US”&#xff0…

2023牛客暑期多校训练营7(C/I/M)

目录 C.Beautiful Sequence I.We Love Strings M.Writing Books C.Beautiful Sequence 思路&#xff1a;显然若得到了a[1]&#xff0c;则整个序列a我们都知道了。所以我们要求出第k大的a[1]&#xff0c;这个可以利用序列a为不递减序列的性质来得出。 首先&#xff0c;由题…

Unity开发笔记:将Texture2D裁剪出指定圆角用来输出png等图片

学习记录整理&#xff0c;自用&#xff0c;也希望能帮助到有相同需求的人。 圆角原理见大佬的博客&#xff1a; 圆角原理 简单来说就是将图片分成四个区域&#xff0c;找出拐角处的拐子的设置为透明 ![](https://img-blog.csdnimg.cn/a788825545614816895a9cca42ddc4a9.png 如…

Feign实现远程调用

文章目录 Feign引入依赖添加注解编写Feign的客户端测试自定义配置配置文件方式Java代码方式 Feign使用优化引入依赖配置连接池 总结 Feign Feign是一个基于Java的声明式Web服务客户端&#xff0c;由Netflix开发。它简化了使用RESTful API进行远程服务调用的过程&#xff0c;并…

SketchUp Pro 2023 for Mac(草图大师)

SketchUp Pro 2023 for Mac提供了简单易学的用户界面和强大的工具集&#xff0c;使用户可以快速创建复杂的3D模型。其中包括智能绘图工具、自动生成几何体、高级纹理编辑器、实时阴影、交互式地形建模工具等功能。 一、创建形象化您的想法 手工绘制的乐趣。超级智能的3D建模软…

IDEA搭建Springboot项目

一、配置Maven&#xff08;参考Maven配置教程&#xff09; 注意&#xff1a; 1.maven版本的选择&#xff0c;一般情况下&#xff0c;不建议下载最新版本&#xff0c;这种会遇见很多没有必要的麻烦&#xff01;如我在使用最新版本apache-maven-3.9.0的时候就遇见了不知名BUG。 …

【C++】开源:abseil-cpp基础组件库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍abseil-cpp基础组件库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#…

亚马逊公告:订单存档政策调整,超过两年将于9月起存档

站斧浏览器获悉&#xff1a; 亚马逊新公告&#xff1a;2023年9月起&#xff0c;亚马逊美国站和欧洲站宣布将调整订单数据存档政策。这一政策的调整旨在保护客户的个人隐私和数据安全&#xff0c;从而提高客户的购物体验。据悉&#xff0c;所有历时超过两年以上的订单将按月进行…

【C++】AVL(平衡二叉搜索树)树的原理及实现

文章目录 一、引言 二、AVL树的概念 三、AVL树的插入 3、1 AVL树的简单插入 3、2 旋转分类 3、2、1 新节点插入较高右子树的右侧&#xff1a;左单旋 3、2、2 新节点插入较高左子树的左侧&#xff1a;右单旋 3、2、3 新节点插入较高左子树的右侧&#xff1a;左右双旋&#xff08…

【Eureka技术指南】「SpringCloud」从源码层面让你认识Eureka工作流程和运作机制(下)

原理回顾 Eureka Server 提供服务注册服务&#xff0c;各个节点启动后&#xff0c;会在Eureka Server中进行注册&#xff0c;这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息&#xff0c;服务节点的信息可以在界面中直观的看到。Eureka Client 是一个Java 客…

SAP Fiori 将GUI中的自开发报表添加到Fiori 工作台

1. 首先我们在workbench 中开发一个GUI report 这里我们开发的是一个简单的物料清单报表 2. 分配一个事务代码。 注意这里的SAP GUI for HTML 要打上勾 3. 创建语义对象&#xff08; Create Semantic Object&#xff09; 事物代码&#xff1a; path: SAP NetWeaver ->…