zoukankan      html  css  js  c++  java
  • Linux高级字符设备之Poll操作

    在用户程序中,select()和poll()也是与设备阻塞与非阻塞访问息息相关的,使用非阻塞I/O的应用程序通常会使用select和poll系统调用查询是否可对设备进行无阻塞的访问。select系统调用最终会引发设备驱动中的poll函数被执行。
    一、select()系统调用
    用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程。
    1.select()原型:
    int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout);
    /*
    *@maxfd : 需要检查的文件描述符个数,数值应该比是三组fd_set中最大数更大(即一般取所有文件描述符的最大值加1),而不是实际文件描述符的总数。
    *@readfds: 用来检查可读性的一组文件描述符。
    *@writesfds: 用来检查可写性的一组文件描述符。
    *@exceptsfds:用来检查意外状态的文件描述符。(注:错误并不是意外状态)
    *@timeout:NULL指针代表无限等待,否则是指向timeval结构的指针,代表最长等待时间。(如果其中tv_sec和tv_usec都等于0, 则文件描述符的状态不被影响,但函数并不挂起) 
    返回值:
    (1)正常情况下返回满足要求的文件描述符个数;
    (2)经过了timeout等待后仍无文件满足要求,返回0;
    (3)如果select被某个信号中断,将返回-1并设置errno为EINTR;
    (4)若出错,返回-1并设置相应的errno;
    2.select的使用方法
    (1)将要监控的文件添加到文件描述符集;
    (2)调用select开始监控;
    (3)判断文件是否发生变化;
    3.系统提供四个宏对描述符集进行操作
    void FD_SET(int fd, fd_set *fdset); //将文件描述符fd添加到文件描述符集fdset中;
    void FD_CLR(int fd, fd_set *fdset); //从文件描述符集fdset中清除文件描述符fd;
    void FD_ISSET(int fd, fd_set *fdset); //在调用select后使用FD_ISSET来检测文件描述符集中的文件fd发生了变化
    void FD_ZERO(fd_set *fdset);//清空文件描述符集
    二、Poll方法:
    1.poll函数原型:
    unsigned int(*poll)(struct file *filp, struct poll_table *wait);
    //第一个参数为file结构体指针,第二个参数为轮询表指针。
    这个函数应该进行以下两项工作:
    (1)对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应等待队列添加到poll_table中; 
    (2)返回表示是否能对设备进行无阻塞可读或可写访问的掩码;
      位掩码:POLLRDNORM, POLLIN,POLLOUT,POLLWRNORM
      设备可读,通常返回:(POLLIN | POLLRDNORM)
      设备可写,通常返回:(POLLOUT | POLLWRNORM)
    三、调用过程:
    Linux下select调用的过程:
    1、用户层应用程序调用select(),底层调用poll())
    2、核心层调用sys_select() ------> do_select()
      最终调用文件描述符fd对应的struct file类型变量的struct file_operations *f_op的poll函数。
      poll指向的函数返回当前可否读写的信息。
      1)如果当前可读写,返回读写信息。
      2)如果当前不可读写,则阻塞进程,并等待驱动程序唤醒,重新调用poll函数,或超时返回。
    3、驱动需要实现poll函数。
    当驱动发现有数据可以读写时,通知核心层,核心层重新调用poll指向的函数查询信息。
    poll_wait(filp,&wait_q,wait) // 此处将当前进程加入到等待队列中,但并不阻塞

      在中断中使用wake_up_interruptible(&wait_q)唤醒等待队列。

    四、实例分析:
    1.memdev.h
    1. #ifndef _MEMDEV_H_  
    2. #define _MEMDEV_H_  
    3.   
    4. #ifndef MEMDEV_MAJOR  
    5. #define MEMDEV_MAJOR 0   /*预设的mem的主设备号*/  
    6. #endif  
    7.   
    8. #ifndef MEMDEV_NR_DEVS  
    9. #define MEMDEV_NR_DEVS 2    /*设备数*/  
    10. #endif  
    11.   
    12. #ifndef MEMDEV_SIZE  
    13. #define MEMDEV_SIZE 4096  
    14. #endif  
    15. /*mem设备描述结构体*/  
    16. struct mem_dev                                       
    17. {                                                          
    18.   char *data;                        
    19.   unsigned long size;   
    20.   wait_queue_head_t inq;    
    21. };  
    22.   
    23. #endif /* _MEMDEV_H_ */ 
    2.memdev.c
    1. #include <linux/module.h>  
    2. #include <linux/types.h>  
    3. #include <linux/fs.h>  
    4. #include <linux/errno.h>  
    5. #include <linux/mm.h>  
    6. #include <linux/sched.h>  
    7. #include <linux/init.h>  
    8. #include <linux/cdev.h>  
    9. #include <asm/io.h>  
    10. #include <asm/system.h>  
    11. #include <asm/uaccess.h>  
    12.   
    13. #include <linux/poll.h>  
    14. #include "memdev.h"  
    15.   
    16. static mem_major = MEMDEV_MAJOR;  
    17. bool have_data = false/*表明设备有足够数据可供读*/  
    18.   
    19. module_param(mem_major, int, S_IRUGO);  
    20.   
    21. struct mem_dev *mem_devp; /*设备结构体指针*/  
    22.   
    23. struct cdev cdev;   
    24.   
    25. /*文件打开函数*/  
    26. int mem_open(struct inode *inode, struct file *filp)  
    27. {  
    28.     struct mem_dev *dev;  
    29.       
    30.     /*获取次设备号*/  
    31.     int num = MINOR(inode->i_rdev);  
    32.   
    33.     if (num >= MEMDEV_NR_DEVS)   
    34.             return -ENODEV;  
    35.     dev = &mem_devp[num];  
    36.       
    37.     /*将设备描述结构指针赋值给文件私有数据指针*/  
    38.     filp->private_data = dev;  
    39.       
    40.     return 0;   
    41. }  
    42.   
    43. /*文件释放函数*/  
    44. int mem_release(struct inode *inode, struct file *filp)  
    45. {  
    46.   return 0;  
    47. }  
    48.   
    49. /*读函数*/  
    50. static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)  
    51. {  
    52.   unsigned long p =  *ppos;  
    53.   unsigned int count = size;  
    54.   int ret = 0;  
    55.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/  
    56.   
    57.   /*判断读位置是否有效*/  
    58.   if (p >= MEMDEV_SIZE)  
    59.     return 0;  
    60.   if (count > MEMDEV_SIZE - p)  
    61.     count = MEMDEV_SIZE - p;  
    62.       
    63.   while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while */  
    64.   {  
    65.         if (filp->f_flags & O_NONBLOCK)  
    66.             return -EAGAIN;  
    67.       
    68.     wait_event_interruptible(dev->inq,have_data);  
    69.   }  
    70.   
    71.   /*读数据到用户空间*/  
    72.   if (copy_to_user(buf, (void*)(dev->data + p), count))  
    73.   {  
    74.     ret =  - EFAULT;  
    75.   }  
    76.   else  
    77.   {  
    78.     *ppos += count;  
    79.     ret = count;  
    80.      
    81.     printk(KERN_INFO "read %d bytes(s) from %d ", count, p);  
    82.   }  
    83.     
    84.   have_data = false/* 表明不再有数据可读 */  
    85.   /* 唤醒写进程 */  
    86.   return ret;  
    87. }  
    88.   
    89. /*写函数*/  
    90. static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)  
    91. {  
    92.   unsigned long p =  *ppos;  
    93.   unsigned int count = size;  
    94.   int ret = 0;  
    95.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/  
    96.     
    97.   /*分析和获取有效的写长度*/  
    98.   if (p >= MEMDEV_SIZE)  
    99.     return 0;  
    100.   if (count > MEMDEV_SIZE - p)  
    101.     count = MEMDEV_SIZE - p;  
    102.   
    103.   /*从用户空间写入数据*/  
    104.   if (copy_from_user(dev->data + p, buf, count))  
    105.     ret =  - EFAULT;  
    106.   else  
    107.   {  
    108.     *ppos += count;  
    109.     ret = count;  
    110.       
    111.     printk(KERN_INFO "written %d bytes(s) from %d ", count, p);  
    112.   }  
    113.     
    114.   have_data = true/* 有新的数据可读 */  
    115.       
    116.     /* 唤醒读进程 */  
    117.     wake_up(&(dev->inq));  
    118.   
    119.   return ret;  
    120. }  
    121.   
    122. /* seek文件定位函数 */  
    123. static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)  
    124. {   
    125.     loff_t newpos;  
    126.   
    127.     switch(whence) {  
    128.       case 0: /* SEEK_SET */  
    129.         newpos = offset;  
    130.         break;  
    131.   
    132.       case 1: /* SEEK_CUR */  
    133.         newpos = filp->f_pos + offset;  
    134.         break;  
    135.   
    136.       case 2: /* SEEK_END */  
    137.         newpos = MEMDEV_SIZE -1 + offset;  
    138.         break;  
    139.   
    140.       default/* can't happen */  
    141.         return -EINVAL;  
    142.     }  
    143.     if ((newpos<0) || (newpos>MEMDEV_SIZE))  
    144.         return -EINVAL;  
    145.           
    146.     filp->f_pos = newpos;  
    147.     return newpos;  
    148.   
    149. }  
    150. unsigned int mem_poll(struct file *filp, poll_table *wait)  
    151. {  
    152.     struct mem_dev  *dev = filp->private_data;   
    153.     unsigned int mask = 0;  
    154.       
    155.    /*将等待队列添加到poll_table */  
    156.     poll_wait(filp, &dev->inq,  wait);  
    157.    
    158.       
    159.     if (have_data)         mask |= POLLIN | POLLRDNORM;  /* readable */  
    160.   
    161.     return mask;  
    162. }  
    163.   
    164.   
    165. /*文件操作结构体*/  
    166. static const struct file_operations mem_fops =  
    167. {  
    168.   .owner = THIS_MODULE,  
    169.   .llseek = mem_llseek,  
    170.   .read = mem_read,  
    171.   .write = mem_write,  
    172.   .open = mem_open,  
    173.   .release = mem_release,  
    174.   .poll = mem_poll,  
    175. };  
    176.   
    177. /*设备驱动模块加载函数*/  
    178. static int memdev_init(void)  
    179. {  
    180.   int result;  
    181.   int i;  
    182.   
    183.   dev_t devno = MKDEV(mem_major, 0);  
    184.   
    185.   /* 静态申请设备号*/  
    186.   if (mem_major)  
    187.     result = register_chrdev_region(devno, 2, "memdev");  
    188.   else  /* 动态分配设备号 */  
    189.   {  
    190.     result = alloc_chrdev_region(&devno, 0, 2, "memdev");  
    191.     mem_major = MAJOR(devno);  
    192.   }    
    193.     
    194.   if (result < 0)  
    195.     return result;  
    196.   
    197.   /*初始化cdev结构*/  
    198.   cdev_init(&cdev, &mem_fops);  
    199.   cdev.owner = THIS_MODULE;  
    200.   cdev.ops = &mem_fops;  
    201.     
    202.   /* 注册字符设备 */  
    203.   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);  
    204.      
    205.   /* 为设备描述结构分配内存*/  
    206.   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);  
    207.   if (!mem_devp)    /*申请失败*/  
    208.   {  
    209.     result =  - ENOMEM;  
    210.     goto fail_malloc;  
    211.   }  
    212.   memset(mem_devp, 0, sizeof(struct mem_dev));  
    213.     
    214.   /*为设备分配内存*/  
    215.   for (i=0; i < MEMDEV_NR_DEVS; i++)   
    216.   {  
    217.         mem_devp[i].size = MEMDEV_SIZE;  
    218.         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);  
    219.         memset(mem_devp[i].data, 0, MEMDEV_SIZE);  
    220.     
    221.       /*初始化等待队列*/  
    222.      init_waitqueue_head(&(mem_devp[i].inq));  
    223.      //init_waitqueue_head(&(mem_devp[i].outq));  
    224.   }  
    225.      
    226.   return 0;  
    227.   
    228.   fail_malloc:   
    229.   unregister_chrdev_region(devno, 1);  
    230.     
    231.   return result;  
    232. }  
    233.   
    234. /*模块卸载函数*/  
    235. static void memdev_exit(void)  
    236. {  
    237.   cdev_del(&cdev);   /*注销设备*/  
    238.   kfree(mem_devp);     /*释放设备结构体内存*/  
    239.   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/  
    240. }  
    241.   
    242. MODULE_AUTHOR("David Xie");  
    243. MODULE_LICENSE("GPL");  
    244.   
    245. module_init(memdev_init);  
    246. module_exit(memdev_exit); 
    3.app-write.c
    1. #include <stdio.h>  
    2.   
    3. int main()  
    4. {  
    5.     FILE *fp = NULL;  
    6.     char Buf[128];  
    7.       
    8.       
    9.     /*打开设备文件*/  
    10.     fp = fopen("/dev/memdev0","r+");  
    11.     if (fp == NULL)  
    12.     {  
    13.         printf("Open Dev memdev Error! ");  
    14.         return -1;  
    15.     }  
    16.       
    17.     /*写入设备*/  
    18.     strcpy(Buf,"memdev is char dev!");  
    19.     printf("Write BUF: %s ",Buf);  
    20.     fwrite(Buf, sizeof(Buf), 1, fp);  
    21.       
    22.     sleep(5);  
    23.     fclose(fp);  
    24.       
    25.     return 0;      
    26.   
    4.app-read.c
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <unistd.h>  
    4. #include <sys/ioctl.h>  
    5. #include <sys/types.h>  
    6. #include <sys/stat.h>  
    7. #include <fcntl.h>  
    8. #include <sys/select.h>  
    9. #include <sys/time.h>  
    10. #include <errno.h>  
    11.   
    12. int main()  
    13. {  
    14.     int fd;  
    15.     fd_set rds;  
    16.     int ret;  
    17.     char Buf[128];  
    18.       
    19.     /*初始化Buf*/  
    20.     strcpy(Buf,"memdev is char dev!");  
    21.     printf("BUF: %s ",Buf);  
    22.       
    23.     /*打开设备文件*/  
    24.     fd = open("/dev/memdev0",O_RDWR);  
    25.       
    26.     FD_ZERO(&rds);  
    27.     FD_SET(fd, &rds);  
    28.   
    29.     /*清除Buf*/  
    30.     strcpy(Buf,"Buf is NULL!");  
    31.     printf("Read BUF1: %s ",Buf);  
    32.   
    33.     ret = select(fd + 1, &rds, NULL, NULL, NULL);  
    34.     if (ret < 0)   
    35.     {  
    36.         printf("select error! ");  
    37.         exit(1);  
    38.     }  
    39.     if (FD_ISSET(fd, &rds))   
    40.         read(fd, Buf, sizeof(Buf));              
    41.       
    42.     /*检测结果*/  
    43.     printf("Read BUF2: %s ",Buf);  
    44.       
    45.     close(fd);  
    46.       
    47.     return 0;      
  • 相关阅读:
    1046 Shortest Distance (20 分)(模拟)
    1004. Counting Leaves (30)PAT甲级真题(bfs,dfs,树的遍历,层序遍历)
    1041 Be Unique (20 分)(hash散列)
    1036 Boys vs Girls (25 分)(查找元素)
    1035 Password (20 分)(字符串处理)
    1044 Shopping in Mars (25 分)(二分查找)
    onenote使用小Tip总结^_^(不断更新中...)
    1048 Find Coins (25 分)(hash)
    三个故事
    领导者的举止
  • 原文地址:https://www.cnblogs.com/liuchengchuxiao/p/4214243.html
Copyright © 2011-2022 走看看