如何在通过exec调用的父进程中获取已执行应用程序的状态?
Posted
技术标签:
【中文标题】如何在通过exec调用的父进程中获取已执行应用程序的状态?【英文标题】:How to get Status of the executed application in parent process called through exec? 【发布时间】:2016-06-09 19:08:18 【问题描述】:我正在开发一个简单的应用程序,它执行以下操作:
主应用程序将有子进程,其中正在通过 exec 调用调用应用程序。此应用程序实际上正在执行固件下载操作。 例如。 execl("/usr/bin/fwdownload","fwdownload", "args", NULL);
在父进程中,我将再次分叉它,以便我将再次拥有子进程。在这个子进程中,我调用 Xmodem 实用程序从本地机器接收固件映像文件。我将接收到的数据包写入命名的 fifo 文件(使用 mkfifo 创建)。这个命名的 fifo 文件将由“fwdownload”应用程序访问,以读取数据包以刷新固件。
所以再次在父进程中,当 xmodem 文件传输发生时,我检查“fwdownload”应用程序的状态。
我在这里面临的问题是:
当失败时,我无法在父进程中获取“fwdownload”应用程序的状态。如何获得这种状态。尝试了所有可能的方法
当我从“fwdownload”应用程序获得故障状态时,如何终止通过第二个子进程调用的 xmodem 实用程序? .
伪代码:
void SIGTERM_Handler(int signal)
exit(0); // Kill the Xmodem utility
int main()
pid_t cpid_1, cpid_2 ;
cpid_1 = fork();
if( cpid_1 == 0 ) // child process
execl("/usr/bin/fwdownload", "fwdownload", NULL);
printf("exec Failed");
exit(FAILED);
else // Parent process
cpid_2 = fork();
if( cpid_2 == 0 )
mkfifo("/tmp/fifo_file");
signal(SIGTERM, SIGTERM_Handler);
execl("/bin/rx", "rx", "/tmp/fifo_file", NULL); // fifo_file
printf("exec failed");
exit(FAILED);
else
wait_status = waitpid(cpid_1, &status, WUNTRACED | WCONTINUED);
if( WIFEXITED(status))
kill(cpid_2, SIGTERM);
printf(" FW Download app is exited \n");
【问题讨论】:
为什么是 FIFO 而不是子进程之间的管道?还是只是一个普通的文件?我个人永远不会假设固件传输成功,并且总是希望固件安装程序应用程序检测固件下载是否失败或中断(例如,由于网络中断或其他原因)。如果固件安装程序总是将整个映像读入内存(因为它在某处有一个校验和),它确实应该支持从标准输入读取数据。如果没有,我肯定会使用临时文件并单独的 sha256sum 校验和...... 我没有使用普通文件,因为 fwdownload 应用程序希望文件传输以数据包方式进行。我没有任何理由不使用 pipe 。如果我们使用普通管道而不是 FIFO 文件,我们有什么额外的好处吗? . 使用管道有几个优点。如果下载应用程序死机/退出,安装程序将通过下一个read()
返回 0 来检测它。如果安装程序死机/退出,下载应用程序将从下一个 write()
获得 -1,errno == EPIPE
。如果使用 FIFO,另一端将阻塞,直到另一端也打开,并且总是存在其他进程干预的风险(通过也打开 FIFO);此外,必须根据需要创建和删除 FIFO 文件系统对象。简单地说,FIFO 更复杂,风险更大,在这个用例中没有任何好处。
非常感谢。是的你是对的 。就我而言,我怀疑正在发生死锁。当一个写入 FIFO 的进程启动时,从同一个 FIFO 读取的其他进程必须同时执行。但在我的情况下,第二个进程(从 FIFO 读取)正在退出或返回,这将使第一个进程处于阻塞状态。因此,您建议我,如果我们使用管道,这种情况不会发生? .
如果两个程序在退出前明确关闭管道,那不应该发生。写入器(下载器)会阻塞,直到读取器(安装器)读取数据为止(除了每个管道有一个至少 512 字节的缓冲区可以“立即”写入,只要管道的另一端仍然打开);读取器将阻塞,直到写入器关闭管道或写入更多数据。您是否考虑过编写一个最小的测试程序——比如说,如果孩子们看到数据中的特定字符,他们就会退出,在其他一些字符上睡觉,否则不做真正的工作?
【参考方案1】:
要获取终止进程的状态,您可以使用 WEXITSTATUS(status) 宏。这个宏会给你子进程返回的代码。
在调用 execl 之前捕获信号也是没用的,因为(从 execve 手册页中摘录):
任何被捕获的信号的处理都被重置为默认值(signal(7))。
在你的情况下,你会得到这个代码:
int main()
pid_t cpid_1, cpid_2 ;
cpid_1 = fork();
if( cpid_1 == 0 ) // child process
execl("/usr/bin/fwdownload", "fwdownload", NULL);
printf("exec Failed");
exit(FAILED);
else // Parent process
cpid_2 = fork();
if( cpid_2 == 0 )
mkfifo("/tmp/fifo_file");
//signal(SIGTERM, SIGTERM_Handler);
execl("/bin/rx", "rx", "/tmp/fifo_file", NULL); // fifo_file
printf("exec failed");
exit(FAILED);
else
wait_status = waitpid(cpid_1, &status, WUNTRACED | WCONTINUED);
if( WIFEXITED(status) && WEXITSTATUS(status) != 0)
kill(cpid_2, SIGTERM);
printf(" FW Download app is exited \n");
【讨论】:
据我了解,signal() 系统调用将为该进程注册指定的信号,如果该信号发生,相应的 signal_handler 将处理。正如您所提到的, signal() 并非用于捕获信号。这只是为了注册特定的信号。如果我错了,请纠正我的朋友。以上是关于如何在通过exec调用的父进程中获取已执行应用程序的状态?的主要内容,如果未能解决你的问题,请参考以下文章