c - fork 后 libev 出现段错误

标签 c linux fork libev

我想使用 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/

相关文章:

c - 使用警报让父进程等待子进程几秒钟

C++ fork() 在 linux 终端上看起来很奇怪

linux - 如何在 kubernetes 中部署 nginx.config 文件

c++ - 进程在不同机器上的虚拟内存大小

c - 如何使 SqLite 在 Windows 10 中工作

c - 我如何使用 setsockopt(SO_REUSEADDR)?

c++ - 将进程的输出写入缓冲区

c - 当我们在c中使用fork时,进程之间是否共享数据?

c - 通过 Socket 将结构从客户端传递到服务器

c - 固件中存储串口数据的数据结构