Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize POSIX shared memory. A working example

I have a shared dynamic array within POSIX model between two different applications. I would like to have an ability to change its size without copying. Unfortunately I couldn't find right solution to increase and decrease POSIX shared memory in C language. In the web I have found many documents with poor explanations and wretched examples. I've managed to find some interesting topics, but all of them are unsuitable to me:

  1. "Linux System Programming" - "Mapping Files into Memory" Part: "Resizing a Mapping" - where is no working example to resize SHM.

  2. How do I implement dynamic shared memory resizing? - A description only. Have no example.

  3. mremap function failed to allocate new memory - Favorite answer works wrong.

  4. Fast resize of a mmap file

  5. Characteristics of mremap function in Linux

  6. mremap function failed to allocate new memory

  7. c/linux - ftruncate and POSIX Shared Memory Segments - rszshm doesn't use mremap() at all. It copy memory instead. The worst way.

I've developed an example as I understand the documentation. Unfortunately it is not working right. Please give me an advise, where I am wrong. And please be so kind as to give me a working example.

In the documentation I have found that I have to use ftruncate() before mremap(), but I couldn't find right syntax for using them. Besides, mremap() works with aligned memory pages. How to properly increase shared memory in this case?

/* main.c */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>

int main(void)
{
    size_t size_of_mem = 1024;
    int fd = shm_open("/myregion", O_CREAT | O_RDWR,
                      S_IRWXO | S_IRUSR | S_IWUSR);
    if (fd == -1)
    {
        perror("Error in shm_open");
        return EXIT_FAILURE;
    }

    if (ftruncate(fd, size_of_mem) == -1)
    {
        perror("Error in ftruncate");
        return EXIT_FAILURE;
    }

    void *shm_address = mmap(0, size_of_mem,
                             PROT_READ | PROT_WRITE | PROT_EXEC,
                             MAP_SHARED, fd, 0);
    if (shm_address == MAP_FAILED)
    {
        perror("Error mmapping the file");
        return EXIT_FAILURE;
    }

    /* Increase shard memory */
    for (size_t i=0; i<1024; ++i){

        /* Does 8 align memory page? */
        size_t new_size_of_mem = 1024+(8*i);

        if (ftruncate(fd, new_size_of_mem) == -1)
        {
            perror("Error in ftruncate");
            return EXIT_FAILURE;
        }

        /*
           mremap() works with  aligned memory pages.
           How to properly increase shared memory in this case?
        */
        void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE);
        if(temp == (void*)-1)
        {
            perror("Error on mremap()");
            return EXIT_FAILURE;
        }

        size_of_mem = new_size_of_mem;

    }

    return 0;
}

Build:

$ gcc -g -O0 -ggdb -pipe -Wall -Wextra -Wpedantic -Wshadow -march=native -std=c11 -o ./main ./main.c -lrt

Run:

$ ./main
Error on mremap(): Bad address
like image 737
Dennis V Avatar asked Nov 03 '16 10:11

Dennis V


1 Answers

You are loosing the address of the new allocated/remapped memory assigned to temp.

That means that, since the second cycle of for loop, you are moving an already moved memory.

After the check of mremap returned value you can ressign the new address to the shm_address pointer.

void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE);
if(temp == (void*)-1)
{
    perror("Error on mremap()");
    return EXIT_FAILURE;
}

shm_address = temp;
like image 83
LPs Avatar answered Oct 14 '22 17:10

LPs