ИМЯ shmat, shmdt - операции с общей памятью System V
ОБЗОР #include <sys/types.h> #include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
ОПИСАНИЕ shmat() Вызов shmat() подключает сегмент общей памяти System V с идентификатором shmid к адресному пространству вызывающего процесса. Адрес подключения, указанный в shmaddr, учитывается следующим образом:
* Если значение shmaddr равно NULL, то система выбирает подходящий (неиспользуемый) выровненный по странице адрес для подключения сегмента.
* Если значение shmaddr не равно NULL, а в shmflg указан флаг SHM_RND, то подключение производится по адресу shmaddr, округлённому до ближайшего значения кратного SHMLBA.
* В противном случае shmaddr должно быть выровнено по адресу страницы, к которому производится подключение.
В дополнении к SHM_RND, в аргументе битовой маски shmflg могут быть указаны следующие флаги:
SHM_EXEC (есть только в Linux; начиная с Linux 2.6.9) Разрешить выполнение содержимого сегмента. Вызывающий должен иметь права на выполнение сегмента.
SHM_RDONLY Разрешить доступ к сегменту только для чтения. Процесс должен иметь права на чтение сегмента. Если этот флаг не указан, то сегмент подключается с правом чтения и записи, и процесс должен иметь права на чтение и запись сегмента. Об общих сегментах памяти, доступных только на запись, ничего не упоминается.
SHM_REMAP (есть только в Linux) Этот флаг указывает, что отображение сегмента должно замещать любые существующие отображения в диапазоне, начиная с shmaddr и до размера сегмента (обычно выдается ошибка EINVAL, если в этом диапазоне адресов уже есть отображение). В этом случае значение shmaddr не должно быть равно NULL.
Значение brk(2) вызывающего процесса от подключения не изменяется. При завершении работы процесса сегмент будет автоматически отсоединён. Один и тот же сегмент может быть подключён в адресное пространство процесса несколько раз, как только для чтения, так и для чтения-записи.
При успешном выполнении системный вызов shmat() обновляет поля структуры shmid_ds (см. shmctl(2)), связанной с общим сегментом памяти, следующим образом:
Полю shm_atime присваивается значение текущего времени.
Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
Значение shm_nattch увеличивается на 1. Полю shm_dtime присваивается значение текущего времени.
Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
Значение shm_nattch уменьшается на 1. Если оно становится равным 0 и сегмент помечен для удаления, то сегмент удаляется.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ При успешном выполнении shmat() возвращается адрес подключённого общего сегмента памяти; при ошибке возвращается (void *) -1, а в errno содержится код ошибки.
При успешном выполнении shmdt() возвращается 0; при ошибке возвращается -1, а в errno содержится код ошибки.
ОШИБКИ Значения errno, устанавливаемые при возникновении ошибок в shmat():
EACCES Вызывающий процесс не имеет прав для подключения заданного типа и не имеет мандата CAP_IPC_OWNER в пространстве имён пользователя, который управляет его пространством имён IPC.
EIDRM Значение shmid указывает на удалённый идентификатор.
EINVAL Неправильное значение shmid, не выровненное (по границе страницы и не указан SHM_RND) или неправильное значение shmaddr, или невозможно подключить сегмент по адресу shmaddr, или был указан SHM_REMAP, но shmaddr равно NULL.
ENOMEM Невозможно выделить память для дескриптора или страничных таблиц.
Значения errno, устанавливаемые при возникновении ошибок в shmdt():
EINVAL По адресу shmaddr подключённый общий сегмент памяти отсутствует; или значение shmaddr не выровнено по границе страницы.
СООТВЕТСТВИЕ СТАНДАРТАМ POSIX.1-2001, POSIX.1-2008, SVr4.
В SVID 3 (возможно, чуть раньше) тип аргумента shmaddr изменён с char * на const void *, а тип возвращаемого значения shmat() с char * на void *.
ЗАМЕЧАНИЯ При вызове fork(2) потомки наследуют подключённые общие сегменты памяти.
При вызове execve(2) все подключённые общие сегменты памяти отключаются.
При вызове _exit(2) все подключённые общие сегменты памяти отключаются.
Для улучшения переносимости программ при подключении общего сегмента памяти рекомендуется использовать shmat() с аргументом shmaddr, установленным в NULL. Необходимо учитывать, что сегмент памяти, подключаемый таким способом, в разных процессах может подключаться по разным адресам. Поэтому все указатели в области общей памяти должны быть не абсолютными, а относительными (как правило относительно адреса начала сегмента).
В Linux сегмент общей памяти можно подключить даже, если он помечен для удаление. Однако в POSIX.1 об этом ничего не сказано, и многие другие реализации это не поддерживают.
На работу shmat() влияют следующие системные параметры: Реализацией не ограничивается количество общих сегментов общей памяти на процесс (SHMSEG).
СМОТРИТЕ ТАКЖЕ brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), svipc(7)
|