前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >epoll 能监听普通文件吗?

epoll 能监听普通文件吗?

作者头像
用户7686797
发布2021-06-15 16:09:16
2.5K0
发布2021-06-15 16:09:16
举报
文章被收录于专栏:Linux内核那些事Linux内核那些事

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

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

代码语言:javascript
复制
#include <stdio.h>
#include <sys/epoll.h>
#include <fcntl.h>

int main()
{
   int epfd, fd;
   struct epoll_event ev, events[2];
   int result;

   epfd = epoll_create(10);
   if (epfd < 0) {
       perror("epoll_create()");
       return -1;
  }

   fd = open("./test.txt", O_RDONLY | O_CREAT);
   if (fd < 0) {
       perror("open()");
       return -1;
  }

   ev.events = EPOLLIN;

   result = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
   if (result < 0) {
       perror("epoll_ctl()");
       return -1;
  }

   epoll_wait(epfd, events, 2, -1);

   return 0;
}
代码语言:javascript
复制

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

代码语言:javascript
复制
[vagrant@localhost epoll]$ gcc epoll.c -o epoll
[vagrant@localhost epoll]$ ./epoll
epoll_ctl(): Operation not permitted
代码语言:javascript
复制

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

寻根究底

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

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

代码语言:javascript
复制
SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
               struct epoll_event __user *, event)
{
   int error;
   struct file *file, *tfile;

  ...

   error = -EBADF;
   file = fget(epfd);  // epoll 句柄对应的文件对象
   if (!file)
       goto error_return;

   tfile = fget(fd);   // 被监听的文件句柄对应的文件对象
   if (!tfile)
       goto error_fput;

   error = -EPERM; // Operation not permitted 错误号
   if (!tfile->f_op || !tfile->f_op->poll)
       goto error_tgt_fput;

  ...

error_tgt_fput:
   fput(tfile);
error_fput:
   fput(file);
error_return:

   return error;
}
代码语言:javascript
复制

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

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

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

代码语言:javascript
复制
const struct file_operations ext4_file_operations = {
  .llseek         = generic_file_llseek,
  .read           = do_sync_read,
  .write          = do_sync_write,
  .aio_read       = generic_file_aio_read,
  .aio_write      = ext4_file_write,
  .unlocked_ioctl = ext4_ioctl,
  .mmap           = ext4_file_mmap,
  .open           = ext4_file_open,
  .release        = ext4_release_file,
  .fsync          = ext4_sync_file,
  .splice_read    = generic_file_splice_read,
  .splice_write   = generic_file_splice_write,
};
代码语言:javascript
复制

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux内核那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 寻根究底
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档