table of contents
FUTEX(2) | Руководство программиста Linux | FUTEX(2) |
ИМЯ¶
futex - системный вызов быстрых блокировок из пространства пользователя
ОБЗОР¶
#include <linux/futex.h> #include <sys/time.h> int futex(int *uaddr, int op, int val, const struct timespec *timeout,
int *uaddr2, int val3);
ОПИСАНИЕ¶
Системный вызов futex() предоставляет программам метод для ожидания изменения значения по указанному адресу памяти и метод для пробуждения всех ожидающих на определённом адресе (хотя адреса для одного и того же участка памяти в разных процессах могут быть не идентичны, ядро отображает их внутренне так, что один участок памяти, отображённый в разные места, будет соответствовать одним вызовам futex()). Обычно этот системный вызов используется для реализации блокировок в общей памяти, как это описано в futex(7).
Когда операция futex(7) оканчивается без завершения спора в пространстве пользователя, должен быть сделан вызов к ядру для выноса решения. Решением может быть как усыпление вызывающего процесса, так и наоборот — пробуждение ожидающего процесса.
Вызывающие эту функцию должны твердо придерживаться семантики, описанной в futex(7). Так как эта семантика приводит к созданию непереносимых инструкций ассемблера, то фактически это приведёт к тому, что большинство использующих их пользователей станут авторами библиотек, а не создателями программ.
Аргумент uaddr должен указывать на выровненное целое, хранящее счетчик. Тип операции для исполнения указывает в параметре op, а её значение в val.
В данный момент определены пять операций:
- FUTEX_WAIT
- Эта
операция
атомарно
проверяет,
что по
адресу uaddr futex
все ещё
содержится
значение
val, и
засыпает в
ожидании
FUTEX_WAKE на этом
адресе futex.
Если
аргумент
timeout не равен
NULL, то его
содержимое
описывает
максимальную
задержку
ожидания,
иначе это
время
бесконечно.
Аргументы
uaddr2 и val3
игнорируются.
По futex(7) этот вызов исполняется, если уменьшение счетчика даёт отрицательное значение (указывая на наличие спора), или будет спать, пока другой процесс не освободит futex и не выполнит операцию FUTEX_WAKE.
- FUTEX_WAKE
- Эта
операция
пробуждает
не больше
val
процессов,
ожидающих
на этом
адресе futex (т.е.
внутри FUTEX_WAIT).
Аргументы
timeout, uaddr2 и val3
игнорируются.
По futex(7) этот вызов исполняется, если увеличение счетчика показало, что есть ожидающие, как только значение futex стало равным 1 (показывает, что есть доступные ожидающие).
- FUTEX_FD (существует до Linux 2.6.25 включительно)
- Для
поддержки
асинхронных
пробуждений
эта
операция
связывает
дескриптор
файла с futex.
Если
другой
процесс
выполняет
FUTEX_WAKE, то
процесс
будет
получать
номер
сигнала,
переданный
в val.
Вызывающий
процесс
должен
закрыть
возвращаемый
дескриптор
файла
после
использования.
Аргументы
timeout, uaddr2 и val3
игнорируются.
Для предотвращения состязательности, вызывающий после возврата при FUTEX_FD должен проверять, не был ли futex увеличен.
Так как по своей природе операция FUTEX_FD приводит к состязательности, она была удалена из Linux, начиная с версии 2.6.26.
- FUTEX_REQUEUE (начиная с Linux 2.5.70)
- Эта операция была введена для того, чтобы избежать эффекта "громыхающего стада (thundering herd)", когда используется FUTEX_WAKE и все процессы просыпаются, чтобы захватить другой futex. Этот вызов пробуждает до val процессов и повторно ставит в очередь остальных ожидающих futex по адресу uaddr2. Аргументы timeout и val3 игнорируются.
- FUTEX_CMP_REQUEUE (начиная с Linux 2.6.7)
- Чтобы избежать состязательности при FUTEX_REQUEUE, была введена FUTEX_CMP_REQUEUE. Она похожа на FUTEX_REQUEUE, но сначала проверяет, что расположенное по адресу uaddr значение всё ещё равно val3. Если нет, то операция завершается с ошибкой EAGAIN. Аргумент timeout игнорируется.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
В зависимости от типа используемой операции при успешном выполнении возвращаемое значение может иметь разный смысл.
- FUTEX_WAIT
- Если процесс пробуждается по FUTEX_WAKE, то возвращается 0. В случае истечения срока таймера возвращается с ошибкой ETIMEDOUT. Если futex не был эквивалентен ожидаемому значению, то операция возвращается с ошибкой EWOULDBLOCK. При сигналах (см. signal(7)) или других случайных пробуждениях операция FUTEX_WAIT завершается с ошибкой EINTR.
- FUTEX_WAKE
- Возвращается количество разбуженных процессов.
- FUTEX_FD
- Возвращается новый файловый дескриптор, связанный с futex.
- FUTEX_REQUEUE
- Возвращается количество разбуженных процессов.
- FUTEX_CMP_REQUEUE
- Возвращается количество разбуженных процессов.
В случае ошибки все операции возвращают -1, а errno устанавливается в соответствующее значение.
ОШИБКИ¶
- EACCES
- Нет доступа на чтение памяти futex.
- EAGAIN
- При FUTEX_CMP_REQUEUE обнаружено не то значение futex. (Вероятно, это указывает на состязательность; используйте теперь безопасный FUTEX_WAKE.)
- EFAULT
- Ошибка при получении информации timeout из пользовательского пространства.
- EINVAL
- Неопределённая операция или ошибка выравнивания страницы.
- ENFILE
- Достигнуто максимальное количество открытых файлов в системе.
- ENOSYS
- В op задана неверная операция.
ВЕРСИИ¶
Начальная поддержка futex была встроена в Linux 2.5.7, но с другой семантикой, отличающейся от описанной выше. Семантика системного вызова с четырьмя аргументами, описанная в этой странице, появилась в Linux 2.5.40. В Linux 2.5.70 был добавлен ещё один аргумент. В Linux 2.6.7 был добавлен шестой аргумент — захламлено, особенно для архитектуре s390.
СООТВЕТСТВИЕ СТАНДАРТАМ¶
Данный вызов есть только в Linux.
ЗАМЕЧАНИЯ¶
Еще раз повторим: в чистом виде futex не являются лёгкой в использовании абстракцией для конечных пользователей (в glibc нет обёрточных функций для данного системного вызова). Реализующие их программисты должны иметь хороший запас знаний об ассемблере и уметь читать исходный код библиотеки futex для пользовательского пространства, указанной далее.
СМОТРИТЕ ТАКЖЕ¶
Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux
(доклад на
симпозиума
по Linux в
Оттаве в 2002
году),
доступно
как
http://kernel.org/doc/ols/2002/ols2002-pages-479-495.pdf
Пример
библиотеки
futex, futex-*.tar.bz2,
доступен
на
ftp://ftp.nl.kernel.org/pub/linux/kernel/people/rusty/.
2010-08-29 | Linux |