SEMCTL(2)

ИМЯ
semctl - операции управления семафорами System V

ОБЗОР
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

ОПИСАНИЕ
Вызов semctl выполняет операцию, определённую в cmd, над набором семафоров System V, указанном в semid, или над семафором с номером semnum из этого набора (семафоры нумеруются, начиная с 0).

Данный вызов имеет три или четыре аргумента, в зависимости от значения cmd. Если аргументов четыре, то четвертый аргумент arg имеет тип union semun. В вызывающей программе это объединение должно быть определено следующим образом:
union semun {
    int              val;    /* значение для SETVAL */
    struct semid_ds *buf;    /* буфер для IPC_STAT, IPC_SET */
    unsigned short  *array;  /* массив для GETALL, SETALL */
    struct seminfo  *__buf;  /* буфер для IPC_INFO
                                (есть только в Linux) */
};

Структура данных semid_ds определена в <sys/sem.h> следующим образом:
struct semid_ds {
    struct ipc_perm sem_perm;  /* владелец и права */
    time_t          sem_otime; /* время последней операции semop */
    time_t          sem_ctime; /* время последнего изменения */
    unsigned long  sem_nsems; /* кол-во семафоров в наборе */
};

Структура ipc_perm определена следующим образом (значения полей устанавливаются с помощью IPC_SET):

struct ipc_perm {
    key_t          __key; /* ключ, передаваемый в semget(2) */
    uid_t          uid;   /* эффективный UID владельца */
    gid_t          gid;   /* эффективный GID владельца */
    uid_t          cuid;  /* эффективный UID создателя */
    gid_t          cgid;  /* эффективный GID создателя */
    unsigned short mode;  /* права */
    unsigned short __seq; /* порядковый номер */
};

Возможные значения cmd:

IPC_STAT
    Копирует информацию из структуры данных ядра, связанной с semid, в структуру semid_ds, расположенную по адресу arg.buf. Аргумент semnum игнорируется. Вызывающий процесс должен иметь права на чтение набора семафоров.

IPC_SET
    Записывает значения некоторых полей структуры semid_ds, на которую указывает arg.buf, в структуру данных ядра, связанную с этим набором семафоров, также обновляя при этом поле sem_ctime. Обновляются следующие поля структуры: sem_perm.uid, sem_perm.gid и (младшие 9 значащих битов) sem_perm.mode. Эффективный UID вызывающего процесса должен совпадать с идентификатором владельца (sem_perm.uid) или создателя (sem_perm.cuid) набора семафоров, или вызывающий должен иметь расширенные права. Аргумент semnum игнорируется.

IPC_RMID
    Немедленно удаляет набор семафоров, пробуждая все процессы, заблокированные в вызове semop(2) (при этом возвращается сообщение об ошибке, а errno присваивается значение EIDRM). Эффективный идентификатор пользователя вызывающего процесса должен совпадать с идентификатором создателя или владельца набора семафоров, или вызывающий должен иметь расширенные права. Аргумент semnum игнорируется.

IPC_INFO (есть только в Linux)
    Возвращает параметры и информацию о системных ограничениях семафоров в структуре, указанной в arg.__buf. Данная структура имеет тип seminfo, который определён в <sys/sem.h>, если определён макрос тестирования свойств _GNU_SOURCE:
    struct  seminfo {
        int semmap;  /* количество записей в карте
                        семафоров; не используется в ядре */
        int semmni;  /* максимальное количество наборов
                        семафоров */
        int semmns;  /* максимальное количество семафоров во
                         всех наборах семафоров */
        int semmnu;  /* максимальное количество структур undo
                        в системе; не используется в ядре */
        int semmsl;  /* максимальное количество семафоров в
                        наборе */
        int semopm;  /* максимальное количество операция для
                        semop(2) */
        int semume;  /* максимальное количество записей undo на
                        процесс; не используется в ядре */
        int semusz;  /* размер struct sem_undo */
        int semvmx;  /* максимальное значение семафора */
        int semaem;  /* максимальное значение, которое может
                        быть записано для регулирования
                        семафора (SEM_UNDO) */
    };
    Значения semmsl, semmns, semopm и semmni можно изменить через /proc/sys/kernel/sem; подробности в proc(5).

SEM_INFO (есть только в Linux)
    Возвращает структуру seminfo, содержащую такую же информацию что и для IPC_INFO, за исключением того, что следующие поля содержат информацию о системных ресурсах, потребляемых семафорами: в поле semusz возвращается количество наборов семафоров, существующих в системе; в поле semaem возвращается общее количество семафоров во всех наборах семафоров в системе.

SEM_STAT (есть только в Linux)
    Возвращает структуру semid_ds как для IPC_STAT. Однако аргумент semid содержит не идентификатор семафора, а индекс во внутреннем массиве ядра, который хранит информацию о всех наборах семафоров в системе.

GETALL
    Возвращает значение semval (т.е. текущее значение) всех семафоров в наборе в arg.array. Аргумент semnum игнорируется. Вызывающему процессу нужны права на чтение набора семафоров.

GETNCNT
    Возвращает значение semncnt для semnum-того семафора (т.е., число процессов, ожидающих увеличения значения semval в semnum-ом семафоре набора). Вызывающему процессу нужны права на чтение набора семафоров.

GETPID
    Возвращает значение sempid для semnum-того семафора набора. Это PID процесса, который последним выполнял операцию с этим семафором (но смотрите ЗАМЕЧАНИЯ). Вызывающему процессу нужны права на чтение набора семафоров.

GETVAL
    Возвращает значение semval для semnum-того семафора набора. Вызывающему процессу нужны права на чтение набора семафоров.

GETZCNT
    Возвращает значение semzcnt для semnum-того семафора (т.е., количество процессов, ожидающих, когда значение semval semnum-того семафора набора станет равным 0). Вызывающему процессу нужны права на чтение набора семафоров.

SETALL
    Устанавливает значение semval всех семафоров набора, используя arg.array и изменяя также поле sem_ctime структуры semid_ds, связанной с набором. Записи undo (см. semop(2)) очищаются для изменённых семафоров во всех процессах. Если изменения значений семафоров приводят к отмене блокировки в вызове semop(2) других процессов, то эти процессы пробуждаются. Аргумент semnum игнорируется. Вызывающему процессу нужны права на запись в набор семафоров.

SETVAL
    Устанавливает значение semval равным arg.val для semnum-го семафора набора, изменяя также поле sem_ctime в структуре semid_ds, связанной с этим набором. Записи undo очищаются для изменённых семафоров во всех процессах. Если изменения значений семафоров приводят к отмене блокировки в вызове semop(2) других процессов, то эти процессы пробуждаются. Аргумент semnum игнорируется. Вызывающему процессу нужны права на запись в набор семафоров.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При ошибке semctl() возвращает -1, а переменной errno присваивается номер ошибки. При успешном выполнении системный вызов возвращает положительное значение, зависящее от cmd:

GETNCNT
    значение semncnt.

GETPID
    значение sempid.

GETVAL
    значение semval.

GETZCNT
    значение semzcnt.

IPC_INFO
    самое большое значение индекса, использованного в записи внутреннего массива ядра, содержащего информацию о всех наборах семафоров (эта информация может использоваться в повторяющихся операциях SEM_STAT для получения информации о всех наборах семафоров в системе).

SEM_INFO
    как для IPC_INFO.

SEM_STAT
    идентификатор набора семафоров, индекс которого указан в semid.

Для всех остальных значений cmd возвращается 0.

ОШИБКИ
При ошибке errno присваиваются следующие значения:

EACCES
    Аргумент cmd равен GETALL, GETPID, GETVAL, GETNCNT, GETZCNT, IPC_STAT, SEM_STAT, SETALL или SETVAL и вызывающий процесс не имеет достаточно прав на набор семафоров и не имеет мандата CAP_IPC_OWNER в пространстве имён пользователя, который управляет его пространством имён IPC.

EFAULT
    Адрес, указанный в arg.buf или arg.array, недоступен.

EIDRM
    Набор семафоров был удалён.

EINVAL
    Неверное значение cmd или semid. Или: при операции SEM_STAT значение индекса, указанное в semid, ссылается на место в массиве, которое в данные момент не используется.

EPERM
    Аргумент cmd имеет значение IPC_SET или IPC_RMID, но эффективный идентификатор пользователя вызывающего процесса не совпадает с ID создателя (указанного в sem_perm.cuid) или с ID владельца (указанного в sem_perm.uid) набора семафоров, и процесс не имеет мандата CAP_SYS_ADMIN.

ERANGE
    Аргумент cmd имеет значение SETALL или SETVAL и значение, присваиваемое semval (для какого-то семафора в наборе), меньше нуля или больше, чем ограничение реализации SEMVMX.

СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4. В POSIX.1 указано, что поле sem_nsems структуры semid_ds имеет тип unsigned short, и это так на в большинстве других систем. Это было и в Linux 2.2 и более ранних версиях, но начиная с Linux 2.4 это поле имеет тип unsigned long.

ЗАМЕЧАНИЯ
Включение файлов <sys/types.h> и <sys/ipc.h> не требуется в Linux или любых версий POSIX. Однако, некоторые старые реализации требуют включения данных заголовочных файлов, и это также требуется по SVID. В приложениях, которые нужно перенести на такие старые системы, может потребоваться включить данных заголовочные файлы. Операции IPC_INFO, SEM_STAT и SEM_INFO используются программой ipcs(1) для получения информации о выделенных ресурсах. В будущем для этого может быть задействован интерфейс файловой системы /proc.

В Linux 2.2 различные поля struct semid_ds имели тип short. В Linux 2.4 тип был изменён на long. Для задействования преимуществ этого изменения необходима перекомпиляция программы с glibc-2.1.91 или более поздней версией (ядро различает старые и новые вызовы по флагу IPC_64 в аргументе cmd).

В некоторых ранних версиях glibc объединение semun определялось в <sys/sem.h>, но в POSIX.1 требовалось, чтобы это объединение определял вызывающий. В версиях glibc, в которых это объединение не определено, в <sys/sem.h> определён макрос _SEM_SEMUN_UNDEFINED.

На работу наборов семафоров и вызова semctl() влияет системное ограничение:

SEMVMX
    Максимальное значение semval: зависит от реализации (32767).

Для лучшей переносимости программ желательно всегда вызывать semctl() c четырьмя аргументам.

  Значение sempid
В POSIX.1 значение sempid определено как «ID процесса последней операции» над семафором, и явно отмечено, что это значение устанавливается успешным вызовом semop(2), подразумевая, что больше никто не изменяет sempid. Одни реализации следуют требованиям, указанным в POSIX.1, а другие нет (вина здесь, вероятно, лежит на POSIX.1, так как ему не удастся охватить поведение всех существующих реализаций). Также, разные реализации обновляют sempid другими операциями, обновляющими значение семафора: SETVAL и SETALL, а также изменение семафора, выполняемое при завершении процесса как следствие использования флага SEM_UNDO (смотрите semop(2)). Linux также обновляет sempid при операциях SETVAL и регулировки семафора. Однако, непоследовательно, ранние версии Linux по 4.5 включительно не обновляли sempid при операциях SETALL. Это было исправлено в Linux 4.6.

СМОТРИТЕ ТАКЖЕ
ipc(2), semget(2), semop(2), capabilities(7), sem_overview(7), svipc(7)