首页 > 其他分享 >poll机制实例参考

poll机制实例参考

时间:2023-02-23 10:00:10浏览次数:40  
标签:include struct 参考 irq drv 实例 poll forth

poll机制:为了减少CPU资源的占用率,在编写驱动函数中添加poll机制

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

       POLL:应用程序在一定时间内没有事件发生回返回来执行其它下面函数

       先说poll,poll或select为大部分Unix/Linux程序员所熟悉,这俩个东西原理类似,性能上也不存在明显差异,但select对所监控的文件描述符数量有限制,所以这里选用poll做说明。
    
       poll是一个系统调用,其内核入口函数为sys_poll,sys_poll几乎不做任何处理直接调用do_sys_poll,do_sys_poll的执行过程可以分为三个部分:

       1,将用户传入的pollfd数组拷贝到内核空间,因为拷贝操作和数组长度相关,时间上这是一个O(n)操作,这一步的代码在do_sys_poll中包括从函数开始到调用do_poll前的部分。

       2,查询每个文件描述符对应设备的状态,如果该设备尚未就绪,则在该设备的等待队列中加入一项并继续查询下一设备的状态。查询完所有设备后如果没有一个设备就绪,这时则需要挂起当前进程等待,直到设备就绪或者超时,挂起操作是通过调用schedule_timeout执行的。设备就绪后进程被通知继续运行,这时再次遍历所有设备,以查找就绪设备。这一步因为两次遍历所有设备,时间复杂度也是O(n),这里面不包括等待时间。相关代码在do_poll函数中。

       3,将获得的数据传送到用户空间并执行释放内存和剥离等待队列等善后工作,向用户空间拷贝数据与剥离等待队列等操作的的时间复杂度同样是O(n),具体代码包括do_sys_poll函数中调用do_poll后到结束的部分。

poll实现步骤:

1、在驱动函数file_operation结构体上添加一个.poll函数,然后在函数里执行poll_wait,这个函数用来判断硬件事件是否发生

2、测试程序需要调用ret = poll(fds, 1, 5000)函数来获取事件发生信息。

比如一个按键事件:

1、查询方法:一直在查询,不断去查询是否有事件发生,整个过程都是占用CPU资源,消耗CPU资源非常打。

2、中断方式:当有事件发生时,就去跳转到相应事件去处理,CPU占用时间少。

3、poll方式: 中断方式虽然占用CPU资源少,但是在应用程序上需要不断在死循环里面执行读取函数,应用程序不能去做其它事情。poll机制解决了这个问题,当有事件发生时,才去执行读read函数,按键事件没有按下时,超过时间后返回,去执行其它的处理函数。

以下为poll按键事件的例子:

forth_drv.c:

 

复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>


static struct class *forthdrv_class;
static struct class_device    *forthdrv_class_dev;

volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;



volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;


static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
static volatile int ev_press = 0;


struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;

struct pin_desc pins_desc[4] = {
    {S3C2410_GPF0, 0x01},
    {S3C2410_GPF2, 0x02},
    {S3C2410_GPG3, 0x03},
    {S3C2410_GPG11, 0x04},
};


/*
  * 确定按键值
  */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    struct pin_desc * pindesc = (struct pin_desc *)dev_id;
    unsigned int pinval;
    
    pinval = s3c2410_gpio_getpin(pindesc->pin);

    if (pinval)
    {
        /* 松开 */
        key_val = 0x80 | pindesc->key_val;
    }
    else
    {
        /* 按下 */
        key_val = pindesc->key_val;
    }

    ev_press = 1;                  /* 表示中断发生了 */
    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

    
    return IRQ_RETVAL(IRQ_HANDLED);
}

static int forth_drv_open(struct inode *inode, struct file *file)
{
    /* 配置GPF0,2为输入引脚 */
    /* 配置GPG3,11为输入引脚 */
    request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
    request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
    request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
    request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    

    return 0;
}

ssize_t forth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if (size != 1)
        return -EINVAL;

    /* 如果没有按键动作, 休眠 */
    wait_event_interruptible(button_waitq, ev_press);

    /* 如果有按键动作, 返回键值 */
    copy_to_user(buf, &key_val, 1);
    ev_press = 0;
    
    return 1;
}


int forth_drv_close(struct inode *inode, struct file *file)
{
    free_irq(IRQ_EINT0, &pins_desc[0]);
    free_irq(IRQ_EINT2, &pins_desc[1]);
    free_irq(IRQ_EINT11, &pins_desc[2]);
    free_irq(IRQ_EINT19, &pins_desc[3]);
    return 0;
}

static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &button_waitq, wait); // 不会立即休眠

    if (ev_press)
        mask |= POLLIN | POLLRDNORM;

    return mask;
}



static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open    =  forth_drv_open,     
    .read     =    forth_drv_read,       
    .release =  forth_drv_close,
    .poll    =  forth_drv_poll,
};


int major;
static int forth_drv_init(void)
{
    major = register_chrdev(0, "forth_drv", &sencod_drv_fops);

    forthdrv_class = class_create(THIS_MODULE, "forth_drv");

    forthdrv_class_dev = class_device_create(forthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;

    gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;

    return 0;
}

static void forth_drv_exit(void)
{
    unregister_chrdev(major, "forth_drv");
    class_device_unregister(forthdrv_class_dev);
    class_destroy(forthdrv_class);
    iounmap(gpfcon);
    iounmap(gpgcon);
    return 0;
}


module_init(forth_drv_init);

module_exit(forth_drv_exit);

MODULE_LICENSE("GPL");
复制代码

 

forthdrvtest.c:

复制代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>


/* forthdrvtest 
  */
int main(int argc, char **argv)
{
    int fd;
    unsigned char key_val;
    int ret;

    struct pollfd fds[1];
    
    fd = open("/dev/buttons", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
    }

    fds[0].fd     = fd;
    fds[0].events = POLLIN;
    while (1)
    {
        ret = poll(fds, 1, 5000);
        if (ret == 0)
        {
            printf("time out\n");
        }
        else
        {
            r
                fvbbfdfnb
                
            gb'
            fdd
                b'b'bbfvdv'v
            cv'
            v'
            df'd'ead(fd, &key_val, 1);
            printf("key_val = 0x%x\n", key_val);
        }
    }
    
    return 0;
}
复制代码

标签:include,struct,参考,irq,drv,实例,poll,forth
From: https://www.cnblogs.com/kn-zheng/p/17146880.html

相关文章

  • 触发模式和EPOLLONESHOT
    触发模式和EPOLLONESHOT1.基本概念水平触发:LT缺省的工作模式,当被监控的文件描述符上有可读写的事件发生时,epoll_wait()就会给用户通知,如果用户没有一次的将数据读......
  • 树状分级框架UI实例
    树状分级框架UI实例;(内容参考https://zhuanlan.zhihu.com/p/108485875) #coding:utf8#!/usr/bin/envpython#@author:9527importwximportwx.auifrompubsubimp......
  • Springboot 系列 (22) - Springboot+Netty | 使用 Netty 封装的 WebSocket 实现消息实
    Netty是由JBOSS提供的一个Java开源框架。Netty是一个基于JavaNIO的开发框架,主要针对在TCP协议下,面向Client端的高并发应用,或者Peer-to-Peer场景下的大量数......
  • hadoop - hadoop2.6 分布式 - 简单实例学习 - 统计某年的最高温度和按年份将温度从高
    1.背景   哎,学习hadoop不容易啊,各种bug,摸不着头脑,时而管用,时而不知道namenode怎么停止了,确实郁闷!还好,坚持下去了!好了,不说了,开始简单示例: 1.1 数据格式:   ......
  • CDC设计实例-01
    CDC设计实例ClockGatingCell&GlitchFreeClockSwitch(门控单元和动态切换时钟)一个电路有多个时钟输入进来,希望在工作当中能够动态切换时钟;比如CPU根据工作负载(A......
  • 脚本实例
    【shell脚本分享】linux运维拿来即用序列~点击关注......
  • QPython实例03-制作【ONE一个】可视化应用
    一、前言QPython3c在大佬的改进下,拥有了基于sl4a的FullScreenWrapper2全屏框架。文章将用该框架制作我们的可视化应用【ONE一个】。二、最终效果如下三、准备工作AI......
  • Winform只运行一个实例
    创建帮助类单例帮助类 publicclassMainHelper{publicstaticProcessRunningInstance(stringlocation){varcurrent=Proce......
  • 转字符驱动实例gpio
    概述:字符设备驱动程序:是按照字符设备要求完成的由操作系统调用的代码。重点理解以下内容: 1.驱动是写给操作系统的代码,它不是直接给用户层程序调用的,而是给系统调用的......
  • epoll分析
    1.什么是epollepoll是当前在Linux下开发大规模并发网络程序的热门人选,epoll在Linux2.6内核中正式引入,和select相似,都是I/O多路复用(IOmultiplexing)技术,按照man手册的......