首页 > 解决方案 > 通过管道在 gdb 的 MI 输出上级别触发的 epoll_wait() 不通知“(gdb)\n”行的存在

问题描述

在一个应用程序中,我生成 gdb 并将其stdout(和其他)连接到管道。然后我epoll_wait在这个管道(和其他管道)上收到来自 gdb 的响应的通知。

每次epoll_wait以正返回值唤醒(有一个 fd 可供读取),我从 gdb 的管道中读取一行stdout如果那是带有事件的 fd),然后返回到epoll_wait.

这一切都很好,除了有时 gdb 响应的最后一行(总是"(gdb)\n")没有被读取,并且epoll_wait永远返回 0。如果我等待几秒钟,然后从 gdb 的stdout管道中读取,尽管epoll_wait返回 0,我可以收到该"(gdb)\n"行。

这是怎么回事?该数据显然在管道中准备好从中读取,但级别触发的 epoll 没有为它生成事件。

一些注意事项:

标签: pipeepoll

解决方案


我怀疑问题在于 C 标准库所做的缓冲。以下是我对事件时间线的猜测:

  • 你打电话getline
  • getline来电read
  • 管道中有两条线可用,并read返回它们
  • getline给你第一行并缓冲第二行
  • 你打电话epoll_wait
  • epoll_wait块,因为内核看到管道中没有数据
  • epoll_wait几秒钟后超时
  • getline再打电话
  • getline给你它之前缓冲的第二行

核心问题是,就内核而言,用户空间标准输入缓冲区中的数据与您已经读取和处理的数据之间没有区别。要解决此问题,切勿将 FD 提供给将其包装在 a 中的任何函数,并直接使用系统调用FILE *自己进行所有读取。read


推荐阅读