0

So. I have to read and write from a named pipe and I tried to accomplish this by doing the following : Parent process writes a command to a FIFO then waits for the kid to die. The child process reads the command, and writes something in another fifo. The parent Parent reads the message from the other FIFO and prints the result. I am restricted to using fopen because in my code I use the open from unistd elsewhere, so I don't have the nonblock flag. I ll attach a snippet below. Also, if I use the "w" flag on the child process, the code freezes completely. I get FIFO is a blocking way of communication but I don't get why my parent can't read. Thanks in advance.

int main()
{
    FILE *fp1;
    FILE* fp2;
    unlink(FIFO_NAME1);
    unlink(FIFO_NAME2);
    //FIFO_NAME[1|2] is a macro containing the FIFO path
    if(mkfifo(FIFO_NAME1, 0666) == -1)
    {
        printf("Something went wrong");
        return -1;
    }
    if(mkfifo(FIFO_NAME2, 0666) == -1)
    {
        printf("Something went wrong");
        return -1;
    }
    while(1)
    {
        char command[MAX_SIZE];
        pid_t pid;
        if((pid=fork()) !=0)
        {
            //parent
                fgets(command, MAX_SIZE, stdin);

                if((fp1= fopen(FIFO_NAME1, "w")) == NULL)
                {
                    printf("Error");
                }
                fprintf(fp1, "%s", command);

                fclose(fp1);
                wait(SIGKILL);
                //it never prints this or execute past the wait
                printf("Here \n");

                char response[MAX_SIZE];
                if((fp2= fopen(FIFO_NAME2,"r"))==NULL)
                    perror("");

                fgets(response, MAX_SIZE, fp2);
                fclose(fp2);
                //printf("%s",response);
            }

        
        else
        {
            //child
            char msg[MAX_SIZE];
                   if((fp1 = fopen(FIFO_NAME1, "r")) == NULL)

                {
                    printf("Error");
                }
                fgets(msg, MAX_SIZE, fp1);
                fclose(fp1);

            
                if((fp2= fopen(FIFO_NAME2, "w+")) == NULL)
                {
                    printf("Error");
                }

                char buffer[MAX_SIZE];
                strcpy(buffer,"TEST MESSAGE");
       
                fprintf(fp2, "%s", buffer);
                fclose(fp2);

           
            fflush(stdout);
            kill(getpid(), SIGKILL);
        }

    }

}
Diana
  • 33
  • 4

1 Answers1

0

The basic problem here is that you cannot half open a FIFO. At least, not unless you open it for reading in non-blocking mode, which you cannot do with fopen(). Normally, opening a FIFO for reading will block until the same FIFO is also opened for writing, and vice versa.

You are ok in that regard with respect to FIFO_NAME1. The parent opens it for writing and the child opens it for reading. Once both have done so, they both continue.

But then the parent calls wait() (with an incorrect argument, too, but that's a separate issue). The parent will not return successfully from that wait until one of its children terminates. Only then does it attempt to open FIFO_NAME2 (for reading), but since the child has already terminated, that FIFO is not open for writing by any process, and the attempt to open it will block indefinitely.

Then there is the child. It successfully opens the second FIFO only because you specify mode "w+", so that the child alone satisfies both the requirement for a reader and the requirement for a writer. That is dangerous, however, because if the child does not actually consume any data from the FIFO then it can deadlock by trying to write more data to it than the kernel is willing to buffer at one time. Moreover, it does not achieve your communication objective, because there is no guarantee that the FIFO will retain the data written by the child when it stops being open for either reading or writing. Indeed, it probably doesn't.

You need to move or remove the wait() call, and if you choose the former then you need to check the docs to discover what kind of argument you should be passing. If you are willing to trust that the child will not fill the pipe's buffer, then you can move the wait to after the parent opens FIFO_NAME2 and before it attempts to read anything. For its part, the child should be certain to open the second FIFO in write-only mode to ensure that parent and child both get that FIFO open before the child starts writing to it.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157