fcntl
—— 系統(tǒng)調(diào)用 fcntl
和 ioctl
?
本模塊基于文件描述符來進(jìn)行文件控制和 I/O 控制。它是 Unix 系統(tǒng)調(diào)用 fcntl()
和 ioctl()
的接口。關(guān)于這些調(diào)用的完整描述,請參閱 Unix 手冊的 fcntl(2) 和 ioctl(2) 頁面。
本模塊的所有函數(shù)都接受文件描述符 fd 作為第一個(gè)參數(shù)。可以是一個(gè)整數(shù)形式的文件描述符,比如 sys.stdin.fileno()
的返回結(jié)果,或?yàn)?io.IOBase
對象,比如 sys.stdin
提供一個(gè) fileno()
,可返回一個(gè)真正的文件描述符。
在 3.8 版更改: fcntl 模塊現(xiàn)在有了 F_ADD_SEALS
、F_GET_SEALS
和 F_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.
這個(gè)模塊定義了以下函數(shù):
- fcntl.fcntl(fd, cmd, arg=0)?
對文件描述符 fd 執(zhí)行 cmd 操作(能夠提供
fileno()
方法的文件對象也可以接受)。 cmd 可用的值與操作系統(tǒng)有關(guān),在fcntl
模塊中可作為常量使用,名稱與相關(guān) C 語言頭文件中的一樣。參數(shù) arg 可以是整數(shù)或bytes
對象。若為整數(shù)值,則本函數(shù)的返回值是 C 語言fcntl()
調(diào)用的整數(shù)返回值。若為字節(jié)串,則其代表一個(gè)二進(jìn)制結(jié)構(gòu),比如由struct.pack()
創(chuàng)建的數(shù)據(jù)。該二進(jìn)制數(shù)據(jù)將被復(fù)制到一個(gè)緩沖區(qū),緩沖區(qū)地址傳給 C 調(diào)用fcntl()
。調(diào)用成功后的返回值位于緩沖區(qū)內(nèi),轉(zhuǎn)換為一個(gè)bytes
對象。返回的對象長度將與 arg 參數(shù)的長度相同。上限為 1024 字節(jié)。如果操作系統(tǒng)在緩沖區(qū)中返回的信息大于 1024 字節(jié),很可能導(dǎo)致內(nèi)存段沖突,或更為不易察覺的數(shù)據(jù)錯(cuò)誤。如果
fcntl()
調(diào)用失敗,會(huì)觸發(fā)OSError
。引發(fā)一條 auditing 事件
fcntl.fcntl
,參數(shù)為fd
、cmd
、arg
。
- fcntl.ioctl(fd, request, arg=0, mutate_flag=True)?
本函數(shù)與
fcntl()
函數(shù)相同,只是參數(shù)的處理更加復(fù)雜。request 參數(shù)的上限是 32位。
termios
模塊中包含了可用作 request 參數(shù)其他常量,名稱與相關(guān) C 頭文件中定義的相同。參數(shù) arg 可為整數(shù)、支持只讀緩沖區(qū)接口的對象(如
bytes
)或支持讀寫緩沖區(qū)接口的對象(如bytearray
)。除了最后一種情況,其他情況下的行為都與
fcntl()
函數(shù)一樣。如果傳入的是個(gè)可變緩沖區(qū),那么行為就由 mutate_flag 參數(shù)決定。
如果 mutate_flag 為 False,緩沖區(qū)的可變性將被忽略,行為與只讀緩沖區(qū)一樣,只是沒有了上述 1024 字節(jié)的上限——只要傳入的緩沖區(qū)能容納操作系統(tǒng)放入的數(shù)據(jù)即可。
如果 mutate_flag 為 True(默認(rèn)值),那么緩沖區(qū)(實(shí)際上)會(huì)傳給底層的 系統(tǒng)調(diào)用
ioctl()
,其返回代碼則會(huì)回傳給調(diào)用它的 Python,而緩沖區(qū)的新數(shù)據(jù)則反映了ioctl()
的運(yùn)行結(jié)果。這里做了一點(diǎn)簡化,因?yàn)槿羰墙o出的緩沖區(qū)少于 1024 字節(jié),首先會(huì)被復(fù)制到一個(gè) 1024 字節(jié)長的靜態(tài)緩沖區(qū)再傳給ioctl()
,然后把結(jié)果復(fù)制回給出的緩沖區(qū)去。如果
ioctl()
調(diào)用失敗,則會(huì)觸發(fā)OSError
異常。舉個(gè)例子:
>>> 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()
調(diào)用失敗,就會(huì)觸發(fā)OSError
異常。觸發(fā)一條 審計(jì)事件
fcntl.flock
,參數(shù)為fd
、operation
。
- fcntl.lockf(fd, cmd, len=0, start=0, whence=0)?
本質(zhì)上是對
fcntl()
加鎖調(diào)用的封裝。fd 是要加解鎖的文件描述符(也接受能提供fileno()
方法的文件對象),cmd 是以下值之一:LOCK_UN
——解鎖LOCK_SH
—— 獲取一個(gè)共享鎖LOCK_EX
—— 獲取一個(gè)獨(dú)占鎖
如果 cmd 為
LOCK_SH
或LOCK_EX
,則還可以與LOCK_NB
進(jìn)行按位或運(yùn)算,以避免在獲取鎖時(shí)出現(xiàn)阻塞。 如果用了LOCK_NB
,無法獲取鎖時(shí)將觸發(fā)OSError
,此異常的 errno 屬性將被設(shè)為EACCES
或EAGAIN
(視操作系統(tǒng)而定;為了保證可移植性,請檢查這兩個(gè)值)。 至少在某些系統(tǒng)上,只有當(dāng)文件描述符指向需要寫入而打開的文件時(shí),才可以使用LOCK_EX
。len 是要鎖定的字節(jié)數(shù),start 是自 whence 開始鎖定的字節(jié)偏移量,whence 與
io.IOBase.seek()
的定義一樣。0
—— 自文件起始位置(os.SEEK_SET
)。1
—— 自緩沖區(qū)當(dāng)前位置(os.SEEK_CUR
)2
—— 自文件末尾(os.SEEK_END
)
start 的默認(rèn)值為 0,表示從文件起始位置開始。len 的默認(rèn)值是 0,表示加鎖至文件末尾。 whence 的默認(rèn)值也是 0。
觸發(fā)一條 審計(jì)事件
fcntl.lockf
,參數(shù)為fd
、cmd
、len
、start
、whence
。
示例(都是運(yùn)行于符合 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)
注意,在第一個(gè)例子中,返回值變量 rv 將存有整數(shù);在第二個(gè)例子中,該變量中將存有一個(gè) bytes
對象。lockdata 變量的結(jié)構(gòu)布局視系統(tǒng)而定——因此采用 flock()
調(diào)用可能會(huì)更好。