Search code examples
cunixmkfifo

Executable for the writer file with mkfifo halts


In my understanding, according to the https://linux.die.net/man/3/mkfifo,

I got an implication that I must have reader and writer file, in order to

utilize the pipe file. The source below is the writer file,

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>

int main(){

    int fd;
    char *myfifo = "./myfifo";

    mkfifo(myfifo, 0777);
    fd = open(myfifo, O_WRONLY);    


    int PID = fork();   

    if(PID == 0){

        execl("./reader.o", "reader", (char*)NULL);

    }

    write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
    close(fd);
    unlink(myfifo);

    return 0;

}

and the source being provided below is for the reader file.

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_BUF 1024

int main(){

    int fd;

    char* myfifo = "./myfifo";
    char buf[MAX_BUF];

    fd = open(myfifo, O_RDONLY);
    read(fd, buf, MAX_BUF);
    write(STDOUT_FILENO, buf, MAX_BUF);

    close(fd);
    exit(EXIT_SUCCESS);

    return 0;

}

When run the executable for the writer file, the command prompt goes into

halt, after printing a newline. My assumption for this problem is because the

open() in the writer file is not being able to detect the pipe file,

is that the case?

Thank you.


Solution

  • I suggest that you should create the FIFO before the fork, but only open the FIFO after the fork. This avoids an assortment of problems. For the most part, I've used write() to report errors to standard error; it isn't as convenient as using fprintf(stderr, …) though.

    Note that the writer writes a null byte at the end of the message. The reader gets the null byte, but overwrites it with a newline before writing the resulting character array (it is no longer a string; strings have a terminal null byte at the end) to standard output. If the code used <stdio.h> to write the data (e.g. printf("%s\n", buf)), it wouldn't need to replace the null byte with a newline.

    writer.c

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    #ifndef READER
    #define READER "./reader"
    #endif
    
    int main(void)
    {
        char *myfifo = "./myfifo";
    
        if (mkfifo(myfifo, 0777) != 0)
        {
            write(STDERR_FILENO, "Failed to create FIFO\n",
                          sizeof("Failed to create FIFO\n") - 1);
        }
    
        int PID = fork();
    
        if (PID == 0)
        {
            execl(READER, "reader", (char *)NULL);
            write(STDERR_FILENO, "Failed to execute reader\n",
                          sizeof("Failed to execute reader\n") - 1);
            exit(EXIT_FAILURE);
        }
        if (PID < 0)
        {
            write(STDERR_FILENO, "Failed to fork\n",
                          sizeof("Failed to fork\n") - 1);
            exit(EXIT_FAILURE);
        }
    
        int fd = open(myfifo, O_WRONLY);
        if (fd < 0)
        {
            write(STDERR_FILENO, "Failed to open FIFO for writing\n",
                          sizeof("Failed to open FIFO for writing\n") - 1);
            unlink(myfifo);
            exit(EXIT_FAILURE);
        }
    
        write(fd, "Rock and roll baby", sizeof("Rock and roll baby"));
        close(fd);
        unlink(myfifo);
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("Child %d exited with status 0x%.4X\n", corpse, status);
    
        return 0;
    }
    

    reader.c

    #include <fcntl.h>
    #include <unistd.h>
    
    #define MAX_BUF 1024
    
    int main(void)
    {
        char* myfifo = "./myfifo";
        int fd = open(myfifo, O_RDONLY);
        if (fd < 0)
            write(STDERR_FILENO, "Failed to open FIFO for reading\n",
                          sizeof("Failed to open FIFO for reading\n")-1);
        else
        {
            char buf[MAX_BUF];
            int nbytes = read(fd, buf, MAX_BUF);
            if (nbytes > 0)
            {
                buf[nbytes-1] = '\n';
                write(STDOUT_FILENO, buf, nbytes);
            }
            close(fd);
        }
        return 0;
    }
    

    Example output

    Rock and roll baby
    Child 43734 exited with status 0x0000