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


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

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

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

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

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

對(duì)文件描述符 fd 執(zhí)行 cmd 操作(能夠提供 fileno() 方法的文件對(duì)象也可以接受)。 cmd 可用的值與操作系統(tǒng)有關(guān),在 fcntl 模塊中可作為常量使用,名稱與相關(guān) C 語言頭文件中的一樣。參數(shù) arg 可以是整數(shù)或 bytes 對(duì)象。若為整數(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 對(duì)象。返回的對(duì)象長(zhǎng)度將與 arg 參數(shù)的長(zhǎng)度相同。上限為 1024 字節(jié)。如果操作系統(tǒng)在緩沖區(qū)中返回的信息大于 1024 字節(jié),很可能導(dǎo)致內(nèi)存段沖突,或更為不易察覺的數(shù)據(jù)錯(cuò)誤。

如果 fcntl() 調(diào)用失敗,會(huì)觸發(fā) OSError。

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ū)接口的對(duì)象(如 bytes )或支持讀寫緩沖區(qū)接口的對(duì)象(如 bytearray )。

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

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

如果為 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)簡(jiǎn)化,因?yàn)槿羰墙o出的緩沖區(qū)少于 1024 字節(jié),首先會(huì)被復(fù)制到一個(gè) 1024 字節(jié)長(zhǎng)的靜態(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])
fcntl.flock(fd, operation)?

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

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

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

This is essentially a wrapper around the fcntl() locking calls. fd is the file descriptor of the file to lock or unlock, and cmd is one of the following values:

  • LOCK_UN ——解鎖

  • LOCK_SH —— 獲取一個(gè)共享鎖

  • LOCK_EX —— 獲取一個(gè)獨(dú)占鎖

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

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

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

示例(都是運(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 對(duì)象。lockdata 變量的結(jié)構(gòu)布局視系統(tǒng)而定——因此可能采用 flock() 調(diào)用會(huì)更好。

參見

模塊 os

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