}
printf("\n");
free(vec);
}
int
main(int argc, char *argv[])
{
char *addr;
size_t len, lockLen;
long pageSize, stepSize, j;
if (argc!= 4 || strcmp(argv[1], "-help") == 0)
usageErr("%s num-pages lock-page-step lock-page-len\n", argv[0]);
pageSize = sysconf(_SC_PAGESIZE);
if (pageSize == -1)
errExit("sysconf(_SC_PAGESIZE)");
len = getInt(argv[1], GN_GT_0, "num-pages") * pageSize;
stepSize = getInt(argv[2], GN_GT_0, "lock-page-step") * pageSize;
lockLen = getInt(argv[3], GN_GT_0, "lock-page-len") * pageSize;
addr = mmap(NULL, len, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, — 1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
printf("Allocated %ld (%#lx) bytes starting at %p\n",
(long) len, (unsigned long) len, addr);
printf("Before mlock: \n");
displayMincore(addr, len);
/* Запираем в памяти страницы, указанные с помощью аргументов командной строки */
for (j = 0; j + lockLen <= len; j += stepSize)
if (mlock(addr + j, lockLen) == -1)
errExit("mlock");
printf("After mlock: \n");
displayMincore(addr, len);
exit(EXIT_SUCCESS);
}
vmem/memlock.c
В следующей сессии командной строки показан пример выполнения программы из листинга 46.2. Мы выделяем семь групп по три смежные страницы в каждой (всего 32 страницы):
$ su
Password:
# ./memlock 32 8 3
Allocated 131072 (0x20000) bytes starting at 0x4014a000
Before mlock:
0x4014a000:…………………………..
After mlock:
0x4014a000: ***…..***…..***…..***…..
В этом программном выводе для обозначения страниц, которые находятся в физической памяти и пространстве подкачки, используются соответственно звездочки и точки. Как можно видеть в последней строке вывода, в каждой группе из восьми страниц три находятся в физическом адресном пространстве.
В данном примере мы получили повышенные привилегии, чтобы программа могла задействовать вызов mlock(). Начиная с Linux 2.6.9, данный шаг стал необязательным (при условии, что объем блокируемой памяти не превышает мягкое ограничение LIMIT_MEMLOCK).
Системный вызов madvise() служит для улучшения производительности программы путем информирования ядра о том, как именно вызывающий процесс (скорее всего) будет применять страницы памяти в диапазоне длиной length байт, начиная с адреса addr. С помощью данной информации ядро может повысить эффективность операций ввода/вывода, выполняемых с файлом, который отображается на эти страницы (обсуждение файловых отображений см. в разделе 45.4). В ядре Linux вызов madvise() доступен с версии 2.4.
#define _BSD_SOURCE
#include
int madvise(void *
Возвращает 0 при успешном завершении или -1 при ошибке
Значение addr должно быть выровнено по странице, а аргумент length в итоге округляется к следующему значению, кратному размеру страницы памяти в системе. Аргумент advice может быть равен одной из следующих констант.
• MADV_NORMAL — поведение по умолчанию. Страницы передаются в виде небольших групп. Это приводит к упреждающему и отложенному чтению.
• MADV_RANDOM — обращение к страницам на данном участке будет произвольным, поэтому упреждающее чтение не повлечет никакой выгоды. Таким образом, в каждой операции чтения ядро должно извлекать как можно меньший объем данных.
• MADV_SEQUENTIAL — обращение к страницам на этом участке будет последовательным. Таким образом, ядро может прибегнуть к агрессивному упреждающему чтению; после доступа к страницам их можно быстро освобождать.
• MADV_WILLNEED — страницы на этом участке следует считывать наперед, готовясь к будущему доступу. Операция MADV_WILLNEED по своим результатам похожа на вызов readahead() (доступный только в Linux) и posix_fadvise() с флагом POSIX_FADV_WILLNEED.
• MADV_DONTNEED — вызывающий процесс больше не требует, чтобы страницы на данном участке находились в физической памяти. Результаты применения этого флага варьируются в зависимости от реализации UNIX. Для начала посмотрим, как он ведет себя в Linux. Отображенные страницы на участке MAP_PRIVATE всегда отклоняются; это значит, что будут потеряны все внесенные в них изменения. Диапазон адресов виртуальной памяти остается доступным, но при следующем доступе к каждой странице произойдет отказ, который приведет к ее повторной инициализации (с помощью либо содержимого отображенного на нее файла, либо (если это анонимное отображение) нулей). Данную особенность можно использовать как средство повторной инициализации содержимого участка MAP_PRIVATE. В случае с участком MAP_SHARED ядро