1
votes

I am now learning about folk, exec etc and I have this piece of code:

#include    <stdio.h>
#include    <sys/types.h>
#include    <unistd.h>
#include    <string.h>
#include    <stdlib.h>

int main(int argc, char *argv[])
{
    pid_t childpid;
    int status;
    childpid=fork();
    if (childpid== -1){
        perror("Failed to fork\n");
        exit(1);
    }
    if (childpid==0) {
        printf("I am in child process with id = %lu\n", (long)getpid());
        execvp(argv[1], &argv[1]);
        perror("exec failure ");
        exit(1);
    }
    else {
        printf("I am in parent process with id = %lu\n", (long)getpid());
        exit(1);
    }

}

The child process works fine but after that for some reason the program continues running without doing anything. It never prints "I am in child process with id = ...." or "I am in parent process with id =... ". It's like it never goes to parent process. Do you have any ideas why? Thanks in advance

1
You are creating a zombie process. This is because the parent process is not waiting for the child to complete. The parent process will terminate [relatively] quickly. Thus, the child loses its parent and becomes a zombie. A zombie will be reparented by the kernel as a child of process 1 (e.g. systemd or initd). To fix, add: wait(NULL); after the final printf.Craig Estey
Thanks a lot! Therefore do I need to always put wait(NULL) in these types of situations?PanD22
Can you fix the spelling in your question so it can be useful to other people?Sean McCauliff

1 Answers

1
votes

From my top comment ...

You are creating a zombie process. This is because the parent process is not waiting for the child to complete.

The parent process will terminate [relatively] quickly. Thus, the child loses its parent and becomes a zombie. A zombie will be reparented by the kernel as a child of process 1 (e.g. systemd or initd).

To fix, add: wait(NULL); after the final printf


UPDATE:

Therefore do I need to always put wait(NULL) in these types of situations?

The TL;DR is ... Yes!

This is what you normally want to do for most programs.

One of the few times you would want to create a zombie is (e.g.) if you're a server program (e.g. inetd).

Servers want to run "detached". That is, as a child of the init process (e.g. systemd, initd, etc.). There is one and only one init process on the system.

All other processes are children of init, even if indirectly. For example, your program's process hierarchy was something like:

init -> window_manager -> xterm -> bash -> your_program

Anyway, most server programs these days are fired up by systemd directly. It examines some config files and starts things based on these config options. So, now, most server programs don't have to do anything special.

But, if you were testing a server of your own, invoked it from the command line, and wanted it to run [detached] in the background, you might do:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>

int opt_d;

int
main(int argc, char **argv)
{
    char *cp;
    pid_t childpid;
    int status;

    // skip over program name
    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        cp += 2;
        switch (cp[-1]) {
        case 'd':
            opt_d = 1;
            break;
        }
    }

    // detach into background
    if (opt_d) {
        childpid = fork();

        if (childpid == -1) {
            perror("Failed to detach\n");
            exit(1);
        }

        // exit the parent -- child is now detached [and a zombie] and a child
        // of the init process
        if (childpid != 0)
            exit(0);
    }

    childpid = fork();

    if (childpid == -1) {
        perror("Failed to fork\n");
        exit(1);
    }

    if (childpid == 0) {
        printf("I am in child process with id = %lu\n", (long) getpid());
        execvp(*argv, argv);
        perror("exec failure ");
        exit(1);
    }

    printf("I am in parent process with id = %lu\n", (long) getpid());
    wait(&status);

    return 0;
}