Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 433 – 파일 디스크립터 상속을 더 쉽게 억제하기

Author:
Victor Stinner <vstinner at python.org>
Status:
Superseded
Type:
Standards Track
Created:
10-Jan-2013
Python-Version:
3.4
Superseded-By:
446

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

파일 디스크립터를 생성하는 함수에 선택적 cloexec 매개변수를 새로 추가하고, 이 매개변수의 기본값을 변경하는 여러 방법을 추가하며, 다음 네 가지 새 함수를 추가합니다:

  • os.get_cloexec(fd)
  • os.set_cloexec(fd, cloexec=True)
  • sys.getdefaultcloexec()
  • sys.setdefaultcloexec(cloexec)

근거

파일 디스크립터에는 해당 파일 디스크립터가 상속될지 여부를 나타내는 close-on-exec 플래그가 있습니다.

UNIX에서는 close-on-exec 플래그가 설정되어 있으면 파일 디스크립터가 상속되지 않습니다. 즉, 자식 프로세스가 실행될 때 닫힙니다. 설정되어 있지 않으면 파일 디스크립터는 자식 프로세스에 상속됩니다.

Windows에서는 close-on-exec 플래그가 설정되어 있으면 파일 디스크립터가 상속되지 않습니다. close-on-exec 플래그가 해제되어 있고 CreateProcess()가 bInheritHandles 매개변수를 TRUE로 설정한 채 호출되면(예를 들어 subprocess.Popen이 close_fds=False로 생성될 때) 파일 디스크립터는 자식 프로세스에 상속됩니다. Windows에는 “close-on-exec” 플래그가 없고, 정확히 반대 값을 갖는 상속 플래그가 있습니다. 예를 들어 close-on-exec 플래그를 설정한다는 것은 핸들의 HANDLE_FLAG_INHERIT 플래그를 해제한다는 의미입니다.

Python 3.3의 현황

UNIX에서 subprocess 모듈은 Python 3.2부터 기본적으로 2보다 큰 파일 디스크립터를 닫습니다 [1]. 부모 프로세스가 생성한 모든 파일 디스크립터는 자식 프로세스에서 자동으로 닫힙니다.

xmlrpc.server.SimpleXMLRPCServer는 리스닝 소켓에 close-on-exec 플래그를 설정하지만, 부모 클래스인 socketserver.TCPServer는 이 플래그를 설정하지 않습니다.

서브프로세스를 생성하거나 새 프로그램을 실행하면서도 파일 디스크립터가 닫히지 않는 경우가 더 있습니다. os.spawn*() 계열과 os.exec*() 계열의 함수, 그리고 exec() 또는 fork() + exec()를 호출하는 서드파티 모듈이 그렇습니다. 이 경우 파일 디스크립터가 부모 프로세스와 자식 프로세스 사이에 공유되는데, 이는 대개 의도하지 않은 것이며 여러 가지 문제를 일으킵니다.

이 PEP는 Python 3.2에서 subprocess를 변경하며 시작한 작업을 이어 가서, subprocess를 사용하는 코드뿐만 아니라 모든 코드에서 이 문제를 해결할 것을 제안합니다.

상속된 파일 디스크립터로 인한 문제

부모 프로세스에서 파일 디스크립터를 닫아도 관련 자원(파일, 소켓 등)은 닫히지 않습니다. 자식 프로세스에서 여전히 열려 있기 때문입니다.

TCPServer의 리스닝 소켓은 exec() 시에 닫히지 않습니다. 따라서 자식 프로세스가 새 클라이언트의 연결을 받을 수 있습니다. 부모가 리스닝 소켓을 닫고 같은 주소에 새 리스닝 소켓을 만들면 “address already is used” 오류가 발생합니다.

파일 디스크립터를 닫지 않으면 자원 고갈로 이어질 수 있습니다. 부모가 모든 파일을 닫더라도 자식 프로세스에서 파일이 여전히 열려 있기 때문에, 새 파일 디스크립터를 생성하는 작업이 “too many files” 오류로 실패할 수 있습니다.

다음 이슈도 참고하십시오:

보안

파일 디스크립터 누수는 중대한 보안 취약점입니다. 신뢰할 수 없는 자식 프로세스가 누수된 파일 디스크립터를 통해 비밀번호 같은 민감한 데이터를 읽고 부모 프로세스를 장악할 수 있습니다. 예를 들어 이는 chroot에서 탈출하는 데 쓰이는 알려진 취약점입니다.

CERT 권고 사항도 참조하십시오: FIO42-C. Ensure files are properly closed when they are no longer needed.

취약점 사례:

원자성

다중 스레드 애플리케이션에서 fcntl()로 close-on-exec 플래그를 설정하는 것은 안전하지 않습니다. 파일 디스크립터를 생성한 시점과 fcntl(fd, F_SETFD, new_flags)를 호출하는 시점 사이에 어떤 스레드가 fork()와 exec()를 호출하면, 해당 파일 디스크립터는 자식 프로세스에 상속됩니다. 최신 운영 체제는 파일 디스크립터를 생성하면서 플래그를 설정하는 함수를 제공하므로 이러한 경쟁 조건을 피할 수 있습니다.

이식성

Python 3.2에서 socket.SOCK_CLOEXEC 플래그가 추가되었고, Python 3.3에서 os.O_CLOEXEC 플래그와 os.pipe2() 함수가 추가되었습니다. Python 3.3에서는 파일을 열거나 파이프 또는 소켓을 생성할 때 이미 close-on-exec 플래그를 원자적으로 설정할 수 있습니다.

문제는 이러한 플래그와 함수가 이식성이 없다는 점입니다. 최신 버전의 운영 체제만 이를 지원합니다. O_CLOEXEC 및 SOCK_CLOEXEC 플래그는 오래된 Linux 버전에서 무시되므로 fcntl(fd, F_GETFD)를 사용하여 FD_CLOEXEC 플래그를 확인해야 합니다. 커널이 O_CLOEXEC 또는 SOCK_CLOEXEC 플래그를 무시하면, close-on-exec 플래그를 설정하기 위해 fcntl(fd, F_SETFD, flags)를 호출해야 합니다.

Note

5.2보다 오래된 OpenBSD는 exec() 전에 fork()를 사용하면 close-on-exec 플래그가 설정된 파일 디스크립터를 닫지 않지만, fork() 없이 exec()를 호출하면 올바르게 동작합니다. openbsd_bug.py를 실행해 보십시오.

범위

애플리케이션은 여전히 fork() 후에 파일 디스크립터를 명시적으로 닫아야 합니다. close-on-exec 플래그는 exec() 후에만, 즉 fork() + exec() 후에만 파일 디스크립터를 닫습니다.

이 PEP는 Python 표준 라이브러리나 표준 라이브러리를 사용하는 모듈이 생성한 파일 디스크립터의 close-on-exec 플래그만 변경합니다. 표준 라이브러리를 사용하지 않는 서드파티 모듈은 이 PEP를 따르도록 수정해야 합니다. 예를 들어 새 os.set_cloexec() 함수를 사용할 수 있습니다.

Note

exec() 없이 fork()만 사용하는 경우에 쓸 수 있는 해결책은 Close file descriptors after fork 절을 참조하십시오.

제안

파일 디스크립터를 생성하는 함수에 새로운 선택적 cloexec 매개변수를 추가하고, 이 매개변수의 기본값을 변경하는 여러 방법을 추가합니다.

새 함수를 추가합니다:

  • os.get_cloexec(fd:int) -> bool: 파일 디스크립터의 close-on-exec 플래그를 가져옵니다. 일부 플랫폼에서는 사용할 수 없습니다.
  • os.set_cloexec(fd:int, cloexec:bool=True): 파일 디스크립터의 close-on-exec 플래그를 설정하거나 해제합니다. 일부 플랫폼에서는 사용할 수 없습니다.
  • sys.getdefaultcloexec() -> bool: cloexec 매개변수의 현재 기본값을 가져옵니다
  • sys.setdefaultcloexec(cloexec: bool): cloexec 매개변수의 기본값을 설정합니다

다음 항목에 새로운 선택적 매개변수 cloexec를 추가합니다:

  • asyncore.dispatcher.create_socket()
  • io.FileIO
  • io.open()
  • open()
  • os.dup()
  • os.dup2()
  • os.fdopen()
  • os.open()
  • os.openpty()
  • os.pipe()
  • select.devpoll()
  • select.epoll()
  • select.kqueue()
  • socket.socket()
  • socket.socket.accept()
  • socket.socket.dup()
  • socket.socket.fromfd
  • socket.socketpair()

cloexec 매개변수의 기본값은 sys.getdefaultcloexec()입니다.

기본적으로 close-on-exec 플래그를 설정하도록 새 명령줄 옵션 -e와 환경 변수 PYTHONCLOEXEC를 추가합니다.

subprocess는 pass_fds 매개변수로 전달된 파일 디스크립터의 close-on-exec 플래그를 해제합니다.

표준 라이브러리에서 파일 디스크립터를 생성하는 모든 함수는 cloexec 매개변수의 기본값인 sys.getdefaultcloexec()를 따라야 합니다.

파일 디스크립터 0(stdin), 1(stdout), 2(stderr)는 상속될 것으로 기대되지만, Python은 이들을 다르게 처리하지 않습니다. os.dup2()를 사용하여 표준 스트림을 교체할 때는 cloexec=False를 명시적으로 지정해야 합니다.

이 제안의 단점:

  • 소스 코드만 읽어서는 새로 생성된 파일 디스크립터에 close-on-exec 플래그가 설정될지 여부를 더 이상 알 수 없습니다.
  • 파일 디스크립터의 상속이 중요하다면 이제 cloexec 매개변수를 명시적으로 지정해야 하며, 그렇지 않으면 cloexec 매개변수의 기본값에 따라 라이브러리나 애플리케이션이 동작하지 않을 수 있습니다.

대안

기본적으로 상속 활성화, 기본값 변경 불가

파일 디스크립터를 생성하는 함수에 새로운 선택적 매개변수 cloexec를 추가합니다. cloexec 매개변수의 기본값은 False이며, 이 기본값은 변경할 수 없습니다. 파일 디스크립터 상속을 기본적으로 활성화하는 것은 POSIX와 Windows에서도 기본 동작입니다. 이 대안은 가장 보수적인 선택지입니다.

이 선택지는 Rationale 절에 나열된 문제를 해결하지 못하며, 문제를 고치기 위한 도우미만 제공할 뿐입니다. 이러한 문제를 모두 고치려면 애플리케이션이 사용하는 각 모듈에서 파일 디스크립터를 생성하는 모든 함수가 cloexec=True를 설정하도록 수정해야 합니다.

기본적으로 상속 활성화, 기본값은 True로만 설정 가능

이 대안은 제안에 기반하며, 유일한 차이점은 sys.setdefaultcloexec()가 인자를 받지 않고 cloexec 매개변수의 기본값을 True로 설정하는 데에만 사용할 수 있다는 것입니다.

기본적으로 상속 비활성화

이 대안은 제안에 기반하며, 유일한 차이점은 cloexec 매개변수의 기본값이 (False 대신) True라는 것입니다.

파일을 자식 프로세스가 상속해야 한다면 cloexec=False 매개변수를 사용할 수 있습니다.

close-on-exec 플래그를 기본적으로 설정할 때의 장점:

close-on-exec 플래그를 기본적으로 설정할 때의 단점:

  • 최소 놀람의 원칙에 위배됩니다. os 모듈을 사용하는 개발자는 Python이 POSIX 표준을 준수하며, 따라서 close-on-exec 플래그가 기본적으로 설정되지 않으리라고 기대할 수 있습니다.
  • os 모듈은 시스템 호출(C 표준 라이브러리의 함수)에 대한 얇은 래퍼로 작성되어 있습니다. close-on-exec 플래그를 설정하는 원자적 플래그가 지원되지 않는 경우(Appendix: Operating system support 참조), 한 번의 Python 함수 호출이 2~3번의 시스템 호출을 할 수 있습니다(Performances 절 참조).
  • 추가 시스템 호출이 있다면 Python의 속도가 느려질 수 있습니다. Performances를 참조하십시오.

하위 호환성: 파일 디스크립터 상속에 의존하는 프로그램은 소수에 불과하며, 이들 프로그램도 적은 수의 파일 디스크립터만, 보통은 하나만 전달합니다. 이러한 프로그램은 EBADF 오류로 즉시 실패할 것이며, 고치기도 간단합니다. cloexec=False 매개변수를 추가하거나 os.set_cloexec(fd, False)를 사용하면 됩니다.

어차피 subprocess 모듈은 Popen 생성자의 pass_fds 매개변수에 나열된 파일 디스크립터의 close-on-exec 플래그를 해제하도록 변경될 것입니다. 따라서 이러한 프로그램이 subprocess 모듈을 사용한다면 아무런 수정도 필요하지 않을 수 있습니다.

fork 후 파일 디스크립터 닫기

이 PEP는 exec() 없이 fork()를 사용하는 애플리케이션의 문제를 해결하지 않습니다. Python에는 fork 후에 호출될 콜백을 등록하는 범용적인 절차가 필요합니다. #16500: atfork 모듈 추가을 참조하십시오. 이러한 레지스트리는 fork() 직후에 파일 디스크립터를 닫는 데 사용할 수 있습니다.

단점:

  • Windows에서는 문제를 해결하지 못합니다. Windows에는 fork()가 존재하지 않습니다
  • 이 대안은 fork() 없이 exec()을 사용하는 프로그램의 문제를 해결하지 못합니다.
  • 서드파티 모듈이 C 함수 fork()를 직접 호출할 수 있는데, 이 함수는 “atfork” 콜백을 호출하지 않습니다.
  • 파일 디스크립터를 생성하는 모든 함수가 콜백을 등록하고, 파일이 닫힐 때 그 콜백의 등록을 해제하도록 변경되어야 합니다. 아니면 열려 있는 모든 파일 디스크립터의 목록을 유지해야 합니다.
  • 파일 디스크립터를 자동으로 닫는 일은 Python보다 운영 체제가 맡는 것이 더 적합합니다. 예를 들어, 파일을 닫는 동작과 그 파일을 닫는 콜백의 등록을 해제하는 동작 사이의 경쟁 조건을 피하기가 쉽지 않습니다.

open(): mode에 “e” 플래그 추가

새로운 “e” 모드는 close-on-exec 플래그를 설정합니다(최선의 노력 방식).

이 대안은 open()의 문제만 해결합니다. 예를 들어 socket.socket()과 os.pipe()에는 mode 매개변수가 없습니다.

GNU libc는 버전 2.7부터 fopen()에 "e" 플래그를 지원합니다. 가능하면 O_CLOEXEC을 사용하고, 그렇지 않으면 fcntl(fd, F_SETFD, FD_CLOEXEC)를 사용합니다. Visual Studio에서는 fopen()이 O_NOINHERIT을 사용하는 “N” 플래그를 받습니다.

새 매개변수 이름에 대한 바이크쉐딩

  • inherit, inherited: Windows의 정의에 더 가깝습니다
  • sensitive
  • sterile: “자손을 낳지 않습니다.”

파일 디스크립터 상속을 사용하는 애플리케이션

대부분의 개발자는 파일 디스크립터가 기본적으로 상속된다는 사실을 모릅니다. 대부분의 프로그램은 파일 디스크립터 상속에 의존하지 않습니다. 예를 들어, Python 3.2에서 subprocess.Popen은 기본적으로 자식 프로세스에서 2보다 큰 모든 파일 디스크립터를 닫도록 변경되었습니다. 아직 이 동작 변경에 대해 불만을 제기한 사용자는 없습니다.

fork를 사용하는 네트워크 서버는 클라이언트 소켓을 자식 프로세스에 전달하고 싶을 수 있습니다. 예를 들어, UNIX에서 CGI 서버는 dup2()를 사용하여 파일 디스크립터 0(stdin)과 1(stdout)을 통해 클라이언트 소켓을 전달합니다.

1024보다 낮은 TCP 포트에서 수신 대기하는 소켓을 생성하거나 비밀번호 같은 민감한 데이터가 담긴 파일을 읽는 등 제한된 자원에 접근하기 위한 일반적인 방법은 다음과 같습니다. root 사용자로 시작하여 파일 디스크립터를 생성하고, 자식 프로세스를 생성하고, 권한을 내려놓고(예: 현재 사용자 변경), 파일 디스크립터를 자식 프로세스에 전달한 뒤 부모 프로세스를 종료합니다.

이러한 사용 사례에서는 보안이 매우 중요합니다. 다른 파일 디스크립터가 누출되면 심각한 보안 취약점이 됩니다(Security 참조). root 프로세스는 종료하지 않고 대신 자식 프로세스를 감시하다가, 이전 자식 프로세스가 비정상 종료되면 새 자식 프로세스를 다시 시작하고 같은 파일 디스크립터를 전달할 수도 있습니다.

명령줄 옵션을 사용하여 부모 프로세스로부터 파일 디스크립터를 받는 프로그램의 예:

  • gpg: --status-fd <fd>, --logger-fd <fd> 등
  • openssl: -pass fd:<fd>
  • qemu: -add-fd <fd>
  • valgrind: --log-fd=<fd>, --input-fd=<fd> 등
  • xterm: -S <fd>

Linux에서는 "/dev/fd/<fd>" 파일 이름을 사용하여 파일 이름을 기대하는 프로그램에 파일 디스크립터를 전달할 수 있습니다.

성능

close-on-exec 플래그를 설정하면 새 파일 디스크립터를 생성할 때마다 추가 시스템 호출이 필요할 수 있습니다. 추가 시스템 호출의 횟수는 플래그를 설정하는 데 사용하는 방법에 따라 달라집니다:

  • O_NOINHERIT: 추가 시스템 호출 없음
  • O_CLOEXEC: 추가 시스템 호출이 한 번 필요하지만, 플래그가 지원되는지 확인하기 위해 첫 번째 파일 디스크립터를 생성할 때만 필요합니다. 플래그가 지원되지 않으면 Python은 다음 방법으로 대체해야 합니다.
  • ioctl(fd, FIOCLEX): 파일 디스크립터마다 추가 시스템 호출 한 번
  • fcntl(fd, F_SETFD, flags): 파일 디스크립터마다 추가 시스템 호출 두 번. 한 번은 기존 플래그를 가져오고, 한 번은 새 플래그를 설정합니다

Linux에서 close-on-flag 플래그 설정이 성능에 미치는 오버헤드는 낮습니다. Linux 3.6에서 실행한 bench_cloexec.py 결과는 다음과 같습니다:

  • close-on-flag 플래그 미설정: 7.8 us
  • O_CLOEXEC: 1% 느림 (7.9 us)
  • ioctl(): 3% 느림 (8.0 us)
  • fcntl(): 3% 느림 (8.0 us)

구현

os.get_cloexec(fd)

파일 디스크립터의 close-on-exec 플래그를 가져옵니다.

의사 코드:

if os.name == 'nt':
    def get_cloexec(fd):
        handle = _winapi._get_osfhandle(fd);
        flags = _winapi.GetHandleInformation(handle)
        return not(flags & _winapi.HANDLE_FLAG_INHERIT)
else:
    try:
        import fcntl
    except ImportError:
        pass
    else:
        def get_cloexec(fd):
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
            return bool(flags & fcntl.FD_CLOEXEC)

os.set_cloexec(fd, cloexec=True)

파일 디스크립터의 close-on-exec 플래그를 설정하거나 해제합니다. 이 플래그는 파일 디스크립터가 생성된 후에 설정되므로 원자적이지 않습니다.

의사 코드:

if os.name == 'nt':
    def set_cloexec(fd, cloexec=True):
        handle = _winapi._get_osfhandle(fd);
        mask = _winapi.HANDLE_FLAG_INHERIT
        if cloexec:
            flags = 0
        else:
            flags = mask
        _winapi.SetHandleInformation(handle, mask, flags)
else:
    fnctl = None
    ioctl = None
    try:
        import ioctl
    except ImportError:
        try:
            import fcntl
        except ImportError:
            pass
    if ioctl is not None and hasattr('FIOCLEX', ioctl):
        def set_cloexec(fd, cloexec=True):
            if cloexec:
                ioctl.ioctl(fd, ioctl.FIOCLEX)
            else:
                ioctl.ioctl(fd, ioctl.FIONCLEX)
    elif fnctl is not None:
        def set_cloexec(fd, cloexec=True):
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
            if cloexec:
                flags |= FD_CLOEXEC
            else:
                flags &= ~FD_CLOEXEC
            fcntl.fcntl(fd, fcntl.F_SETFD, flags)

fcntl은 시스템 호출이 두 번 필요하지만 ioctl은 한 번만 필요하므로 fcntl보다 ioctl을 우선 사용합니다.

Note

fcntl(fd, F_SETFD, flags)는 플래그를 하나(FD_CLOEXEC)만 지원하므로 fcntl(fd, F_GETFD) 호출을 생략할 수도 있습니다. 하지만 앞으로 다른 플래그가 생기면 그 플래그가 지워질 수 있으므로 두 함수를 모두 호출하는 편이 더 안전합니다.

Note

GNU libc의 fopen() 함수는 fcntl(fd, F_SETFD, flags) 호출이 실패해도 오류를 무시합니다.

open()

  • Windows: O_NOINHERIT 플래그를 사용한 open() [원자적]
  • O_CLOEXEC flag를 사용한 open() [원자적]
  • open() + os.set_cloexec(fd, True) [최선 노력]

os.dup()

  • Windows: DuplicateHandle() [원자적]
  • fcntl(fd, F_DUPFD_CLOEXEC) [원자적]
  • dup() + os.set_cloexec(fd, True) [최선 노력]

os.dup2()

  • fcntl(fd, F_DUP2FD_CLOEXEC, fd2) [원자적]
  • O_CLOEXEC 플래그를 사용한 dup3() [원자적]
  • dup2() + os.set_cloexec(fd, True) [최선 노력]

os.pipe()

  • Windows: SECURITY_ATTRIBUTES.bInheritHandle=TRUE를 사용한 CreatePipe() 또는 O_NOINHERIT 플래그를 사용한 _pipe() [원자적]
  • O_CLOEXEC 플래그를 사용한 pipe2() [원자적]
  • pipe() + os.set_cloexec(fd, True) [최선 노력]

socket.socket()

  • Windows: WSA_FLAG_NO_HANDLE_INHERIT 플래그를 사용한 WSASocket() [원자적]
  • SOCK_CLOEXEC 플래그를 사용한 socket() [원자적]
  • socket() + os.set_cloexec(fd, True) [최선 노력]

socket.socketpair()

  • SOCK_CLOEXEC 플래그를 사용한 socketpair() [원자적]
  • socketpair() + os.set_cloexec(fd, True) [최선 노력]

socket.socket.accept()

  • SOCK_CLOEXEC 플래그를 사용한 accept4() [원자적]
  • accept() + os.set_cloexec(fd, True) [최선 노력]

하위 호환성

하위 호환성을 깨뜨리는 변경은 없습니다. 기본 동작은 변경되지 않습니다. close-on-exec 플래그는 기본적으로 설정되지 않습니다.

부록: 운영 체제 지원

Windows

Windows에는 O_NOINHERIT 플래그가 있습니다. 이 플래그의 의미는 “자식 프로세스에 상속하지 않음”입니다.

예를 들어 open()과 _pipe()가 이 플래그를 지원합니다.

이 플래그는 SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0)을 사용하여 해제할 수 있습니다.

CreateProcess()에는 bInheritHandles 매개변수가 있습니다. 이 값이 FALSE이면 핸들이 상속되지 않습니다. 이 값이 TRUE이면 HANDLE_FLAG_INHERIT 플래그가 설정된 핸들이 상속됩니다. subprocess.Popen은 close_fds 옵션을 사용하여 bInheritHandles를 정합니다.

ioctl

함수:

  • ioctl(fd, FIOCLEX, 0): close-on-exec 플래그를 설정합니다.
  • ioctl(fd, FIONCLEX, 0): close-on-exec 플래그를 해제합니다.

사용 가능 환경: Linux, Mac OS X, QNX, NetBSD, OpenBSD, FreeBSD.

fcntl

함수:

  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags | FD_CLOEXEC): close-on-exec 플래그를 설정합니다.
  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC): close-on-exec 플래그를 해제합니다.

사용 가능 환경: AIX, Digital UNIX, FreeBSD, HP-UX, IRIX, Linux, Mac OS X, OpenBSD, Solaris, SunOS, Unicos.

원자적 플래그

새 플래그:

  • O_CLOEXEC: Linux(2.6.23), FreeBSD(8.3), OpenBSD 5.0, Solaris 11, QNX, BeOS, 차기 NetBSD 릴리스(6.1?)에서 사용할 수 있습니다. 이 플래그는 POSIX.1-2008의 일부입니다.
  • socket()과 socketpair()의 SOCK_CLOEXEC 플래그는 Linux 2.6.27, OpenBSD 5.2, NetBSD 6.0에서 사용할 수 있습니다.
  • WSASocket()의 WSA_FLAG_NO_HANDLE_INHERIT 플래그: SP1이 적용된 Windows 7, SP1이 적용된 Windows Server 2008 R2 및 그 이후 버전에서 지원됩니다.
  • fcntl(): F_DUPFD_CLOEXEC 플래그는 Linux 2.6.24, OpenBSD 5.0, FreeBSD 9.1, NetBSD 6.0, Solaris 11에서 사용할 수 있습니다. 이 플래그는 POSIX.1-2008의 일부입니다.
  • fcntl(): F_DUP2FD_CLOEXEC 플래그는 FreeBSD 9.1과 Solaris 11에서 사용할 수 있습니다.
  • recvmsg(): MSG_CMSG_CLOEXEC 플래그는 Linux 2.6.23, NetBSD 6.0에서 사용할 수 있습니다.

2.6.23보다 오래된 Linux에서는 O_CLOEXEC 플래그가 그냥 무시됩니다. 따라서 fcntl()을 호출하여 해당 플래그가 지원되는지 확인해야 합니다. 동작하지 않으면 ioctl() 또는 fcntl()을 사용하여 플래그를 설정해야 합니다.

2.6.27보다 오래된 Linux에서는 소켓 타입에 SOCK_CLOEXEC 플래그가 설정되어 있으면 socket() 또는 socketpair()가 실패하고 errno가 EINVAL로 설정됩니다.

Windows XPS3에서는 WSA_FLAG_NO_HANDLE_INHERIT 플래그를 사용하면 WSASocket()이 WSAEPROTOTYPE으로 실패합니다.

새 함수:

  • dup3(): Linux 2.6.27(및 glibc 2.9)에서 사용할 수 있습니다.
  • pipe2(): Linux 2.6.27(및 glibc 2.9)에서 사용할 수 있습니다.
  • accept4(): Linux 2.6.28(및 glibc 2.10)에서 사용할 수 있습니다.

2.6.28보다 오래된 Linux에서 accept4()를 호출하면 accept4()는 -1(실패)을 반환하고 errno는 ENOSYS로 설정됩니다.

링크

링크:

Python 이슈:

다른 언어:

각주