Stralos
Stralos

Reputation: 5075

multi-pipe C program does not work

I decided to write a simple, hard coded c program to better understand how pipes work. The program has 3 commands: find . -name '.' | sed 's/.*\.// | sort

And it works with 1 pipe (if i use only 2 commands) but it fails with 2 pipes(sort just does not get the information).

I think the error is in close or waitpid, but I have tried everything(i could think of) and it still does not work. What am I missing ? information i used:

Is it possible to have pipe between two child processes created by same parent (LINUX, POSIX)

http://www.quora.com/Unix/How-can-I-write-a-code-for-PIPE-in-C-shell-script-python <--Sams example

Implementation of multiple pipes in C

EDIT: the commands are written with no mistakes. The problem is definitely not in them (since they work if I only use 1 pipe) My code:

#include <errno.h>
#include <stdio.h>
#include <unistd.h>  

int main(int argc, char* argv[]) {


    pid_t test, test2, test3;
    int old_pipe[2];
    int new_pipe[2];


    //test command
    //char *argv1[] = {"ls", "-1", "-h", NULL};
    char *argv1[] = {"find", ".", "-name", "*.*",NULL};
    char *argv2[] = {"sed", "s/.*\\.//", NULL};
    char *argv3[] = {"sort", NULL};

    //creates a pipe
    pipe(old_pipe);
    pipe(new_pipe);

    test = fork();
    if(test == 0){
        dup2(old_pipe[1], 1);
        close(old_pipe[0]);

        execvp(argv1[0], argv1);
            perror("exec");
            return 1;
    }

    test2 = fork();
    if(test2 == 0){
        dup2(old_pipe[0], 0);
        close(old_pipe[1]);
        dup2(new_pipe[1], 1);
        close(new_pipe[0]);

        execvp(argv2[0], argv2);
            perror("exec");
            return 1;
    }


    test3 = fork();
    if(test3 == 0){
        dup2(new_pipe[0], 0);
        close(new_pipe[1]);

        execvp(argv3[0], argv3);
        perror("exec");
        return 1;
    }

    close(old_pipe[0]);
    close(old_pipe[1]);

    close(new_pipe[0]);
    close(new_pipe[1]); 

    waitpid(test);
    waitpid(test2);
    waitpid(test3);

    return 0;
}

Upvotes: 0

Views: 1507

Answers (1)

ensc
ensc

Reputation: 6994

your 3rd exec (starting "sort") does not close old_pipe[1] and keeps it open. sed will not see the EOF and stays alive. You should call pipe(2) very late.

I suggest to look into /proc/<pid>/fd resp. use lsof to see which filedescriptors are open. E.g. after

    dup2(old_pipe[1], 1);
    close(old_pipe[0]);

you should close old_pipe[1] when it is not 1.

Some more explanations (as asked in comment): You program has

pipe(old_pipe);
pipe(new_pipe);

test = fork();
   /* --> 'find'; writes into old_pipe[1] */
test2 = fork();
   /* --> 'sed'; reads from old_pipe[0], writes into new_pipe[1] */
test3 = fork();
   /* --> 'sort'; reads from new_pipe[0] */

The test2 program does not exit as long as its input (old_pipe[0]) is open. Because this pipe is alive for test3 (which waits for test2 to finish), it will deadlock.

Closing fds in child branches does not close them in the parent process.

Upvotes: 1

Related Questions