linux轮询操作和epoll使用和字符设备poll函数实现

本文介绍了Linux系统中,如何进行轮询操作,并详细阐述了epoll的使用步骤,包括引入相关库。通过实例代码展示了在字符设备中如何实现poll函数,为Linux运维人员提供实用的操作指南。
摘要由CSDN通过智能技术生成

一、是什么?

当多路复用文件数量大 ,IO频繁时候,一般不使用select()poll()
使用epoll
int epoll_create(int size);
创建一个epoll的句柄,size用来告诉内核要监听多个个fd,
当创建好epoll句柄后,它本身占用一个fd值,使用epoll后,需要close掉.
int epoll_create(int size);
int epoll_ctrl(int epfd,int op,int fd,struct epoll_event*event);
第二个参数表示动作:
EPOLL_CTL_ADD:注册新的fd到efd中.
EPOLL_CTL_MOD:修改已经注册的fd监听事件.
EPOLL_CTL_DEL:从epfd删除一个fd.
第三个参数是需要监听的fd.
第四个参数是告诉内核需要监听的事件类型.
struct epoll_event
{
  _uint32_t events; // epoll_event
  epoll_data data; // user data variable
};

events:或事件
EPOLLIN:文件描述符可读
EPOLLOUT:文件描述符可写
EPOLLPRI:对应的文件描述符可读.
EPOLLERR:对应的文件描述符发生错误.
EPOLHUP:对应描述符被挂断
EPOLLET:将epoll设为边缘触发模式.
EPOLLONESHOT:意味着一次监听,当监听完这次事件之后,如果还需要继续监听,需要
再次把这个fd加入到epoll队列里。

int epoll_wait(int epfd,struct epoll_event*events,int maxevents,int timeout);
timeout参数是ms为单位  0 立即返回 -1 永久等待  
该函数返回值需要处理的事件数目,如返回0,表示超时。


设备驱动中轮询编程
设备驱动中poll()函数原型
unsigned int (*poll)(struct file*file,struct poll_table*wait);
file结构体指针
wait表示轮询表指针
将等待队列调用Poll_wait函数,将对应的等待队列头部添加到poll_table
返回表示是否对设备进行无阻塞读/写访问的掩码.
函数原型:
void poll_wait(struct file*filp,wait_queue_head_t*queue,poll_table*wait);
返回设备资源的可获取状态POLLIN POLLOUT POLLPRI POLLERR POLLVAL等宏位的或结果。
static unsigned int xxx_poll(struct file*filp,poll_table*wait)
{
     unsigned int mask =0;
	 struct xxx_dev*dev = filp->private_data;//
	 
	 poll_wait(filp,&dev->r_wait,wait); //加入读等待队列 
	 poll_wait(filp,&dev->w_wait,wait); //加入写等待队列
	 if(xxx)
	    mask |= POLLIN | POLLRNORM;  //可读
		
	 if(xxx)
	    mask |= POLLOUT | POLLWRNORM; // 可写 
     return mask;		
}

//通过判断dev->current_len是否等于0表示设备可读状态
//通过判断dev->current_len是否等于GLOBALFIFO_SIZE来获得设备可写状态.

二、使用步骤

1.引入库

代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>

#define FIFO_CLEAR 0x1 
#define BUFFER_LEN  20 

int main(int argc,char*argv[])
{
  int fd,num;
  char rd_ch[BUFFER_LEN];
  fd_set rfds,wfds; //读/写文件描述符集
  //以非阻塞方式打开
  fd = open("/dev/global_dev0",O_RDONLY|O_NONBLOCK);
  if(fd!=-1)
  {
    //FIFO清0 
    if(ioctl(fd,FIFO_CLEAR,0)<0) 
    {
		printf("ioctl command failure\n");
	}		
	while(1)
	{
		FD_ZERO(&rfds);
		FD_ZERO(&wfds);
		FD_SET(fd,&rfds);
		FD_SET(fd,&wfds);
		select(fd+1,&rfds,&wfds,NULL,NULL);
		//数据可读
		if(FD_ISSET(fd,&rfds))
	    {
			printf("poll monitor can be read\n");
		}
		
		if(FD_ISSET(fd,&wfds))
		{
			printf(" poll monitor:can be write\n");
		}
	}
  }
  else 
  {
	  printf("Device open failure\n");
  }
  return 0;
}

poll monitor can be read
poll monitor can be read
poll monitor can be read
poll monitor can be read
同步队列可用于同步驱动中事件发生的先后的顺序
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<strings.h>
#include<sys/epoll.h>

#define FIFO_CLEAR  0x1 
#define BUFFER_LEN  20


int main(int argc,char*argv[])
{
	int fd;
	struct epoll_event ev_globalfifo;
	int err;
	int epfd;
	  fd = open("/dev/global_dev0",O_RDONLY|O_NONBLOCK);
	  if(fd!=-1)
	  {
		  
		  
		  if(ioctl(fd,FIFO_CLEAR,0)<0)
		  {
			  printf("ioctl command failured\n");
		  }
		  epfd = epoll_create(1);
		  if(epfd<0)
		  {
			  perror("epoll_create failure\n");
			  return;
		  }
		  bzero(&ev_globalfifo,sizeof(struct epoll_event));
		  ev_globalfifo.events = EPOLLIN|EPOLLPRI;
		  err = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev_globalfifo);
		  if(err<0)
		  {
			  perror("epoll_crtl()");
			  return;
		  }
		  err = epoll_wait(epfd,&ev_globalfifo,1,10000);
		  if(err<0)
			  perror("epfd wait\n");
		  else if(err == 0)
			  printf("no data input fifo with 10s \n");
		  else 
		  {
			  printf("FIFO is not empty");
		  }
		  err = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&ev_globalfifo);
		  if(err)
			  perror("epoll_ctrl\n");
	  }
  return 0;
}
root@ubuntu:/nfsroot/system# ./a.out 
no data input fifo with 10s 
驱动增加poll函数实现
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/device.h>
#include<linux/wait.h>
#include<linux/poll.h>

static int debug = 1;
module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debuging infomation");
#define dprintk(args...)\
        if(debug){ \
			printk(KERN_DEBUG args);\
		}
		
#define GLOBALMEM_SIZE  0x1000
#define MEM_CLEAR  0x01
#define GLOBALMEM_MAJOR  230
#define DEVICE_NUM  1

static int globalmem_major = GLOBALMEM_MAJOR; 
module_param(globalmem_major,int,S_IRUGO);

struct globalmem_dev{
	struct cdev cdev;
	unsigned int current_len;// 表示当前FIFO中有效数据的长度 0 当前FIFO为空,current_len等于GLOBALFIFO_SIZE意味着满
	unsigned char  mem[GLOBALMEM_SIZE];
	struct mutex mutex;
	wait_queue_head_t r_wait;
	wait_queue_head_t w_wait;
	
};
struct globalmem_dev*globalmem_devp;
static struct class*global_mem_class;



static ssize_t globalmem_read(struct file*filp,char __user*buf,size_t size,
loff_t*ppos)
{
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev*dev = filp->private_data;
	
	DECLARE_WAITQUEUE(wait,current);
	mutex_lock(&dev->mutex);
	add_wait_queue(&dev->r_wait,&wait);
	
	while(dev->current_len == 0)
	{
		 if(filp->f_flags&O_NONBLOCK)
		 {
			 ret = -EAGAIN;
			 goto out;
		 }

		 __set_current_state(TASK_INTERRUPTIBLE);
		 mutex_unlock(&dev->mutex);
		 schedule();
		 if(signal_pending(current))  //信号打断
		 {
			 ret = -ERESTARTSYS;
			 goto out2;
		 }
		 mutex_lock(&dev->mutex);
	}
	
	if(count > dev->current_len)
	{
		count = dev->current_len;
	}
	
	if(copy_to_user(buf,dev->mem,count))
	{
		ret = -EFAULT;
		goto out;
	}
	else 
	{ 
		memcpy(dev->mem,dev->mem+count,dev->current_len-count);
		dev->current_len -=count;
		printk(KERN_INFO"read %d bytes(s),current_len:%d\n",count,dev->current_len);
		wake_up_interruptible(&dev->w_wait);
		ret = count;
	}
out:
    mutex_unlock(&dev->mutex);
out2:
	remove_wait_queue(&dev->r_wait,&wait);
	set_current_state(TASK_RUNNING);
	
	return ret;
}

static int globalmem_open(struct inode*inode,struct file*filp)
{
    //filp->private_data = globalmem_devp;
	struct globalmem_dev*dev  = container_of(inode->i_cdev,struct globalmem_dev,cdev);
	filp->private_data = dev;
	return 0;
}

static ssize_t globalmem_write(struct file*filp,const char __user*buf,
size_t size,loff_t*ppos)
{
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev*dev = filp->private_data;
	DECLARE_WAITQUEUE(wait,current);
	
	mutex_lock(&dev->mutex);
	add_wait_queue(&dev->w_wait,&wait);
	while(dev->current_len == GLOBALMEM_SIZE)
	{
		if(filp->f_flags&O_NONBLOCK)   // f_flags 
		{
			ret = -EAGAIN;
			goto out;
		}
		__set_current_state(TASK_INTERRUPTIBLE);
		mutex_unlock(&dev->mutex);
		schedule();
		if(signal_pending(current))
		{
			ret = -ERESTARTSYS;
			goto out2;
		}
		mutex_lock(&dev->mutex);
	}
	
	if(count > GLOBALMEM_SIZE - dev->current_len)
	{
		count = GLOBALMEM_SIZE - dev->current_len;
	}
	
	if(copy_from_user(dev->mem+dev->current_len,buf,count))
	{
		ret = -EFAULT;
		goto out;
	}
	else 
	{
		dev->current_len +=count;
		printk(KERN_INFO"written %d bytes,corrent_len %d\n",count,dev->current_len);
	    wake_up_interruptible(&dev->r_wait);
		ret = count;
	}
out:
	mutex_unlock(&dev->mutex);
out2:
	remove_wait_queue(&dev->w_wait,&wait);
	set_current_state(TASK_RUNNING);
	return ret;
}

static long globalmem_ioctl(struct file*filp,unsigned int cmd,unsigned long arg)
{
	struct globalmem_dev*dev = filp->private_data;
	switch(cmd)
	{
		case MEM_CLEAR:
		     memset(dev->mem,0,GLOBALMEM_SIZE);
			 printk(KERN_INFO"globalmem is set to zero\n");
			 break;
		default:
		     return -EINVAL;
	}
	return 0;
}

//从文件开头和当前位置的偏移
static loff_t globalmem_llseek(struct file*filp,loff_t offset,int orig)
{
	loff_t ret = 0;
	switch(orig)
	{
		case 0:
		 if(offset<0)
			 ret = -EINVAL;
		  break;
		  if((unsigned int)offset>GLOBALMEM_SIZE){
			ret = -EINVAL;
			break;
		  }
		  filp->f_pos = (unsigned int )offset;
		  ret = filp->f_pos;
		  break;
		 case 1:
		   if((filp->f_pos+offset)>GLOBALMEM_SIZE)
		   {
			   ret = -EINVAL;
			   break;
		   }
		   if((filp->f_pos+offset)<0)
		   {
			   ret = -EINVAL;
			   break;
		   }
		   filp->f_pos +=offset;
		   ret=filp->f_pos;
		   break;
		   default:
		     ret = -EINVAL;
			 break;
	}
	return ret;
}



static unsigned int globalmem_poll(struct file*filp,poll_table*wait)
{
	
	unsigned int mask = 0;
	struct globalmem_dev*dev = filp->private_data;
	
	mutex_lock(&dev->mutex);
	poll_wait(filp,&dev->r_wait,wait);
	poll_wait(filp,&dev->w_wait,wait);
	
	if(dev->current_len!=0)
	{
		mask |= POLLIN|POLLRDNORM;
	}
	
	if(dev->current_len != GLOBALMEM_SIZE)
	{
		mask |= POLLOUT|POLLWRNORM;
	}
	mutex_unlock(&dev->mutex);
	return mask;
}

static const struct file_operations globalmem_fops = 
{
	.owner = THIS_MODULE,
	.llseek = globalmem_llseek,
	.read = globalmem_read,
	.write = globalmem_write,
	.unlocked_ioctl = globalmem_ioctl,
	.poll = globalmem_poll,
	.open = globalmem_open,
	.release = NULL,
};

static void globalmem_setup_cdev(struct globalmem_dev*dev,int index)
{
  char buf[20];
  int err,devno = MKDEV(globalmem_major,index);
  cdev_init(&dev->cdev,&globalmem_fops);
  dev->cdev.owner = THIS_MODULE;
  err = cdev_add(&dev->cdev,devno,1);
  if(err)
  {
	  printk(KERN_NOTICE"Error%d adding globalmem_mem%d",err,index);
  }
  sprintf(buf,"global_dev%d",index);  //整形转换字符串
  device_create(global_mem_class,NULL,devno,NULL,buf);
  
}

static int __init globalmem_init(void)
{
	int ret;
	int i = 0;
	dev_t devno = MKDEV(globalmem_major,0);
	if(globalmem_major)
		ret = register_chrdev_region(devno,DEVICE_NUM,"globalmem");
	else 
	{
		ret = alloc_chrdev_region(&devno,0,DEVICE_NUM,"globalmem");
		globalmem_major = MAJOR(devno);
	}
	if(ret<0)
		return ret;
    globalmem_devp = kzalloc((sizeof(struct globalmem_dev)*DEVICE_NUM),GFP_KERNEL);
	if(!globalmem_devp)
	{
		ret = -ENOMEM;
		goto fail_malloc;
	}
	
	global_mem_class = class_create(THIS_MODULE,"globalclass");
	if(IS_ERR(global_mem_class))
	{
		printk(KERN_INFO"create class error\n");
		return -1;
	}
	
	for(i=0;i<DEVICE_NUM;i++)
		globalmem_setup_cdev(globalmem_devp+i,i);
	mutex_init(&globalmem_devp->mutex);
	
	init_waitqueue_head(&globalmem_devp->r_wait);
	init_waitqueue_head(&globalmem_devp->w_wait);
	return 0;
fail_malloc:
	unregister_chrdev_region(devno,DEVICE_NUM);
	return ret;
}

static void __exit globalmem_exit(void)
{
	int i = 0;
	for(i=0;i<DEVICE_NUM;i++)
	cdev_del(&(globalmem_devp+i)->cdev);
	kfree(globalmem_devp);
	unregister_chrdev_region(MKDEV(globalmem_major,0),DEVICE_NUM);
	class_destroy(global_mem_class);
}
module_init(globalmem_init);
module_exit(globalmem_exit);
MODULE_LICENSE("GPL");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天少内耗10点半睡觉和今天早晚运动

老铁的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值