0

我想用libev. 我想在键盘输入上有一个观察者,它将解析几个命令,如“开始”“停止”“退出”。在“开始”时,我想创建一个管道并派生应用程序以在子级中启动一些工作程序(例如ffmpeg使用exec()或只是一些打印某些字符的循环),并在父级的该管道上设置一个观察者以将输出打印到控制台。在“停止”命令中,我想杀死一个孩子并移除一个观察者。

我已经实现了这个程序,但是在 fork 之后,当孩子运行时,我总是在键盘输入上遇到段错误。

起初我以为是因为 ifSTDIN可以在孩子和父母之间共享。我试图分离孩子,关闭STDIN孩子。然后我尝试在开始时dup STDIN关闭 parent 中的默认值STDIN,并在 duplicated 上设置一个观察者STDIN。我还尝试STDOUT/ERR在分叉之前关闭描述符并在分叉之后将它们恢复到父级中。

我停下来开始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分支。

返回的 fdepoll是 0,但无论如何我都没有使用 0 作为 fd。此外,对于 0,有一个观察者loop->anfds对我的回调有user_input回调。在之前的迭代中,当我输入任何字符串时,没有事件为 0。我检查了管道 fds,它们也有一个大于 0 的数字。

我无法弄清楚这里发生了什么以及我做错了什么。我可以在这里放一些代码,但那里没有什么特别的。这篇文章足够大,所以如果有人要求提供代码,我稍后会发布。

谢谢。

4

1 回答 1

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;
...
}

因此,将回调中的事件指针转换为我自己的结构是一场彻底而巨大的灾难。

于 2013-04-19T12:16:28.650 回答