我想使用 libev
制作一个示例应用程序。我想要一个键盘输入观察程序,它将解析几个命令,例如“开始”“停止”“退出”。在“启动”时,我想创建一个管道并 fork 应用程序以启动一些工作程序(例如使用 exec() 或只是打印一些字符的循环)子级并在父级中的该管道上设置观察程序以将输出打印到控制台。在“停止”命令中,我想杀死一个 child 并删除一个观察者。
我已经实现了这个程序,但是在 fork 之后,当 child 运行时,我总是在键盘输入上出现段错误。
起初我认为这是因为如果 STDIN
可以在子级和父级之间共享。我尝试分 ionic 项,关闭子项中的 STDIN
。然后我尝试了 dup
STDIN
并在开始时关闭父级中的默认 STDIN
并在重复的 STDIN
上设置观察程序。我还尝试在 fork 之前关闭 STDOUT/ERR 描述符,并在 fork 后将它们恢复到父级中。
我停止并在 user_input
回调中启动 user_input
观察程序,以防这可能有所帮助。
然后我尝试在子进程中执行 ev_default_fork()
和 ev_loop_fork()
(这不是必需的,因为我想要 exec()
就在 fork 之后或者在任何情况下子循环都不会获得控制)但没有成功。
我还尝试使用不同的后端(select
而不是 epoll
)。
我还尝试忽略一些信号,例如 SIGHUP
SIGPIPE
SIGCHILD
。
我还注意到,在 fork()
之后的输入会导致段错误,并且 bash 将其作为命令获取,因此如果我执行类似的操作(使用“>”我表示自己手写的输入,并且带有“<”的程序和系统输出):
> $ ./libev_example
> start
< Debug: fork data got:
< [Data got from child through pipe]
> asd
< Segmentation fault (core dumped)
< $ asd
< bash: asd: command not found...
然后我从源代码构建了 libev
并尝试进行调试。段错误发生在 ev.c:1698
if (expect_false (w_->pending))
pendings [pri][w_->pending - 1].events |= revents;
else
pri
值为 4,据我所知,这是一个优先级。 pendings[4]
是 0x0
因此会发生段错误。当程序没有崩溃时,代码将进入 else
分支。
epoll
返回的fd是0,但我无论如何都没有使用0作为fd。此外,对于 0,loop->anfds
中有一个观察程序,它具有对我的 user_input
回调的回调。在之前的迭代中,当我输入任何字符串时,没有 0 的事件。我检查了管道 fd,它们也有一个大于 0 的数字。
我不知道这里发生了什么以及我做错了什么。我可以在这里放置一些代码,但那里没有什么特别的。这篇文章足够大,所以如果有人索要代码,我稍后会发布。
谢谢。
最佳答案
好的。一段时间用gdb解决了这个问题。我在代码中发现了几个与 libev 或 fork 没有直接联系的错误。
导致这种奇怪行为的问题是我的打字错误,由于我的疏忽而没有注意到。我对标准 ev_io
结构进行了子类化,但出于某种原因我做了这个:
typedef struct lee_user_input_event_t{
struct ev_io *event;
struct lee_process_data_t *child_process_data;
...
};
而不是这个:
typedef struct lee_user_input_event_t{
struct ev_io event;
struct lee_process_data_t *child_process_data;
...
}
因此,将回调中的事件指针转换为我自己的结构是一场彻底而巨大的灾难。
关于c - fork 后 libev 出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16101756/