table of contents
semop(2) | System Calls Manual | semop(2) |
ИМЯ¶
semop, semtimedop - операции с семафорами System V
LIBRARY¶
Standard C library (libc, -lc)
СИНТАКСИС¶
#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 *_Nullable timeout);
semtimedop():
_GNU_SOURCE
ОПИСАНИЕ¶
С каждым семафором в наборе семафоров System V связаны следующие значения:
unsigned short semval; /* semaphore value */ unsigned short semzcnt; /* # waiting for zero */ unsigned short semncnt; /* # waiting for increase */ pid_t sempid; /* PID of process that last
modified the semaphore value */
Вызов 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.
If sem_op is a positive integer, the operation adds this value to the semaphore value (semval). Furthermore, if SEM_UNDO is specified for this operation, the system subtracts the value sem_op from the semaphore adjustment (semadj) value for this semaphore. This operation can always proceed—it never forces a thread to wait. The calling process must have alter permission on the semaphore set.
Если значение sem_op равно нулю, то процесс должен иметь права на чтение набора семафоров. Эта операция «ожидания нуля»: если semval равно нулю, то операция может выполнится сразу. Иначе, если в поле семафора sem_flg указан флаг IPC_NOWAIT, то semop() завершается с ошибкой и errno присваивается значение EAGAIN (и ни одна операция из sops не выполняется). Или же semzcnt (счётчик нитей, ожидающих пока значение семафора не сравнялось с нулём) увеличивается на единицу, а нить переходит в режим ожидания пока не случится одно из:
- •
- Значение semval станет равным 0, тогда значение semzcnt уменьшается.
- •
- Набор семафоров удалится: semop() завершается с ошибкой, а errno присваивается значение EIDRM.
- •
- Вызывающая нить получит сигнал: значение semncnt уменьшается и semop() завершается с ошибкой, а 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 не изменяется.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
On success, semop() and semtimedop() return 0. On failure, they return -1, and set errno to indicate the error.
ОШИБКИ¶
- E2BIG
- Значение аргумента nsops больше SEMOPM, максимального количества операций, которое может выполнить один системный вызов.
- EACCES
- Вызывающий процесс не имеет прав, требуемых для выполнения указанных операций над семафорами, и не имеет мандата CAP_IPC_OWNER, который управляет его пространством имён IPC.
- EAGAIN
- Операция не может быть выполнена немедленно и, либо IPC_NOWAIT был указан в sem_flg, либо истекло время лимита, определённое в timeout.
- EFAULT
- Адрес, указанный в sops или timeout, не доступен.
- EFBIG
- Для некоторых операций значение sem_num меньше нуля или больше или равно количеству семафоров в наборе.
- EIDRM
- Набор семафоров был удалён.
- EINTR
- Нить, находясь в режиме ожидания, получила сигнал; смотрите signal(7).
- EINVAL
- Набор семафоров не существует, или значение semid меньше нуля, или nsops имеет не положительное значение.
- ENOMEM
- Для некоторых операций в поле sem_flg задан флаг SEM_UNDO, и система не может выделить достаточно памяти для структуры откатов.
- ERANGE
- Для некоторых операций sem_op+semval больше чем SEMVMX, максимального значения semval (зависит от реализации).
СТАНДАРТЫ¶
POSIX.1-2008.
ВЕРСИИ¶
Linux 2.5.52 (backported into Linux 2.4.22), glibc 2.3.3. POSIX.1-2001, SVr4.
ПРИМЕЧАНИЯ¶
Структуры процесса sem_undo не наследуются потомками, созданными через fork(2), но они наследуются при выполнении системного вызова execve(2).
Вызов semop() никогда автоматически не перезапускается после прерывания обработчиком сигнала, независимо от установки флага SA_RESTART при настройке обработчика сигнала.
A semaphore adjustment (semadj) value is a per-process, per-semaphore integer that is the negated sum of all operations performed on a semaphore specifying the SEM_UNDO flag. Each process has a list of semadj values—one value for each semaphore on which it has operated using SEM_UNDO. When a process terminates, each of its per-semaphore semadj values is added to the corresponding semaphore, thus undoing the effect of that process's operations on the semaphore (but see BUGS below). When a semaphore's value is directly set using the SETVAL or SETALL request to semctl(2), the corresponding semadj values in all processes are cleared. The clone(2) CLONE_SYSVSEM flag allows more than one process to share a semadj list; see clone(2) for details.
Значения 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).
Реализация не накладывает существенных ограничений на максимальное значение (SEMAEM), на которое можно изменить значение семафора при выходе, максимальное количество системных структур откатываемых операций (SEMMNU) и максимальное количество элементов отката системных параметров на процесс.
ОШИБКИ¶
При завершении процесса его набор связанных структур semadj используется для отката выполненных действий над семафорами, для которых был установлен флаг SEM_UNDO. Это повышает сложность: если одно (или более) этих изменений семафоров привело бы в результате к попытке уменьшить значение семафора ниже нуля, что должно быть сделано в реализации? Одним из возможных решений была бы блокировка до тех пор, пока не выполнятся все изменения семафоров. Однако это нежелательно, так как это привело бы к блокированию процесса на неопределённый срок при его завершении. Другим вариантом является игнорирование сразу всех изменений семафоров (в некоторой степени, аналогично завершению с ошибкой, когда для операции с семафором указан IPC_NOWAIT). В Linux используется третий вариант: уменьшение значения семафора до тех пор, пока это возможно ( т.е. до нуля) и разрешение немедленного завершения процесса.
In Linux 2.6.x, x <= 10, there is a bug that in some circumstances prevents a thread that is waiting for a semaphore value to become zero from being woken up when the value does actually become zero. This bug is fixed in Linux 2.6.11.
ПРИМЕРЫ¶
В следующем фрагменте кода используется semop() для атомарного ожидания момента, когда значение семафора 0 станет равным нулю и последующего увеличения значения семафора на единицу.
struct sembuf sops[2]; int semid; /* Code to set semid omitted */ sops[0].sem_num = 0; /* Operate on semaphore 0 */ sops[0].sem_op = 0; /* Wait for value to equal 0 */ sops[0].sem_flg = 0; sops[1].sem_num = 0; /* Operate on semaphore 0 */ sops[1].sem_op = 1; /* Increment value by one */ sops[1].sem_flg = 0; if (semop(semid, sops, 2) == -1) {
perror("semop");
exit(EXIT_FAILURE); }
A further example of the use of semop() can be found in shmop(2).
СМОТРИТЕ ТАКЖЕ¶
clone(2), semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7), sysvipc(7), time(7)
ПЕРЕВОД¶
Русский перевод этой страницы руководства разработал Alexander Golubev <fatzer2@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Hotellook, Nikita <zxcvbnm3230@mail.ru>, Spiros Georgaras <sng@hellug.gr>, Vladislav <ivladislavefimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику по его адресу электронной почты или по адресу списка рассылки русских переводчиков.
2 мая 2024 г. | Linux man-pages (unreleased) |