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