blockIO_unblockIO_async
linux kernel 阻塞IO/非阻塞IO/异步通知的编写,都分为三步:
创建 struct file_operations 变量
创建 阻塞IO/非阻塞IO/异步通知
唤醒
编写应用程序
阻塞IO
1. 创建 struct file_operations 变量
const struct file_operations xxx_fops = {
.read = xxx_read,
};
2. 创建阻塞IO
DECLARE_WAIT_QUEUE_HEAD(xxx_waitQueueHead); // 定义及初始化等待队列头
ssize_t xxx_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
unsigned char ret;
if(file->f_flags & O_NONBLOCK)
{
// 非阻塞IO模式
}
else
{
// 阻塞IO模式
DECLARE_WAITQUEUE(wq, current); // 创建等待队列
add_wait_queue(&xxx_waitQueueHead, &wq); // 将 等待队列 加入 等待队列头
set_current_state(TASK_INTERRUPTIBLE);
schedule(); // 睡眠,等待唤醒
remove_wait_queue(&xxx_waitQueueHead, &wq);// 唤醒后,从 等待队列头 删除 等待队列
}
......
// 将内核空间kernel_buffer复制到用户空间buf
ret = copy_to_user(buf, &kernel_buffer, size);
return 0;
}
3. 唤醒
唤醒步骤一般在中断处理函数或下半部函数中调用
wake_up(&xxx_waitQueueHead);
4. 编写应用程序
int main(int argc, char **argv)
{
int fd;
char status;
fd = open("/dev/xxxDev", O_RDWR); // 默认以阻塞IO模式打开
while(1) {
read(fd, &status, 1); // 调用kernel xxx_read()
printf("read: %d\n", status);
}
close(fd);
return 0;
}
非阻塞IO
1. 创建 struct file_operations 变量
const struct file_operations xxx_fops = {
.poll = xxx_poll,
};
2. 创建非阻塞IO
DECLARE_WAIT_QUEUE_HEAD(xxx_waitQueueHead); // 定义及初始化等待队列头
unsigned int xxx_poll(struct file *file, struct poll_table_struct *wait)
{
poll_wait(file, &xxx_waitQueueHead, wait); // 睡眠,等待唤醒
return xxx_val? POLLIN : 0;
}
3. 唤醒
唤醒步骤一般在中断处理函数或下半部函数中调用
wake_up(&xxx_waitQueueHead);
4. 编写应用程序
SELECT_METHOD
#include <sys/select.h> int main(int argc, char **argv) { fd_set readfds; int nfds; struct timeval timeout; int fd, ret; char status; fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开 while(1) { FD_ZERO(&readfds); // 置零读文件描述符 FD_SET(fd, &readfds);// 将fd加入读文件描述符 nfds = fd + 1; // 设置读文件描述符的个数 timeout.tv_sec = 3; // 3秒超时 timeout.tv_usec = 0; /* * 调用kernel xxx_poll() * 如果3秒内,有数据可读,调用read() * 如果3秒内,没有数据可读,返回超时状态 */ ret = select(nfds, &readfds, NULL, NULL, &timeout); if(ret > 0) { if(FD_ISSET(fd, &readfds)) { read(fd, &status, 1); // 调用kernel xxx_read() printf("read: %d\n", status); } else { printf("no this fd!\n"); } } else if(ret == 0) { printf("timeout!\n"); } else { printf("error!\n"); } } close(fd); return 0; }
POLL_METHOD
#include <poll.h> int main(int argc, char **argv) { struct pollfd fds; nfds_t nfds; int timeout; int fd, ret; char status; fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开 fds.fd = fd; fds.events = POLLIN; // 监听POLLIN事件 nfds = 1; timeout = 500; // 500ms超时 while(1) { /* * 调用kernel xxx_poll() * 如果500ms内,有数据可读,调用read() * 如果500ms内,没有数据可读,返回超时状态 */ ret = poll(&fds, nfds, timeout); if(ret > 0) { read(fd, &status, 1); // 调用kernel xxx_read() printf("read: %d\n", status); } else if(ret == 0) { printf("timeout!\n"); } else { printf("error!\n"); } } close(fd); return 0; }
异步通知
1. 创建 struct file_operations 变量
const struct file_operations xxx_fops = {
.fasync = xxx_fasync,
};
2. 创建异步通知
struct fasync_struct *fasync_queue; // 定义异步通知
int xxx_fasync(int fd, struct file *file, int on)
{
return fasync_helper(fd, file, on, &fasync_queue); // 初始化异步通知
}
3. 唤醒
唤醒步骤一般在中断处理函数或下半部函数中调用
kill_fasync(&fasync_queue, SIGIO, POLL_IN); // 向应用程序发送SIGIO信号
4. 编写应用程序
#include <signal.h>
int fd;
void xxx_sighandler(int num)
{
char status;
read(fd, &status, 1); // 调用kernel xxx_read()
printf("read: %d\n", status);
}
int main()
{
fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开
fcntl(fd, F_SETOWN, getpid()); // 将当前进程的进程号告诉给内核
// 设置异步通知模式,调用kernel xxx_fasync()
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
/*
* 设置SIGIO信号的处理函数为xxx_sighandler()
*
* 当kernel调用kill_fasync()向应用程序发送SIGIO信号时,
* 应用程序调用xxx_sighandler()
*/
signal(SIGIO, xxx_sighandler);
while(1);
close(fd);
return 0;
}
Last updated
Was this helpful?