fcntl —— 系統(tǒng)調用 fcntlioctl?


本模塊基于文件描述符來進行文件控制和 I/O 控制。它是 Unix 系統(tǒng)調用 fcntl()ioctl() 的接口。關于這些調用的完整描述,請參閱 Unix 手冊的 fcntl(2)ioctl(2) 頁面。

本模塊的所有函數(shù)都接受文件描述符 fd 作為第一個參數(shù)??梢允且粋€整數(shù)形式的文件描述符,比如 sys.stdin.fileno() 的返回結果,或為 io.IOBase 對象,比如 sys.stdin 提供一個 fileno(),可返回一個真正的文件描述符。

在 3.3 版更改: 本模塊的操作以前觸發(fā)的是 IOError,現(xiàn)在則會觸發(fā) OSError

在 3.8 版更改: fcntl 模塊現(xiàn)在有了 F_ADD_SEALS 、F_GET_SEALSF_SEAL_* 常量,用于文件描述符 os.memfd_create() 的封裝。

在 3.9 版更改: On macOS, the fcntl module exposes the F_GETPATH constant, which obtains the path of a file from a file descriptor. On Linux(>=3.15), the fcntl module exposes the F_OFD_GETLK, F_OFD_SETLK and F_OFD_SETLKW constants, which are used when working with open file description locks.

在 3.10 版更改: 在 Linux 2.6.11 以上版本中,fcntl 模塊提供了 F_GETPIPE_SZ 和``F_SETPIPE_SZ`` 常量,分別用于檢查和修改管道的大小。

在 3.11 版更改: On FreeBSD, the fcntl module exposes the F_DUP2FD and F_DUP2FD_CLOEXEC constants, which allow to duplicate a file descriptor, the latter setting FD_CLOEXEC flag in addition.

這個模塊定義了以下函數(shù):

fcntl.fcntl(fd, cmd, arg=0)?

對文件描述符 fd 執(zhí)行 cmd 操作(能夠提供 fileno() 方法的文件對象也可以接受)。 cmd 可用的值與操作系統(tǒng)有關,在 fcntl 模塊中可作為常量使用,名稱與相關 C 語言頭文件中的一樣。參數(shù) arg 可以是整數(shù)或 bytes 對象。若為整數(shù)值,則本函數(shù)的返回值是 C 語言 fcntl() 調用的整數(shù)返回值。若為字節(jié)串,則其代表一個二進制結構,比如由 struct.pack() 創(chuàng)建的數(shù)據(jù)。該二進制數(shù)據(jù)將被復制到一個緩沖區(qū),緩沖區(qū)地址傳給 C 調用 fcntl()。調用成功后的返回值位于緩沖區(qū)內,轉換為一個 bytes 對象。返回的對象長度將與 arg 參數(shù)的長度相同。上限為 1024 字節(jié)。如果操作系統(tǒng)在緩沖區(qū)中返回的信息大于 1024 字節(jié),很可能導致內存段沖突,或更為不易察覺的數(shù)據(jù)錯誤。

如果 fcntl() 調用失敗,會觸發(fā) OSError 。

引發(fā)一條 auditing 事件 fcntl.fcntl,參數(shù)為 fd 、cmdarg。

fcntl.ioctl(fd, request, arg=0, mutate_flag=True)?

本函數(shù)與 fcntl() 函數(shù)相同,只是參數(shù)的處理更加復雜。

request 參數(shù)的上限是 32位。termios 模塊中包含了可用作 request 參數(shù)其他常量,名稱與相關 C 頭文件中定義的相同。

參數(shù) arg 可為整數(shù)、支持只讀緩沖區(qū)接口的對象(如 bytes )或支持讀寫緩沖區(qū)接口的對象(如 bytearray )。

除了最后一種情況,其他情況下的行為都與 fcntl() 函數(shù)一樣。

如果傳入的是個可變緩沖區(qū),那么行為就由 mutate_flag 參數(shù)決定。

如果 mutate_flag 為 False,緩沖區(qū)的可變性將被忽略,行為與只讀緩沖區(qū)一樣,只是沒有了上述 1024 字節(jié)的上限——只要傳入的緩沖區(qū)能容納操作系統(tǒng)放入的數(shù)據(jù)即可。

如果 mutate_flag 為 True(默認值),那么緩沖區(qū)(實際上)會傳給底層的 系統(tǒng)調用 ioctl() ,其返回代碼則會回傳給調用它的 Python,而緩沖區(qū)的新數(shù)據(jù)則反映了 ioctl() 的運行結果。這里做了一點簡化,因為若是給出的緩沖區(qū)少于 1024 字節(jié),首先會被復制到一個 1024 字節(jié)長的靜態(tài)緩沖區(qū)再傳給 ioctl() ,然后把結果復制回給出的緩沖區(qū)去。

如果 ioctl() 調用失敗,則會觸發(fā) OSError 異常。

舉個例子:

>>>
>>> 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])

觸發(fā)一條 auditing 事件 fcntl.ioctl,參數(shù)為 fd 、request 、arg。

fcntl.flock(fd, operation)?

在文件描述符 fd 上執(zhí)行加鎖操作 operation (也接受能提供 fileno() 方法的文件對象)。 詳見 Unix 手冊 flock(2)。 (在某些系統(tǒng)中,此函數(shù)是用 fcntl() 模擬出來的。)

如果 flock() 調用失敗,就會觸發(fā) OSError 異常。

觸發(fā)一條 審計事件 fcntl.flock,參數(shù)為 fdoperation。

fcntl.lockf(fd, cmd, len=0, start=0, whence=0)?

本質上是對 fcntl() 加鎖調用的封裝。fd 是要加解鎖的文件描述符(也接受能提供 fileno() 方法的文件對象),cmd 是以下值之一:

  • LOCK_UN ——解鎖

  • LOCK_SH —— 獲取一個共享鎖

  • LOCK_EX —— 獲取一個獨占鎖

如果 cmdLOCK_SHLOCK_EX,則還可以與 LOCK_NB 進行按位或運算,以避免在獲取鎖時出現(xiàn)阻塞。 如果用了 LOCK_NB,無法獲取鎖時將觸發(fā) OSError,此異常的 errno 屬性將被設為 EACCESEAGAIN (視操作系統(tǒng)而定;為了保證可移植性,請檢查這兩個值)。 至少在某些系統(tǒng)上,只有當文件描述符指向需要寫入而打開的文件時,才可以使用 LOCK_EX。

len 是要鎖定的字節(jié)數(shù),start 是自 whence 開始鎖定的字節(jié)偏移量,whenceio.IOBase.seek() 的定義一樣。

start 的默認值為 0,表示從文件起始位置開始。len 的默認值是 0,表示加鎖至文件末尾。 whence 的默認值也是 0。

觸發(fā)一條 審計事件 fcntl.lockf,參數(shù)為 fd 、 cmdlen、 startwhence。

示例(都是運行于符合 SVR4 的系統(tǒng)):

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 將存有整數(shù);在第二個例子中,該變量中將存有一個 bytes 對象。lockdata 變量的結構布局視系統(tǒng)而定——因此采用 flock() 調用可能會更好。

參見

模塊 os

如果 os 模塊中存在加鎖標志 O_SHLOCKO_EXLOCK (僅在BSD上),那么 os.open() 函數(shù)提供了 lockf()flock() 函數(shù)的替代方案。