FIFOs โ€” Named Pipes mkfifo(), Filesystem Entry, Unrelated Process IPC

 

๐Ÿ“‚ FIFOs โ€” Named Pipes
mkfifo(), Filesystem Entry, Unrelated Process IPC
Part 6 of 9
FIFOs
Topic
Named Pipes
Level
Intermediate

What Is a FIFO?

A FIFO (First In, First Out) is also called a named pipe. Unlike anonymous pipes which exist only in memory, a FIFO has a name in the filesystem โ€” you can see it with ls -l where it shows up with type p.

The key advantage: any two unrelated processes on the same system can communicate through a FIFO, as long as they agree on the FIFO’s pathname. No shared ancestry is required.

Key Concepts

mkfifo() mknod() S_IFIFO open() blocking O_RDONLY O_WRONLY unlink() filesystem entry

๐Ÿ“Š Anonymous Pipe vs FIFO

๐Ÿ“Š Anonymous Pipe
โœ… Created with pipe()
โŒ No filesystem entry
โŒ Only related processes
โœ… Faster (no fs overhead)
โœ… Auto-destroyed when all fds closed

๐Ÿ“‚ FIFO (Named Pipe)
โœ… Created with mkfifo()
โœ… Has a path (e.g., /tmp/myfifo)
โœ… Any unrelated processes can use
โœ… Persists until unlink() called
โŒ Needs filesystem access
Both are kernel-buffered, byte-stream, unidirectional IPC mechanisms.

โš™๏ธ Creating a FIFO

There are two ways to create a FIFO:

#include <sys/types.h>
#include <sys/stat.h>

/* Method 1: mkfifo() โ€” preferred */
int mkfifo(const char *pathname, mode_t mode);
/* Returns 0 on success, -1 on error */

/* Method 2: mknod() with S_IFIFO */
int mknod(const char *pathname, mode_t mode, dev_t dev);
/* For FIFO: dev = 0, mode includes S_IFIFO */

Or from the shell:

# Shell commands to create a FIFO:
mkfifo /tmp/myfifo           # create with default permissions
mkfifo -m 0666 /tmp/myfifo  # create with explicit permissions

# View the FIFO:
ls -l /tmp/myfifo
# prw-rw-rw- 1 ravi ravi 0 Jun 7 12:00 /tmp/myfifo
# ^--- 'p' means FIFO/pipe type

Example 1: Create and verify a FIFO

/* create_fifo.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_PATH  "/tmp/ep_demo_fifo"

int main(void)
{
    struct stat st;

    /* Create the FIFO if it doesn't exist */
    if (mkfifo(FIFO_PATH, 0666) == -1) {
        perror("mkfifo");
        /* Continue if it already exists */
    }

    /* Verify it's a FIFO */
    if (stat(FIFO_PATH, &st) == -1) {
        perror("stat");
        return 1;
    }

    printf("File type: ");
    if (S_ISFIFO(st.st_mode))
        printf("FIFO (named pipe) โœ“\n");
    else
        printf("Not a FIFO!\n");

    printf("Permissions: %o\n", st.st_mode & 0777);
    printf("FIFO path: %s\n", FIFO_PATH);
    printf("Now you can open it from two separate processes.\n");

    /* Cleanup */
    unlink(FIFO_PATH);
    printf("FIFO removed with unlink()\n");

    return 0;
}

๐Ÿ”“ Opening a FIFO โ€” Blocking Semantics

A FIFO is opened with the standard open() call. The important difference from regular files: opening a FIFO blocks by default until the other end is also opened.

FIFO open() Blocking Behavior

Reader opens first (O_RDONLY)
โ†’ open() BLOCKS
โ†’ Waits until writer opens FIFO with O_WRONLY
โ†’ Both unblock together
โ†’ Data can now flow

Writer opens first (O_WRONLY)
โ†’ open() BLOCKS
โ†’ Waits until reader opens FIFO with O_RDONLY
โ†’ Both unblock together
โ†’ Data can now flow

O_NONBLOCK flag
O_RDONLY | O_NONBLOCK โ†’ returns immediately even if no writer
O_WRONLY | O_NONBLOCK โ†’ fails with ENXIO if no reader

Example 2: FIFO Writer Process

/* fifo_writer.c โ€” run in one terminal */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define FIFO_PATH "/tmp/ep_chat_fifo"

int main(void)
{
    int fd;
    char buf[256];

    /* Create FIFO (ignore EEXIST error) */
    mkfifo(FIFO_PATH, 0666);

    printf("[Writer] Opening FIFO for writing...\n");
    printf("[Writer] Blocking until a reader opens the other end...\n");

    /* This open() BLOCKS until reader opens same FIFO with O_RDONLY */
    fd = open(FIFO_PATH, O_WRONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    printf("[Writer] Reader connected! Start typing (Ctrl+D to stop):\n");

    /* Read from stdin, write to FIFO */
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        ssize_t n = write(fd, buf, strlen(buf));
        if (n == -1) {
            perror("write");
            break;
        }
    }

    close(fd);
    printf("[Writer] Done. Closing FIFO.\n");
    return 0;
}

Example 3: FIFO Reader Process

/* fifo_reader.c โ€” run in another terminal */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define FIFO_PATH "/tmp/ep_chat_fifo"

int main(void)
{
    int fd;
    char buf[256];
    ssize_t n;

    printf("[Reader] Opening FIFO for reading...\n");
    printf("[Reader] Blocking until a writer opens the other end...\n");

    /* This open() BLOCKS until writer opens same FIFO with O_WRONLY */
    fd = open(FIFO_PATH, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    printf("[Reader] Writer connected! Receiving data:\n");

    /* Read data from FIFO until EOF */
    while ((n = read(fd, buf, sizeof(buf) - 1)) > 0) {
        buf[n] = '\0';
        printf("[Reader] Received: %s", buf);
    }

    close(fd);
    printf("[Reader] EOF received. Writer closed the FIFO.\n");
    return 0;
}

/* To test:
   Terminal 1: gcc -o fifo_reader fifo_reader.c && ./fifo_reader
   Terminal 2: gcc -o fifo_writer fifo_writer.c && ./fifo_writer
   (Both will unblock when the other opens the FIFO)
*/

๐Ÿ’ป Example 4: FIFO Communication Between Parent and Child
/* fifo_fork.c โ€” parent and child communicate via FIFO */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define FIFO_PATH "/tmp/ep_fork_fifo"

int main(void)
{
    /* Create the FIFO before forking */
    mkfifo(FIFO_PATH, 0666);

    pid_t pid = fork();
    if (pid == -1) { perror("fork"); return 1; }

    if (pid == 0) {
        /* ===== CHILD: reads from FIFO ===== */
        int fd = open(FIFO_PATH, O_RDONLY);
        char buf[128];
        ssize_t n = read(fd, buf, sizeof(buf) - 1);
        buf[n] = '\0';
        printf("[Child PID=%d] Received: \"%s\"\n", getpid(), buf);
        close(fd);
        _exit(0);

    } else {
        /* ===== PARENT: writes to FIFO ===== */
        int fd = open(FIFO_PATH, O_WRONLY);
        const char *msg = "Hello child, from parent via FIFO!";
        write(fd, msg, strlen(msg));
        printf("[Parent PID=%d] Sent: \"%s\"\n", getpid(), msg);
        close(fd);
        wait(NULL);
    }

    /* Cleanup */
    unlink(FIFO_PATH);
    return 0;
}

๐ŸŽฏ Interview Questions โ€” FIFOs
Q1. What is a FIFO and how is it different from an anonymous pipe?
A: A FIFO is a named pipe with a filesystem entry. Unlike anonymous pipes (visible only to related processes), any two processes can communicate via a FIFO as long as they know its pathname. FIFOs persist in the filesystem until explicitly removed with unlink().
Q2. What system call creates a FIFO?
A: mkfifo(pathname, mode) creates a FIFO at the given path with the given permissions. Alternatively, mknod(path, S_IFIFO | mode, 0) can be used.
Q3. What happens when a process opens a FIFO with O_RDONLY?
A: By default, the open() call blocks until another process opens the same FIFO with O_WRONLY. This synchronization ensures both ends are ready before data flows.
Q4. What does the ‘p’ character mean in ls -l output?
A: The ‘p’ in the first character of the permissions field indicates the file is a FIFO (pipe). For example: prw-rw-rw- 1 user group 0 ... /tmp/myfifo.
Q5. How do you remove a FIFO?
A: Use unlink(pathname) to remove the FIFO’s directory entry. Active connections are unaffected until all processes close their file descriptors.
Q6. What happens with O_NONBLOCK when opening a FIFO for writing with no reader?
A: open(path, O_WRONLY | O_NONBLOCK) fails immediately with errno = ENXIO if no process has the FIFO open for reading. This is different from O_RDONLY | O_NONBLOCK, which succeeds even without a writer.

Leave a Reply

Your email address will not be published. Required fields are marked *