linux应用访问驱动的4种方式
linux应用访问驱动的4种方式
1.非阻塞
与阻塞方式相反,在应用获取驱动返回的数据时,不管此时驱动有没有数据,都立即返回
在应用程序中 ,APP调用open函数时,传入“O_NONBLOCK”表示“非阻塞”
//头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//函数原型: int open(const char *pathname, int flags);
//例子:
fd= open(file, O_RDWR | O_NONBLOCK);
2.阻塞方式
与非阻塞方式相反,在应用获取驱动返回的数据时,有数据立即返回,无数据则休眠,等到数据到来,将其唤醒
//头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//函数原型: int open(const char *pathname, int flags);
//例子:
fd = open(file, O_RDWR);
3.POLL/SELECT方式方式
POLL机制、SELECT机制是完全一样的,只是APP接口函数不一样。
//头文件
#include <poll.h>
//函数原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//其中 struct pollfd结构体
struct pollfd {
int fd; /* 文件描述 */
short events; /* 设置我们希望发生的事件 */
short revents; /* 实际发生的事件 */
};
nfds_t 调用者应在 nfds 中指定 fds 数组中的项目数。
timeout 参数指定 poll() 应该阻塞等待文件描述符准备好的毫秒数。
调用将阻塞,直到:
* 文件描述符已经准备好;
* 调用被信号处理程序中断;
* 超时
//events; 举例(不全,详细请去参考man poll)
// POLLIN 有数据要读取
// POLLPRI 文件描述符有一些异常情况。可能性包括:
* TCP 套接字上有带外数据
* 数据包模式下的伪终端主机在从机上看到状态更改
* 修改了 cgroup.events 文件
//POLLOUT 现在可以进行写入,
//例子
struct pollfd fds;
nfds_t nfds = 1;
fds.fd = fd;
fds.events = POLLIN; //期待输入事件
fds.revents = 0;
ret = poll(fds, nfds, 5000);
SELECT机制
//头文件
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
//函数原型: int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
//fd_set使用下列函数配置
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
提供了四个宏来操作集合。 FD_ZERO() 清除一组。 FD_SET() 和 FD_CLR() 分别从集合中添加和删除给定的文件描述符。 FD_ISSET() 测试文件描述符是否是集合的一部分
//nfds 应设置为三个集合中任何一个中编号最高的文件描述符,加 1
// timeout
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
//例子
int nfds;
struct timeval tv;
fd_set readfds;
/* 设置超时时间 */
tv.tv_sec = 5;
tv.tv_usec = 0;
/* 想监测哪些文件? */
FD_ZERO(&readfds); /* 全部清零 */
FD_SET(fd, &readfds); /* 想监测fd */
nfds = fd + 1; /* nfds 是最大的文件句柄+1, 注意: 不是文件个数, 与poll不一样 */
ret = select(nfds, &readfds, NULL, NULL, &tv);
4.异步通知
所谓异步通知,就是APP处理自身的事情,当驱动程序有数据时它会主动给APP发信号
#include <signal.h>
//signal() 将信号符号的处置设置为处理程序,它可以是 SIG_IGN、SIG_DFL 或程序员定义的函数(“信号处理程序”)的地址。
如果将信号signum 传递给进程,则会发生以下情况之一:
* 如果处置设置为SIG_IGN,则忽略该信号。
* 如果处置设置为 SIG_DFL,则发生与信号关联的默认操作。
* 如果处置设置为函数,则首先处置被重置为 SIG_DFL,或者信号被阻塞,然后使用参数 signum 调用处理程序。如果处理程序的调用导致信号被阻塞,则信号在从处理程序返回时被解除阻塞。
注意:信号 SIGKILL 和 SIGSTOP 不能被捕获或忽略。
例子:
① 编写信号处理函数:
static void sig_func(int sig)
{
int val;
read(fd, &val, 4);
printf("get value : 0x%x\n", val);
}
② 注册信号处理函数:
signal(SIGIO, sig_func);
③ 打开驱动:
fd = open(file, O_RDWR);
④ 把进程ID告诉驱动
fcntl(fd, F_SETOWN, getpid());
⑤ 使能驱动的FASYNC功能:
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);