Understanding Shared Memory in Linux IPC

Understanding Shared Memory in Linux IPC

INTRODUCTION

In modern Linux systems, processes typically operate in isolated memory spaces, making direct communication between them impossible without specialized mechanisms. This is where Interprocess Communication (IPC) becomes essential. Among various IPC techniques, shared memory stands out for its efficiency and speed, especially in scenarios where large amounts of data need to be exchanged quickly between processes.

This blog post focuses on System V shared memory, a powerful and widely-used IPC method in Linux. Whether you’re an embedded systems enthusiast or an engineering student exploring operating system concepts, understanding shared memory will significantly enhance your system-level programming skills. In this tutorial, we’ll cover essential system calls like shmget, shmat, shmdt, and shmctl, followed by a hands-on example to demonstrate how two processes—one writer and one reader—can communicate using shared memory.

Let’s dive into the world of fast, efficient, and real-time process communication with System V shared memory.


 

Shared Memory

  • Shared memory is a memory shared between two or more processes. However, why do we need to share memory or some other means of communication?
  • To reiterate, each process has its own address space, if any process wants to communicate with some information from its own address space to other processes, then it is only possible with IPC (inter process communication) techniques. As we are already aware, communication can be between related or unrelated processes.
  • Usually, inter-related process communication is performed using Pipes or Named Pipes. Unrelated processes (say one process running in one terminal and another process in another terminal) communication can be performed using Named Pipes or through popular IPC techniques of Shared Memory and Message Queues.
  • We have seen the IPC techniques of Pipes and Named pipes and now it is time to know the remaining IPC techniques viz., Shared Memory, Message Queues, Semaphores, Signals, and Memory Mapping.
  • In this chapter, we will know all about shared memory.

    Understanding Shared Memory in Linux IPC

  • We know that to communicate between two or more processes, we use shared memory but before using the shared memory what needs to be done with the system calls, let us see this –

Shared Memory Operations in System V IPC

  • Create the shared memory segmentor use an already existing one using the shmget()

shmget() returns a shared memory identifier (shmid) which is used for further operations.

  • Attach the processto the created or existing shared memory segment using the shmat()

This function maps the shared memory segment into the process’s address space and returns a pointer to it.

  • Detach the processfrom the shared memory segment using the shmdt()

This removes the mapping of the shared memory from the process’s address space.

  • Perform control operationson the shared memory segment using the shmctl()

Used for operations like changing permissions, reading status, or removing the shared memory segment.

Let us look at a few details of the system calls related to shared memory.

#include <sys/ipc.h>

#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg)

  • The above system call creates or allocates a System V shared memory segment. The arguments that need to be passed are as follows –
  • The first argument, key,recognizes the shared memory segment. The key can be either an arbitrary value or one that can be derived from the library function ftok(). The key can also be IPC_PRIVATE, means, running processes as server and client (parent and child relationship) i.e., inter-related process communiation. If the client wants to use shared memory with this key, then it must be a child process of the server. Also, the child process needs to be created after the parent has obtained a shared memory.
  • The second argument, size,is the size of the shared memory segment rounded to multiple of PAGE_SIZE.
  • The third argument, shmflg,specifies the required shared memory flag/s such as IPC_CREAT (creating new segment) or IPC_EXCL (Used with IPC_CREAT to create new segment and the call fails, if the segment already exists). Need to pass the permissions as well.
  • Note:−Refer earlier sections for details on permissions.
  • This call would return a valid shared memory identifier (used for further calls of shared memory) on success and -1 in case of failure. To know the cause of failure, check with errno variable or perror() function.

#include <sys/types.h>

#include <sys/shm.h>

void * shmat(int shmid, const void *shmaddr, int shmflg)

  • The above system call performs shared memory operation for System V shared memory segment i.e., attaching a shared memory segment to the address space of the calling process. The arguments that need to be passed are as follows –
  • The first argument, shmid,is the identifier of the shared memory segment. This id is the shared memory identifier, which is the return value of shmget() system call.
  • The second argument, shmaddr,is to specify the attaching address. If shmaddr is NULL, the system by default chooses the suitable address to attach the segment. If shmaddr is not NULL and SHM_RND is specified in shmflg, the attach is equal to the address of the nearest multiple of SHMLBA (Lower Boundary Address). Otherwise, shmaddr must be a page aligned address at which the shared memory attachment occurs/starts.
  • The third argument, shmflg,specifies the required shared memory flag/s such as SHM_RND (rounding off address to SHMLBA) or SHM_EXEC (allows the contents of segment to be executed) or SHM_RDONLY (attaches the segment for read-only purpose, by default it is read-write) or SHM_REMAP (replaces the existing mapping in the range specified by shmaddr and continuing till the end of segment).
  • This call would return the address of attached shared memory segment on success and -1 in case of failure. To know the cause of failure, check with errno variable or perror() function.

#include <sys/types.h>

#include <sys/shm.h>

int shmdt(const void *shmaddr)

The above system call performs shared memory operation for System V shared memory segment of detaching the shared memory segment from the address space of the calling process. The argument that needs to be passed is –

The argument, shmaddr, is the address of shared memory segment to be detached. The to-be-detached segment must be the address returned by the shmat() system call.

This call would return 0 on success and -1 in case of failure. To know the cause of failure, check with errno variable or perror() function.

#include <sys/ipc.h>

#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

  • The above system call performs control operation for a System V shared memory segment. The following arguments needs to be passed –
  • The first argument, shmid, is the identifier of the shared memory segment. This id is the shared memory identifier, which is the return value of shmget() system call.
  • The second argument, cmd, is the command to perform the required control operation on the shared memory segment.

Valid values for cmd are –

Control Commands Used with shmctl()
  • IPC_STAT

    Copies the current values of each member of the struct shmid_dsinto the structure pointed to by buf.
    Requires read permission on the shared memory segment.

  • IPC_SET

    Sets values such as the user ID, group ID, and permissions of the shared memory segment using the data in the structure pointed to by buf.

  • IPC_RMID

    Marks the shared memory segment for destruction.
    The segment is actually destroyed only after all processes have detached it.

  • IPC_INFO

    Returns system-wide limits and parameters related to shared memory.
    Stores the result in the structure pointed to by buf.

  • SHM_INFO

    Returns a shm_infostructure containing statistics about shared memory usage and system resources consumed.

  1. The third argument, buf, is a pointer to the shared memory structure named struct shmid_ds. The values of this structure would be used for either set or get as per cmd.
  2. This call returns the value depending upon the passed command. Upon success of IPC_INFO and SHM_INFO or SHM_STAT returns the index or identifier of the shared memory segment or 0 for other operations and -1 in case of failure. To know the cause of failure, check with errno variable or perror() function.

Let us consider the following sample program.

1.Create two programs:
      • c → writes data to shared memory
      • c → reads data from shared memory
2.In shm_write.c:
      • Create 1KB shared memory using shmget()
      • Attach to it using shmat()
      • Write A to E (5 times), each 1023 bytes
      • Use last byte to mark end of buffer
      • Set a flag (complete) when done writing
3.In shm_read.c:
      • Attach to the same shared memory
      • Read data and print to screen
      • Stop when complete flag is set
Run both programs at the same time
    • Reading and writing happen together
    • Run for a few times to keep it simple