fcntl —— 系統調用 fcntlioctl?


本模塊基于文件描述符來(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.3 版更改: 本模塊的操作以前觸發(fā)的是 IOError,現在則會(huì )觸發(fā) OSError。

在 3.8 版更改: fcntl 模塊現在有了 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.

這個(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è)獨占鎖

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

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

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ì )更好。

參見(jiàn)

模塊 os

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