| SEMCTL(2) | Руководство программиста Linux | 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:
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) */
};
    
  При ошибке semctl() возвращает -1, а переменной errno присваивается номер ошибки.
При успешном выполнении системный вызов возвращает положительное значение, зависящее от cmd:
Для всех остальных значений cmd возвращается 0.
При ошибке errno присваиваются следующие значения:
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() влияет системное ограничение:
Для лучшей переносимости программ желательно всегда вызывать semctl() c четырьмя аргументам.
В 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)
| 2019-03-06 | Linux |