【问题标题】:Is it possible to use event file descriptor in combination with interrupt-driven input?是否可以将事件文件描述符与中断驱动输入结合使用?
【发布时间】:2016-01-16 19:17:19
【问题描述】:

这是最小的例子(故意忽略错误检查和信号安全):

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/eventfd.h>
#include <stdio.h>
#include <sys/wait.h>

void reader(int a)
{
  printf("hello!\n");
  wait(NULL);
  exit(EXIT_SUCCESS);
}

int main()
{
  signal(SIGIO, reader);
  int efd = eventfd(0, EFD_NONBLOCK);
  fcntl(efd, F_SETOWN, getpid());
  int flags;
  flags= fcntl(efd, F_GETFL);
  fcntl(efd, F_SETFL, flags | O_ASYNC);

  pid_t p = fork();
  if (p)
  {
    for(;;)
      pause();
  }
  else 
  {
    uint64_t buff = 1;
    if (write(efd, &buff, sizeof(buff)) == -1)
      printf("write error\n");
    exit(EXIT_SUCCESS);
  }
}

在子进程写入事件文件描述符后,这段代码应该在父进程中生成 SIGIO,但它没有。我什至尝试从 eventfd 系统调用中删除 EFD_NONBLOCK 并且我有相同的行为。所以这里有几个问题。

这是处理中断驱动的 I/O 的正确方法吗?

中断驱动的 I/O 能否与事件文件描述符结合使用?如何使用?

【问题讨论】:

    标签: c linux io system-calls


    【解决方案1】:

    eventfd 文件描述符不支持O_ASYNC 标志。

    似乎man open(2) 描述了所有当前 O_ASYNC 功能的实现者:

    此功能仅适用于终端、伪终端、套接字以及(自 Linux 2.6 起)管道和 FIFO。

    一般情况下,如果具体文件不支持O_ASYNC 标志,它会被静默忽略。可以检查标志是否成功由随后的 F_GETFL 设置:

    // Try to set the flag
    int flags;
    flags= fcntl(efd, F_GETFL);
    fcntl(efd, F_SETFL, flags | O_ASYNC);
    // Check whether the flag is set
    int new_flags = fcntl(efd, F_GETFL);
    if(!(new_flags & O_ASYNC)) {
        // Failed to set the flag.
    }
    

    如果想要设置特定文件不支持的 O_ASYNC 标志,建议 fcntl 返回错误。 This mailing 就是其中之一。但是根据内核函数setfl的当前实现,它们已被拒绝:

    if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync)
    

    FASYNC 是 O_ASYNC 的同义词,-&gt;fasync 回调,如果存在,实现具体文件的标志更改)。

    【讨论】:

    • 谢谢!我正在寻找某种报告,为什么它无法工作但找不到任何东西。当系统调用静默失败时,这是非常令人困惑的。我接受你的回答。
    • F_SETFL 模式 fcntl 默默地忽略一些标志。可能,当 O_ASYNC 标志设置为不适当的文件时,它也选择了相同的决定。我已经用其他详细信息和检测方式更新了我的答案,无论标志是否已成功设置。
    【解决方案2】:

    通过调用eventfd() 返回的文件描述符与通过调用write() 更改内容时生成信号无关。

    如果你想让父每次唤醒文件描述符,一个 8 字节的值。被写入,然后让父级使用select(),其中输入变量包含从对eventfd()的调用返回的文件描述符。

    eventfd() 的 linux 手册页包含如何使用 eventfd() 函数的示例。

    select() 的 linux 手册页包含如何使用 select() 函数的示例。

    【讨论】:

    • 我不想使用 select、poll、epoll 等 API。该问题清楚地说明了中断驱动的 I/O (gnu.org/software/libc/manual/html_node/…) 会导致传递信号。我知道如何将它与 select 一起使用,但它不适合我的需要。
    • 问题清楚地表明您想使用从eventfd() 返回的文件描述符来产生信号。那不会发生。
    • 但是在使用 FIFO 和 PIPE 时可能会收到信号,所以我想知道是否有人知道解决方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 2021-07-06
    • 1970-01-01
    相关资源
    最近更新 更多