DazedFury
DazedFury

Reputation: 59

Read pipe in child process hanging on second read

I'm working on an assignment where I have to create a linked list consisting of processes that communicate via pipes called nodes. The program must start with the root process and a child process called Node 1. The user is given four options, I'm stuck on option number 1 where the user should be able to add nodes (processes).

The root process should be the only one that asks for user input. The rest should loop around until it hits a read block and waits to be written to.

When the user inputs a 1, the program checks if the current process is the last node (in this case Node 1). If it isn't, the process writes the input to the next node via a pipe created before each fork. If it is, the process resets the isLast variable and creates a new pipe and forks. The child process (Node 2) then loops around and gets stuck at read, with the parent following in its footsteps. Root then once again asks for use input.

The problem is that the program seems to have no trouble going through once and creating Node 2, but the second time through, Node 1 hangs even though the root writes to it in "Add Node"

Any help is much appreciated!

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

int main(){
    int isLast = 0;
    int originPID = getpid();
    int input = 0;
    int node;
    int p[2];

    //Node 1
    printf("%s\n", "Forking");
    pipe(p);
    int pid = fork();

    //Set Node 1 to last
    if(pid == 0){
        isLast = 1;
        node = 1;
    }

    while(input != 4){
        //Node Read Block
        if(getpid() != originPID){
            printf("stuck\n");
            read(p[0], &input, sizeof(input));
            printf("free\n");
        }

        //MENU (Root Only)
        if(getpid() == originPID){      
            sleep(1);
            printf("%s", "User Options: Enter a number \n1. Add Node\n2. List Processes\n3. Remove Node\n4. Quit\n");
            scanf("%d", &input);
        }

        //(1) Add Node
        if(input == 1){
            //Checks if last. 
            if(isLast == 1){
                isLast = 0;     //Reset isLast

                //Create pipe and new process
                printf("%s\n", "Forking");
                pipe(p);
                pid = fork();
                if(pid == 0){       
                    isLast = 1;
                    node++;      //Label Node
                }
            }
            //Write to next node
            else{       
                write(p[1], &input, sizeof(input));     
            }
        }
    }
}

Upvotes: 0

Views: 1273

Answers (1)

John Bollinger
John Bollinger

Reputation: 180111

When the last node reads a 1 from the pipe, it must create a new pipe by which to communicate with the new node it is about to create. I presume that's why it calls pipe(p). But that's a problem, because p[0] contains its only copy of the file handle from which it reads its own input. When it next tries to read input, then, it will be trying to read from the pipe it set up for the next node -- it has effectively disconnected itself from its predecessor.

There's nothing magic about the array in which pipe() writes its file handles. The handles are just integers. A simple solution, then, would be for the child to make and use a copy of the read file descriptor it inherits from its parent, instead of referring to the value stored in the array element.

Also, you should be sure that after the fork, parent and child each closes their own copy of the end of the pipe that they will not use. (Parent closes the read end; child closes the write end.) You might be able to get the program working without, but at minimum, it will leak file descriptors. Under some circumstances, leaving extra copies of your file descriptors open can result in program hangs.

Upvotes: 1

Related Questions