分叉后libev中的分段错误
Posted
技术标签:
【中文标题】分叉后libev中的分段错误【英文标题】:Segmentation fault in libev after fork 【发布时间】:2013-04-19 09:44:04 【问题描述】:我想用libev
制作一个示例应用程序。我想在键盘输入上有一个观察者,它将解析几个命令,如“开始”“停止”“退出”。在“开始”时,我想创建一个管道并派生应用程序以在子级中启动一些工作程序(例如 ffmpeg
和 exec()
或只是一些打印一些字符的循环),并在父级的该管道上设置一个观察者将输出打印到控制台。在“停止”命令中,我想杀死一个孩子并移除一个观察者。
我已经实现了这个程序,但是在 fork 之后,当孩子运行时,我总是在键盘输入上遇到段错误。
起初我以为是因为STDIN
可以在孩子和父母之间共享。我试图分离孩子,在孩子中关闭STDIN
。然后我尝试了dup
STDIN
,并在开头关闭了父级中的默认STDIN
,并在重复的STDIN
上设置了一个观察者。我还尝试在分叉之前关闭 STDOUT/ERR
描述符,并在分叉之后将它们恢复到父级中。
我停止并在user_input
回调中启动user_input
观察者,以防万一这有帮助。
然后我尝试在一个子进程中执行ev_default_fork()
和ev_loop_fork()
(这不是必需的,因为我想在fork 之后执行exec()
,或者在任何情况下子循环都不会获得控制)但没有成功。
我还尝试使用不同的后端(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。我检查了管道 fds,它们也有一个数字,然后是 0。
我不知道这里发生了什么以及我做错了什么。我可以在这里放一些代码,但那里没有什么特别的。这篇文章够大,如果有人要代码,我会在稍后发布。
谢谢。
【问题讨论】:
【参考方案1】:好的。用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;
...
因此,将回调中的事件指针转换为我自己的结构是一场彻底而巨大的灾难。
【讨论】:
以上是关于分叉后libev中的分段错误的主要内容,如果未能解决你的问题,请参考以下文章