POSIX Shared Memory in Linux

July 25, 2021 0 Comments

POSIX Shared Memory in Linux

POSIX Shared Memory in Linux, A slice of kernel memory is designated as shared memory. This memory is not owned by any process. When a process runs under Linux, it is given a part of the system’s virtual memory. The virtual address space of a process refers to this area of memory.

A process can only access memory addresses that are contained in its virtual address space. Linux OS terminates it (Segmentation fault) when a process tries to access an address outside of its virtual address space.

As the process requests more memory from the OS or releases memory, the virtual memory region of the process expands and shrinks.

The kernel has its own memory, which is referred to as kernel memory. This kernel memory is not owned by any userspace process. A user process can ask for a kernel memory region to be created.

Because this kernel memory region is outside of any process’ virtual address space, no process may access it directly. Applications can access kernel memory using the shared memory technique.

With the same portion of kernel memory segment, two or more processes can do this mapping at the same time. If the contents of the shared memory region are changed or updated by one process. Other processes that have mapped the same memory region can see the changes.

As a result, there is no actual data movement between processes, making this strategy ideal for transferring huge files between processes. Once a process has been completed using the shared memory region, it must unmap the memory region.

Write-write conflict occurs when many processes attempt to update the shared memory at the same time. We need to use mutual exclusion-based synchronization to deal with this scenario.

shm_open:

shm_open() creates and opens a new, or opens an existing, POSIX shared memory object. A POSIX shared memory object is in effect a handle that can uses by unrelated processes to mmap(2) the same region of shared memory. The shm_unlink() function performs the converse operation, removing an object previously created by shm_open().

The operation of shm_unlink() is analogous to unlink(2): it removes a shared memory object name, and, once all processes have unmapped the object, deallocates and destroys the contents of the associated memory region.

#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */

int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);

Link with -lrt.

ftruncate:

ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes.

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

int ftruncate(int fd, off_t length);

mmap:

mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length of the mapping (which must be greater than 0).

If addr is NULL, then the kernel chooses the (page-aligned) address at which to create the mapping; this is the most portable method of creating a new mapping.

The munmap() system call deletes the mappings for the specified address range and causes further references to addresses within the range to generate invalid memory references.

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
int munmap(void *addr, size_t length);

Example write

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>

int main (int argc, char **argv){

        char *key = "/introduction";
        char *intro = "Hello, Welcome to India";

        int shm_fd, size;
        size = strlen(intro);
        shm_fd = shm_open(key, O_CREAT | O_RDWR | O_TRUNC, 0660);

        if (shm_fd < 0) {
                printf("failure on shm_open on shm_fd, errcode = %d\n", errno);
                return -1;
        }

        if (ftruncate(shm_fd, size) == -1) {
                printf("Error on ftruncate to allocate size of shared memory region\n");
                return -1;
        }

        void *shm_reg = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

        memset(shm_reg, 0, size);
        memcpy(shm_reg, intro, size);
        munmap(shm_reg, size);
        //shm_unlink(key);
        close(shm_fd);
        return 0;
}

Example reader

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

int main (int argc, char **argv){

        char *key = "/introduction";
        char buffer[128];
        memset(buffer, 0, 128);
        int shm_fd = 0, rc = 0;

        shm_fd = shm_open(key, O_CREAT | O_RDONLY , 0660);

        if (shm_fd < 0) {
                printf("failure on shm_open on shm_fd, error code = %d", errno);
                return -1;
        }

        void *shm_mem = mmap (NULL, 128, PROT_READ, MAP_SHARED, shm_fd, 0);

        if(shm_mem == MAP_FAILED){
                printf("Error on mapping\n");
                return -1;
        }

        memcpy(buffer, shm_mem, 128);
        printf("Data read = %s\n", buffer);
        rc = munmap(shm_mem, 128);

        if(rc < 0){
                printf("munmap failed\n");
                return -1;
        }
        shm_unlink(key);
        close(shm_fd);
        return 0;
}
Output:
gcc writer.c -o writer -lrt
gcc reader.c -o reader -lrt

run writer one terminal
./writer

run reader other terminal
./reader
 Data read = Hello, Welcome to India

Share This: