如何在通过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调用的父进程中获取已执行应用程序的状态?的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统编程之程序的执行(exec函数族)

shell多进程实例

exec函数族

如何在nodejs里调用执行系统命令

Linux系统编程——进程替换:exec 函数族

Linux调用可执行程序