jstm88
jstm88

Reputation: 3355

UNIX Pipes Between Child Processes

I'm trying to write a program that will spawn an arbitrary number of child processes and pipe between them, similar to a command line pipeline. In my case I'm trying to do "ls -l | more" and output that to stdout, then have the parent continue executing more commands.

I have the following code as a minimal example:

int main (int argc, const char * argv[]) {
    int fd[2];
    pipe(fd); 
    chdir("/directory/with/lots/of/files");

    // Create one child process for more
    int pid = fork();
    if (pid == 0) {
        close(fd[1]);
        int ret = dup2(fd[0],0);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "more";  argv[1] = NULL;
        execvp("more", argv);
    } 
    // Create another child process for ls
    int pid2 = fork();
    if (pid2 == 0) {
        int ret = dup2(fd[1],1);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "ls";    argv[1] = "-l";   
        argv[2] = NULL;
        execvp("ls", argv);
    }

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}

Now, when I execute the program (enclosed in a main() function of course) what I end up with is more, which is expected. I'll hit "d" to page down more's output and "u" to go up, and it seems to work fine. But when I reach the bottom, instead of exiting like more does, it just leaves a blank line. Ctrl-C works to exit it but it exits the entire program, meaning the "Done!" line never gets printed. A movie is available here that illustrates what happens (note that at the very end I press Ctrl-C to get back to bash).

Any thoughts on this? I'm just trying to figure out how to change it to where instead of going to a blank line after more reaches the bottom, more quits and returns to the parent process so it can continue executing.

Upvotes: 10

Views: 20051

Answers (2)

Tiago
Tiago

Reputation: 1337

I think it is because of the wait() function. Following the logic, your second child process outputs to the first child process, meaning it should end first than the second one.

In your wait function you are waiting for the first process to end, but you are not waiting for the second process. That means that if the second process does not send an EOF to the output ever, your first process won't end, i guess.

You can try to wait for the second process instead of the first and find out if that's the problem.

Upvotes: -1

Robie Basak
Robie Basak

Reputation: 6760

You need to close() at least the writing end of your pipe, otherwise more will never see EOF. For example:

    ...

    // close parent's pipes
    close(fd[0]);
    close(fd[1]);

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}

Upvotes: 11

Related Questions