Функция
shmat
подстыковывает сегмент разделяемой памяти
shmid
к адресному пространству вызывающего процесса.
Адрес подстыковываемого сегмента определяется
shmaddr
с помощью одного из перечисленных ниже критериев:
Если
shmaddr
равен
NULL,
то система выбирает для подстыкованного сегмента подходящий (неиспользованный) адрес.
Если
shmaddr
не равен
NULL,
а в поле
shmflg
включен флаг
SHM_RND,
то подстыковка производится по адресу
shmaddr,
округленному вниз до ближайшего кратного
SHMLBA.
В противном случае
shmaddr
должен быть округленным до размера страницы адресом, к которому
производится подстыковка.
Если в поле
shmflg
включен флаг
SHM_RDONLY,
то подстыковываемый сегмент будет доступен только для чтения,
и вызывающий процесс должен иметь права на чтение этого сегмента.
Иначе, сегмент будет доступен для чтения и записи, и у процесса
должны быть соответствующие права.
Сегментов "только-запись" не существует.
Флаг
SHM_REMAP
(специфичный для Linux) может быть указан в
shmflg
для обозначения того, что распределение сегмента должно замещать
любые существующие распределения в диапазоне, начиная с
shmaddr
и до размера сегмена.
(Обычно выдается ошибка
EINVAL
если уже существует распределение в этом диапазоне адресов.)
В этом случае
shmaddr
не должно быть равно
NULL.
Значение
brk
вызывающего процесса подстыковкой не изменяется.
При завершении работы процесса сегмент будет отстыкован.
Один и тот же сегмент может быть подстыкован в адресное пространство
процесса несколько раз, как "только для чтения", так и в режиме
"чтение-запись".
При удачном выполнении системный вызов
shmat
обновляет содержимое структуры
shmid_ds,
связанной с разделяемым сегментом памяти, следующим образом:
shm_atime
устанавливается в текущее время.
shm_lpid
устанавливается в идентификатор вызывающего процесса.
shm_nattch
увеличивается на 1.
Заметьте, что пристыковка производится и в том случае, если
пристыковываемый сегмент помечен на удаление.
Функция
shmdt
отстыковывает сегмент разделяемой памяти, находящийся по адресу
shmaddr,
от адресного пространства вызвающего процесса.
Отстыковываемый сегмент должен быть среди пристыкованных
ранее функцией
shmat.
Параметр
shmaddr
должен быть равен значению, которое возвратила
соответствующая функция
shmat.
При удачном выполнении системный вызов
shmdt
обновляет содержимое структуры
shmid_ds,
связанной с разделяемым сегментом памяти, следующим образом:
shm_dtime
устанавливается в текущее время.
shm_lpid
устанавливается в идентификатор вызывающего процесса.
shm_nattch
уменьшается на 1.
Если это значение становится равным 0, а сегмент помечен
на удаление, то сугмент удаляется из памяти.
Эта функция освобождает занятую ранее этим сегментом область
памяти в адресном пространстве процесса.
СИСТЕМНЫЕ ВЫЗОВЫ
fork()
При исполнении
fork()
дочернии процесс наследует пристыкованные сегменты разделяемой
памяти.
exec()
При исполнении
exec()
все подстыкованные сегменты памяти отстыковываются от процесса.
exit()
При исполнении
exit()
все подстыкованные сегменты памяти отстыковываются от процесса.
ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ
При ошибке обе функции возвращают
-1,
а переменной
errno
присваивается номер ошибки.
При удачном выполнении
shmat
возвращает адрес подстыкованного сегмента памяти, а
shmdt
возвращает
0.
НАЙДЕННЫЕ ОШИБКИ
При ошибке функции
shmat
переменная
errno
может принимать следующие коды ошибок:
EACCES
Вызывающий процесс не имеет прав для подстыковки заданного типа.
EINVAL
Неправильное значение
shmid,
не выравненное по границе страницы или неправильное значение
shmaddr,
или ошибка подключения к
brk,
или
SHM_REMAP
было определено, но
shmaddr
равно
NULL.
ENOMEM
Не хватает памяти для описателя или таблиц страниц.
Функция
shmdt
может неудачно завершиться только в одном случае: если
по адресу
shmaddr,
нет сегмента разделяемой памяти. В этом случае
errno
будет содержать
EINVAL.
ЗАМЕЧАНИЯ
Для улучшемия переносимости программ рекомендуется использовать
shmat
с аргументом
shmaddr
установленным в
NULL.
Необходимо учитывать, что что сегмент разделяемой памяти, пристыковываемый
таким способом, может быть в разных процессах пристыкова к разным адресам.
Поэтому все указатели в области разделяемой памяти должны быть не абсолютными,
а относительными (как правило относительно адреса начала сегмента).
На работу системного вызова
shmat
влияет следующий системный параметр:
SHMLBA
Коэффициент округления нижней границы сегмента.
Должен нацело делиться на размер страницы.
На настоящий момент
SHMBLA
равен
PAGE_SIZE.
В текущей реализации не существует явного предела максимального
количества подстыкованных сегментов разделяемой памяти на процесс:
(SHMSEG)
СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, SVID. SVr4 описывает дополнительный код ошибки EMFILE.
В SVID-v4 тип аргумента shmaddr изменен с
char *
на
const void *,
и возвращаемое значение shmat() - с
char *
на
void *.
(В Linux libc4 и libc5 в прототипе указано
char *;
а в glibc2 -
void *.)