IPC Overview & Taxonomy

 

Chapter 43 – IPC Overview & Taxonomy
TLPI Series · Linux System Programming · EmbeddedPathashala
43.1
IPC Taxonomy
3
IPC Categories
File 1/3
of Chapter 43

Key Terms in This File
IPC Interprocess Communication Pipe FIFO Socket Shared Memory Semaphore Signal File Lock Message Queue

What is IPC?

When you run two programs at the same time — say a web server and a database — they are separate processes. By default, each process lives in its own isolated memory space. They cannot read each other’s variables. But in real systems, these processes need to talk to each other.

Interprocess Communication (IPC) is the set of mechanisms the Linux kernel provides to let processes exchange data, coordinate actions, and signal each other. Chapter 43 of TLPI is a bird’s-eye view of all these mechanisms before diving deep in later chapters.

Think of IPC like tools in a toolbox. A hammer, a screwdriver, and a wrench all exist for a reason. Similarly, pipes, sockets, shared memory, semaphores all solve slightly different problems. Understanding the big picture first helps you pick the right tool.

43.1 – A Taxonomy of IPC Facilities

UNIX gives us a rich variety of IPC mechanisms. They fall into three broad categories:

Category Sub-Type Mechanism / Facility Notes
Communication Data Transfer Pipe, FIFO Byte stream — undelimited bytes
System V MQ, POSIX MQ, Datagram Socket Message — delimited packets
Pseudoterminal Specialized use (Chapter 64)
Shared Memory System V SHM, POSIX SHM, mmap() All processes see same RAM pages
Synchronization Semaphore (SysV/POSIX), File Lock (flock/fcntl) Coordinate access, prevent race conditions
Signal kill(), sigqueue(), Realtime signals Async notification; rarely carries data

Why Do So Many Similar Facilities Exist?

You will notice pipes, FIFOs, sockets all look similar. There are two historical reasons:

Reason 1 – Different UNIX Variants

FIFOs came from System V UNIX. Stream sockets came from BSD UNIX. Both were later merged into Linux. So we have both.

Reason 2 – Design Improvements

POSIX IPC (message queues, semaphores, shared memory) was built to fix design problems in older System V IPC. Newer = cleaner API.

Important: Even though we lump everything under “IPC,” facilities in the same group can behave very differently. For example, stream sockets work over a network (TCP/IP), while FIFOs work only between processes on the same machine.

Signals as a Communication/Sync Tool

Signals are primarily used for notifications (SIGTERM = terminate, SIGINT = Ctrl+C). But they can sometimes carry information:

  • The signal number itself is information (e.g., SIGUSR1 vs SIGUSR2)
  • Realtime signals (SIGRTMIN to SIGRTMAX) can carry an integer or pointer as payload via sigqueue()
  • They are asynchronous — delivery interrupts the receiving process at any time

Coding Example 1 – Sending a Signal Between Processes

/*
 * signal_ipc.c
 * Demonstrates using kill() to send a signal as a basic IPC notification.
 * Process A (parent) sends SIGUSR1 to Process B (child).
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sigusr1_handler(int sig) {
    /* This runs in the child when signal is received */
    printf("[Child] Received SIGUSR1 from parent! Signal number = %d\n", sig);
}

int main(void) {
    pid_t child_pid;

    child_pid = fork();

    if (child_pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (child_pid == 0) {
        /* --- CHILD PROCESS --- */
        /* Register handler for SIGUSR1 */
        signal(SIGUSR1, sigusr1_handler);

        printf("[Child] PID=%d, waiting for signal...\n", getpid());

        /* pause() sleeps until any signal is received */
        pause();

        printf("[Child] Resuming after signal. Exiting.\n");
        exit(EXIT_SUCCESS);

    } else {
        /* --- PARENT PROCESS --- */
        sleep(1);  /* Give child time to set up handler */

        printf("[Parent] Sending SIGUSR1 to child PID=%d\n", child_pid);
        kill(child_pid, SIGUSR1);

        /* Wait for child to finish */
        wait(NULL);
        printf("[Parent] Child finished. Done.\n");
    }

    return 0;
}
/* Compile: gcc signal_ipc.c -o signal_ipc
   Run:     ./signal_ipc
   Output:
     [Child] PID=12345, waiting for signal...
     [Parent] Sending SIGUSR1 to child PID=12345
     [Child] Received SIGUSR1 from parent! Signal number = 10
     [Child] Resuming after signal. Exiting.
     [Parent] Child finished. Done.
*/

Coding Example 2 – Realtime Signal Carrying Data (sigqueue)

/*
 * rt_signal_ipc.c
 * Realtime signals can carry an integer payload using sigqueue().
 * This is IPC: the parent sends a value to the child via signal.
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void rt_handler(int sig, siginfo_t *info, void *ucontext) {
    printf("[Child] Got realtime signal %d with value = %d\n",
           sig, info->si_value.sival_int);
}

int main(void) {
    pid_t child_pid = fork();

    if (child_pid == 0) {
        /* CHILD: use sigaction with SA_SIGINFO to receive payload */
        struct sigaction sa;
        sa.sa_sigaction = rt_handler;
        sa.sa_flags = SA_SIGINFO;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGRTMIN, &sa, NULL);

        printf("[Child] Waiting for realtime signal...\n");
        pause();
        exit(EXIT_SUCCESS);

    } else {
        sleep(1);

        /* PARENT: send SIGRTMIN with integer value 42 */
        union sigval sv;
        sv.sival_int = 42;

        printf("[Parent] Sending SIGRTMIN with value 42 to PID=%d\n", child_pid);
        sigqueue(child_pid, SIGRTMIN, sv);

        wait(NULL);
    }
    return 0;
}
/* Compile: gcc rt_signal_ipc.c -o rt_signal_ipc
   Run:     ./rt_signal_ipc
   Output:
     [Child] Waiting for realtime signal...
     [Parent] Sending SIGRTMIN with value 42 to PID=...
     [Child] Got realtime signal 34 with value = 42
*/

Interview Questions – IPC Overview & Taxonomy
Q1. What is IPC and why is it needed in Linux?
IPC (Interprocess Communication) is a set of kernel-provided mechanisms that allow separate processes to exchange data and coordinate their actions. It is needed because each process runs in isolated virtual memory by default — they cannot directly access each other’s variables. IPC bridges this isolation.
Q2. Name the three broad categories of UNIX IPC facilities.
1) Communication (data transfer + shared memory), 2) Synchronization (semaphores, file locks), 3) Signals (asynchronous notifications that can also carry data via realtime signals).
Q3. Why does Linux have both FIFOs and sockets if both transfer data?
They evolved on different UNIX variants: FIFOs on System V, stream sockets on BSD. Both were later included in Linux. They also serve different scopes: FIFOs are local-machine only, while sockets can communicate across a network.
Q4. Can signals be used for IPC? What are the limitations?
Yes. Standard signals carry only the signal number as information. Realtime signals (via sigqueue) can carry a single integer or pointer payload. Limitations: signals are asynchronous, they have limited data capacity, and handling them correctly requires care (signal safety, masking, reentrancy).
Q5. What is the difference between System V IPC and POSIX IPC?
System V IPC is older, uses integer keys and IPC identifiers (ipcs/ipcrm tools). POSIX IPC is newer, uses filesystem-like named objects (e.g., /dev/shm for shared memory), has a cleaner API, and integrates better with file descriptor semantics (select/poll support on POSIX MQ).
Q6. What does kill() actually do at the system-call level?
kill(pid, sig) is a system call that instructs the kernel to deliver signal number sig to the process (or process group) identified by pid. It does not “kill” the process directly — it delivers a signal, and the process’s signal handler (or default action) determines what happens.

Leave a Reply

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