Рисунок 11.9. Структуры данных, используемые при разделении памяти
Процесс присоединяет область разделяемой памяти к своему виртуальному адресному пространству с помощью системной функции shmat:
virtaddr = shmat(id, addr, flags);
Значение id, возвращаемое функцией shmget, идентифицирует область разделяемой памяти, addr является виртуальным адресом, по которому пользователь хочет подключить область, а с помощью флагов (flags) можно указать, предназначена ли область только для чтения и нужно ли ядру округлять значение указанного пользователем адреса. Возвращаемое функцией значение, virtaddr, представляет собой виртуальный адрес, по которому ядро произвело подключение области и который не всегда совпадает с адресом, указанным пользователем.
В начале выполнения системной функции shmat ядро проверяет наличие у процесса необходимых прав доступа к области (Рисунок 11.10). Оно исследует указанный пользователем адрес; если он равен 0, ядро выбирает виртуальный адрес по своему усмотрению.
Область разделяемой памяти не должна пересекаться в виртуальном адресном пространстве процесса с другими областями; следовательно, ее выбор должен производиться разумно и осторожно. Так, например, процесс может увеличить размер принадлежащей ему области данных с помощью системной функции brk, и новая область данных будет содержать адреса, смежные с прежней областью; поэтому, ядру не следует присоединять область разделяемой памяти слишком близко к области данных процесса. Так же не следует размещать область разделяемой памяти вблизи от вершины стека, чтобы стек при своем последующем увеличении не залезал за ее пределы. Если, например, стек растет в направлении увеличения адресов, лучше всего разместить область разделяемой памяти непосредственно перед началом области стека.
алгоритм shmat /* подключить разделяемую память */
входная информация:
(1) дескриптор области разделяемой памяти
(2) виртуальный адрес для подключения области
(3) флаги
выходная информация: виртуальный адрес, по которому область подключена фактически
{
проверить правильность указания дескриптора, права доступа к области;
if (пользователь указал виртуальный адрес)
{
округлить виртуальный адрес в соответствии с флагами;
проверить существование полученного адреса, размер области;
}
else /* пользователь хочет, чтобы ядро само нашло подходящий адрес */
ядро выбирает адрес: в случае неудачи выдается ошибка;
присоединить область к адресному пространству процесса (алгоритм attachreg);
if (область присоединяется впервые)
выделить таблицы страниц и отвести память под нее (алгоритм growreg);
return (виртуальный адрес фактического присоединения области);
}
Рисунок 11.10. Алгоритм присоединения разделяемой памяти
Ядро проверяет возможность размещения области разделяемой памяти в адресном пространстве процесса и присоединяет ее с помощью алгоритма attachreg. Если вызывающий процесс является первым процессом, который присоединяет область, ядро выделяет для области все необходимые таблицы, используя алгоритм growreg, записывает время присоединения в соответствующее поле таблицы разделяемой памяти и возвращает процессу виртуальный адрес, по которому область была им подключена фактически.
Отсоединение области разделяемой памяти от виртуального адресного пространства процесса выполняет функция
shmdt(addr)
где addr — виртуальный адрес, возвращенный функцией shmat. Несмотря на то, что более логичной представляется передача идентификатора, процесс использует виртуальный адрес разделяемой памяти, поскольку одна и та же область разделяемой памяти может быть подключена к адресному пространству процесса несколько раз, к тому же ее идентификатор может быть удален из системы. Ядро производит поиск области по указанному адресу и отсоединяет ее от адресного пространства процесса, используя алгоритм detachreg (раздел 6.5.7). Поскольку в таблицах областей отсутствуют обратные указатели на таблицу разделяемой памяти, ядру приходится просматривать таблицу разделяемой памяти в поисках записи, указывающей на данную область, и записывать в соответствующее поле время последнего отключения области.
Читать дальше