Реализация буфера копирования при записи с помощью mmap в Mac OS X

Я играл с буферами копирования при записи в Linux, и следующий пример, похоже, работает так, как задумано:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define SIZE 4096

#define SHM_NAME "foobar"

int main(void)
{
    int fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);
    int r = ftruncate(fd, SIZE);

    char *buf1 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);

    strcpy(buf1, "Original buffer");

    char *buf2 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
                      MAP_PRIVATE, fd, 0);

    // At this point buf2 is aliased to buf1

    // Now modifying buf2 should trigger copy-on-write)...

    strcpy(buf2, "Modified buffer");

    // buf1 and buf2 are now two separate buffers

    strcpy(buf1, "Modified original buffer");

    // clean up

    r = munmap(buf2, SIZE);
    printf("munmap(buf2): %i\n", r);
    r = munmap(buf1, SIZE);
    printf("munmap(buf1): %i\n", r);
    r = shm_unlink(SHM_NAME);
    printf("shm_unlink: %i\n", r);

    return EXIT_SUCCESS;
}

Однако в OS X (10.10) второй вызов mmap возвращает MAP_FAILED с errno = 22 (EINVAL). справочная страница OS X для mmap кажется, что это должно работать (в описании флага MAP_PRIVATE даже упоминается копирование при записи), и я экспериментировал с различными флагами для вызовов mmap, но, похоже, ничего не работает. Есть идеи ?


person Paul R    schedule 13.03.2015    source источник
comment
В OS X использование MAP_PRIVATE не обрабатывает файловые дескрипторы одинаково.   -  person l'L'l    schedule 14.03.2015
comment
@l'L'l: спасибо за подсказку - можете ли вы дать мне больше деталей?   -  person Paul R    schedule 14.03.2015
comment
Посмотрите здесь.   -  person l'L'l    schedule 14.03.2015
comment
Спасибо, но не похоже, что вы передаете offset в mmap в этом примере?   -  person Paul R    schedule 14.03.2015
comment
Хорошо, спасибо, я поиграю. Я не уверен, что это поможет, поскольку я пытаюсь получить буфер MAP_PRIVATE, который изначально имеет псевдоним для буфера MAP_SHARED, а затем переназначается с помощью копирования при записи. Поэтому я думаю, что offset должен быть равен 0 для обоих, но я готов попробовать что угодно. ;-)   -  person Paul R    schedule 14.03.2015
comment
Вот один с использованием open; Кажется, что использование shm_open и выполнение псевдонима с MAP_SHARED и MAP_PRIVATE каким-то образом портит дескриптор файла. Судя по внешнему виду, это может быть ошибка.   -  person l'L'l    schedule 14.03.2015
comment
Спасибо - это выглядит более многообещающе - я не думал попробовать обычный файл - попробую...   -  person Paul R    schedule 14.03.2015
comment
Удивительно - я только что попробовал open с обычным файлом вместо shm_open, и теперь все работает! Большое спасибо за вашу помощь - не стесняйтесь написать это как ответ, если хотите, и я проголосую/приму его, в противном случае я сделаю это сам позже для всех, у кого может возникнуть такая же проблема в будущем. .   -  person Paul R    schedule 14.03.2015


Ответы (1)


Похоже, что использование shm_open с MAP_SHARED и MAP_PRIVATE делает что-то нежелательное с файловым дескриптором. Использование open является возможным обходным путем:

int fd = open(SHM_NAME, O_RDWR | O_CREAT, 0666);
...

Результат:

munmap(buf2): 0
munmap(buf1): 0
shm_unlink: -1

Использование shm_open с MAP_SHARED и MAP_PRIVATE приводит к Invalid file descriptor, хотя использование его с MAP_SHARED и MAP_SHARED, например, не дает. Мне неясно, является ли это ошибкой или задумано - хотя поведение не кажется правильным.

person l'L'l    schedule 14.03.2015
comment
Спасибо - переход с shm_open на open с обычным файлом решил мою проблему! - person Paul R; 14.03.2015