fcntl — fcntl 및 ioctl 시스템 호출
fcntl — fcntl 및 ioctl 시스템 호출
이 모듈은 파일 디스크립터에 대한 파일 및 I/O 제어를 수행해요. 유닉스 루틴 fcntl()과 ioctl()의 인터페이스예요. 전체 세부 사항은 유닉스 매뉴얼 페이지 fcntl(2)와 ioctl(2)를 참고하세요.
가용성: Unix, WASI가 아님.
출처: Python 표준 라이브러리
본문
이 모듈의 모든 함수는 파일 디스크립터 fd를 첫 번째 인자로 받아요. fd는 sys.stdin.fileno()가 돌려주는 것 같은 정수 파일 디스크립터일 수도 있고, 진짜 파일 디스크립터를 돌려주는 fileno()를 제공하는 sys.stdin 자체 같은 io.IOBase 객체일 수도 있어요.
버전 3.3에서 변경: 이 모듈의 연산은 이전에 IOError를 발생시켰는데, 이제 OSError를 발생시킴.
버전 3.8에서 변경: fcntl 모듈은 이제 os.memfd_create() 파일 디스크립터의 실링(sealing)을 위한 F_ADD_SEALS, F_GET_SEALS, F_SEAL_* 상수를 포함함.
버전 3.9에서 변경: macOS에서 fcntl 모듈은 파일 디스크립터에서 파일의 경로를 얻는 F_GETPATH 상수를 노출함. Linux(>=3.15)에서는 열린 파일 설명 잠금(open file description lock) 작업 시 쓰는 F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW 상수를 노출함.
버전 3.10에서 변경: Linux >= 2.6.11에서 fcntl 모듈은 파이프 크기를 각각 확인·수정할 수 있는 F_GETPIPE_SZ와 F_SETPIPE_SZ 상수를 노출함.
버전 3.11에서 변경: FreeBSD에서 fcntl 모듈은 파일 디스크립터를 복제할 수 있는 F_DUP2FD와 F_DUP2FD_CLOEXEC 상수를 노출함(후자는 추가로 FD_CLOEXEC 플래그도 설정).
버전 3.12에서 변경: Linux >= 4.5에서 fcntl 모듈은 일부 파일시스템(예: btrfs, OCFS2, XFS)에서 reflink로 한 파일의 일부 데이터를 다른 파일과 공유할 수 있는 FICLONE과 FICLONERANGE 상수를 노출함. 이 동작은 흔히 "copy-on-write"라고 불려요.
버전 3.13에서 변경: Linux >= 2.6.32에서 fcntl 모듈은 I/O 가용성 신호를 특정 스레드·프로세스·프로세스 그룹으로 보낼 수 있는 F_GETOWN_EX, F_SETOWN_EX, F_OWNER_TID, F_OWNER_PID, F_OWNER_PGRP 상수를 노출함. Linux >= 4.13에서는 주어진 inode나 특정 열린 파일 설명을 통한 쓰기의 상대적 예상 수명을 커널에 알릴 수 있는 F_GET_RW_HINT, F_SET_RW_HINT, F_GET_FILE_RW_HINT, F_SET_FILE_RW_HINT, RWH_WRITE_LIFE_* 상수를 노출함. Linux >= 5.1과 NetBSD에서는 F_ADD_SEALS와 F_GET_SEALS 연산에 쓸 F_SEAL_FUTURE_WRITE 상수를 노출함. FreeBSD에서는 F_READAHEAD, F_ISUNIONSTACK, F_KINFO 상수를, macOS와 FreeBSD에서는 F_RDAHEAD 상수를, NetBSD와 AIX에서는 F_CLOSEM 상수를, NetBSD에서는 F_MAXFD 상수를, macOS와 NetBSD에서는 F_GETNOSIGPIPE와 F_SETNOSIGPIPE 상수를 노출함.
버전 3.14에서 변경: Linux >= 6.1에서 fcntl 모듈은 같은 파일을 가리키는 파일 디스크립터를 조회하는 F_DUPFD_QUERY를 노출함.
모듈은 다음 함수들을 정의해요.
fcntl.fcntl(fd, cmd, arg=0, /)
파일 디스크립터 fd에 대해 연산 cmd를 수행해요(fileno() 메서드를 제공하는 파일 객체도 허용). cmd에 쓰는 값은 운영체제에 따라 달라지며, 관련 C 헤더 파일에서 쓰는 것과 같은 이름으로 fcntl 모듈에 상수로 제공돼요. 인자 arg는 정수 값, bytes류 객체, 또는 문자열일 수 있어요.
arg의 타입과 크기는 관련 C 문서에 명시된 연산 인자의 타입·크기와 일치해야 해요.
arg가 정수면 함수는 C fcntl() 호출의 정수 반환 값을 돌려줘요.
인자가 bytes류 객체면 이진 구조를 나타내는데, 예를 들어 struct.pack()으로 만든 것이에요. 문자열 값은 UTF-8 인코딩으로 이진으로 인코딩돼요. 이진 데이터는 주소가 C fcntl() 호출에 전달되는 버퍼로 복사돼요. 성공적인 호출 후의 반환 값은 버퍼의 내용을 bytes 객체로 변환한 것이에요. 반환 객체의 길이는 arg 인자의 길이와 같아요. 이것은 1024바이트로 제한돼요.
fcntl() 호출이 실패하면 OSError가 발생해요.
참고 —
arg의 타입·크기가 연산 인자의 타입·크기와 일치하지 않으면(예: 포인터가 기대되는데 정수를 전달하거나, 운영체제가 버퍼에 반환한 정보가 1024바이트보다 크면) 세그멘테이션 위반이나 더 미묘한 데이터 손상이 발생할 가능성이 높아요.
인자 fd, cmd, arg와 함께 감사 이벤트 fcntl.fcntl을 발생시켜요.
버전 3.14에서 변경: bytes뿐 아니라 임의의 bytes류 객체에 대한 지원 추가.
fcntl.ioctl(fd, request, arg=0, mutate_flag=True, /)
이 함수는 인자 처리가 훨씬 더 복잡하다는 점을 제외하면 fcntl() 함수와 동일해요.
request 매개변수는 플랫폼에 따라 32비트 또는 64비트에 들어갈 수 있는 값으로 제한돼요. request 인자로 쓰기 위한 추가 상수는 관련 C 헤더 파일에서 쓰는 것과 같은 이름으로 termios 모듈에서 찾을 수 있어요.
매개변수 arg는 정수, bytes류 객체, 또는 문자열일 수 있어요. arg의 타입·크기는 관련 C 문서에 명시된 연산 인자의 타입·크기와 일치해야 해요.
arg가 읽기-쓰기 버퍼 인터페이스를 지원하지 않거나 mutate_flag가 거짓이면 동작은 fcntl() 함수와 같아요.
arg가 읽기-쓰기 버퍼 인터페이스를 지원하고(bytearray처럼) mutate_flag가 참(기본값)이면, 버퍼가 (사실상) 기본 ioctl() 시스템 호출로 전달되고, 후자의 반환 코드가 호출한 Python으로 다시 전달되며, 버퍼의 새 내용이 ioctl()의 동작을 반영해요. 이것은 약간의 단순화인데, 제공된 버퍼가 1024바이트보다 짧으면 먼저 1024바이트 길이의 정적 버퍼로 복사된 다음 ioctl()로 전달되고 제공된 버퍼로 다시 복사되기 때문이에요.
ioctl() 호출이 실패하면 OSError 예외가 발생해요.
참고 —
arg의 타입·크기가 연산 인자의 타입·크기와 일치하지 않으면(예: 포인터가 기대되는데 정수를 전달하거나, 운영체제가 버퍼에 반환한 정보가 1024바이트보다 크거나, 가변 bytes류 객체의 크기가 너무 작으면) 세그멘테이션 위반이나 더 미묘한 데이터 손상이 발생할 가능성이 높아요.
예시를 볼게요.
>>> 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])
인자 fd, request, arg와 함께 감사 이벤트 fcntl.ioctl을 발생시켜요.
버전 3.14에서 변경: 시스템 호출 중에 GIL이 항상 해제됨. EINTR로 실패하는 시스템 호출은 자동으로 재시도됨.
fcntl.flock(fd, operation, /)
파일 디스크립터 fd에 대해 잠금 연산 operation을 수행해요(fileno() 메서드를 제공하는 파일 객체도 허용). 세부 사항은 유닉스 매뉴얼 flock(2)을 참고하세요. (일부 시스템에서는 이 함수가 fcntl()을 사용해 에뮬레이트돼요.)
flock() 호출이 실패하면 OSError 예외가 발생해요.
인자 fd, operation과 함께 감사 이벤트 fcntl.flock을 발생시켜요.
fcntl.lockf(fd, cmd, len=0, start=0, whence=0, /)
이것은 기본적으로 fcntl() 잠금 호출의 래퍼예요. fd는 잠그거나 해제할 파일의 파일 디스크립터(fileno() 메서드를 제공하는 파일 객체도 허용)이고, cmd는 다음 값 중 하나예요.
fcntl.LOCK_UN— 기존 잠금 해제.fcntl.LOCK_SH— 공유 잠금 획득.fcntl.LOCK_EX— 배타적 잠금 획득.fcntl.LOCK_NB— 다른 세LOCK_*상수와 비트 OR해서 요청을 비블로킹으로 만듦.
LOCK_NB를 쓰는데 잠금을 획득할 수 없으면 OSError가 발생하고, 예외의 errno 속성이 EACCES 또는 EAGAIN으로 설정돼요(운영체제에 따라 다르며, 이식성을 위해 두 값을 모두 확인하세요). 적어도 일부 시스템에서는 LOCK_EX는 파일 디스크립터가 쓰기용으로 열린 파일을 가리킬 때만 쓸 수 있어요.
len은 잠글 바이트 수, start는 whence에 상대적인 잠금 시작 바이트 오프셋, whence는 io.IOBase.seek()와 같아요. 구체적으로:
0— 파일 시작에 상대적 (os.SEEK_SET)1— 현재 버퍼 위치에 상대적 (os.SEEK_CUR)2— 파일 끝에 상대적 (os.SEEK_END)
start의 기본값은 0으로 파일 시작부터 시작한다는 뜻이고, len의 기본값은 0으로 파일 끝까지 잠근다는 뜻이며, whence의 기본값도 0이에요.
인자 fd, cmd, len, start, whence와 함께 감사 이벤트 fcntl.lockf를 발생시켜요.
예시(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)
첫 번째 예시에서 반환 값 변수 rv가 정수 값을 갖고, 두 번째 예시에서는 bytes 객체를 갖는다는 점에 주의하세요. lockdata 변수의 구조 레이아웃은 시스템에 따라 달라요 — 그래서 flock() 호출을 쓰는 게 더 나을 수도 있어요.
더 알아보기
os모듈 — 잠금 플래그O_SHLOCK과O_EXLOCK이os모듈에 있으면(BSD에서만),os.open()함수가lockf()와flock()함수의 대안을 제공해요.