之前在网络的进程开发中,我们有学习过多路复用,这次我们将select,poll应用到我们的按键驱动中。
主要应用于单线程,单进程中同时读取多个设备或文件的情况。
具体可以复习下“42.Linux网络编程--IO多路复用”章节。
一 .POLL的函数实现
函数 | int poll(struct pollfd *fds, nfds_t nfds, int timeout); |
参数 | 参数1: 表示多个文件描述符集合 struct pollfd描述的是文件描述符到信息 struct pollfd { int fd; //文件描述符 short events; //希望监控fd的什么事件:读,写,出错 POLLIN 读, POLLOUT 写, POLLERR出错 short revents; //结果描述,表示当前的fd是否有读,写,出错 //用于判断,是内核自动赋值 POLLIN 读, POLLOUT 写, POLLERR出错 }; 参数2:被监控到fd的个数 参数3: 监控的时间: 正: 表示监控多少ms 负数: 无限的时间去监控 0: 等待0ms,类似于非阻赛 |
返回值 | 返回值:负数:出错 大于0,表示fd中有数据 等于0: 时间到 |
二.使用Poll对设备文件进行监控
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
struct key_event{
int code; // 表示按键的类型: home, esc, Q,W,E,R,T, ENTER
int value; // 表示按下还是抬起 1 / 0
};
#define KEY_ENTER 28
int main(int argc, char *argv[])
{
int ret;
struct key_event event;
char in_buf[128];
int fd = open("/dev/key0", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
//监控多个文件fd
struct pollfd pfd[2];
pfd[0].fd = fd; //监控按键设备
pfd[0].events = POLLIN;
pfd[1].fd = 0; //标准输入
pfd[1].events = POLLIN;
while(1)
{
//poll只能执行一次,所以想一直监控要放在循环中
ret = poll(pfd, 2, -1); // 驱动需要去实现poll接口,类似于open, read,
printf("ret = %d\n", ret);
if(ret > 0)
{
if(pfd[0].revents & POLLIN)
{
read(pfd[0].fd, &event, sizeof(struct key_event));
if(event.code == KEY_ENTER)
{
if(event.value)
{
printf("APP__ key enter pressed\n");
}else
{
printf("APP__ key enter up\n");
}
}
}
if(pfd[1].revents & POLLIN)
{
fgets(in_buf, 128, stdin);//如果没有poll就会一直阻塞在这里等待用户输入
printf("in_buf = %s\n", in_buf);
}
}else{
perror("poll");
exit(1);
}
}
close(pfd[0].fd);
return 0;
}
key_dev.c驱动中添加poll接口
unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
// 返回一个mask值
unsigned int mask;
// 调用poll_wait,将当前到等待队列注册系统中
poll_wait(filp, &key_dev->wq_head, pts);
// 1,当没有数据到时候返回一个0
if(!key_dev->key_state)
mask = 0;
// 2,有数据返回一个POLLIN
if(key_dev->key_state)
mask |= POLLIN;
return mask;
}
const struct file_operations key_fops = {
.open = key_drv_open,
.read = key_drv_read,
.write = key_drv_write,
.release = key_drv_close,
.poll = key_drv_poll,
};
这样就可以同时监控按键和屏幕输入。
资源占用也是非常低的。