Документация Python неофициальный перевод

35.9. fcntl – системные вызовы fcntl и ioctlfcntl – The fcntl and ioctl system calls

Этот модуль выполняет управление файлами и вводом-выводом для файловых дескрипторов. Он является интерфейсом к системным вызовам Unix fcntl() и ioctl().

Все функции этого модуля принимают файловый дескриптор fd в качестве первого аргумента. Это может быть целочисленный файловый дескриптор, например, возвращаемый sys.stdin.fileno(), или объект io.IOBase, такой как сам sys.stdin, который предоставляет метод fileno(), возвращающий настоящий файловый дескриптор.

Изменено в версии 3.3: Ранее операции в этом модуле возбуждали IOError, а теперь возбуждают OSError.

Модуль определяет следующие функции:

fcntl.fcntl(fd, op[, arg])

Выполняет операцию op над файловым дескриптором fd (также принимаются файловые объекты, предоставляющие метод fileno()). Значения, используемые для op, зависят от операционной системы и доступны в виде констант в модуле fcntl, с теми же именами, что и в соответствующих C-заголовочных файлах. Аргумент arg необязателен; по умолчанию равен целому числу 0. Если он задан, то может быть как целым числом, так и строкой. Если аргумент опущен или является целым числом, возвращаемое значение этой функции равно целочисленному результату C-вызова fcntl(). Если аргумент – строка, она представляет двоичную структуру, например, созданную с помощью struct.pack(). Двоичные данные копируются в буфер, адрес которого передаётся C-вызову fcntl(). Возвращаемое значение после успешного вызова – содержимое буфера, преобразованное в строковый объект. Длина возвращаемой строки будет равна длине аргумента arg. Это ограничено 1024 байтами. Если информация, возвращаемая операционной системой в буфер, превышает 1024 байта, это, скорее всего, приведёт к ошибке сегментации или более тонкому повреждению данных.

Если fcntl() завершается неудачей, возбуждается исключение OSError.

fcntl.ioctl(fd, op[, arg[, mutate_flag]])

Эта функция идентична функции fcntl(), за исключением того, что обработка аргументов ещё более сложная.

The op parameter is limited to values that can fit in 32-bits. Additional constants of interest for use as the op argument can be found in the termios module, under the same names as used in the relevant C header files.

Параметр arg может быть целым числом, отсутствовать (рассматривается так же, как целое число 0), объектом, поддерживающим интерфейс буфера только для чтения (скорее всего, обычная строка Python), или объектом, поддерживающим интерфейс буфера для чтения и записи.

Во всех случаях, кроме последнего, поведение такое же, как для функции fcntl().

Если передан изменяемый буфер, то поведение определяется значением параметра mutate_flag.

Если он ложен, изменяемость буфера игнорируется, и поведение такое же, как для буфера только для чтения, за исключением того, что упомянутое выше ограничение в 1024 байта не действует – до тех пор, пока передаваемый буфер имеет длину не меньше той, которую операционная система хочет туда записать, всё должно работать.

Если mutate_flag истинен (по умолчанию), то буфер (фактически) передаётся базовому системному вызову ioctl(), его код возврата передаётся обратно в вызывающий код Python, а новое содержимое буфера отражает действие ioctl(). Это небольшое упрощение, потому что если предоставленный буфер короче 1024 байт, он сначала копируется в статический буфер длиной 1024 байта, который затем передаётся ioctl() и копируется обратно в исходный буфер.

Если ioctl() завершается неудачей, возбуждается исключение IOError.

Пример:

>>> import array, fcntl, struct, termios, os
>>> os.getpgrp()
13341
>>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, "  "))[0]
13341
>>> buf = array.array('h', [0])
>>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1)
0
>>> buf
array('h', [13341])
fcntl.flock(fd, op)

Выполняет операцию блокировки op над файловым дескриптором fd (также принимаются файловые объекты, предоставляющие метод fileno()). Подробнее см. в руководстве Unix flock(2). (В некоторых системах эта функция эмулируется с помощью fcntl().)

Если flock() завершается неудачей, возбуждается исключение IOError.

fcntl.lockf(fd, operation[, length[, start[, whence]]])

По сути, это обёртка над вызовами блокировки fcntl(). fd – файловый дескриптор файла, который нужно заблокировать или разблокировать, а operation – одно из следующих значений:

  • LOCK_UN – разблокировать
  • LOCK_SH – захватить разделяемую блокировку
  • LOCK_EX – захватить исключительную блокировку

Когда operation равно LOCK_SH или LOCK_EX, его можно также побитово объединить с LOCK_NB, чтобы избежать блокировки при захвате блокировки. Если используется LOCK_NB и блокировку не удаётся захватить, будет возбуждено OSError, и у исключения будет атрибут errno, установленный в EACCES или EAGAIN (в зависимости от операционной системы; для переносимости следует проверять оба значения). По крайней мере, в некоторых системах LOCK_EX может использоваться только если файловый дескриптор ссылается на файл, открытый для записи.

length – количество блокируемых байт, start – смещение в байтах, с которого начинается блокировка, относительно whence, а whence определяется так же, как в io.IOBase.seek(), а именно:

  • 0 – относительно начала файла (os.SEEK_SET)
  • 1 – относительно текущей позиции буфера (os.SEEK_CUR)
  • 2 – относительно конца файла (os.SEEK_END)

Значение по умолчанию для start – 0, что означает начало от начала файла. Значение по умолчанию для length – 0, что означает блокировку до конца файла. Значение по умолчанию для whence также равно 0.

Примеры (все на системе, совместимой с SVR4):

import struct, fcntl, os

f = open(...)
rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)

lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)

Обратите внимание, что в первом примере переменная rv будет содержать целое число, а во втором – строку. Структура данных для переменной lockdata зависит от системы – поэтому использование вызова flock() может быть предпочтительнее.

См. также

Модуль os
Если флаги блокировки O_SHLOCK и O_EXLOCK присутствуют в модуле os (только на BSD), функция os.open() предоставляет альтернативу функциям lockf() и flock().