user1768079
user1768079

Reputation: 713

Program hangs after using pipe, fork and exec

I am using pipe fork and exec, to implement a generic pipe for any two shell programs. I am specifically using ls | grep to test it. It works, the data gets copied over to grep, grep searches for matches and then outputs them to stdout. However after that the program just hangs.

This is my code that is executed when a pipe is detected. I fork, and then fork again because I wish to have the parent process of the first fork continue to run after the exec calls. I believe due to debug code that after the exec() call that executes grep is made that nothing is happening.

    if(pipeFlag == 1){
    pipe(fd);
    PID  = fork();
        if (PID == 0){//child process
    fPID = fork();
    if(fPID == 0){//child of child
        printf("in child of child\n");
        dup2(fd[1], 1);
                execvp(command, argv);//needs error checking
                printf("mysh: %s: command not found\n", argv[0]);
            exit(EXIT_FAILURE);
    }
    if(fPID > 0){//parent of 2nd child
        printf("in parent of 2nd child\n");
        dup2(fd[0], 0);
                execvp(command1, argv1);//needs error checking
                printf("mysh: %s: command not found\n", argv[0]);
            exit(EXIT_FAILURE);
    }
    if(PID == -1){
                printf("ERROR:\n");
                switch (errno){
                    case EAGAIN:
                    printf("Cannot fork process: System Process Limit Reached\n");
                case ENOMEM:
                    printf("Cannot fork process: Out of memory\n");
                }
                return 1;
    }
        }
        if(PID > 0){//parent
            wait(PID, 0, 0);
    printf("in outer parent\n");
        }
        if(PID == -1){
            printf("ERROR:\n");
            switch (errno){
                case EAGAIN:
                printf("Cannot fork process: System Process Limit Reached\n");
            case ENOMEM:
                printf("Cannot fork process: Out of memory\n");
            }
            return 1;
        }
}

Upvotes: 2

Views: 2919

Answers (1)

user1768079
user1768079

Reputation: 713

Below is my solution to the problem. I'm not sure if it's a permanent solution. I'm not even 100% sure if my reasoning for why this works and the previous code did not isn't. All I did was switch the command that is waiting for input from the pipe(grep) to the parent process, and the command writing output to the pipe(ls) to the child process.

My reasoning for why this works is thus: I was testing with ls | grep, ls was finished writing to the pipe before grep's child process ever got set up, and therefore never closed the pipe and grep never received EOF. By changing their position grep was ready and waiting for ls to write by the time the process running ls is set up. I believe that this is a very imperfect fix, so for anyone who reads this in the future, I hope you can provide a better answer. There are a number of conditions I can think of where this could still mess up, if my reasoning for why it works is correct.

 if(pipeFlag == 1){
    pipe(fd);
    PID  = fork();
        if (PID == 0){//child process
    fPID = fork();
    if(fPID == 0){//child of child
        printf("in child of child\n");
        dup2(fd[0], 0);
                execvp(command1, argv1);//needs error checking
                printf("mysh: %s: command not found\n", argv[0]);
            exit(EXIT_FAILURE);
    }
    if(fPID > 0){//parent of 2nd child
        printf("in parent of 2nd child\n");
        dup2(fd[1], 1);
                execvp(command, argv);//needs error checking
                printf("mysh: %s: command not found\n", argv[0]);
            exit(EXIT_FAILURE);
    }
    if(PID == -1){
                printf("ERROR:\n");
                switch (errno){
                    case EAGAIN:
                    printf("Cannot fork process: System Process Limit Reached\n");
                case ENOMEM:
                    printf("Cannot fork process: Out of memory\n");
                }
                return 1;
    }
        }
        if(PID > 0){//parent
            wait(PID, 0, 0);
    printf("in outer parent\n");
        }
        if(PID == -1){
            printf("ERROR:\n");
            switch (errno){
                case EAGAIN:
                printf("Cannot fork process: System Process Limit Reached\n");
            case ENOMEM:
                printf("Cannot fork process: Out of memory\n");
            }
            return 1;
        }
}

Upvotes: 0

Related Questions