Изменение размера общей памяти POSIX. Рабочий пример

у меня есть общий динамический массив в модели POSIX между двумя различными приложениями. Я хотел бы иметь возможность изменять его размер без копирования. К сожалению, я не смог найти правильное решение для увеличения и уменьшения общей памяти POSIX на языке C. В Интернете я нашел много документов с плохими объяснениями и жалкими примерами. Мне удалось найти несколько интересных тем, но все они мне не подходят:

  1. "Система Linux Программирование" - "отображение файлов в память" Часть: "изменение размера отображения" - где нет рабочего примера для изменения размера SHM.

  2. как реализовать динамическое изменение размера общей памяти? - это только описание. Нет примера.

  3. функция mremap не смогла выделить новую память - любимый ответ работает неправильно.

  4. быстрое изменение размера mmap файл

  5. характеристики функции mremap в Linux

  6. функция mremap не смогла выделить новую память

  7. c / linux - сегменты общей памяти FTRUNCATE и POSIX - rszshm вообще не использует mremap (). Вместо этого он копирует память. Худший способ.

Я разработал пример, как я понимаю документацию. К сожалению, это не работает. Пожалуйста, дайте мне совет, где я ошибаюсь. И, пожалуйста, будьте добры, приведите мне рабочий пример.

в документации я обнаружил, что я должен использовать ftruncate() перед mremap (), но я не мог найти правильный синтаксис для их использования. Кроме того, mremap() работает с выровненными страницами памяти. Как правильно увеличить общую память в этом случае?

/* 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

1 ответов


вы теряете адрес новой выделенной / переназначенной памяти, назначенной temp.

это означает, что со второго цикла цикла for вы перемещаете уже перемещенную память.

после проверки mremap возвращенное значение, вы можете ressign новый адрес shm_address указатель.

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;