linux poll mechanism uses (a)

A role, poll mechanisms

Mechanism of action 1.poll

In the foregoing manner using the interrupt to read the key value ( Linux Management Interrupt (IV) ). Use this button reads, if the button is not pressed, the application has been in a state of sleep. If you want even if the button is not pressed, can return after a certain period of time, to achieve this function, you can use poll机制. ( select IO复用And epollcan also perform this function, write-only poll mechanism here)

Second, the mechanism for application programming poll

1. Application Interface Layer Function

1).API:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

2) .Paramet:

fds nfds timeout
Parameter Type:
    struct the pollfd {
    int FD; / * file descriptor /
    Short Events; /
occurrence of an event type to wait /
    Short the revents; /
event type actually returned * /
    };
Parameter Description:
    FDS structure is a pointer, i.e. poll function can wait for one or more file descriptors while events
Parameter Type:
    nfds_t, in fact, int type
parameters:
    for explaining the number of poll while monitoring fds
Parameter Type:
    int
parameters:
    equal to -1: wait forever
    equal to 0: immediately returns
    greater than 0: Timeout time in milliseconds

3).Return:

return value description
<0 Error return
=0 Timeout to return
>0 Back revents domain structure thereof is not the number of file descriptors 0

2. Applications

The main use of the poll application reads the value of the key, and set the timeout wait 5000ms

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>


/* poll机制测试 
 */
int main(int argc, char **argv)
{
    int fd;
    unsigned char key_val;
    int ret;
    /* 定义一个 struct pollfd 结构体数组*/
    struct pollfd fds[1];
    /* 打开一个设备文件 */
    fd = open("/dev/my_button", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
    }
    /**************** 初始化 struct pollfd 结构体 *************/
    /* 初始化文件描述符 */
    fds[0].fd     = fd;
    /* 初始化监听的事件事件 */
    fds[0].events = POLLIN;
    while (1)
    {
        /* 调用poll函数,超时时间是5000ms */
        ret = poll(fds, 1, 5000);
        
        if (ret == 0){
            /* 超时返回 */
            printf("time out\n");
        }else if(ret<0){
            /* 出错返回 */
        printf("poll error\n"); 
        }else{     
            /* 有数据可读,读取数据 */
            /* 这里为了简单就不对返回的事件revents,做判断和重置了 */
            read(fd, &key_val, 1);
            printf("key_val = %d\n", key_val);
        }
    }
    
    return 0;
}

Third, drivers

Mainly in the preparation of the driver file_operationsof pollthe members to add a function interface button_poll. The following program is in linux interrupt management (iv) change (but this chapter uses only one button). Code changes are as follows:

#include <linux/device.h> 
#include <linux/interrupt.h>
#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 <linux/cdev.h>
#include <linux/poll.h>


/* 申请一个等待队列头 */
DECLARE_WAIT_QUEUE_HEAD (button_waitq);
/* 事件触发标志 */
int ev_press;


/* 用一个结构体来描述一个按键,抽象的或许不是很好 */
struct but_irq_desc{
    /* 中断名称 */
    char *button_nane;
    /* 按键的状态,1松开,0按下 */
    unsigned char key_state;
    /* 按键所接的GPIO口 */
    unsigned long pin;
    /* 按键的中断号 */
    unsigned int irq;   
};


struct but_irq_desc but_irq_descs={
    .button_nane="button1",
    .key_state = 1,
    .pin = S3C2410_GPF0,
    .irq=IRQ_EINT0,
};

static struct cdev *button_cdev;
static struct class *button_class;


struct file_operations *button_fops;

/* 中断处理函数 */
static irqreturn_t button_irq(int irq, void * dev_id)
{
    /* 获取这个按键的结构体 */
    struct but_irq_desc *btndesc = (struct but_irq_desc *)dev_id;
    unsigned int pinval;
    /* 读取按键的电平 */
    pinval = s3c2410_gpio_getpin(btndesc->pin);
    /* 如果是高电平*/
    if(pinval){
        /* 按键松开 */
        btndesc->key_state = 1;
    }else{
        btndesc->key_state = 0;
        /* 按键按下 */
    }
    /* 唤醒该等待队列里的进程 */
    wake_up_interruptible(&button_waitq);
    /* 将标志置1 */
    ev_press = 1;
    return IRQ_HANDLED;
}

int button_open (struct inode * inode, struct file *file){
    /* 注册驱动,中断为上升沿和下降沿触发 */
    request_irq(but_irq_descs.irq, button_irq,\
        IRQF_TRIGGER_RISING| IRQF_TRIGGER_FALLING,\
        but_irq_descs.button_nane,(void*)(&but_irq_descs));
    return 0;
}
int button_release (struct inode *inode, struct file * file){
    /* 释放中断 */
    free_irq(but_irq_descs.irq,(void*)(&but_irq_descs));
    return 0;
}

/* 驱动读函数 */
ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t * offset){
    unsigned char key_val;
    if(size!=1){
        return -EINVAL;
    }
    /* 等待按键按下,如果按键按下,则这个进程会被唤醒(以后有时间系一章等待队列的源码分析) */
    /* 如果ev_press等于1的时候则这个进程不会被挂起,等于0的时候这个进程才会被挂起 */
    wait_event_interruptible(button_waitq, ev_press);
    key_val = but_irq_descs.key_state;
    /* 将按键值返回给应用层 */
    copy_to_user(buf, &key_val, 1);
    /* 将标志置0将进程挂起,等待下一次唤醒 */
    ev_press = 0;
    return 1;
}





/*********************本章中增加的函数****************************/
static unsigned int button_poll(struct file *file, poll_table *wait)
{
    unsigned int res = 0;
    poll_wait(file, &button_waitq, wait);
    /************************ poll_wait函数定义如下 **********************/
    /* static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
     * {
     *     if (p && wait_address)
     *         p->qproc(filp, wait_address, p);
     *         //本质调用的是__pollwait(filp, wait_address, p);这个函数
     * }
     */
    /***********************************************************************/
    
    /* p->qproc 是一个函数指针,指向 __pollwait函数。
     * __pollwait 做的事情也就是将当前的进程添加到 button_waitq 等待队列中。
     * 这里只是添加到等待队列而已,并不会立即休眠。
     * (下一章分析poll机制源码的时候会详细分析)
     */
     
    /* 如果当前有按键按下,则返回POLLIN 和 POLLRDNORM事件,
     * 否则返回0
     * 返回非0则当前的进程不会休眠,返回0当前的进程会休眠
     */
    if (ev_press)
        res = POLLIN | POLLRDNORM;
    /* 返回res */
    return res;
}
/*********************本章中增加的函数****************************/

static dev_t dev_id;

/* 模块入口函数 */
static int __init my_button_init(void){
    

    /* 分配一个file_operations 结构体 */
    button_fops = kmalloc(sizeof(struct file_operations), GFP_KERNEL);
    /* 初始化接口函数 */
    button_fops->open = button_open;
    button_fops->release = button_release;
    button_fops->read = button_read;
    button_fops->poll = button_poll;
    /* 动态分配一个设备号 */
    alloc_chrdev_region(&dev_id, 0, 1, "my_button");
    /* 分配一个cdev结构体 */
    button_cdev = cdev_alloc();
    /* 将cdev结构体和 fops结构体绑定*/
    cdev_init(button_cdev, button_fops);
    /* 将驱动注册到内核中 */
    cdev_add(button_cdev, dev_id,1);
    /* 创建一个class */
    button_class = class_create(THIS_MODULE, "my_button");
    /* 根据class内容创建一个设备节点 my_button*/
    class_device_create(button_class, NULL, dev_id, NULL,"my_button");
    return 0;
}



/* 模块出口函数 */
static void __exit my_button_exit(void){
    
    /* 销毁设别节点 */
    class_device_destroy(button_class, dev_id);
    /* 销毁设备节点 */
    class_destroy(button_class);
    /* 释放cdev结构体空间 */
    cdev_del(button_cdev);
    /* 注销设备号 */
    unregister_chrdev_region(dev_id,1);
    /* 释放fops空间 */
    kfree(button_fops);
    
}

/* 声明模块入口 */
module_init(my_button_init);
/* 声明模块出口 */
module_exit(my_button_exit);
/* 遵循GPL协议 */
MODULE_LICENSE("GPL");

Four: experimental results

1. Follow the steps in the previous chapters, the compiler drivers and applications. Then compiled kernel modules and applications to copy the file system. Then insmod xxx.koinserted into the kernel module, the application execution.
2. The observed experimental results (below):

  • When the print key is pressed:key_val=0
  • When you release the button to print:key_val=1
  • If the 5000 ms, there is no key release button is pressed no printtime out

Guess you like

Origin www.cnblogs.com/gulan-zmc/p/12229159.html