poll机制总结、模板、要点

poll机制总结、模板、要点:

一、代码介绍:  代码①为共用key驱动(独立四个按键驱动,同一份代码)  

                         代码②和③为用两种方式调用底层poll机制的代码,poll()和select()两种方式

二、要点:

      (1)每次调用,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

      (2)同时每次调用都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

      (3)它们支持的文件描述符数量太小了,默认是1024

      (4)select与poll原理基本一样,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。驱动代码共用一份,大家只需对比应用层代码,结构体不一样,一个是case形式的遍历,一个是for形式的遍历

三、要产生一下观念:

        poll机制是一种同步机制!

        poll机制是驱动和应用程序结合使用的一种机制!

        poll机制是一个应用程序同时管理多个事件的时候,使用到的一种机制!

/*********************底层驱动*********************/
/*功能介绍:配合poll机制,编写了四个独立的key驱动,如下为其中一个key的驱动代码,代码基本一样。
           key按下--->
           产生中断进入①----->
           mod_timer()计时开始---->
           进入定时器中断②---->
           condition置1为真,wake_up()唤醒等待------>
           wait_event()阻塞解除,③读操作进行,记住此时condition为真,然后进入应用层判断
*/

#include "poll.h"

static  int  i  = 0; 
static  DECLARE_WAIT_QUEUE_HEAD(wq);   
static  bool condition = 0;
static  struct  timer_list  g_ttimer;

//①外部中断服务函数
static  irqreturn_t  key_irq_handler(int irq, void * arg)
{
	struct  keyinfo*   pkey = (struct  keyinfo*)arg;
	
	g_ttimer.data = (unsigned long)pkey;
	mod_timer(&g_ttimer, jiffies + HZ / 200);

	return  IRQ_HANDLED;
}

//②定时器中断服务函数
static  void  key_timer_handler(unsigned long arg)
{
	struct  keyinfo* pk = (struct  keyinfo*)arg;
	printk("timer_handler: %s pressed!\n",  pk->name);

	condition = 1;
	wake_up_interruptible(&wq);
}


// ③ read();  阻塞读
static  ssize_t   key_read(struct file * filp, char __user * buff, size_t count, loff_t * offset)
{
	char buf[32] = {0};
	int ret = 0;

	wait_event_interruptible(wq, condition);
	condition = 0;

	if(!gpio_get_value(g_arrkey[i].gpio))
	{
		sprintf(buf, "%s is pressed!", g_arrkey[i].name);
	}

	ret = copy_to_user(buff, buf, min(strlen(buf), count));
	return  min(strlen(buf), count);
}

static  unsigned int  key_poll(struct file * filp, struct poll_table_struct * table)
{
    unsigned int mask = 0;
	poll_wait(filp, &wq, table);	//阻塞  1.当前设备触发中断  2.超时时间到来  3.其他事件触发 都会导致阻塞消失
	if(condition == 1)
	{
		mask = POLLIN | POLLRDNORM;
        return mask;
	}

	return 0;
}

static  struct file_operations  g_tfops = {
		.owner		=	THIS_MODULE,
		.read		=	key_read,
		.poll		=	key_poll,
};

static  struct miscdevice  g_tmiscdev = {
	.minor 	=	MISC_DYNAMIC_MINOR,
	.name	=	"key1",
	.fops	=	&g_tfops,
};

static  int  __init  xyd_irq_init(void)
{
	int ret = 0;

	gpio_request(g_arrkey[i].gpio, g_arrkey[i].name);
	s3c_gpio_cfgpin(g_arrkey[i].gpio, S3C_GPIO_INPUT);
	g_arrkey[i].irq = gpio_to_irq(g_arrkey[i].gpio);
	ret = request_irq(g_arrkey[i].irq, key_irq_handler, 
		IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 
		g_arrkey[i].name, &g_arrkey[i]);
	
	//初始化定时器
	setup_timer(&g_ttimer, my_timer_handler, 0);
	misc_register(&g_tmiscdev);
	return 0;
}

static  void  __exit  my_irq_exit(void)
{
	misc_deregister(&g_tmiscdev);
	del_timer_sync(&g_ttimer);

	free_irq(g_arrkey[i].irq, &g_arrkey[i]);
	gpio_free(g_arrkey[i].gpio);
}

module_init(my_irq_init);
module_exit(my_irq_exit);

MODULE_LICENSE("GPL");
/************************应用层代码poll()********************/

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

int main(int argc, char* argv[])
{
	int fd1 = 0;
	int fd2 = 0;
	int fd3 = 0;
	int fd4 = 0;

	fd1 = open("/dev/key1", O_RDWR);
	fd2 = open("/dev/key2", O_RDWR);
	fd3 = open("/dev/key3", O_RDWR);
	fd4 = open("/dev/key4", O_RDWR);
	if((fd1 < 0) || (fd2 < 0) || (fd3 < 0) || (fd4 < 0))
	{
		printf("open failed!\n");
		return -1;
	}

	struct pollfd  keyinfo[] = {
		{fd1, POLLIN, 0},	   //{文件描述符,事件类型,返回事件类型}
		{fd2, POLLIN, 0},	
		{fd3, POLLIN, 0},	
		{fd4, POLLIN, 0},	
	};

	int i = 0;
	char buf[32] = {0};
	while(1)
	{
		memset(buf, 0, sizeof(buf));

		poll(keyinfo, sizeof(keyinfo)/sizeof(keyinfo[0]), -1);
                //一方面,传递结构体keyinfo信息,将四个加入等待队列  
                //另一方阻塞,等待事件触发(condition=1时,接受到底层驱动mask返回值,解除阻塞)

		for(i = 0; i < 4; i++)
		{
			if(keyinfo[i].revents & keyinfo[i].events)
			{
				read(keyinfo[i].fd, buf, sizeof(buf));
				printf("%s\n", buf);
			}
		}
	}
	
	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	return 0;
}
/************************应用层代码select()********************/
#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[])
{
	int ret = 0;
	int fd1 = 0;
	int fd2 = 0;
	int fd3 = 0;
	int fd4 = 0;

	fd1 = open("/dev/key1", O_RDWR);
	fd2 = open("/dev/key2", O_RDWR);
	fd3 = open("/dev/key3", O_RDWR);
	fd4 = open("/dev/key4", O_RDWR);
	if((fd1 < 0) || (fd2 < 0) || (fd3 < 0) || (fd4 < 0))
	{
		printf("open failed!\n");
		return -1;
	}

	fd_set  rdfds;              //声明fd_set结构体
	FD_ZERO(&rdfds);            //清空结构体


	FD_SET(fd1, &rdfds);        //将fd加入到rdfds集合
	FD_SET(fd2, &rdfds);
	FD_SET(fd3, &rdfds);
	FD_SET(fd4, &rdfds);


	fd_set  tmp = rdfds;        //用tmp保存rdfds集合

	char buf[32] = {0};
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		rdfds = tmp;             //每次都需要拷贝一次fd集合

		select(fd4+1, &rdfds, NULL, NULL, NULL);	 //阻塞,等待驱动从内核返回mask
                                                     //调用select,内核开始遍历传入fd集合




		if(FD_ISSET(fd1, &rdfds))                    //判断fd1是否存在于rdfds集中
		{
			read(fd1, buf, sizeof(buf))	;       
			printf("fd1: %s\n", buf);
		}
		if(FD_ISSET(fd2, &rdfds))
		{
			read(fd2, buf, sizeof(buf))	;
			printf("fd2: %s\n", buf);
		}
		if(FD_ISSET(fd3, &rdfds))
		{
			read(fd3, buf, sizeof(buf))	;
			printf("fd3: %s\n", buf);
		}
		if(FD_ISSET(fd4, &rdfds))
		{
			read(fd4, buf, sizeof(buf))	;
			printf("fd4: %s\n", buf);
		}
	}

	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35769746/article/details/81069348