Главная » 2017 » Ноябрь » 21 » man 2 semop
01:45
man 2 semop

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


semop, semtimedop - операции с семафорами System V



ОБЗОР


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, size_t nsops);

int semtimedop(int semid, struct sembuf *sops, size_t nsops,
const struct timespec *timeout);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

semtimedop(): _GNU_SOURCE



ОПИСАНИЕ


С каждым семафором в наборе семафоров System V связаны следующие значения:

unsigned short semval; /* значение семафора */
unsigned short semzcnt; /* # ожидает ноль */
unsigned short semncnt; /* # ожидает увеличения */
pid_t sempid; /* PID процесса, выполнявшегося последним

Вызов semop() производит операции над выбранными семафорами из набора семафоров
semid. Каждый из элементов nsops в массиве, указанном в sops является структурой,
которой задаётся операция, выполняемая над отдельным семафором. Элементы этой
структуры имеют тип struct sembuf, который содержит поля:

unsigned short sem_num; /* номер семафора */
short sem_op; /* операция над семафором */
short sem_flg; /* флаги операции */

Флаги в sem_flg могут иметь значения IPC_NOWAIT и SEM_UNDO. Если указан флаг
SEM_UNDO, то при завершении процесса будет выполнена откат операции.

Набор операций из sops выполняется в порядке появления в массиве и является
атомарным, то есть выполняются или все операции, или ни одной. Поведение
системного вызова при обнаружении невозможности немедленного выполнения операций
зависит от наличия флага IPC_NOWAIT в полях sem_flg отдельных операций, как это
описано далее.

Каждая операция выполняется над sem_num-тым семафором из набора, где первый
семафор имеет номер 0. Есть три типа операций, различающихся значением sem_op.

Если значение sem_op — положительное целое число, то оно добавляется к значению
семафора (semval). Если для операции стоит флаг SEM_UNDO, то система вычитает
значение sem_op из значения регулировки (semadj) семафора. Эта операция
выполняется всегда и не переводит нить в режим ожидания. Вызывающий процесс должен
иметь права на изменение набора семафоров.

Если значение sem_op равно нулю, то процесс должен иметь права на чтение набора
семафоров. Эта операция «ожидания нуля»: если semval равно нулю, то операция может
выполнится сразу. Иначе, если в поле семафора sem_flg указан флаг IPC_NOWAIT, то
semop() завершается с ошибкой и errno присваивается значение EAGAIN (и ни одна
операция из sops не выполняется). Или же semzcnt (счётчик нитей, ожидающих пока
завершается с ошибкой, а errno присваивается значение EINTR.

Если значение sem_op меньше нуля, то процесс должен иметь права на изменение
набора семафоров. Если значение semval больше или равно абсолютному значению
sem_op, то операция может выполнятся сразу: абсолютное значение sem_op вычитается
из semval, и, если для этой операции установлен флаг SEM_UNDO, система добавляет
абсолютное значение sem_op к значению регулировки (semadj) семафора. Если
абсолютное значение sem_op больше semval, и в sem_flg указан IPC_NOWAIT, то
semop() завершается с ошибкой, а errno присваивается значение EAGAIN (и ни одна
операция из sops не выполняется). Иначе semncnt (счётчик нитей, ожидающих
увеличения значения семафора) увеличивается на единицу, а нить переходит в режим
ожидания пока не случится одно из:

· semval становится больше или равно абсолютному значению sem_op: операция
продолжается как описано выше.

· Набор семафоров удалится из системы: semop() завершается с ошибкой, а errno
присваивается значение EIDRM.

· Вызывающая нить получит сигнал: значение semncnt уменьшается и semop()
завершается с ошибкой, а errno присваивается значение EINTR.

При успешном выполнении значение sempid для каждого семафора, указанного в
массиве, на который указывает sops, устанавливается равным идентификатору
вызывающего процесса. Также sem_otime присваивается значение текущего времени.

semtimedop()
Системный вызов semtimedop() ведёт себя идентично semop(), за исключением того,
что в случаях, когда вызывающая нить будет спать, длительность этого сна
ограничена количеством времени, определяемым структурой timespec, чей адрес
передаётся в аргументе timeout. Данное значение интервала будет округлено до
точности системных часов, а из-за задержки при планировании в ядре блокирующий
интервал будет немного больше. Если достигнут указанный лимит времени, то
semtimedop() завершится с ошибкой, а errno устанавливается в EAGAIN (и ни одна из
операций в sops не выполняется). Если значение аргумента timeout равно NULL, то
semtimedop() ведёт себя аналогично semop().

Заметим, что если semtimedop() прерывается сигналом, то вызов завершается с
ошибкой EINTR, а содержимое timeout не изменяется.



ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ


При успешном выполнении semop() и semtimedop() возвращается 0; иначе возвращается
-1, а переменной errno присваивается номер ошибки.



ОШИБКИ


В случае возникновения ошибки errno может принимать следующие значения:

E2BIG Значение аргумента nsops больше SEMOPM, максимального количества операций,
которое может выполнить один системный вызов.

EACCES Вызывающий процесс не имеет прав, требуемых для выполнения указанных
операций над семафорами, и не имеет мандата CAP_IPC_OWNER, который
управляет его пространством имён IPC.

EAGAIN Операция не может быть выполнена немедленно и, либо IPC_NOWAIT был указан в
sem_flg, либо истекло время лимита, определённое в timeout.

EINVAL Набор семафоров не существует, или значение semid меньше нуля, или nsops
имеет не положительное значение.

ENOMEM Для некоторых операций в поле sem_flg задан флаг SEM_UNDO, и система не
может выделить достаточно памяти для структуры откатов.

ERANGE Для некоторых операций sem_op+semval больше чем SEMVMX, максимального
значения semval (зависит от реализации).



ВЕРСИИ


Вызов semtimedop() впервые появился в Linux 2.5.52, а затем был перенесён в ядро
версии 2.4.22. Поддержка в glibc для semtimedop() впервые появилась в версии
2.3.3.



СООТВЕТСТВИЕ СТАНДАРТАМ


POSIX.1-2001, POSIX.1-2008, SVr4.



ЗАМЕЧАНИЯ


Включение файлов <sys/types.h> и <sys/ipc.h> не требуется в Linux или любых версий
POSIX. Однако, некоторые старые реализации требуют включения данных заголовочных
файлов, и это также требуется по SVID. В приложениях, которые нужно перенести на
такие старые системы, может потребоваться включить данных заголовочные файлы.

Структуры процесса sem_undo не наследуются потомками, созданными через fork(2), но
они наследуются при выполнении системного вызова execve(2).

Вызов semop() никогда автоматически не перезапускается после прерывания
обработчиком сигнала, независимо от установки флага SA_RESTART при настройке
обработчика сигнала.

Значение регулировки семафора (semadj) есть в каждом процессе. Это целое число —
простой (отрицательный) счётчик всех операций над семафорами, для которых
установлен флаг SEM_UNDO. В каждом процессе есть список значений semadj — по
одному значению на каждый семафор, у которых установлен флаг SEM_UNDO. При
завершении процесса. каждое из значений semadj семафора добавляется к
соответствующему семафору, достигая таким образом эффекта выполнения операций
процесса над семафорами (но смотрите раздел ДЕФЕКТЫ). Когда значение семафора явно
устанавливается с помощью запроса SETVAL или SETALL вызовом semctl(2), то
соответствующие значения semadj во всех процессах очищаются. Флаг CLONE_SYSVSEM
clone(2) позволяет нескольким процессам совместно использовать список semadj;
подробности смотрите в clone(2).

Значения semval, sempid, semzcnt и semnct семафора можно получить с помощью
соответствующих вызовов semctl(2).

Ограничения семафоров
Ниже приведены лимиты ресурсов наборов семафоров, влияющие на вызов semop():

SEMOPM Максимальное количество операций, разрешённых для одного вызова semop(). До
версии Linux 3.19, значение по умолчанию было 3. Начиная с Linux 3.19,
значение по умолчанию равно 500. В Linux это ограничение можно прочитать и
изменить через третье поле /proc/sys/kernel/sem. Замечание: это ограничение
не должно превышать 1000, так как есть риск, что semop(2) завершится с
ошибкой из-за фрагментации памяти ядра при выделении памяти при копировании
массива sops.

SEMVMX Максимально допустимое значение semval: зависит от реализации (32767).
SEM_UNDO. Это повышает сложность: если одно (или более) этих изменений семафоров
привело бы в результате к попытке уменьшить значение семафора ниже нуля, что
должно быть сделано в реализации? Одним из возможных решений была бы блокировка до
тех пор, пока не выполнятся все изменения семафоров. Однако это нежелательно, так
как это привело бы к блокированию процесса на неопределённый срок при его
завершении. Другим вариантом является игнорирование сразу всех изменений семафоров
(в некоторой степени, аналогично завершению с ошибкой, когда для операции с
семафором указан IPC_NOWAIT). В Linux используется третий вариант: уменьшение
значения семафора до тех пор, пока это возможно ( т.е. до нуля) и разрешение
немедленного завершения процесса.

В ядрах 2.6.x, где x <= 10, есть дефект, из-за которого при определённых
обстоятельствах нить, ожидающая установления значения семафора равного нулю, не
будет разбужен когда значение станет равным нулю. Этот дефект исправлен в ядре
2.6.11.



ПРИМЕР


В следующем фрагменте кода используется semop() для атомарного ожидания момента,
когда значение семафора 0 станет равным нулю и последующего увеличения значения
семафора на единицу.

struct sembuf sops[2];
int semid;

/* код для установки semid не показан */

sops[0].sem_num = 0; /* применяем к семафору 0 */
sops[0].sem_op = 0; /* ждём значения, равного 0 */
sops[0].sem_flg = 0;

sops[1].sem_num = 0; /* применяем к семафору 0 */
sops[1].sem_op = 1; /* увеличиваем значение на 1 */
sops[1].sem_flg = 0;

if (semop(semid, sops, 2) == -1) {
perror("semop");
exit(EXIT_FAILURE);
}



СМОТРИТЕ ТАКЖЕ


clone(2), semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7),
svipc(7), time(7)



Категория: (2) Системные вызовы ядра (функции языка Си) | Просмотров: 27 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar