shmget - выделяет
общий
сегмент
памяти System V
Standard C library (
libc,
-lc)
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Вызов
shmget()
возвращает
идентификатор
общего
сегмента
памяти System V,
соответствующего
значению
аргумента
key. Его можно
использовать
для
получения
идентификатора
ранее
созданного
общего
сегмента
памяти
(когда
shmflg
равно нулю
и
key не
содержит
значения
IPC_PRIVATE) или для
создания
нового.
Новый
общий
сегмент
памяти
размером
size,
округлённым
до
значения,
кратного
PAGE_SIZE
создаётся,
если
значение
key
равно
IPC_PRIVATE
или, если
key
не равно
IPC_PRIVATE,
но не
существует
общего
сегмента
памяти,
который бы
соответствовал
значению
key
и в
shmflg есть
флаг
IPC_CREAT.
Если в
shmflg
одновременно
указаны
IPC_CREAT
и
IPC_EXCL и для
значения
key
уже
существует
общий
сегмент
памяти, то
вызов
shmget()
завершается
с ошибкой и
errno
присваивается
EEXIST (такой же
результат
как с
O_CREAT | O_EXCL у
open(2)).
Значение
shmflg
составляется
из
следующих
флагов:
- IPC_CREAT
- Служит
для
создания
нового
сегмента.
Если этого
флага нет,
то вызов shmget()
будет
искать
сегмент,
соответствующий
key, и затем
проверит,
имеет ли
пользователь
права на
доступ к
сегменту.
- IPC_EXCL
- Этот
флаг
используется
совместно
с IPC_CREAT для
того, чтобы
этот вызов
создал
сегмент.
Если
сегмент
уже
существует,
то вызов
завершается
с ошибкой.
-
SHM_HUGETLB
(начиная с Linux
2.6)
- Выделять
сегмент
используя
«огромные
страницы».
Дополнительную
информацию
смотрите в
файле
исходного
кода ядра Linux
Documentation/admin-guide/mm/hugetlbpage.rst.
-
SHM_HUGE_2MB, SHM_HUGE_1GB
(начиная с Linux
3.8)
- Используется
вместе с
SHM_HUGETLB для
выбора
других
размеров
страниц hugetlb
(2 МБ и 1 МБ,
соответственно)
в системах,
которые
поддерживают
несколько
размеров
страниц hugetlb.
- Вообще,
желаемые
размер
огромной
страницы
можно
настроить
закодировав
логарифмом
по
основанию 2
желаемый
размер
страницы в
шести
битах
смещения
SHM_HUGE_SHIFT. Таким
образом,
приведённые
выше
константы
определяются
так:
-
#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
- Дополнительную
информацию
о схожих по
имени
константах
смотрите в
mmap(2).
-
SHM_NORESERVE
(начиная с Linux
2.6.15)
- Этот
флаг нужен
для того
же, что и
флаг MAP_NORESERVE у
mmap(2). Он
указывает
не
резервировать
место в
пространстве
подкачки
для этого
сегмента.
Операцией
резервирования
места в
пространстве
подкачки
гарантируется,
что
сегмент
можно
изменить.
Если место
не
резервировать,
то при
записи
можно
получить
сигнал SIGSEGV,
если
кончится
физическая
память.
Смотрите
также
обсуждение
файла
/proc/sys/vm/overcommit_memory в proc(5).
В
дополнении
к
перечисленным
выше
флагам в
младших 9
битах
shmflg
задаются
права для
владельца,
группы и
всех
остальных.
Формат
значения
битов
совпадает
с
аргументом
mode вызова
open(2).
В данный
момент бит
выполнения
системой
не
используются.
Если
создаётся
новый
общий
сегмент
памяти, то
его
содержимое
инициализируется
нулями, а
соответствующая
ему
структура
данных
shmid_ds
(см.
shmctl(2))
следующим
образом:
- •
- Полям
shm_perm.cuid и shm_perm.uid
присваиваются
значения
эффективного
идентификатора
пользователя
вызывающего
процесса.
- •
- Полям
shm_perm.cgid и shm_perm.gid
присваиваются
значения
эффективного
идентификатора
группы
вызывающего
процесса.
- •
- Младшим 9
битам shm_perm.mode
присваивается
значение
младших 9
бит shmflg.
- •
- Полю shm_segsz
присваивается
значение
size.
- •
- Полям shm_lpid,
shm_nattch, shm_atime и shm_dtime
присваивается
значение 0.
- •
- Полю shm_ctime
присваивается
значение
текущего
времени.
Если общий
сегмент
памяти уже
существует,
то
проверяются
права
доступа к
нему и не
помечен ли
он для
удаления.
При
успешном
выполнении
возвращается
корректный
идентификатор
общей
памяти. При
ошибке
возвращается
-1, а в
errno
записывается
причина
ошибки.
- EACCES
- Пользователь
не имеет
прав
доступа к
общему
сегменту
памяти и не
имеет
мандата
CAP_IPC_OWNER в
пространстве
имён
пользователя,
который
управляет
его
пространством
имён IPC.
- EEXIST
- В shmflg
указаны IPC_CREAT
и IPC_EXCL, но
общий
сегмент
памяти уже
существует
для key.
- EINVAL
- Был
создан
новый
сегмент и
size меньше SHMMIN
или больше
SHMMAX.
- EINVAL
- Сегмент
для
заданного
key
существует,
но size
больше
размера
этого
сегмента.
- ENFILE
- Достигнуто
максимальное
количество
открытых
файлов в
системе.
- ENOENT
- Не
существует
сегмента
для ключа
key и флаг IPC_CREAT
не указан.
- ENOMEM
- Не
хватает
памяти для
выделения
под
перерасход
сегмента.
- ENOSPC
- Все
возможные
идентификаторы
сегментов
уже
распределены
( SHMMNI) или
размер
выделяемого
сегмента
превысит
системные
лимиты по
общей
памяти ( SHMALL).
- EPERM
- The SHM_HUGETLB flag was specified, but the caller
was not privileged (did not have the CAP_IPC_LOCK capability) and
is not a member of the sysctl_hugetlb_shm_group group; see the
description of /proc/sys/vm/sysctl_hugetlb_shm_group in
proc(5).
POSIX.1-2001, POSIX.1-2008, SVr4.
SHM_HUGETLB и
SHM_NORESERVE
являются
расширениями
Linux.
IPC_PRIVATE — не поле
флага, а тип
key_t. Если
key
равно
этому
специальному
значению,
то
системный
вызов
игнорирует
всё кроме
9-ти младших
битов
shmflg и
создаёт
новый
общий
сегмент
памяти.
Ниже
приведены
ограничения
ресурсов
на общий
сегмент
памяти,
влияющие
на вызов
shmget():
- SHMALL
- Системный
лимит на
полный
объём
общей
памяти,
измеряется
в единицах,
равных
размеру
системной
страницы.
- В Linux это
ограничение
можно
прочитать
и изменить
через /proc/sys/kernel/shmmni.
Начиная с 3.16,
значение
по
умолчанию
равно:
-
ULONG_MAX - 2^24
- Эффект
этого
значения
(которое
подходит и
для
32-разрядной,
и для
64-разрядной
системы) —
не задать
ограничение
на
выделения.
Это
значение, в
отличии от
ULONG_MAX, было
выбрано в
качестве
значения
по
умолчанию,
чтобы
предотвратить
некоторые
случаи,
когда
старые
приложения
просто
увеличивают
существующий
предел без
начальной
проверки
его
текущего
значения.
Такие
приложения
переполнили
бы
значение,
если
предел был
равен ULONG_MAX.
- В Linux 2.4 по Linux 3.15
значение
по
умолчанию
этого
ограничения
было:
-
SHMMAX / PAGE_SIZE * (SHMMNI / 16)
- Если SHMMAX и
SHMMNI не
изменены,
то
умножение
результата
этой
формулы на
размер
страницы
(для
получения
значения в
байтах)
даёт
значение
8 ГБ —
ограничение
на общее
количество
памяти,
используемой
во всех
общих
сегментах
памяти.
- SHMMAX
- Максимальный
размер
общего
сегмента
памяти в
байтах.
- В Linux это
ограничение
можно
прочитать
и изменить
через /proc/sys/kernel/shmmax.
Начиная с 3.16,
значение
по
умолчанию
равно:
-
ULONG_MAX - 2^24
- Эффект
этого
значения
(которое
подходит и
для
32-разрядной,
и для
64-разрядной
системы) —
не задать
ограничение
на
выделения.
Смотрите
описание
SHMALL о том,
почему
используется
именно
такое
значение
по
умолчанию
(а не ULONG_MAX).
- From Linux 2.2 up to Linux 3.15, the default value of this
limit was 0x2000000 (32 MiB).
- Так как
невозможно
отобразить
только
часть
общего
сегмента
памяти,
размер
виртуальной
памяти
отличается
от
ограничения
на
максимальный
размер
подходящего
сегмента:
например,
на i386 самые
большие
сегменты,
которые
можно
отображать,
имеют
размер
около 2.8 ГБ,
а на x86-64 —
около 127 ТБ.
- SHMMIN
- Минимальный
размер
общего
сегмента
памяти в
байтах в
системе:
зависит от
реализации
(в
настоящий
момент
равно 1
байту, хотя
на самом
деле
минимальный
выделяемый
размер
равен PAGE_SIZE).
- SHMMNI
- Системный
лимит на
общее
количество
общих
сегментов
памяти.
Начиная с Linux
2.2, значение
по
умолчанию
равно 128;
начиная с Linux
2.4, значение
по
умолчанию
равно 4096.
- В Linux это
ограничение
можно
прочитать
и изменить
через
/proc/sys/kernel/shmmni.
Реализацией
не
ограничивается
максимальное
количество
общих
сегментов
памяти на
процесс (
SHMSEG).
Until Linux 2.3.30, Linux would return
EIDRM for a
shmget() on a
shared memory segment scheduled for deletion.
Имя
IPC_PRIVATE,
возможно,
было
выбрано
неудачно,
IPC_NEW
отражает
смысл
действия
более ясно.
Смотрите
shmop(2).
memfd_create(2),
shmat(2),
shmctl(2),
shmdt(2),
ftok(3),
capabilities(7),
shm_overview(7),
sysvipc(7)
Русский
перевод
этой
страницы
руководства
был сделан
Alexander Golubev <
[email protected]>, Azamat Hackimov
<
[email protected]>, Hotellook, Nikita
<
[email protected]>, Spiros Georgaras <
[email protected]>, Vladislav
<
[email protected]>, Yuri Kozlov <
[email protected]>
и Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]