28、基于Firefly-rk3399 poll使用

一、流程简介

drv_poll 要把自己这个线程挂入等待队列 wq 中。

在这里插入图片描述

poll流程分为以下两种情况:

1、有中断唤醒

(1)drv_poll return false

(2)休眠

(3)中断事件

(4)唤醒休眠

(5)drv_poll return true

(6)read data。

2、无中断唤醒

(1)drv_poll return false

(2)休眠

(3)内核唤醒休眠,休眠结束

(4)drv_poll return false

(5)休眠

(6)内核唤醒休眠,休眠结束

(7)drv_poll return false

(8)poll等待超时

(9)退出,返回异常。

注意

drv_poll 要把线程挂入队列 wq,但是并不是在 drv_poll 中进入休眠,而是在调用 drv_poll 之后休眠

drv_poll 要返回数据状态

APP 调用一次 poll,有可能会导致 drv_poll 被调用 2 次

线程被唤醒的原因有 2:中断发生了去队列 wq 中把它唤醒,超时时间到了内核把它唤醒

APP 要判断 poll 返回的原因:有数据,还是超时。有数据时再去调用 read 函数

二、kernel API

Poll函数原型:

unsigned int (*poll) (struct file *, struct poll_table_struct *);

将当前线程挂入等待队列函数:

void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);

(1)填充file_operations结构体

const struct file_operations key_fops = {
	.owner = THIS_MODULE,
	.open = key_open,	
	.release = key_release,	
	.read = key_read,	
	.write = key_write,
    /* 增加 */
	.poll = key_poll,
};

(2)key_poll函数的实现

static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) {
	poll_wait(file, &gpio_key_wait, wait);
    /* POLLIN 有数据可读 POLLRDNORM 等同于 POLLIN */
	return key_signal ? POLLIN | POLLRDNORM : 0;
}

关于return的解析:
    poll_wait将线程放入队列结束后会休眠,之后进入return只有两种情况:
    	① 超时,若超时则说明未出现中断唤醒gpio_key_wait,此时key_signal为0
    	② 发生中断,此时出现中断唤醒gpio_key_wait,此时key_signal为非0,返回POLLIN | POLLRDNORM给APP

说明

如果 key_poll 执行成功,会返回非负值。
用户态程序通过 poll 或 select 调用检测按键事件,会fds.revents & POLLIN做判断

三、App API

相关函数

在应用层,**poll** 是一个用于监视多个文件描述符是否可读、可写或发生错误的系统调用,常用于处理多路 I/O。它与 select 类似,但没有文件描述符数量限制,性能更优。

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数说明:
  • fds:一个指向 pollfd 结构数组的指针,每个结构表示一个被监控的文件描述符及其事件。

  • nfdsfds 数组的大小,即需要监控的文件描述符数量。

  • timeout

    :超时时间(毫秒)。

    • timeout > 0:等待指定的毫秒数。
    • timeout = 0:立即返回,不阻塞。
    • timeout < 0:无限等待,直到某个事件发生。
返回值:
  • 返回正数:有事件发生的文件描述符数量。
  • 返回0:超时,没有文件描述符发生事件。
  • 返回-1:发生错误,可通过 errno 查看错误信息。

struct pollfd 结构体

pollfd 是一个结构体,定义如下:

struct pollfd {
    int fd;        // 文件描述符
    short events;  // 等待的事件类型
    short revents; // 实际发生的事件类型
};
常见的事件类型:
  • 等待的事件(events
    • POLLIN:表示有数据可读。
    • POLLOUT:表示可以写入数据。
    • POLLERR:发生错误。
    • POLLHUP:挂起(通常是管道关闭)。
    • POLLPRI:有紧急数据可读。
  • 实际发生的事件(revents
    • 可能是上述事件的组合,表示实际发生的事件。

代码示例

#include <stdio.h>
#include <poll.h>
#include <unistd.h>

int main() {
    struct pollfd fds[1];
    int timeout = 5000;
    int fd = 0;

    fd = open("/dev/diy_key_double");
    if(fd == -1) {
        perror("open");
        return -1;
    }

    fds[0].fd = fd;
    fds[0].events = POLLIN;
    fds[0].revents = 0;

    while(1) {
        int ret = poll(fds, 1, timeout);
        if(ret == -1) {
            perror("poll");
            break;
        }
        else if (ret == 0) { 
            printf("Timeout\n");
        }
        else {
            if(fds[0].revents & POLLIN) {
                int buf;
                int nread = read(fd, &buf, sizeof(buf));
                if(nread > 0) {
                    printf("Read: %d\n", buf);
                }
            }
            else {
                printf("Unexpected event\n");
            }
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值