mhkgalvez
mhkgalvez

Reputation: 51

Child process terminating on error

I am facing an issue while trying to use the fork() and exit() functions for a course's homework. The problem is that my child process ends on error when it should finish correctly. Here is my code:

int main(int argc, char** argv)
{
    int shmid;
    int *shmptr;
    int N = 10;

    // Create shared memory segment
    if ((shmid = shmget(IPC_PRIVATE, N * N * sizeof(int), 0600)) < 0)
    {
        puts("parent: shmget error");
        return -1;
    }

    // Attach shared memory segment
    if ((shmptr = shmat(shmid, 0, 0)) == (void *) -1)
    {
        puts("parent: shmat error");
        return -1;
    }   

    int ret = fork();
    if (ret == 0) 
    {   
        int status = 0;
        if (wait(&status) == -1)
        {
            puts("parent: Child terminated on error.");
        }
        else 
        {
            printf("parent: status of child: %d\n", status);
        }   
        puts("parent: End parent.");        
    }
    else 
    {
        puts("child: End child.");
        _exit(0);
    }

    exit(0);
}

I always get a Child terminated on error warning. Any suggestions?

Upvotes: 0

Views: 1083

Answers (2)

John Bollinger
John Bollinger

Reputation: 180058

Your diagnostic "Child terminated on error" is an incorrect characterization of the condition that produces it. The wait() function returns -1 in the event that it has an error; this can happen if the calling process has no children to wait for or if the function is interrupted by a signal.

In your case the cause is the former. When it is successful, the fork() function returns 0 in the child process, and it returns the new child's process id (a number greater than 0) in the parent process. Among other things, this is how the parent and child can distinguish which is which. You are calling wait() in the child, which has no child processes of its own.

Note that it is potentially problematic for the child to call _exit() instead of exit(), as the former will stop the child abruptly (without flushing open files, among other things) and will also cause the parent to be signaled (with SIGCHILD). That is occasionally what you want, but I don't see why you would want it in this case.

Note, too, that the status provided by wait() encodes several separate details of the collected process, including, but not limited to, its exit code. It is normally not useful to do anything with the status as a whole except extract the parts of interest via the various macros provided for that purpose. For example, to get the child's exit code you should pass the status to the WEXITSTATUS() macro. In real code, it might be wise also to test whether the process exited normally, as opposed to terminating because of a signal. The WEXITED() macro can extract that information from the status. There is other information encoded too, and other macros for extracting it.

Thus, you might do better with something like this:

    int pid = fork();
    if (pid == 0) 
    {   
        /* child */
        puts("child: End child.\n");
        exit(0);
    }
    else if (pid > 0)
    {
        /* parent */
        int status = 0;
        if (wait(&status) == -1)
        {
            puts("parent: failed to wait.\n");
        }
        else 
        {
            printf("parent: child's exit code: %d\n", WEXITSTATUS(status));
        }   
        puts("parent: End parent.\n");        
    }
    else 
    {
        /* parent; error */
        puts("failed to fork.\n");
    }

Upvotes: 1

VHarisop
VHarisop

Reputation: 2826

ret should be 0 inside the child process. In the parent process, ret should contain the child's PID.

 int ret = fork();
 if (ret < 0) { perror("fork"); exit(1); } /* handle fork error */
 if (ret == 0)
 {
    puts("child: End child.");
    _exit(0);
 }
 else 
 {
     /* <wait> code goes here */
 }

Upvotes: 0

Related Questions