Копирование данных из объекта, отображаемого в общую память, с помощью sendfile()/fcopyfile()

Возможно ли — и если это так разумно — использовать sendfile() (или его двоюродного брата Darwin/BSD fcopyfile()) для передачи данных непосредственно между объектом общей памяти и файлом?

Такие функции, как sendfile() и fcopyfile(), могут полностью выполнять все необходимые механистические операции, лежащие в основе такой передачи данных, не покидая пространства ядра — вы передаете два открытых дескриптора, источник и место назначения, при вызове этих функций, и они берут их оттуда.

Другие средства копирования данных неизменно потребуют ручного маневрирования через границу между пространством ядра и пространством пользователя; такие переключения контекста по своей сути довольно затратны с точки зрения производительности.

Я не могу найти ничего определенного по поводу использования дескриптора разделяемой памяти в качестве аргумента: нет статей за или против этой практики; ничего на соответствующих man-страницах; никаких твитов, публично считающих sendfile() использование дескрипторов общей памяти вредным; &c... Но я думаю, что смогу сделать что-то вроде этого:

char const* name = "/yo-dogg-i-heard-you-like-shm"; /// only one slash, at zero-index
int len = A_REASONABLE_POWER_OF_TWO;                /// valid per shm_open()
int descriptor = shm_open(name, O_RDWR | O_CREAT, 0600);
int destination = open("/tmp/yodogg.block", O_RDWR | O_CREAT, 0644);
void* memory = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, descriptor, 0);
off_t bytescopied = 0;
sendfile(destination, descriptor, &bytescopied, len);
/// --> insert other stuff with memset(…), memcopy(…) &c. here, possibly
munmap(memory, len);
close(descriptor); close(destination);
shm_unlink(name);

… Это заблуждение или действующий метод?

И если последнее, можно ли настроить размер общей карты в памяти перед копированием данных?


РЕДАКТИРОВАТЬ: я разрабатываю проект, к которому относится этот запрос, на macOS 10.12.4; Я стремлюсь к тому, чтобы он работал на Linux с возможной совместимостью с FreeBSD.


person fish2000    schedule 13.05.2017    source источник
comment
Что произошло, когда вы попробовали это?   -  person user207421    schedule 14.05.2017
comment
@EJP Я еще не пробовал именно эту схему — комбо-удар из трех ударов shm_open(), mmap(…, MAP_SHARED, …) и sendfile() — пока по двум причинам. Во-первых, второстепенный момент: прямо сейчас я разрабатываю исходно для macOS, поэтому мой sendfile() — это полифилл, использующий fcopyfile()… во-вторых: моя текущая задача — реализовать доступ к отображаемой памяти записываемых файлов через класс-оболочку (которую эта оболочка уже предлагает карты памяти только для чтения, см. github.com/fish2000 /libimread/blob/master/src/); Я буду использовать то, что я узнаю, делая это и из SO, для решения проблемы с общей памятью.   -  person fish2000    schedule 14.05.2017


Ответы (1)


Копирование данных между двумя «вещами», отображенными в памяти — как в приведенном выше примере — действительно потребует копирования вещей из ядра в пространство пользователя, а затем обратно. И нет, боюсь, вы не можете использовать системный вызов sendfile(2) для отправки файловому дескриптору.

Но вы должны быть в состоянии сделать это следующим образом:

  1. Создайте объект общей памяти (или файл, на самом деле; из-за второго шага он все равно будет совместно использоваться в памяти
  2. Отобразите его в памяти с помощью MAP_SHARED; вы получите указатель
  3. Откройте файл назначения
  4. запись (destination_fd, source_pointer, source_length)

В этом случае системному вызову записи не потребуется копировать данные в ваш процесс. Однако не уверен, каковы будут фактические характеристики производительности. Разумное использование madvise(2) может помочь.

person Edward Tomasz Napierala    schedule 02.06.2017
comment
Полезно знать — и спасибо за совет по использованию write(…). На первый взгляд кажется, что разумное использование как madvise(…), так и fadvise(…)FADV_SEQUENTIAL) может привести к оптимальным результатам для каждой платформы. - person fish2000; 03.06.2017