Scroll to navigation

FCNTL(2) Руководство программиста Linux FCNTL(2)

ИМЯ

fcntl - работа с файловым дескриптором

ОБЗОР

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

ОПИСАНИЕ

fcntl() позволяет выполнять различные команды над открытым файловым дескриптором fd. Команда определяется содержимым аргумента cmd.

fcntl() может принимать необязательный третий аргумент. Необходимость его указания зависит от значения, указанного в cmd. Тип необходимого аргумента указан в скобках после каждого имени значения cmd (в большинстве случаев требуется тип int, и мы определяем аргумент с помощью имени arg), или указывается void, если аргумент не нужен.

Создание дубликата файлового дескриптора

Найти наименьший доступный номер файлового дескриптора, который больше или равен arg, и сделать из него копию дескриптора fd. Отличие от dup2(2) в том, что там дескриптор задаётся явно.
При успешном выполнении этой команды, возвращается новый файловый дескриптор.
Дополнительную информацию смотрите в dup(2).
Как F_DUPFD, но на новом дескрипторе дополнительно устанавливается флаг закрытия-при-exec. Установка этого флага позволяет программам не делать дополнительный вызов fcntl() с командой F_SETFD для установки флага FD_CLOEXEC. О том, зачем нужен этот флаг, смотрите описание O_CLOEXEC в open(2).

Флаги файлового дескриптора

Следующие команды работают с флагами, связанными с файловым дескриптором. В настоящее время определён только один флаг: FD_CLOEXEC, флаг закрытия-при-exec. Если бит FD_CLOEXEC равен 0, то файловый дескриптор останется открытым при вызове execve(2), иначе он будет закрыт.

Прочитать флаги файлового дескриптора; arg игнорируется.
Установить флаги файлового дескриптора согласно значению, указанному в аргументе arg.

Флаги состояния файла

Каждое описание открытого файла имеет несколько связанных с ним флагов состояния, которые инициализируются вызовом open(2) и, возможно, изменяются затем вызовом fcntl(). Эти флаги совместно используются копиями файловых дескрипторов (сделанными с помощью dup(2), fcntl(F_DUPFD), fork(2) и т.д.), которые указывают на одно описание открытого файла.

Эти флаги состояния и их смысл описаны в open(2).

Получить права доступа к файлу и флаги состояния файла; arg игнорируется.
Установить флаги состояния файла согласно значению, указанному в аргументе arg. Режим доступа к файлу (O_RDONLY, O_WRONLY, O_RDWR) и флаги создания файла (т.е. O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) в arg игнорируются. В Linux эта команда может изменять только флаги O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME и O_NONBLOCK.

Консультативная (advisory) блокировка

Команды F_GETLK, F_SETLK и F_SETLKW используются для установки, снятия и тестирования существования блокировок записей (также известных как блокировки сегмента или области файла). Третий аргумент, lock, является указателем на структуру, которая имеет, по крайней мере, следующие поля (в произвольном порядке):

struct flock {

...
short l_type; /* Тип блокировки: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* Как интерпретировать l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Начальное смещение для блокировки */
off_t l_len; /* Количество блокируемых байт */
pid_t l_pid; /* PID процесса, блокирующего нашу блокировку
(только для F_GETLK) */
... };

Поля l_whence, l_start и l_len этой структуры задают диапазон байт, который мы хотим заблокировать. Могут блокироваться байты за концом файла, но не перед началом файла.

l_start — это начальное смещение для блокировки, которое интерпретируется как начало файла (если значение l_whence равно SEEK_SET); как текущая позиция в файле (если значение l_whence равно SEEK_CUR); как конец файла (если значение l_whence равно SEEK_END). В последних двух случаях, l_start может иметь отрицательное значение, предоставляя смещение, которого не может указать до начала файла.

В l_len задаётся количество байт, которые нужно заблокировать. Если l_len положительно, то диапазон блокировки начинается со l_start и кончается l_start+l_len-1 включительно. Если в l_len указан 0, то блокируются все байты начиная с места, указанного l_whence и l_start и до конца файла, независимо от величины файла.

POSIX.1-2001 позволяет (но не требует) реализации поддерживать отрицательное значение l_len; если l_len отрицательно, то интервал, описываемый lock, имеет размер l_start+l_len до l_start-1 включительно. Это поддерживается в Linux начиная с ядер версии 2.4.21 и 2.5.49.

Поле l_type может быть использовано для указания типа блокировки файла: чтение (F_RDLCK) или запись (F_WRLCK). Любое количество процессов могут удерживать блокировку на чтение (общая блокировка) области файла, но только один процесс может удерживать блокировку на запись (эксклюзивная блокировка). Эксклюзивная блокировка исключает все другие блокировки, как общие так и эксклюзивные. Один процесс может удерживать только один тип блокировки области файла; если происходит новая блокировка уже заблокированной области, то существующая блокировка преобразуется в новый тип блокировки. (Такие преобразования могут привести к разбиению, уменьшению или срастанию с существующей блокировкой, если диапазон байт, заданный для новой блокировки, неточно совпадает с диапазоном существующей блокировки.)

Установить блокировку (когда l_type равен F_RDLCK или F_WRLCK) или снять блокировку (когда l_type равен F_UNLCK) байтов, указанных полями l_whence, l_start и l_len структуры lock. Если конфликтующая блокировка удерживается другим процессом, то данный вызов вернёт -1 и установит значение errno в EACCES или EAGAIN.
Как F_SETLK, но если конфликтующая блокировка удерживается на файле, то выполняется ожидание снятия этой блокировки. Если во время ожидания поступил сигнал, то данный вызов прерывается и (после возврата из обработчика сигнала) из него происходит немедленный возврат (возвращается значение -1 и errno устанавливается в EINTR; см. signal(7)).
При входе в этот вызов, lock описывает блокировку, которую мы хотели бы установить на файл. Если такая блокировка не может быть установлена, fcntl() не устанавливает её, но возвращает F_UNLCK в поле l_type структуры lock и оставляет другие поля структуры неизменёнными. Если одна или более несовместимых блокировок мешают установке этой блокировки, то fcntl() возвращает подробности об одной из этих блокировок в полях l_type, l_whence, l_start и l_len структуры lock и присваивает l_pid значение PID того процесса, который удерживает блокировку.

Для того, чтобы установить блокировку на чтение, fd должен быть открыт на чтение. Для того, чтобы установить блокировку на запись, fd должен быть открыт на запись. Чтобы установить оба типа блокировки, дескриптор должен быть открыт на запись и на чтение.

Также как и при снятии блокировки через явное указание F_UNLCK, блокировка автоматически снимается, когда процесс завершается или если он закрывает любой файловый дескриптор, ссылающийся на файл, на котором удерживается блокировка. Это плохо: это означает, что процесс может потерять блокировки на файлах типа /etc/passwd или /etc/mtab, когда по какой-либо причине библиотечная функция решает их открыть, прочитать и закрыть.

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

Поскольку буферизация выполняется через библиотеку stdio(3), использование блокировок с функциями в этом пакете нужно избегать; вместо этих функций используйте read(2) и write(2).

Обязательная (mandatory) блокировка

(Не POSIX) Описываемые блокировки могут быть или консультативные, или обязательные; по умолчанию используются консультативные.

Консультативные блокировки не обязательны к выполнению и полезны только в сотрудничающих процессах.

Обязательные блокировки влияют на все процессы. Если процесс пытается получить несовместимый доступ (например, read(2) и write(2)) к области файла, на которую установлена несовместимая обязательная блокировка, то результат зависит от состояния флага O_NONBLOCK в описании этого открытого файла. Если флаг O_NONBLOCK не установлен, то системный вызов блокируется до удаления блокировки или преобразуется в режим, который совместим с доступом. Если флаг O_NONBLOCK установлен, то системный вызов завершается с ошибкой EAGAIN.

Чтобы использовать обязательные блокировки, обязательное блокирование должно быть включено в файловой системе, содержащей файл, и на самом файле. Обязательное блокирование включается в файловой системе с помощью параметра "-o mand" команды mount(8) или с помощью флага MS_MANDLOCK в mount(2). Обязательное блокирование включается на файле посредством отключения права исполнения группе и установкой бита set-group-ID (см. chmod(1) и chmod(2)).

Реализация обязательного блокирования в Linux ненадёжна. Смотрите раздел ДЕФЕКТЫ далее.

Управление сигналами

Для управления сигналами доступности ввода/вывода используются команды F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG и F_SETSIG:

Получить (как результат работы функции) идентификатор процесса или группы процесса, который в текущий момент принимает сигналы SIGIO и SIGURG для событий на файловом дескрипторе fd. Идентификатор процесса возвращается как положительное число; идентификатор группы возвращается как отрицательное число (но см. раздел ДЕФЕКТЫ далее). Аргумент arg игнорируется.
Установить идентификатор процесса или группы процесса, которые будут принимать сигналы SIGIO и SIGURG для событий на файловом дескрипторе fd; идентификатор задаётся в аргументе arg. Идентификатор процесса задаётся положительным числом, идентификатор группы задаётся отрицательным числом. Обычно, вызывающий процесс указывает самого себя в качестве принимающего (то есть в arg указывается результат getpid(2)).

Если вы установили на файловый дескриптор флаг состояния O_ASYNC с помощью команды F_SETFL в fcntl(), то сигнал SIGIO посылается всякий раз, когда для данного файлового дескриптора становится возможным ввод или вывод. F_SETSIG можно использовать для включения доставки сигнала, отличного от SIGIO. Если такая проверка разрешения завершится неудачно, то сигнал просто отбрасывается.

Отправка сигнала процессу-владельцу (группе), указанному с помощью F_SETOWN — такая же проверка прав, как описанная для kill(2), где посылающий процесс один из тех, который может пользоваться F_SETOWN (но см. раздел ДЕФЕКТЫ далее).

Если файловый дескриптор fd указывает на сокет, то по команде F_SETOWN для него также выбирается получатель сигналов SIGURG, которые доставляются, когда на сокет поступают внеполосные данные. (SIGURG посылается во всех ситуациях, когда вызов select(2) говорит, что сокет находится в состоянии "исключительной ситуации".)

Следующее верно для ядер 2.6.x, до 2.6.11 включительно:

Если для F_SETSIG передаётся ненулевое значение в многонитивой процесс, работающий с библиотекой нитей (например, NPTL), которая обеспечивает поддержку групп нитей, то положительное значение, переданное F_SETOWN, имеет другой смысл: вместо указания ID процесса, описывающего весь процесс, она является ID нити, указывающим на определённую нить процесса. Поэтому может понадобиться передать в F_SETOWN результат gettid(2), а не getpid(2), чтобы получить правильный результат при использовании F_SETSIG. (В имеющихся реализациях Linux ID главной нити совпадает с ID процесса. Это означает, что в программе с одной нитью можно использовать любой вызов, gettid(2) или getpid(2), в этом случае.) Однако заметим, что утверждения этого абзаца не применимы к сигналу SIGURG, генерируемому для внеполосных данных сокета: этот сигнал всегда посылается или процессу или группе процессов, в зависимости от значения, указанного для F_SETOWN.
Описанное выше поведение было случайно удалено из Linux 2.6.12, и так и не восстановлено. Начиная с Linux 2.6.32 используйте F_SETOWN_EX при назначении сигналов SIGIO и SIGURG для определённой нити.
Получить настройки владения текущим файловым дескриптором, установленные предыдущей командой F_SETOWN_EX. Информация возвращается в структуре, указанной в arg, которая имеет следующий вид:

struct f_owner_ex {
int type;
pid_t pid; };
Поле type будет равно: F_OWNER_TID, F_OWNER_PID или F_OWNER_PGRP. Значением поля pid будет положительное целое, представляющее ID нити, ID процесса или ID группы процессов. Подробности смотрите в описании F_SETOWN_EX.
Эта команда выполняет задачу, подобную F_SETOWN. Она позволяет вызывающему назначить сигналы доступности ввода-вывода определённой нити, процессу или группе процессов. Вызывающий указывает приёмник сигналов в arg, выражаемый указателем на структуру f_owner_ex. Поле type имеет одно из следующих значений, которое определяет чем считать pid:
Посылать сигнал нити, чей ID (значение, возвращаемое вызовом clone(2) или gettid(2)) указан в pid.
Посылать сигнал процессу, чей ID указан в pid.
Посылать сигнал группе процессов, чей ID указан в pid. (Заметим, что в отличие от F_SETOWN, ID группы процессов здесь задаётся как положительное значение.)
Получить (как результат функции) сигнал, посылаемый, когда становится возможным ввод или вывод. Значение 0 означает сигнал SIGIO. Любое другое значение (включая SIGIO) является другим сигналом, и в этом случае для обработчика сигнала доступна дополнительная информация, если он был установлен с SA_SIGINFO. Аргумент arg игнорируется.
Установить сигнал, который будет посылаться когда станет возможен ввод или вывод, в значение, указанное в arg. Значение 0 означает сигнал по умолчанию SIGIO. Любое другое значение (включая SIGIO) является другим сигналом, и в этом случае, для обработчика сигнала доступна дополнительная информация, если он был установлен с SA_SIGINFO.

В случае использования F_SETSIG с ненулевым значением и установкой SA_SIGINFO для обработчика сигнала (см. sigaction(2)) обработчику передаётся дополнительная информация о событиях ввода/вывода в структуре siginfo_t. Если поле si_code показывает, что источник — SI_SIGIO, то поле si_fd содержит файловый дескриптор, ассоциированный с событием. В противном случае не существует никакого механизма, чтобы сообщить с каким файловым дескриптором связан полученный сигнал, и вы должны использовать обычные механизмы (select(2), poll(2), read(2) с установленным O_NONBLOCK и т.д.), чтобы определить какой файловый дескриптор доступен для ввода/вывода.

При выборе сигнала реального времени (значение >= SIGRTMIN) в очередь может добавляться несколько событий ввода-вывода с одинаковыми номерами сигналов. (Размер очереди зависит от доступной памяти). Дополнительная информация будет доступна как описано выше, если для обработчика сигнала будет установлено SA_SIGINFO.

Заметим, что в Linux есть предел на количество сигналов реального времени, которые могут находиться в очереди процесса (см. getrlimit(2) и signal(7)), и если этот предел достигнут, то ядро изменяет пункт доставки SIGIO, и этот сигнал доставляется всему процессу, а не указанной нити.

Используя эти механизмы, программа может реализовать полностью асинхронный ввод-вывод почти не используя в своей работе select(2) или poll(2).

Использование O_ASYNC, F_GETOWN, F_SETOWN является специфичным для BSD и Linux. Команды F_GETOWN_EX, F_SETOWN_EX, F_GETSIG и F_SETSIG являются специфичными для Linux. POSIX описывает асинхронный ввод-вывод и структуру aio_sigevent, используемую для сходных вещей; она также доступна в Linux как часть библиотеки GNU C (Glibc).

Аренда

Команды F_SETLEASE и F_GETLEASE (в Linux 2.4 и выше) используются, соответственно, для установки новой и получения текущей аренды открытого описания файла, на который указывает файловый дескриптор fd. Аренда файла предоставляет механизм, посредством которого процесс, который удерживает аренду («арендатор»), уведомляется (отправкой сигнала), когда процесс («нарушитель аренды») пытается выполнить вызов open(2) или truncate(2) на файл, указанный в этом файловом дескрипторе.

Установить или удалить аренду файла, в соответствии со значениями, указываемыми в arg:
Установить аренду чтения. Это приведёт к генерации уведомления вызывающего процесса, когда файл открывается для записи или усечения. Аренда чтения может быть выделена только на файловый дескриптор, открытый только на чтение.
Установить аренду записи. Это приведёт к генерации уведомления вызывающего процесса, когда файл открывается для чтения или записи или выполняется его усечение. Аренда записи может быть установлена на файл, только если этот файл не имеет других открытых файловых дескрипторов.
Удалить аренду с указанного файла.

Аренды ассоциируются с открытым файловым описанием (см. open(2)). Это значит, что дублированные файловые дескрипторы (созданные, например, fork(2) или dup(2)) указывают на одну и ту же аренду, и эта аренда может изменяться или освобождаться через любой из этих дескрипторов. Более того, аренда освобождается или через явную команду F_UNLCK на любом из этих дублированных дескрипторов, или когда все эти дескрипторы будут закрыты.

Аренды могут быть выданы только на обычные файлы. Непривилегированный процесс может получить аренду только на файл, чей UID (владельца) совпадает с UID на файловой системе процесса. Процесс с мандатом CAP_LEASE может получить аренду на любые файлы.

Узнать какой тип аренды ассоциирован с файловым дескриптором fd; возвращается одно из значений F_RDLCK, F_WRLCK или F_UNLCK, соответственно означающих аренду на чтение, запись или что аренды нет. Аргумент arg игнорируется.

Когда процесс («нарушителя аренды») выполняет вызов open(2) или truncate(2), который конфликтует с арендой, установленной через F_SETLEASE, то системный вызов блокируется ядром и ядро уведомляет арендатора сигналом (по умолчанию SIGIO). Арендатор должен при получении этого сигнала выполнить все необходимые действия по очистке для подготовки этого файла к использованию другим процессом (например, сбросить буферы кэша) и затем удалить или снизить условия аренды. Аренда удаляется по команде F_SETLEASE с аргументом arg, установленным в F_UNLCK. Если арендатор удерживает аренду на запись в файл, и нарушитель аренды открывает файл на чтение, то достаточно того, что арендатор понизит условия аренды до аренды на чтение. Это выполняется командой F_SETLEASE с аргументом arg, установленным в F_RDLCK.

Если арендатор не освободит аренду или не снизит условия в течении определённого количества секунд, указанного в файле /proc/sys/fs/lease-break-time, то ядро принудительно удалит или снизит условия аренды для арендатора.

После того, как был начат разрыв аренды, F_GETLEASE возвращает тип назначения аренды (или F_RDLCK или F_UNLCK, в зависимости от необходимости совместимости с нарушителем аренды) до тех пор, пока держатель аренды добровольно не отдаст или не удалит аренду или ядро принудительно не сделает это после истечения таймера разрыва аренды.

После того как аренда снята держателем аренды или принудительно удалена и снижены условия, и предполагая, что нарушитель аренды не выполнял неблокирующий системный вызов, ядро позволяет продолжить работу системного вызова нарушителя аренды.

Если нарушитель аренды, заблокированный в open(2) или truncate(2), прерывается обработчиком сигнала, то системный вызов завершается неудачно с ошибкой EINTR, но другие шаги по-прежнему выполняются как описано ранее. Если нарушитель аренды завершается по сигналу будучи блокированным в open(2) или truncate(2), то другие шаги по-прежнему выполняются как описано ранее. Если нарушитель аренды указал флаг O_NONBLOCK при вызове open(2), то вызов немедленно завершается неудачей с ошибкой EWOULDBLOCK, но другие шаги по-прежнему выполняются как описано ранее.

По умолчанию, для уведомления арендатора используется сигнал SIGIO, но его можно изменить, используя команду F_SETSIG для fcntl(). Если выполняется команда F_SETSIG (даже назначая сигнал SIGIO), и при этом обработчик сигнала устанавливается с использованием SA_SIGINFO, то обработчик получит в качестве второго аргумента структуру siginfo_t, в которой поле si_fd будет содержать дескриптор арендованного файла, к которому пытается получить доступ другой процесс. (Это полезно, если вызывающий процесс удерживает аренду на несколько файлов).

Уведомления об изменении файла и каталога (dnotify)

(Начиная с Linux 2.4) Уведомлять при смене каталога, на который указывает fd или когда изменились файлы, которые в нём содержатся. События, о наступлении которых делается уведомление, задаются в аргументе arg, который является битовой маской, получаемой сложением (OR) одного или более следующих бит:

Был произведён доступ к файлу (read, pread, readv).
Файл был изменён (write, pwrite, writev, truncate, ftruncate).
Файл был создан (open, creat, mknod, mkdir, link, symlink, rename).
Файл был удалён (unlink, rename to another directory, rmdir).
Файл был переименован внутри каталога (rename).
У файла были изменены атрибуты (chown, chmod, utime[s]).
(Чтобы получить эти определения, нужно задать макрос тестирования свойств _GNU_SOURCE перед всеми остальными заголовочными файлами.)

Уведомления об изменении состояния каталога обычно однократные и приложение должно перерегистрировать установку уведомлений, чтобы и дальше получать их. Однако, если в аргумент arg, добавить DN_MULTISHOT, то уведомления будут приходить до тех пор, пока не будут явно отменены.

Серии запросов F_NOTIFY добавляются к событиям в arg, которые уже установлены. Чтобы выключить уведомления всех событий, выполните вызов F_NOTIFY, указав 0 в arg.

Уведомления выполняются через доставку сигнала. По умолчанию это SIGIO, но вы можете изменить его, используя команду F_SETSIG для вызова fcntl(). В последнем случае, обработчик сигнала принимает в качестве второго аргумента структуру siginfo_t (если обработчик был установлен с помощью SA_SIGINFO), а поле si_fd в этой структуре содержит дескриптор файла, для которого было сгенерировано уведомление (полезно, когда устанавливается уведомление для нескольких каталогов).

Кроме того, когда используется DN_MULTISHOT, для уведомлений должен бы быть использован сигнал реального времени, так что множественные уведомления могут быть поставлены в очередь.

ЗАМЕЧАНИЕ: В новых приложениях нужно использовать интерфейс inotify (доступен начиная с ядра 2.6.13), который предоставляет намного лучший интерфейс для получения уведомлений о событиях в файловой системе. Смотрите inotify(7).

Изменение ёмкости канала

Изменяет ёмкость канала, на который указывает fd; она становится равной не менее arg байт. Непривилегированный процесс может подстроить ёмкость канала до любого значения начиная с размера системной страницы до предела, заданного в /proc/sys/fs/pipe-max-size (см. proc(5)). При задании ёмкости меньше размера страницы, она будет без ошибок округлена до размера страницы. При задании непривилегированным процессом ёмкости канала больше предела из /proc/sys/fs/pipe-max-size приведёт к ошибке EPERM; привилегированный процесс (с CAP_SYS_RESOURCE) может превысить этот ограничение. При выделении буфера под канал ядро может использовать ёмкость больше чем указано в arg, если это удобно в реализации. По команде F_GETPIPE_SZ возвращается реально использованный размер. Попытка установить ёмкость канала меньше чем количество пространства в буфере, в настоящее время используемого для хранения данных, приведёт к ошибке EBUSY.
Возвращает (как результат функции) ёмкость канала, указываемого fd.

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

При успешном выполнении возвращаемое значение зависит от используемой команды:

Новый дескриптор.
Значение флагов файлового дескриптора.
Значение флагов состояния файла.
Тип аренды, установленной на файлом дескрипторе.
Значение, представляющее собой владельца дескриптора.
Значение сигнала, посылаемого когда становится возможным чтение или запись или ноль для традиционного поведения SIGIO.
Ёмкость канала.
Все остальные команды
Ноль.

В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.

ОШИБКИ

Операция запрещена блокировками, которые удерживаются другими процессами.
Операция запрещена, потому что файл отображается в память другим процессом.
Значение fd не является открытым файловым дескриптором или была указана команда F_SETLK или F_SETLKW, но режим открытия файлового дескриптора не совпадает с типом запрошенной блокировки.
Было обнаружено, что указанная команда F_SETLKW привела бы к взаимной блокировке (deadlock).
Значение lock находится за пределами доступного адресного пространства.
Выполнение команды F_SETLKW было прервана сигналом, см. signal(7). Выполнение команд F_GETLK и F_SETLK было прервано сигналом перед тем как блокировка была проверена или установлена. Большинство таких ошибок случается при блокировке удалённого файла (например, блокировка через NFS), но иногда такое может случаться и локально.
При выполнении команды F_DUPFD значение arg отрицательное или больше максимально возможного значения. При выполнении F_SETSIG значение arg не содержит допустимый номер сигнала.
При выполнении команды F_DUPFD процесс достиг максимального количества открытых файловых дескрипторов.
Открыто слишком много блокировок сегментов, таблица блокировок заполнена или ошибка протокола удалённой блокировки (например, при блокировке через NFS).
Попытка сбросить флаг O_APPEND на файле, который открыт с атрибутом только для добавления.

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

SVr4, 4.3BSD, POSIX.1-2001. В POSIX.1-2001 указаны только команды F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK и F_SETLKW.

F_GETOWN и F_SETOWN указаны в POSIX.1-2001. (Для получения их определений, определите BSD_SOURCE или _XOPEN_SOURCE со значением 500 или больше, или определите _POSIX_C_SOURCE со значением 200809L или больше.)

F_DUPFD_CLOEXEC указана в POSIX.1-2008. (Для получения определения, определите _POSIX_C_SOURCE со значением 200809L или больше, или _XOPEN_SOURCE со значением 700 или больше.)

Команды F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE и F_SETLEASE есть только в Linux. (Для задействования этих определений определите макрос _GNU_SOURCE.)

ЗАМЕЧАНИЯ

Первоначальная версия системного вызова fcntl() в Linux не умела работать с большими файловыми смещениями (в структуре flock). Позднее, в Linux 2.4 был добавлен системный вызов fcntl64(). Новый системный вызов использует другую структуру для блокировки файлов — flock64 и соответствующие команды — F_GETLK64, F_SETLK64 и F_SETLKW64. Однако, это различие может игнорироваться приложениями, которые используют glibc, так как имеющаяся в ней обёрточная функция fcntl() самостоятельно задействует более новый системный вызов, если он доступен.

Ошибки, возвращаемые dup2(2), отличаются от тех, что возвращаются при F_DUPFD.

Начиная с ядра 2.0, не существует разницы между типами блокировки, которые осуществляют flock(2) и fcntl().

Некоторые системы имеют дополнительные поля в структуре struct flock, например, l_sysid. Вообще-то, один l_pid не очень-то полезен, если процесс, удерживающий блокировку, может работать на другой машине.

ДЕФЕКТЫ

Ограничение в соглашениях по системным вызовам Linux на некоторых архитектурах (в частности i386) приводит к тому, что если значение ID группы процесса (отрицательное), возвращаемое по команде F_GETOWN, попадает в диапазон от -1 до -4095, то оно неправильно интерпретируется glibc и считается ошибкой в системном вызове; то есть возвращаемое значение fcntl() будет равно -1, а errno будет содержать значение ID группы процесса (положительное). Команда F_GETOWN_EX (есть только в Linux) не подвержена этой проблеме. Начиная с glibc версии 2.11, glibc делает проблему для F_GETOWN невидимой, реализовав F_GETOWN с помощью F_GETOWN_EX.

В Linux 2.4 и более раннем, есть ошибка, которая может произойти когда непривилегированный процесс использует F_SETOWN для задания владельца дескриптора файла сокета как процесса (группу) отличного от вызывающего. В этом случае fcntl() может вернуть -1 с errno равным EPERM, даже когда процесс (группа) владелец такая же как и вызывающий имеет право посылать сигнал. Несмотря на возвращаемую ошибку, владелец файлового дескриптора всё равно устанавливается и сигналы будут посылаться владельцу.

Реализация обязательной блокировки во всех известных версиях Linux проводит к состязательности процессов, что делает её ненадёжной: вызов write(2), пересекающийся с блокировкой, может изменить данные после установления обязательной блокировки; вызов read(2), пересекающийся с блокировкой, может обнаружить изменившиеся данные, которые были внесены уже установления блокировки на запись. Подобная состязательность существует между обязательными блокировками и mmap(2). Поэтому нецелесообразно полагаться на обязательную блокировку.

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

dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7)

Смотрите также файлы locks.txt, mandatory-locking.txt и dnotify.txt из каталога с исходным кодом ядра Documentation/filesystems/. (В старых ядрах эти файлы были в каталоге Documentation/, а mandatory-locking.txt назывался mandatory.txt.)

2012-04-15 Linux