在命名管道(FIFO)上使用 poll() 时,看起来 OS X 确实存在错误......专家可以确认吗?

Posted

技术标签:

【中文标题】在命名管道(FIFO)上使用 poll() 时,看起来 OS X 确实存在错误......专家可以确认吗?【英文标题】:It really looks like OS X has a bug when using poll() on a named pipe (FIFO)... can an expert confirm? 【发布时间】:2009-02-26 18:27:28 【问题描述】:

一段时间以来,我一直在尝试从一组命名管道中进行轮询,并且我不断收到对任何命名管道文件描述符的 POLLNVAL 的即时响应。在找到这个blog post about broken polling in OS X 之后,我很确定这是 OS X 中的一个 b-u-g 错误。

我已经计划将我的代码切换为使用 UDP 套接字,但我想请 SO 对此进行验证 a) 以便我确定它确实坏了,并且 b) 出于文档目的。

这是我编写的代码的精简版本(尽管上面链接中的代码经过我测试,拼写得很好):

#includes
...
....
#

static const char* first_fifo_path = "/tmp/fifo1";
static const char* second_fifo_path = "/tmp/fifo2";

int setup_read_fifo(const char* path)
  int fifo_fd = -1;

  if( mkfifo(path, S_IRWXU | S_IRWXG | S_IRWXO) )
    perror("error calling mkfifo()... already exists?\n");

  if((fifo_fd = open(path, O_RDONLY | O_NDELAY)) < 0)
    perror("error calling open()");

  return fifo_fd;


void do_poll(int fd1, int fd2)
  char inbuf[1024];
  int num_fds = 2;
  struct pollfd fds[num_fds];
  int timeout_msecs = 500;

  fds[0].fd = fd1;
  fds[1].fd = fd2;
  fds[0].events = POLLIN;
  fds[1].events = POLLIN;

  int ret;
  while((ret = poll(fds, num_fds, timeout_msecs)) >= 0)
    if(ret < 0)
      printf("Error occured when polling\n");
      printf("ret %d, errno %d\n", ret, errno);
      printf("revents =  %xh : %xh \n\n", fds[0].revents, fds[1].revents);
    

   if(ret == 0)
      printf("Timeout Occurred\n");
      continue;
                                                                       

    for(int i = 0; i< num_fds; i++)
      if(int event = fds[i].revents)

        if(event & POLLHUP)
          printf("Pollhup\n");
        if(event & POLLERR)
          printf("POLLERR\n");
        if(event & POLLNVAL)
          printf("POLLNVAL\n");

        if(event & POLLIN)
          read(fds[i].fd, inbuf, sizeof(inbuf));
          printf("Received: %s", inbuf);
        
      
    
  


int main (int argc, char * const argv[]) 
  do_poll(setup_read_fifo(first_fifo_path), setup_read_fifo(second_fifo_path));
  return 0;

这个输出:

$ ./执行 轮询 轮询 轮询 轮询 轮询 轮询 轮询 轮询 轮询 ...

令人作呕。

还有其他人遇到过这个吗?这是一个真正的错误吧?

【问题讨论】:

【参考方案1】:

这似乎是一个真正的错误。它在 Linux 和 OpenBSD 上按预期工作,但在 OS X 上失败。

【讨论】:

【参考方案2】:

OSX 10.4.1,我可以确认行为。相同的代码在 Linux 上工作正常(只要超时消息正常)。所有的证据,包括这个 - http://www.virtualbox.de/changeset/12347 - 都表明存在真正的问题。

【讨论】:

超时是没有作者的正确行为。我编写了一个简单的编写程序以进行进一步测试,Q 中的程序在 Linx/OpenBSD 上读取 FIFO 并在 OS X 上惨遭失败(同样的 POLLNVAL 问题)。【参考方案3】:

是的,已知的错误。我认为投票中断只是从 10.4 开始,我们不得不在 Fink 中处理它。 Glib 的 configure.in 对此进行了测试,因此您可以确定您没有想象到它。 (嗯,不完全是这个,glib 测试设备上的轮询,而不是 fifos。)

【讨论】:

以上是关于在命名管道(FIFO)上使用 poll() 时,看起来 OS X 确实存在错误......专家可以确认吗?的主要内容,如果未能解决你的问题,请参考以下文章

IPC - 命名管道(fifo)- 使用

IPC - 命名管道(fifo)- 使用

IPC - 命名管道(fifo)- 使用

为啥这里举例说明在 LINUX 中使用命名管道 -FIFO 的程序会遇到竞争条件?

了解 Python 中的命名管道 (FIFO)

当阅读器断开连接时,命名管道 (FIFO) 数据会去哪里?