0

I'm trying to fork two children and exec() them both using a nested switch. However, my code doesn't seem to enter the case for my second child.

// fork the first child 
switch (player0PID = fork()){
    case -1: // error
        return -1;
    case 0: // in child
        // exec ("turn into") a new program
        // first child successfully execs
        execl("./client", "0", "&", (char *) NULL);
        _exit(127); // failed exec
    default: // inside parent 
        // fork second child
        switch (player1PID = fork()){
            case -1: // error
                printf("err spawning of client 1");
                return -1;
            case 0: // in child
                // exec ("turn into") a new program
                // below exec does not execute
                // second child not exec'd
                execl("./client", "1", "&", (char *) NULL);
                _exit(127); // failed exec
            default: // inside parent 
                ;
                // a lot of code the parent executes
                break;
        break; 

Am I doing something wrong with my switch statement? The first child is exec'd fine, and the parent code will execute. However, my second child isn't being forked or exec'd for some reason. The code won't enter into "case 0" for the second switch.


update:

The solution was to correct my use of execl.

My second exec failed because the two exec statements were giving & as an argument to the programs. In order for & to be processed correctly, I need to run the programs using the sh program. The second exec may not have worked because one is not allowed to run two processes concurrently in the foreground?

Example execl usage:

execl("/bin/sh", "sh", "-c", "./client 1 &", (char *) NULL);
LazerSharks
  • 3,089
  • 4
  • 42
  • 67
  • 1
    your `execl` calling seems a little off ... It's customary that the second parameter is also the name of the binary file you execute. – dragosht Aug 12 '14 at 07:36
  • @dragosht Hmm, in my case how would I call execl? `execl("./client", "client", "1", "&", (char ) NULL);`? Printing works now, but my program is still not being exec'd for some reason. I think it's not being exec'd because I'm not seeing any print statements from within the program I'm trying to exec (`./client 1 &`). – LazerSharks Aug 12 '14 at 17:23

2 Answers2

1

fork() system function will return pid to the parent process and 0 to the child process.

In your case Unlike first switch, the second switch is not executing both parent and child.

switch (player1PID = fork())

This condition only executes parent process, That is default case in your second switch. Instead of this condition try the following condition-

switch (fork() == 0)

In this case it will execute the case 0:(child) in second switch. But this time it will not execute the default case(parent).

To avoid this type of errors, a better way to execute both child and parent process is, use nested if-else. Try the following code it will work for you-

Code for, from one parent process -> 2 child process-

int main()
{
    pid_t player0PID, player1PID;
    if(player0PID = fork()){
            // child 1
            printf("In child1 process\n");
            // do your stuff here
    }
    else{
            printf("In parent process\n");
            if(player1PID = fork()){
                    //child 2
                    printf("In child2 process\n");
                    // do your stuff
            }
            else{
                    printf("In parent process\n");                  
                    // do your stuff
            }
    }
    return 0;
}

Code for, from parent process-> child1 process-> child2 process-

int main()
{
    pid_t player0PID, player1PID;
    if(player0PID = fork()){
            // child 1
            printf("In child1 process\n");
            // do your stuff here
            if(player1PID = fork()){
                    //child 2
                    printf("In child2 process\n");
                    // do your stuff
            }
            else{
                    printf("In child1 is parent process here\n");
                    // do your stuff
            }
    }
    else{
            printf("In parent process\n");
            // do your stuff here
    }
    return 0;
}
Sathish
  • 3,740
  • 1
  • 17
  • 28
1

The key reason why the printf() output does not appear is that you don't terminate it with a newline. That means it stays buffered in the child, but that means that when the exec() occurs, the buffered output is lost. You either need to add fflush(stdout); or fflush(0); or a newline to the end of the format string. This is a general guideline — end printf() format strings with newlines unless you want something else to follow on the same line of output.

Personally, I don't like switches for handling forks; I use if statements. However, the switches do work.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks. Hmm, I guess the problem is with my `execl` not executing for some reason. I see the printf() now but my program still isn't being run. – LazerSharks Aug 12 '14 at 17:24
  • 1
    To determine that, try adding an `fprintf(stderr, "Failed to execute ./client (%d: %s)\n", errno, strerror(errno));` before the `_exit(127);`, or something similar. You do realize that your client is being invoked with `argv[0]` set to `1` and `argv[1]` set to `&`, don't you? You don't have a shell involved to run the client in the background because of the `&`, and you've not listed the program name as its `argv[0]`. – Jonathan Leffler Aug 12 '14 at 18:17
  • Ah, right! Found the solution. This worked: `execl("/bin/sh", "sh", "-c", "./client 1 &", (char *) NULL);` Thank you. Unfortunately since this question is marked as a duplicate I can't answer my own question. Feel free to update your answer. – LazerSharks Aug 12 '14 at 18:57