Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - using fork() and exec() twice

Tags:

c

linux

I have the following code:

int main(int argc, char **argv)
{
    char    *program;
    char     stringa[1000] = "";
    int num = 123;
    char snum[10];

    if (argc != 2) {
        printf("Usage: mon fileName\n where fileName is an executable file.\n");
        exit(-1);
    } else {
        program = argv[1];
        sprintf(stringa, "./%s", program);

        pid_t pid = fork();
        if (pid < 0 ) {
            perror("fork failed."); 
            exit(1); }

        else if (pid == 0) {
            char* args[] = {stringa, NULL};
            execv(args[0], args);
        }
        else {

            char procmon_str[] = "./procmon";
            num = pid;
            sprintf(snum, "%d",num);
            pid_t pid2 = fork();
            if (pid2 == 0) {
                char* args2[] = {procmon_str, snum, NULL};
                execv(args2[0], args2); }
            else {

                printf("PID of child is %s", snum);
                int parent_pid = getpid(); 
                printf("PID of parent is %d", parent_pid);}

        }}
    wait(NULL);

    return 0;
}

The name of this program is myProgram. The argument I provide in the shell is:

./myProgram calc

calc is another program I want to launch using myProgram. myProgram then executes calc, takes its PID and passes that PID to another program called procmon that does something with it; that's why I need to fork twice. However, when I run the code above, I get:

procmon: cannot open /proc/6225/stat, the monitored process is not running anymore.

How can I fix this?

What does calc do? It goes into a for loop, increments an int variable and goes to sleep for 3 seconds and repeat that 10 times. So it should run for about 30 seconds.

What does procmon do? procmon simply receives a PID of a process as an argument and displays the corresponding /proc/PID/stat file. It works perfectly when you run it by itself.

like image 478
gambit20088 Avatar asked Jan 17 '17 19:01

gambit20088


2 Answers

You have a race condition. You have no guarantee that the first fork() actually even returns to your parent process before the calc child process finishes executing and exits. You need to synchronize the execution of your processes.

ETA suggestions on where to block and signal

if (pid == 0) 
{
    // block here waiting for the go-ahead from parent
    char* args[] = { stringa, NULL };
    execv( args[ 0 ], args );
}

......

else
{
    // signal calc child here 
    printf( "PID of child is %s", snum );
    int parent_pid = getpid();
    printf( "PID of parent is %d", parent_pid );
}

Learning how to block and signal via interprocess communication is left as an exercise for the questioner.

like image 173
Rob K Avatar answered Oct 04 '22 02:10

Rob K


Didn't notice at first...

Your main process is creating two child processes, proc and prcmon. Your problem is that due to race conditions and schedualling - calc finishes first, so what you want to do is to force calc to wait for its sibling process. You can only wait() on a process that you created... So this way you can't make calc wait for prcmon to finish.

BUT

You can implement some mechanism to make parent process wait on its children and then via pipe pass the return data to other child process. In your case I am not sure. You want in prcmon to get the PID of calc and display it ? I don't know if that is possible as once calc is done, its descriptor is erased and does no longer exist.

A solution to your problem is to make calc do heavy calculation as you only need it alive and not its return value.

like image 40
Tony Tannous Avatar answered Oct 04 '22 02:10

Tony Tannous