通过管道在 gdb 的 MI 输出上级别触发的 epoll_wait() 不通知“(gdb)\n”行的存在
Posted
技术标签:
【中文标题】通过管道在 gdb 的 MI 输出上级别触发的 epoll_wait() 不通知“(gdb)\\n”行的存在【英文标题】:Level-triggered epoll_wait() on gdb's MI output through pipe doesn't notify the existence of the "(gdb)\n" line通过管道在 gdb 的 MI 输出上级别触发的 epoll_wait() 不通知“(gdb)\n”行的存在 【发布时间】:2020-05-21 21:08:18 【问题描述】:在一个应用程序中,我生成 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 并未为其生成事件。
一些注意事项:
连接到 gdb 的stdout
的管道是使用 O_NONBLOCK
创建的。
epoll_create1
是用 EPOLL_CLOEXEC
调用的(仅此而已),即它是级别触发的。
我使用 GNU getline()
读取一行
在每次调用getline()
之后,我clearerr()
管道的fd(我这样做是因为在测试应用程序中我注意到是否达到EOF(因为管道的另一端还没有完成整个写入行),基于 stdio 的函数在认为到达 EOF 时卡住了。我可以处理逐块读取行,所以这很好。我还尝试删除对 clearerr()
的调用,但没有效果)
如果我在每行读取之后和再次epoll_wait
ing 之前添加一秒延迟,epoll_wait
将立即为初始版本+许可证消息的每一行返回stdout
fd,但仍然不是最后一个"(gdb)\n"
线。
【问题讨论】:
【参考方案1】:我怀疑问题在于 C 标准库所做的缓冲。以下是我对事件时间线的猜测:
您拨打getline
getline
致电read
管道中有两条线,read
返回两条线
getline
提供第一行并缓冲第二行
您拨打epoll_wait
epoll_wait
阻塞,因为内核发现管道中没有数据了
epoll_wait
几秒钟后超时
你再拨打getline
getline
提供了它之前缓冲的第二行
核心问题是,就内核而言,用户空间标准输入缓冲区中的数据与您已经读取和处理的数据之间没有区别。要解决此问题,切勿将 FD 提供给将其包装在 FILE *
中的任何函数,并直接使用 read
系统调用自行完成所有读取操作。
【讨论】:
嗯,有道理。我仍然无法解释为什么如果我在epoll_wait
s 之间添加 1s 的延迟,我仍然会为 gdb 输出的每一行得到一个事件(它最初输出像 20 行),但也许这与最后一个有关线这么短。你是对的,我应该放弃阅读FILE *
。谢谢以上是关于通过管道在 gdb 的 MI 输出上级别触发的 epoll_wait() 不通知“(gdb)\n”行的存在的主要内容,如果未能解决你的问题,请参考以下文章