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 并将其 stdout
(和其他)连接到管道。然后我 epoll_wait
在此管道(和其他管道)上收到 gdb 响应的通知。
每次 epoll_wait
以正 return 值醒来(有一个 fd 可以读取),我从 gdb 的 one 行中读取 stdout
管道(如果那是带有事件的 fd),然后返回 epoll_wait
.
这一切工作正常,除了有时 gdb 响应的最后一行(总是 "(gdb)\n"
)未被读取,并且 epoll_wait
returns 永远为 0。如果我等待几秒钟,然后从 gdb 的 stdout
管道读取,尽管 epoll_wait
是 returning 0,我可以收到 "(gdb)\n"
行。
这是怎么回事?该数据显然已在管道中准备好从中读取,但级别触发的 epoll 未为其生成事件。
一些注意事项:
- 连接到 gdb 的
stdout
的管道是用 O_NONBLOCK
创建的。
epoll_create1
是用 EPOLL_CLOEXEC
调用的(没有别的),即它是水平触发的。
- 我用GNU
getline()
读一行
- 每次调用
getline()
后,我 clearerr()
管道的 fd(我这样做是因为在测试应用程序中我注意到是否达到了 EOF(因为管道的另一端没有'在我读完之前写完整行),基于 stdio 的函数会卡住认为达到了 EOF。我可以逐块读取行,所以这很好。我还尝试删除对 [=27= 的调用] 无效)
- 如果我在读取每一行之后和再次
epoll_wait
ing 之前添加一秒延迟,epoll_wait
将立即 return 每一行的 stdout
fd初始版本+许可证消息,但最后 "(gdb)\n"
行仍然没有。
我怀疑问题出在 C 标准库的缓冲上。这是我对事件时间表的猜测:
- 你打电话给
getline
getline
呼叫 read
- 管道中有两条线可用,并且
read
returns它们都是
getline
给你第一行并缓冲第二行
- 你打电话给
epoll_wait
epoll_wait
块,因为内核发现管道中没有剩余数据
epoll_wait
几秒后超时
- 您再次致电
getline
getline
给你它之前缓冲的第二行
核心问题是,就内核而言,用户空间标准输入缓冲区中的数据与您已经读取和处理的数据没有区别。要解决此问题,切勿将 FD 提供给任何将其包装在 FILE *
中的函数,并直接使用 read
系统调用自行完成所有读取操作。
在一个应用程序中,我生成 gdb 并将其 stdout
(和其他)连接到管道。然后我 epoll_wait
在此管道(和其他管道)上收到 gdb 响应的通知。
每次 epoll_wait
以正 return 值醒来(有一个 fd 可以读取),我从 gdb 的 one 行中读取 stdout
管道(如果那是带有事件的 fd),然后返回 epoll_wait
.
这一切工作正常,除了有时 gdb 响应的最后一行(总是 "(gdb)\n"
)未被读取,并且 epoll_wait
returns 永远为 0。如果我等待几秒钟,然后从 gdb 的 stdout
管道读取,尽管 epoll_wait
是 returning 0,我可以收到 "(gdb)\n"
行。
这是怎么回事?该数据显然已在管道中准备好从中读取,但级别触发的 epoll 未为其生成事件。
一些注意事项:
- 连接到 gdb 的
stdout
的管道是用O_NONBLOCK
创建的。 epoll_create1
是用EPOLL_CLOEXEC
调用的(没有别的),即它是水平触发的。- 我用GNU
getline()
读一行 - 每次调用
getline()
后,我clearerr()
管道的 fd(我这样做是因为在测试应用程序中我注意到是否达到了 EOF(因为管道的另一端没有'在我读完之前写完整行),基于 stdio 的函数会卡住认为达到了 EOF。我可以逐块读取行,所以这很好。我还尝试删除对 [=27= 的调用] 无效) - 如果我在读取每一行之后和再次
epoll_wait
ing 之前添加一秒延迟,epoll_wait
将立即 return 每一行的stdout
fd初始版本+许可证消息,但最后"(gdb)\n"
行仍然没有。
我怀疑问题出在 C 标准库的缓冲上。这是我对事件时间表的猜测:
- 你打电话给
getline
getline
呼叫read
- 管道中有两条线可用,并且
read
returns它们都是 getline
给你第一行并缓冲第二行- 你打电话给
epoll_wait
epoll_wait
块,因为内核发现管道中没有剩余数据epoll_wait
几秒后超时- 您再次致电
getline
getline
给你它之前缓冲的第二行
核心问题是,就内核而言,用户空间标准输入缓冲区中的数据与您已经读取和处理的数据没有区别。要解决此问题,切勿将 FD 提供给任何将其包装在 FILE *
中的函数,并直接使用 read
系统调用自行完成所有读取操作。