System V IPC – Introduction & API Overview

 

System V IPC – Introduction & API Overview
Chapter 45 | Linux System Programming | EmbeddedPathashala
3
IPC Mechanisms
Kernel
Persistence
msgget
semget · shmget

Key Terms in This Tutorial
System V IPC Message Queues Semaphores Shared Memory IPC Identifier msgget() semget() shmget() IPC_CREAT IPC_RMID Kernel Persistence XSI IPC

What is System V IPC?

System V IPC stands for System V Inter-Process Communication. It is a set of three communication mechanisms that allow multiple processes running on the same Linux system to talk to each other, share data, and coordinate their work.

The name “System V” comes from where these mechanisms first appeared — they were developed for UNIX System V in the early 1980s. Before that, they were used in internal UNIX implementations for database and transaction-processing systems in telephone company record keeping. Around 1983, they became part of mainstream UNIX with System V.

Because SUSv3 (Single UNIX Specification v3) requires these mechanisms for XSI (X/Open System Interface) conformance, System V IPC is sometimes also called XSI IPC.

Linux Kernel Note: System V IPC is a kernel option configured via CONFIG_SYSVIPC. On most Linux systems it is enabled by default.

The Three IPC Mechanisms

System V IPC provides exactly three mechanisms. Think of them as three different tools for different jobs:

System V IPC — Three Mechanisms at a Glance
📨
Message Queues
Pass typed messages between processes. Messages have integer type field. Can read by type, not just order.
🚦
Semaphores
Synchronize multiple processes. Kernel-maintained integer. Processes signal each other via increment/decrement.
🧠
Shared Memory
Multiple processes share the same memory region (segment). Fastest IPC — no kernel copy needed.

1. Message Queues — In Detail

A message queue is like a post box maintained by the kernel. Processes can drop messages into it (write) and pick them out (read). Unlike a pipe, message queues preserve message boundaries — each read gets exactly one whole message, never a partial one or a mix of two.

Each message has:

  • A data payload (arbitrary bytes)
  • An integer type field — you can ask the kernel “give me only messages of type 5”
Difference from Pipes: Pipes give you a raw byte stream with no boundaries. Message queues deliver typed, bounded messages — the reader always gets exactly what the writer sent.
2. Semaphores — In Detail

A semaphore is a kernel-maintained integer visible to all processes with the right permissions. Its purpose is synchronization — making sure multiple processes don’t step on each other’s toes when accessing a shared resource.

A process signals its peers by adjusting the semaphore value. The classic use case: “I’m using the printer, hands off” — increment the semaphore. “Done, someone else can use it” — decrement it.

System V semaphores are actually sets of semaphores (arrays), not single values. You allocate a set of N semaphores in one call.
3. Shared Memory — In Detail

Shared memory maps the same physical memory pages into the virtual address space of two or more processes. Once attached, any process can read or write that memory directly — no system call is needed for each access.

This makes shared memory the fastest IPC mechanism. The moment one process writes to shared memory, the change is immediately visible to all other processes sharing that segment.

Caution: Shared memory provides no synchronization. You must use semaphores or mutexes alongside shared memory to prevent race conditions.

45.1 — API Overview: System Calls & Header Files

Each IPC mechanism has its own set of system calls and header file. The table below shows the full API at a glance (from Table 45-1 in TLPI):

Interface Message Queues Semaphores Shared Memory
Header file <sys/msg.h> <sys/sem.h> <sys/shm.h>
Data structure msqid_ds semid_ds shmid_ds
Create / Open msgget() semget() shmget() + shmat()
Close object (none) (none) shmdt()
Control ops msgctl() semctl() shmctl()
Perform IPC msgsnd() / msgrcv() semop() Direct memory access
Implementation Note: On most Linux architectures, a single kernel entry point ipc(2) handles all System V IPC operations. The individual functions like msgget() are actually C library wrappers over this one system call. (Alpha and IA-64 are exceptions where they are real individual syscalls.)

How “get” Calls Work — Key → Identifier

Each IPC mechanism has a get call (msgget(), semget(), shmget()). These work like open() for files — given a key, they return an identifier.

Key → get() → Identifier Flow
Integer
Key (key_t)
e.g. 0x4d0731db
System Call
msgget() / semget() / shmget()
+ IPC_CREAT | permissions
Integer
Identifier (int)
System-wide, e.g. 163842
Two outcomes of a get call:

  1. If no object with that key exists + IPC_CREAT set → creates new object, returns new identifier
  2. If object with that key exists → opens it, returns its existing identifier

The identifier is different from a file descriptor. A file descriptor is private to a process, but an IPC identifier is a system-wide property of the object itself. All processes accessing the same object use the same identifier.

Coding Example 1 — Creating a Message Queue

The simplest way to create a System V IPC object — here a message queue:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(void) {
    key_t key = 12345;   /* integer key — any agreed-upon number */
    int id;

    /* Create a new message queue (or open if it already exists)
       Permissions: owner can read and write (S_IRUSR | S_IWUSR) */
    id = msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR);
    if (id == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    printf("Message queue created. Identifier = %d\n", id);

    /* The identifier is system-wide — any other process can use
       the same key to get the same identifier */
    return 0;
}
Output example: Message queue created. Identifier = 65536
The identifier value depends on the kernel’s internal algorithm (explained in the algorithm tutorial).

Coding Example 2 — IPC_CREAT and IPC_EXCL Flags

These two flags control whether a get call creates a new object or opens an existing one:

  • IPC_CREAT — like O_CREAT for open(): create if not exists
  • IPC_EXCL — like O_EXCL for open(): fail if already exists
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(void) {
    key_t key = 99999;
    int id;

    /* IPC_CREAT | IPC_EXCL: create, but FAIL if already exists */
    id = msgget(key, IPC_CREAT | IPC_EXCL | 0600);
    if (id == -1) {
        if (errno == EEXIST) {
            printf("Queue with this key already exists!\n");
        } else {
            perror("msgget");
        }
        exit(EXIT_FAILURE);
    }

    printf("New queue created exclusively. ID = %d\n", id);

    /* Now delete the queue we just created */
    if (msgctl(id, IPC_RMID, NULL) == -1) {
        perror("msgctl IPC_RMID");
        exit(EXIT_FAILURE);
    }
    printf("Queue deleted successfully.\n");

    return 0;
}
IPC_RMID is the generic “delete” operation available for all three IPC mechanisms via their respective ctl() call.

Coding Example 3 — Shared Memory Create & Delete
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

#define SHM_SIZE 4096   /* 4 KB shared memory segment */

int main(void) {
    key_t key = 55555;
    int shmid;

    /* Create a shared memory segment */
    shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600);
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("Shared memory created. ID = %d\n", shmid);

    /* Attach the shared memory to this process's address space */
    void *addr = shmat(shmid, NULL, 0);
    if (addr == (void *) -1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    printf("Shared memory attached at address: %p\n", addr);

    /* Write something into shared memory */
    char *msg = (char *)addr;
    snprintf(msg, 64, "Hello from PID %d", getpid());
    printf("Written: %s\n", msg);

    /* Detach (does NOT delete the segment) */
    if (shmdt(addr) == -1) {
        perror("shmdt");
        exit(EXIT_FAILURE);
    }
    printf("Shared memory detached.\n");

    /* Delete the shared memory segment */
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl IPC_RMID");
        exit(EXIT_FAILURE);
    }
    printf("Shared memory deleted.\n");

    return 0;
}
Key difference: For shared memory, IPC_RMID schedules deletion — the actual removal happens only when all processes have called shmdt(). For message queues and semaphores, deletion is immediate.

Kernel Persistence of IPC Objects

System V IPC objects have kernel persistence. This means once created, an IPC object keeps living in the kernel until:

  • It is explicitly deleted using the IPC_RMID operation, OR
  • The system is shut down

Persistence Comparison
📁 Files (for comparison)
Deleted when: last file descriptor closed + last directory link removed
Lifetime: process-controlled via open/close
🔧 System V IPC Objects
Deleted when: explicit IPC_RMID call OR system reboot
Lifetime: kernel-maintained, survives process exit
Disadvantage of kernel persistence:

  • There are system-imposed limits on the number of IPC objects of each type
  • If you forget to delete unused objects, you can hit these limits and cause application errors
  • Message queues and semaphores are “connectionless” — the kernel doesn’t track which processes have them open, making it hard to know when it’s safe to delete them

🎯 Interview Questions — Introduction & API Overview

Q1. What are the three System V IPC mechanisms and what does each one do?
A: Message queues (exchange typed messages between processes), Semaphores (synchronize process actions using a kernel-maintained integer), and Shared memory (share the same memory region between multiple processes for fast communication).
Q2. What is the difference between an IPC identifier and a file descriptor?
A: A file descriptor is a process-local attribute — each process has its own table of file descriptors. An IPC identifier is a system-wide property of the object itself — all processes accessing the same IPC object use the exact same identifier.
Q3. What does kernel persistence mean for System V IPC objects?
A: IPC objects persist in the kernel beyond the lifetime of the process that created them. They continue to exist until explicitly deleted via IPC_RMID or until the system reboots. This differs from pipes which disappear when all processes close them.
Q4. What is the difference between IPC_CREAT and IPC_EXCL flags?
A: IPC_CREAT creates a new IPC object if none with the given key exists (analogous to O_CREAT). IPC_EXCL, when combined with IPC_CREAT, ensures the call fails with EEXIST if an object with that key already exists — guaranteeing the caller is the one creating it (analogous to O_EXCL).
Q5. Why is shared memory considered the fastest IPC mechanism?
A: Because once the memory is attached (shmat), processes read and write it directly as normal memory — no system call is needed for each access. Changes are instantly visible to all attached processes since they share the same physical page frames.
Q6. What single system call underlies all System V IPC calls on most Linux architectures?
A: The ipc(2) system call. Functions like msgget(), semget(), shmget() etc. are actually C library wrappers around this single system call on most Linux architectures (exceptions: Alpha and IA-64).
Q7. What is XSI IPC and why is it called that?
A: XSI IPC is another name for System V IPC. “XSI” stands for X/Open System Interface. SUSv3 (Single UNIX Specification v3) requires these mechanisms for XSI conformance, so they are alternatively labeled XSI IPC.
Q8. What happens when IPC_RMID is called on a shared memory segment that processes still have attached?
A: For shared memory, the deletion is deferred — the segment is only actually removed after all processes have detached it via shmdt(). For message queues and semaphores, IPC_RMID causes immediate deletion.

Leave a Reply

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