zoukankan      html  css  js  c++  java
  • poll()函数的使用

    分类: LINUX

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

    示例是使用poll函数来监测按键的输入

    ----------------------------------------------------------------------------------------------------------

     

    驱动代码:

    1. #include <linux/config.h>
    2. #include <linux/module.h>
    3. #include <linux/kernel.h>
    4. #include <linux/fs.h>
    5. #include <linux/init.h>
    6. #include <linux/devfs_fs_kernel.h>
    7. #include <linux/miscdevice.h>
    8. #include <linux/delay.h>
    9. #include <asm/irq.h>
    10. #include <asm/arch/regs-gpio.h>
    11. #include <asm/hardware.h>
    12. #include <linux/cdev.h>
    13. #include <linux/mm.h>
    14. #include <linux/interrupt.h>
    15. #include <linux/poll.h>
    16. #include <asm/uaccess.h>
    17. #include <asm/ioctl.h>
    18. #include <asm/arch/regs-irq.h>
    19. #include <asm/io.h>
    20. #define key S3C2410_GPF0
    21. #define key_irq IRQ_EINT0 //IRQ_EINT0是中断号
    22. #define key_cfg S3C2410_GPF0_EINT0 //设置为外部中断功能
    23. #define DEVICE_NAME "key" //注意加上双引号
    24. #define DEVICE_MAJOR major
    25. #define DEVICE_MINOR 0
    26. static dev_t dev; //dev_t类型用于存放主设备号和次设备号
    27. static int major;
    28. struct cdev *p_cdev; //声明一个指向字符设备结构的指针
    29. static int key_event=0; //唤醒中断的条件标记,1时满足唤醒条件,静态全局变量
    30. static int key_value=1; //按键键值
    31. static DECLARE_WAIT_QUEUE_HEAD(wq); //调用宏定义,静态创建一个名为wq的等待队列
    32. static void key_interrupt(void) //中断处理函数,注册中断时已注册了中断程序的入口地址
    33. {
    34.  key_value=s3c2410_gpio_getpin(key);
    35.  key_event=1; //唤醒标记置位,表示条件达到,可以唤醒进程继续执行
    36.  wake_up_interruptible(&wq); //调用宏定义,唤醒标记置位后调用此函数,&wq是队列入口地址
    37. }
    38. static int key_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
    39. {
    40. // wait_event_interruptible(wq,key_event); //key_event0,从此处将进程放入wq等待队列休眠,等待中断;key_event==1时,此宏不执行操作
    41. //调用poll的时候来等待,这里可以不用wait_event_interrupt()
    42.  key_value=s3c2410_gpio_getpin(key);
    43.  copy_to_user(buff,&key_value,sizeof(key_event)); //&key_value地址的值从内核空间复制到用户空间
    44.  key_event=0; //完成中断操作,将唤醒标记清零,继续休眠
    45.  return 0;
    46. }
    47. static unsigned int key_poll(struct file *filp,poll_table *wait)
    48. {
    49.  unsigned int mask=0; //用来记录发生的事件,以unsigned int类型返回
    50.  poll_wait(filp,&wq,wait); //将当前进程添加到wq等待队列中
    51.  if(key_event==1)mask|=POLLIN|POLLRDNORM; //中断事件发生,这时有数据可读,在mask中标记是可读事件发生
    52.  return mask; //返回事件记录,返回0则表示等待事件超时
    53. }
    54. //设置寄存器,申请中断号等在open函数中完成
    55. static int key_open(struct inode *inode,struct file *filp)
    56. {
    57.  int ret;
    58.  s3c2410_gpio_cfgpin(key,key_cfg); //设置引脚功能
    59.  s3c2410_gpio_pullup(key,1); //第二个参数1为禁止内部上拉
    60.  ret=request_irq(key_irq,(void *)key_interrupt,SA_INTERRUPT,DEVICE_NAME,NULL); //注册中断,中断不共享时最后一个参数为NULL
    61.  if(ret) {
    62.   printk("Could not register interrupt ");
    63.   return ret;
    64.  }
    65.  set_irq_type(key_irq,IRQT_BOTHEDGE); //设置中断方式为双边触发
    66.  return 0;
    67. }
    68. static int key_close(struct inode *inode,struct file *filp)
    69. {
    70.  free_irq(key_irq,NULL); //中断无共享时第二个参数为NULL
    71.  return 0;
    72. }
    73. static struct file_operations key_fops={
    74.  .owner=THIS_MODULE,
    75.  .open=key_open,
    76.  .release=key_close,
    77.  .read=key_read,
    78.  .poll=key_poll,
    79. };
    80. int key_init(void)
    81. {
    82.  int ret;
    83.  ret=alloc_chrdev_region(&dev,DEVICE_MINOR,1,DEVICE_NAME); //采用主设备号动态分配
    84.  if(ret<0){
    85.   printk("Register /dev/key failed! ");
    86.   return ret;
    87.  }
    88.  else printk("Register /dev/key successfully! ");
    89.  major=MAJOR(dev); //取得分配到的主设备号
    90.  p_cdev=cdev_alloc(); //申请一个字符设备结构并返回指向它的指针
    91.  cdev_init(p_cdev,&key_fops); //相当于p_cdev->ops=&key_fops
    92.  p_cdev->owner=THIS_MODULE;
    93.  ret=cdev_add(p_cdev,dev,1); //向系统添加这个字符设备
    94.  if(ret<0){
    95.   printk("Add cdev failed! ");
    96.   return ret;
    97.  }
    98.  devfs_mk_cdev(dev,S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP,DEVICE_NAME);
    99.  return 0;
    100. }
    101. void key_exit(void)
    102. {
    103.  unregister_chrdev_region(dev,1);
    104.  cdev_del(p_cdev); //删除字符设备
    105.  devfs_remove(DEVICE_NAME);
    106.  printk("Device unregister! ");
    107. }
    108. MODULE_LICENSE("GPL");
    109. MODULE_AUTHOR("HJW");
    110. module_init(key_init);
    111. module_exit(key_exit);
    112. ---------------------------------------------------------------------------------------------------
    113. 测试程序代码:
    114. #include <stdio.h>
    115. #include <stdlib.h>
    116. #include <unistd.h>
    117. #include <sys/ioctl.h>
    118. #include <sys/types.h>
    119. #include <sys/stat.h>
    120. #include <fcntl.h> /*文件控制*/
    121. #include <sys/select.h>
    122. #include <sys/time.h> /*时间方面的函数*/
    123. #include <errno.h> /*有关错误方面的宏*/
    124. #include<sys/poll.h> //poll()
    125. #include<fcntl.h>
    126. #include<string.h> //memset()
    127. int main(void)
    128. {
    129.  int fd,key_value,ret;
    130.  struct pollfd event; //创建一个struct pollfd结构体变量,存放文件描述符、要等待发生的事件
    131.  fd=open("/dev/key",O_RDWR);
    132.  if(fd<0){
    133.   perror("open /dev/key error! ");
    134.   exit(1);
    135.  }
    136.  printf("open /dev/key sucessfully! ");
    137.  while(1){ //poll结束后struct pollfd结构体变量的内容被全部清零,需要再次设置
    138.   memset(&event,0,sizeof(event)); //memst函数对对象的内容设置为同一值
    139.   event.fd=fd; //存放打开的文件描述符
    140.   event.events=POLLIN; //存放要等待发生的事件
    141.   ret=poll((struct pollfd *)&event,1,5000); //监测event,一个对象,等待5000毫秒后超时,-1为无限等待
    142. //判断poll的返回值,负数是出错,0是设定的时间超时,整数表示等待的时间发生
    143.   if(ret<0){
    144.    printf("poll error! ");
    145.    exit(1);
    146.   }
    147.   if(ret==0){
    148.    printf("Time out! ");
    149.    continue;
    150.   }
    151.   if(event.revents&POLLERR){ //revents是由内核记录的实际发生的事件,events是进程等待的事件
    152.    printf("Device error! ");
    153.    exit(1);
    154.   }
    155.   if(event.revents&POLLIN){
    156.    read(fd,&key_value,sizeof(key_value));
    157.    printf("Key value is '%d' ",key_value);
    158.   }
    159.  }
    160.  close(fd);
    161.  return 0;
    162. }
  • 相关阅读:
    mysql 历史版本下载
    mysql 5.7 版本 You must reset your password using ALTER USER statement before executing this statement报错处理
    5.7 zip 版本的安装 以及遇到的坑
    mysql 5.6zip版本的卸载与5.7 zip 版本的安装
    mysql数据库的备份与还原
    本地Navicat连接docker里的mysql
    docker修改数据库密码
    docker 在push镜像到本地registry出现的500 Internal Server Error
    linux 没有界面内容显示不全解决办法
    json与map互相转换
  • 原文地址:https://www.cnblogs.com/terrytian88/p/5893527.html
Copyright © 2011-2022 走看看