Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4173813
  • 博文数量: 776
  • 博客积分: 13014
  • 博客等级: 上将
  • 技术积分: 10391
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-22 17:00
文章分类

全部博文(776)

文章存档

2015年(55)

2014年(43)

2013年(147)

2012年(20)

2011年(82)

2010年(429)

分类: LINUX

2011-02-11 15:59:24

poll函数用于监测多个等待事件,若事件未发生,进程睡眠,放弃CPU控制权,若监测的任何一个事件发生,poll将唤醒睡眠的进程,并判断是什么等待事件发生,执行相应的操作。poll函数退出后,struct pollfd变量的所有值被清零,需要重新设置。
 
poll_wait()是用在select系统调用中的.

一般你的代码会有一个struct file_operations结构,
其中fop->poll函数指针指向一个你自己的函数,
在这个函数里应该调用poll_wait()

当用户调用select系统调用时,select系统调用会
先调用
poll_initwait(&table);
然后调用你的
fop->poll();
从而将current加到某个等待队列(这里调用poll_wait()),
并检查是否有效
如果无效就调用
schedule_timeout();
去睡眠.

事件发生后,schedule_timeout()回来,调用
fop->poll();
检查到可以运行,就调用
poll_freewait(&table);

从而完成select系统调用.

重要的是fop->poll()里面要检查是否就绪,
如果是,要返回相应标志

参见内核的函数:
fs/select.c/do_select()
kernel/futex.c/futex_poll()
 
示例是使用poll函数来监测按键的输入
-------------------------------------------------------------------------

驱动代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
#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
#include
#include
#include
#include
#include
#include /*文件控制*/
#include
#include /*时间方面的函数*/
#include /*有关错误方面的宏*/
#include //poll()
#include
#include //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;
}

阅读(1624) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~