Mahathi Vempati
Mahathi Vempati

Reputation: 1408

Implement a pipe in C: Is it necessary to fork?

I'm trying to implement a Linux pipe chain in C. For example:

grep file | ls | wc

So, there is a code that splits the arguments into tokens with the pipe as the separator, and sends each part to the following function with an integer specifying whether it precedes a pipe or not:

int control_flow(char** args, int precedes){

    int stdin_copy = dup(0);
    int stdout_copy = dup(1);

    // if the command and its args precedes a pipe
    if (precedes){

        int fd[2];

        if (pipe(fd) == -1){
            fprintf(stderr, "pipe failed\n");
        }

        if (dup2(fd[1], 1)!=1)
            perror("dup2 error 1 to p_in\n"); // 1 points to pipe's input

        status = turtle_execute(args); // executes the argument list, output should go into the pipe

       // Code stops running here

        if (dup2(fd[0], 0)!=0)
            perror("dup2 error 0 to p_out\n"); // 0 points to pipe's output, any process that reads next will read from the pipe

        if (dup2(stdout_copy, 1)!=1)
            perror("dup2 error 1 to stdout_copy\n"); // 1 points back to stdout

    }

    // if the command does not precede a pipe
    else{

        status = turtle_execute(args); // input to this is coming from pipe

        if (dup2(stdin_copy, 0)!=0)  // 0 points back to stdin
            perror("dup2 error 1 to stdin_copy");

    }

    return 0;
}

My code stops running after the first command executes. I suspect it is necessary to fork a process before using this pipe, why is that? If so, how do I do that in my code without changing what I intend to do?

Edit: This is roughly what turtle_execute does:

turtle_execute(args){
    if (args[0] is cd or ls or pwd or echo)
         // Implement by calling necessary syscalls
    else
         // Do fork and exec the process

So wherever I have used exec, I have first used fork, so process getting replaced shouldn't be a problem.

Upvotes: 0

Views: 1414

Answers (1)

Merlin
Merlin

Reputation: 111

The exec system call replaces the current process with the program you are executing. So your process naturally stops working after the turtle_execute, since it was replaced with the new process.

To execute a new process you normally fork to create a copy of the current process and then execute in the copy.

When you are in the shell, normally each command you type is forked and executed. Try typing exec followed by a command into a shell and you will find that the shell terminates once that command has finished executing, since it does not fork in that case.

Edit

I suggest you have a look at the example on the pipe(2) man page (http://man7.org/linux/man-pages/man2/pipe.2.html#EXAMPLE). It shows the usual way of using a pipe:

  • Calling pipe to get the create the pipe
  • Calling fork to fork the process
  • Depending on whether it is child or parent close one end of the pipe and use the other

I think your problem might be that you make the writing end of your pipe the stdout before forking, causing both the parent and the child to have an open writing end. That could prevent an EOF to be sent since one writing end is still open.

I can only guess what happens in most of turtle_execute, but if you fork, exec on one process, and wait for it on the other, without consuming data from the pipe, it might fill the pipe and to the point where writing is blocked. You should always consume data from the pipe while you write to it. It is a pipe after all and not a water tank. For more information have a look at the pipe(7) man page under the 'Pipe capacity' section.

Upvotes: 1

Related Questions