pipe - 通过管道在 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 没有为它生成事件。
一些注意事项:
- 连接到 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"
一行。
解决方案
我怀疑问题在于 C 标准库所做的缓冲。以下是我对事件时间线的猜测:
- 你打电话
getline
getline
来电read
- 管道中有两条线可用,并
read
返回它们 getline
给你第一行并缓冲第二行- 你打电话
epoll_wait
epoll_wait
块,因为内核看到管道中没有数据epoll_wait
几秒钟后超时- 你
getline
再打电话 getline
给你它之前缓冲的第二行
核心问题是,就内核而言,用户空间标准输入缓冲区中的数据与您已经读取和处理的数据之间没有区别。要解决此问题,切勿将 FD 提供给将其包装在 a 中的任何函数,并直接使用系统调用FILE *
自己进行所有读取。read
推荐阅读
- sql - 查找另一个表并乘以行
- amazon-web-services - 无法将 EC2 实例连接到同一 VPC 中的 RDS
- git - 如何只推送小于特定限制的文件?
- node.js - 如果没有为 module.exports 分配任何内容,Node.js 'require()' 会返回什么
- mongodb - 嵌套数组求和/计数 MongoDB Express
- linux - 运行 Bash 脚本时找不到命令,但直接运行命令时有效
- html - 跨越 2 列和 2 行的 Flexbox 单元格
- modelica - 为什么在算法部分中分配任何一个元素时,Modelica数组元素会自动分配为零
- sql - SQL Server:SUM 任务每日累计工作量
- arrays - 这段代码是如何工作的?他们正在根据条件删除数组中的项目。语法让我困惑