驱动学习(十一)异步IO机制

驱动学习(十一)异步IO机制

1. 什么是异步IO机制?

读进程去设备中读数据,设备没有数据可读,那么当前进程继续执行等待通知,若内核检测到设备有数据可读之后,会给读进程发送通知信号,读进程会执行该信号对应的处理函数去读数据。

2. 实现步骤

应用层

A(读数据进程)
	1.注册一个信号处理函数 
		signal(signo,handler)
	2.打开设备文件 
		fd=open("/dev/设备文件名",O_RDWR);
	3.设置文件描述符的宿主为当前进程
	   	fcntl(fd,FD_SETOWN,getpid());
	4.读取文件描述符标志
	   	int flags=fcntl(fd,F_GETFL);
	5.设置文件描述符标志
	  	fcntl(fd,F_SETFL,flags|FASYNC)
		while(1);
        handler--->read  

    注:fcntl是一个系统调用函数,用来获取或者设置文件描述符的的属性
B (写数据进程)
	 1.open("/dev/设备文件名")
     2.write-->驱动对应的write函数-->给A进程发信号
	 3.close

驱动层

1.定义一个全局的异步通知结构体 struct fasync_struct *fasync=NULL;
2.写一个被file_operationsz结构体成员(驱动操作方法结构体).fasync指向的函数:testFasync-->异步通知
	testFasync(int fd,struct file *pFile,int on)异步通知函数
	{
            int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
            作用:(信号的发送方和信号的接收方关联)
            fd:打开设备文件返回的文件描述符
            * filp:指向内核打开的文件
            on:相当于开关 1/0
            *fapp:异步通知结构体指针地址
	}             
	

3. 在file_operationsz结构体成员(驱动操作方法结构体).write指向的testwrite中调用kill_fasync给用户进程A发信号
	void kill_fasync(struct fasync_struct **fp, int sig, int band)
 	**fp:异步通知结构体指针地址
    sig:信号   kill -l     SIGIO
	band:POLL_IN/POLL_OUT(信号携带的指令)
   
    SIGIO(POLL_IN)--->异步通知结构体--》fd-->A进程
	--》signal(SIGIO,handler)-->handler(read)
3. 测试

代码

##### fasync.c 用来读数据

#include <linux/module.h>           //模块驱动的头文件
#include <linux/cdev.h>             //设备信息描述的头文件
#include <linux/fs.h>               //静态申请设备号头文件
#include <linux/kdev_t.h>           //设备号用到的头文件和宏函数
#include <linux/uaccess.h>
#include <linux/device.h>
#include "common.h"
#include <linux/sched.h>
#include <linux/poll.h>

#define BUF_SIZE 100

int major = 0;                      //主设备号
int min = 0;                        //次设备号
int deviceNum = 0;                  //完整设备号
struct cdev* pCdev = NULL;          //描述设备信息的结构体
char *deviceName = "fasync";//设备名
char buff[BUF_SIZE] = "chrdev-test-2022-7-19";
struct class *pClass = NULL;        //设备文件类指针
int devNum = 2;		    	    //设备文件数量
wait_queue_head_t q;                //定义休眠等待队列头
int con = 0;                        //休眠唤醒条件 1唤醒 0休眠
int charCount = 0;                  //实际写入字符数量
struct fasync_struct *fasync = NULL;

int testOpen(struct inode *pNode,struct file *pFile)
{
	printk("------into test open------\n");
	con = 0;
	printk("------leave test open------\n");
	return 0;
}
int testClose(struct inode *pNode,struct file *pFile)
{
	printk("------into test close------\n");
	con = 0;
	printk("------leave test close------\n");
	return 0;
}
ssize_t testRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset)
{
	int res = -1;
	printk("------into testRead------\n");
	if(charCount <= 0)
	{
		if(pFile->f_flags&O_NONBLOCK)
		{
			printk("O_NONBLOCK is setted\n");
			return -EAGAIN;
		}
		else
		{
			wait_event_interruptible(q,con);
		}
	}
	if(count > BUF_SIZE-1)
	{
		count = BUF_SIZE - 1;
	}
	if(count > charCount)
	{
		count = charCount;
	}
	res = copy_to_user(buf,buff,count);
	if(res)
	{
		printk("copy_to_user error\n");
		return -EFAULT;
	}
	charCount -= count;
	printk("copy_to_user ok\n");
	printk("\t buff = %s\t\n",buff);
	printk("------leave testRead------\n");
	return count;
}

ssize_t testWrite(struct file *pFile,const char __user *buf,size_t count,loff_t *pOffset)
{
	int res = -1;
	printk("------into testWrite------\n");
	con = 1;
	wake_up_interruptible(&q);
	if(count > BUF_SIZE-1)
	{
		count = BUF_SIZE - 1;
	}
	res = copy_from_user(buff,buf,count);
	if(res)
	{
		printk("copy_from_user error\n");
		return -EFAULT;
	}
	else
	{
		con = 1;
		wake_up_interruptible(&q);
		printk("wake up \n");
	}
	charCount = count;
	printk("copy_from_user ok\n");
	printk("\t buff = %s\t\n",buff);
	kill_fasync(&fasync,SIGIO,POLL_IN);
	printk("------leave testWrite------\n");
	return count;
}

long testIoctl(struct file *pFile,unsigned int cmd,unsigned long arg)
{
	switch(cmd)
	{
		case TEST_CMD:
			{
				printk("test cmd-------arg = %ld \n",arg);
			}
			break;
		case TEST_CMD1:
			{
				printk("test cmd1-------arg = %ld \n",arg);
			}
			break;
		case TEST_CMD2:
			{
				printk("test cmd2-------arg = %ld \n",arg);
			}
			break;
		default:
			printk("error cmd \n");
	}
	return 0;
}
unsigned int testPoll(struct file *pFile,struct poll_table_struct *ptable)
{
	unsigned int mask = 0;
	printk("into testpoll\n");
	poll_wait(pFile,&q,ptable);
	if(charCount > 0)
	{
		printk("read mask id setted \n");
		mask = POLLIN|POLLRDNORM;
	}
	printk("leave testpoll \n");
	return mask;
}
int testFasync(int fd,struct file *pFile,int on)
{
	int res = -1;
	printk("into Fasync\n");
	res = fasync_helper(fd,pFile,on,&fasync);
	printk("res = %d,on = %d\n",res,on);
	printk("leave Fasync\n");
	return res;
}
struct file_operations fp_arr =
{
	.owner = THIS_MODULE,
	.open = testOpen,
	.read = testRead,
	.write = testWrite,
	.release = testClose,
	.unlocked_ioctl = testIoctl,
	.poll = testPoll,
	.fasync = testFasync
};


int driverr_init(void)               //模块初始化函数
{
	int res = 0;
	int i = 0;
	struct device *pDevTmp = NULL;
	printk("*********into driver init\n");
	//动态申请设备号
	res = alloc_chrdev_region(&deviceNum,min,devNum,deviceName);
	if(res)
	{
		printk("alloc_chrdev_region error\n");
		return res;
	}
	printk("alloc_chrdev_region OK!\n");
	printk("major = %d minor = %d \n",MAJOR(deviceNum),MINOR(deviceNum));
	major = MAJOR(deviceNum);
	//创建设备
	pCdev = cdev_alloc();
	if(NULL == pCdev)
	{
		printk("cdev_alloc error\n");
		unregister_chrdev_region(deviceNum,devNum);
		return -1;
	}
	printk("cdev_alloc ok\n");
	//设备初始化
	cdev_init(pCdev,&fp_arr);
	printk("cdev_init ok\n");
	//设备与设备号关联
	res = cdev_add(pCdev,deviceNum,devNum);
	if(res)
	{
		printk("cdev_add error\n");
		cdev_del(pCdev);
	}
	printk("cdev_add ok\n");
	//创建设备文件类
	pClass = class_create(THIS_MODULE,"fasync");
	if(NULL == pClass)
	{
		printk("class_create error\n");
		cdev_del(pCdev);
	}
	printk("class_create ok\n");
	//创建设备文件
	for(;i < devNum;i++)
	{
		pDevTmp = device_create(pClass,NULL,MKDEV(major,i),NULL,"fasync%d",i);
		if(IS_ERR(pDevTmp))
		{
			printk("device_create error\n");
			for(i = 0;i < devNum;i++)
			{
				device_destroy(pClass,MKDEV(major,i));
			}
			class_destroy(pClass);
			return -2;
		}
	}
	printk("device_create ok\n");
	//初始化休眠等待队列
	init_waitqueue_head(&q);
	printk("init_waitqueue_head ok\n");
	printk("*********leave driver init\n");
	return 0;
}

void driver_clear(void)             //模块清除函数
{
	int i = 0;
	printk("*********into driver clear\n");
	for(;i < devNum; i++)
	{
		device_destroy(pClass,MKDEV(major,i));
	}
	class_destroy(pClass);
	cdev_del(pCdev);
	unregister_chrdev_region(deviceNum,devNum);
	printk("*********leave driver clear\n");
}

module_init(driverr_init);           //模块加载函数
module_exit(driver_clear);          //模块卸载函数


MODULE_LICENSE("GPL");
MODULE_AUTHOR("cfy");
MODULE_ALIAS("liangzai");
MODULE_DESCRIPTION("2022-7-19");
##### test.c 用来读数据

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <string.h>
#include <signal.h>

#define BUF_SIZE 100

int fd=-1;

void handler(int signo)
{
	printf("into hander:signo=%d\r\n",signo);
	char buf[BUF_SIZE]={0};
	read(fd,buf,BUF_SIZE-1);
	printf("buf:%s\r\n",buf);
}

int main()
{
	//1 signal
	signal(SIGIO,handler);
	//2 open fasync0
	fd=open("/dev/fasync0",O_RDWR);
	if(fd<0)
	{
		printf("open fasync0 error!\r\n");
		return -1;
	}
	printf("open fasync0 ok!\r\n");
	//3 set owner
	fcntl(fd,F_SETOWN,getpid());
	//4 get flags
	int flags=fcntl(fd,F_GETFL);
	//5 set flags
	fcntl(fd,F_SETFL,flags|FASYNC);

	while(1)
	{
		printf("看看会不会阻塞\n");
		sleep(3);
	}

	return 0;
}

##### test.c 用来写数据

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define BUF_SIZE 100

int main()
{
	int fd = open("/dev/fasync0",O_RDWR);
	if(fd < 0)
	{
		printf("open fasync0 err\n");
		return -1;
	}
	printf("open fasync0 ok\n");

	char buf[BUF_SIZE] = {0};
	memcpy(buf,"123456",7);
	write(fd,buf,sizeof(buf));	
	while(1)
	{

		//测试写
		printf(">> input:");
		bzero(buf,sizeof(buf));
		scanf("%s",buf);
		write(fd,buf,sizeof(buf));
	}
	
	close(fd);
	return 0;

}

现象

不会阻塞,在test1写入的时候,会通知test去读,在没有通知去读的时候test一直在执行自己的程序。

在这里插入图片描述

结论

好使,就是有点费人。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值