如何在通过exec调用的父进程中获取已执行应用程序的状态?

如何在通过exec调用的父进程中获取已执行应用程序的状态?,c,linux,fork,exec,embedded-linux,C,Linux,Fork,Exec,Embedded Linux,我正在开发一个简单的应用程序,它可以完成以下任务: 主应用程序将具有子进程,其中在am中通过exec调用调用应用程序。此应用程序实际上正在执行固件下载操作。 例如execl(“/usr/bin/fwdownload”,“fwdownload”,“args”,NULL) 在父进程中,我将再次分叉它,以便再次拥有子进程。在这个子进程中,我调用Xmodem实用程序从本地机器接收固件映像文件。我将收到的数据包写入命名的fifo文件(使用mkfifo创建)。“fwdownload”应用程序将访问此命名的f

我正在开发一个简单的应用程序,它可以完成以下任务:

  • 主应用程序将具有子进程,其中在am中通过exec调用调用应用程序。此应用程序实际上正在执行固件下载操作。 例如execl(“/usr/bin/fwdownload”,“fwdownload”,“args”,NULL)

  • 在父进程中,我将再次分叉它,以便再次拥有子进程。在这个子进程中,我调用Xmodem实用程序从本地机器接收固件映像文件。我将收到的数据包写入命名的fifo文件(使用mkfifo创建)。“fwdownload”应用程序将访问此命名的fifo文件,以读取数据包以闪存固件

  • 因此,在父进程中,当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");                    
    
                }       
            }           
        }  
    }
    

    要获取已终止进程的状态,可以使用WEXITSTATUS(status)宏。此宏将为您提供子进程返回的代码

    在调用execl之前捕获信号也是无用的,因为(摘自execve手册页):

    正在捕获的任何信号的处理将重置为默认值(信号(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");                    
    
                }       
            }           
        }  
    }
    

    为什么子进程之间是FIFO而不是管道?还是一个普通的文件?我个人从不认为固件传输成功,并且总是希望固件安装程序应用程序检测固件下载是否失败或中断(例如,由于网络中断或其他原因)。如果固件安装程序总是将整个映像读取到内存中(因为它的某处有一个校验和),那么它确实应该支持从标准输入读取数据。如果不是,我肯定会使用一个临时文件和单独的sha256sum校验和…我不使用普通文件,因为fwdownload应用程序希望文件传输是在分组事务中进行的。我没有任何理由不使用管道。如果我们使用普通管道而不是FIFO文件,我们有什么额外的好处吗。使用管道有几个优点。如果下载应用程序死亡/退出,安装程序将通过下一步
    read()
    返回0来检测它。如果安装程序死亡/退出,下载应用程序将从下一个
    write()
    中获得-1,其中
    errno==EPIPE
    。如果使用FIFO,另一端也将阻塞,直到另一端打开,并且始终存在其他过程干预的风险(通过同时打开FIFO);此外,必须根据需要创建和删除FIFO文件系统对象。简单地说,FIFO更复杂,风险更大,在这个用例中没有好处。非常感谢。是的,你是对的。就我而言,我怀疑有一个死锁正在发生。当写入FIFO的进程启动时,必须同时执行从同一FIFO读取的其他进程。但在我的例子中,第二个进程(从FIFO读取)正在退出或返回,这将使第一个进程处于阻塞状态。因此,你建议我,如果我们使用管道,这种情况不会发生。如果两个程序在退出之前都显式关闭管道,则不应发生这种情况。写入程序(下载程序)将阻塞,直到读卡器(安装程序)读取数据为止(每个管道都有至少512字节的缓冲区,只要管道的另一端仍然打开,就可以“立即”写入);读卡器将阻塞,直到写入器关闭管道或写入更多数据。你有没有考虑过编写一个最小的测试程序——比如说,如果孩子们看到数据中的某个特定字符,就退出这个程序,睡在其他字符上,否则就不会做真正的工作?根据我的理解,signal()系统调用将注册该进程的指定信号,如果该信号发生,则相应的信号处理程序将处理该信号。正如您提到的,signal()不是用来捕捉信号的。这只是为了注册特定的信号。如果我错了,请纠正我,我的朋友。