epoll 能监听普通文件吗?

Linux内核那些事

共 4706字,需浏览 10分钟

 ·

2021-05-11 08:29

epoll 是 Linux 系统中常用的多路复用 I/O 组件,一般用于监听 socket 是否能够进行 I/O 操作。那么,epoll 能监听普通文件吗?

我们先通过下面的例子来验证一下,epoll 能不能监听普通文件:

 1#include <stdio.h>
2#include <sys/epoll.h>
3#include <fcntl.h>
4
5int main()
6
{
7   int epfd, fd;
8   struct epoll_event evevents[2];
9   int result;
10
11   epfd = epoll_create(10);
12   if (epfd < 0) {
13       perror("epoll_create()");
14       return -1;
15  }
16
17   fd = open("./test.txt", O_RDONLY | O_CREAT);
18   if (fd < 0) {
19       perror("open()");
20       return -1;
21  }
22
23   ev.events = EPOLLIN;
24
25   result = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
26   if (result < 0) {
27       perror("epoll_ctl()");
28       return -1;
29  }
30
31   epoll_wait(epfd, events, 2-1);
32
33   return 0;
34}

编译并且运行,结果如下:

[vagrant@localhost epoll]$ gcc epoll.c -o epoll
[vagrant@localhost epoll]$ ./epoll
epoll_ctl(): Operation not permitted

可以看到上面的运行结果报 Operation not permitted 的错误,这说明 epoll 是不能监听普通文件的,为什么呢?

寻根究底

我们应该对追寻真相抱着热衷的态度,所以必须找出 epoll 不能监听普通文件的原因。

因为在上面的例子中,是 epoll_ctl 函数报的错,所以我们首先应该从 epoll_ctl 的源码入手,如下:

 1SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
2               struct epoll_event __user *, event)
3{
4   int error;
5   struct file *file, *tfile;
6
7  ...
8
9   error = -EBADF;
10   file = fget(epfd);  // epoll 句柄对应的文件对象
11   if (!file)
12       goto error_return;
13
14   tfile = fget(fd);   // 被监听的文件句柄对应的文件对象
15   if (!tfile)
16       goto error_fput;
17
18   error = -EPERM; // Operation not permitted 错误号
19   if (!tfile->f_op || !tfile->f_op->poll)
20       goto error_tgt_fput;
21
22  ...
23
24error_tgt_fput:
25   fput(tfile);
26error_fput:
27   fput(file);
28error_return:
29
30   return error;
31}

从上面代码可以看出,当被监听的文件没有提供 poll 接口时,就会返回 EPERM 的错误,这个错误就是 Operation not permitted 的错误号。

所以,出现 Operation not permitted 的原因就是:被监听的文件没有提供 poll 接口。

由于我们的文件系统是 ext4,所以我们来看看 ext4 文件系统中的文件是否提供了 poll 接口(位于文件 /fs/ext4/file.c 中):

 1const struct file_operations ext4_file_operations = {
2  .llseek         = generic_file_llseek,
3  .read           = do_sync_read,
4  .write          = do_sync_write,
5  .aio_read       = generic_file_aio_read,
6  .aio_write      = ext4_file_write,
7  .unlocked_ioctl = ext4_ioctl,
8  .mmap           = ext4_file_mmap,
9  .open           = ext4_file_open,
10  .release        = ext4_release_file,
11  .fsync          = ext4_sync_file,
12  .splice_read    = generic_file_splice_read,
13  .splice_write   = generic_file_splice_write,
14};

ext4 文件的文件操作函数集被设置为 ext4_file_operations(也说就是:file->f_op = ext4_file_operations),从上面代码可以看出,ext4_file_operations 并没有提供 poll 接口。所以,当调用 epoll_ctl 把文件添加到 epoll 中进行监听时,就会返回 Operation not permitted 的错误。

从上面的分析可知,当文件系统提供 poll 接口时,就可以把文件添加到 epoll 中进行监听。


浏览 22
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报