poll()函数的使用

转载 2012年03月28日 15:19:09
poll函数用于监测多个等待事件,若事件未发生,进程睡眠,放弃CPU控制权,若监测的任何一个事件发生,poll将唤醒睡眠的进程,并判断是什么等待事件发生,执行相应的操作。poll函数退出后,struct pollfd变量的所有值被清零,需要重新设置。
示例是使用poll函数来监测按键的输入
----------------------------------------------------------------------------------------------------------

驱动代码:
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/ioctl.h>
#include <asm/arch/regs-irq.h>
#include <asm/io.h>

#define key S3C2410_GPF0
#define key_irq IRQ_EINT0   //IRQ_EINT0是中断号
#define key_cfg S3C2410_GPF0_EINT0  //设置为外部中断功能

#define DEVICE_NAME "key"  //注意加上双引号
#define DEVICE_MAJOR major 
#define DEVICE_MINOR 0

static dev_t dev;  //dev_t类型用于存放主设备号和次设备号
static int major;

struct cdev *p_cdev; //声明一个指向字符设备结构的指针

static int key_event=0;  //唤醒中断的条件标记,1时满足唤醒条件,静态全局变量
static int key_value=1;  //按键键值
static DECLARE_WAIT_QUEUE_HEAD(wq); //调用宏定义,静态创建一个名为wq的等待队列

static void key_interrupt(void)  //中断处理函数,注册中断时已注册了中断程序的入口地址
{
key_value=s3c2410_gpio_getpin(key);
key_event=1; //唤醒标记置位,表示条件达到,可以唤醒进程继续执行
wake_up_interruptible(&wq); //调用宏定义,唤醒标记置位后调用此函数,&wq是队列入口地址
}

static int key_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
// wait_event_interruptible(wq,key_event); //若key_event为0,从此处将进程放入wq等待队列休眠,等待中断;key_event==1时,此宏不执行操作
//调用poll的时候来等待,这里可以不用wait_event_interrupt()
key_value=s3c2410_gpio_getpin(key);
copy_to_user(buff,&key_value,sizeof(key_event)); //将&key_value地址的值从内核空间复制到用户空间
key_event=0;  //完成中断操作,将唤醒标记清零,继续休眠
return 0;
}

static  unsigned int key_poll(struct file *filp,poll_table *wait)
{
unsigned int mask=0; //用来记录发生的事件,以unsigned int类型返回
poll_wait(filp,&wq,wait); //将当前进程添加到wq等待队列中
if(key_event==1)mask|=POLLIN|POLLRDNORM; //中断事件发生,这时有数据可读,在mask中标记是可读事件发生
return mask;   //返回事件记录,返回0则表示等待事件超时
}

//设置寄存器,申请中断号等在open函数中完成
static int key_open(struct inode *inode,struct file *filp)
{
int ret;
s3c2410_gpio_cfgpin(key,key_cfg);  //设置引脚功能
s3c2410_gpio_pullup(key,1);  //第二个参数1为禁止内部上拉
ret=request_irq(key_irq,(void *)key_interrupt,SA_INTERRUPT,DEVICE_NAME,NULL); //注册中断,中断不共享时最后一个参数为NULL
if(ret) {
printk("Could not register interrupt\n");
return ret;
}
set_irq_type(key_irq,IRQT_BOTHEDGE);  //设置中断方式为双边触发
return 0;
}

static int key_close(struct inode *inode,struct file *filp)
{
free_irq(key_irq,NULL); //中断无共享时第二个参数为NULL
return 0;
}

static struct file_operations key_fops={
.owner=THIS_MODULE,
.open=key_open,
.release=key_close,
.read=key_read,
.poll=key_poll,
};

int key_init(void)
{
int ret;
ret=alloc_chrdev_region(&dev,DEVICE_MINOR,1,DEVICE_NAME); //采用主设备号动态分配
if(ret<0){
printk("Register /dev/key failed!\n");
return ret;
}
else printk("Register /dev/key successfully!\n");
major=MAJOR(dev);  //取得分配到的主设备号
p_cdev=cdev_alloc(); //申请一个字符设备结构并返回指向它的指针
cdev_init(p_cdev,&key_fops); //相当于p_cdev->ops=&key_fops
p_cdev->owner=THIS_MODULE; 
ret=cdev_add(p_cdev,dev,1); //向系统添加这个字符设备
if(ret<0){
printk("Add cdev failed!\n");
return ret;
}
devfs_mk_cdev(dev,S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP,DEVICE_NAME);
return 0;
}

void key_exit(void)
{
unregister_chrdev_region(dev,1);
cdev_del(p_cdev);  //删除字符设备
devfs_remove(DEVICE_NAME);
printk("Device unregister!\n");
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("HJW");
module_init(key_init);
module_exit(key_exit);

测试程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制*/
#include <sys/select.h>
#include <sys/time.h> /*时间方面的函数*/
#include <errno.h> /*有关错误方面的宏*/
#include<sys/poll.h> //poll()
#include<fcntl.h>
#include<string.h> //memset()

int main(void)
{
int fd,key_value,ret;
struct pollfd event; //创建一个struct pollfd结构体变量,存放文件描述符、要等待发生的事件
fd=open("/dev/key",O_RDWR); 
if(fd<0){
perror("open /dev/key error!\n");
exit(1);
}
printf("open /dev/key sucessfully!\n");
while(1){ //poll结束后struct pollfd结构体变量的内容被全部清零,需要再次设置
memset(&event,0,sizeof(event)); //memst函数对对象的内容设置为同一值
event.fd=fd; //存放打开的文件描述符
event.events=POLLIN; //存放要等待发生的事件
ret=poll((struct pollfd *)&event,1,5000); //监测event,一个对象,等待5000毫秒后超时,-1为无限等待

//判断poll的返回值,负数是出错,0是设定的时间超时,整数表示等待的时间发生
if(ret<0){
printf("poll error!\n");
exit(1);
}
if(ret==0){
printf("Time out!\n");
continue;
}
if(event.revents&POLLERR){  //revents是由内核记录的实际发生的事件,events是进程等待的事件
printf("Device error!\n");
exit(1);
}
if(event.revents&POLLIN){
read(fd,&key_value,sizeof(key_value));
printf("Key value is '%d'\n",key_value);
}
}
close(fd);
return 0;
}


Linux C——poll函数实现多路复用

多路复用    多路复用一般用于I/O操作可能会被阻塞的情况,对可能会有阻塞的I/O的管道、网路进行编程。 采用管道函数创建有名管道,使用select函数替代使用poll函数实现多路复用:...
  • Eleanor_12
  • Eleanor_12
  • 2016年10月28日 21:49
  • 312

Linux网络编程——I/O复用之poll函数

一、回顾前面的select select优点: 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点 select缺点: 1.每次调用 select(),都...
  • lianghe_work
  • lianghe_work
  • 2015年06月17日 15:09
  • 5318

《unix网络编程》(15)poll函数以及使用poll的客户服务器程序

select存在一个明显缺陷:中定义的FD_SETSIZE常值是数据类型fd_set中描述符总数,其值通常为1024。当今的Unix版本允许每个进程使用无限数目的描述符(受限于内存总量和管理性),然而...
  • u013074465
  • u013074465
  • 2015年04月06日 14:40
  • 1231

poll()函数实例

poll()函数的使用
  • a1028732302
  • a1028732302
  • 2016年05月24日 10:09
  • 1388

一个poll的简单例子

该程序使用poll事件机制实现了一个简单的消息回显的功能,其服务器端和客户端的代码如下所示: 服务器端://start from the very beginning,and to create g...
  • L979951191
  • L979951191
  • 2015年08月26日 23:21
  • 610

poll()函数详解

poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。   #include   int poll(struct pollfd fd[], nfds_t nfd...
  • imxiangzi
  • imxiangzi
  • 2016年01月08日 12:55
  • 1357

UDP卷1:第六章(I/O复用:select和poll函数)

1. I/O模型     一个输入
  • fzyz_sb
  • fzyz_sb
  • 2014年09月18日 22:12
  • 1566

UNIX中的Poll函数

poll函数和select函数非常相似,但是函数接口不一样。   int poll(struct pollfd fdarray[], nfds_t nfds, int timeout); ...
  • DLUTBruceZhang
  • DLUTBruceZhang
  • 2013年03月12日 16:43
  • 3618

select,poll,epoll优缺点及比较

在之前我已经分析了这三个函数,请看我之前的文章: IO多路复用之select函数详解 IO多路复用之poll函数详解 IO多路复用之epoll函数详解   这篇文章只总结优缺点,以便面试时回...
  • lixungogogo
  • lixungogogo
  • 2016年08月17日 01:51
  • 4545

Linux Poll函数初级实例

网络编程
  • XW370168409
  • XW370168409
  • 2016年12月01日 22:36
  • 373
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:poll()函数的使用
举报原因:
原因补充:

(最多只允许输入30个字)