嵌入式内核及驱动开发之学习笔记(九) 多路复用+中断实现读取数据
使用阻塞模型虽然可以避免等待数据过程中,CPU对进程的消耗,但是仅仅是为了等待这一个结果,就让进程进入休眠,对于还要进行其他IO操作的进程而言太“奢侈”。所以引入多路复用的概念,解决这个问题。
非阻塞:立即返回结果,如果想得到期望的结果,要不停的调用这个方法(轮询),非常耗费资源
阻塞:没有得到真正的数据前,不返回结果。此时,进程进入阻塞(休眠)态,直到有数据唤醒进程,这个过程不耗资源。
多路复用:和原理和阻塞类似,不过多路复用是同时进行多个IO读写操作。这样就减少了在等待时间上的浪费,提高效率。
多路复用要对文件描述符进行操作,在应用层上进行实现。关于多路复用在应用层上的使用,之前我有总结过一份笔记。这里使用poll函数完成;应用中使用poll对设备文件进行了监控,那么设备驱动就必须实现poll接口。所以...
- poll函数实现对标准输入流(按键)与设备输入流(按键)的监控
- 在设备驱动中实现poll的接口
Linux环境下使用`man 2 poll`查看poll函数的介绍,程序包含头文件poll.h
#include <poll.h>
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: 时间到
应用程序
-
//key_test.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; // 按键的类型
-
int value; // 状态
-
};
-
-
-
#define KEY_ENTER 28
-
-
int main(int argc, char *argv[])
-
{
-
int ret;
-
char in_buf[128]; //接收标准输入数据
-
struct key_event event; //接收按键设备数据
-
-
int fd = open("/dev/key0", O_RDWR);
-
-
if(fd < 0)
-
{
-
perror("open");
-
exit(1);
-
}
-
//描述2个文件描述符,标准输入0 和 按键设备结点fd
-
struct pollfd pfd[2];
-
-
pfd[0].fd = fd; //监控按键设备
-
pfd[0].events = POLLIN;
-
-
pfd[1].fd = 0; //标准输入
-
pfd[1].events = POLLIN;
-
-
while(1)
-
{
-
ret = poll(pfd, 2, -1); // 多路复用 poll 同时监控按键与标准输入
-
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);
-
printf("in_buf = %s\n", in_buf);
-
}
-
}else{
-
perror("poll");
-
exit(1);
-
}
-
}
-
-
-
-
close(pfd[0].fd);
-
-
-
return 0;
-
-
}
-
-
-
设备驱动文件
1.在file_operations中 poll指向key_drv_poll函数
-
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,
-
-
};
2.在key_drv_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;
-
-
}
最终结果
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/84192417
- 点赞
- 收藏
- 关注作者
评论(0)