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.Popenclose_fds=False로 생성된 경우) 파일 디스크립터는 자식 프로세스에 상속됩니다. Windows에는 “close-on-exec” 플래그가 없고, 정반대 값을 가지는 상속 플래그가 있습니다. 예를 들어, close-on-exec 플래그를 설정한다는 것은 핸들의 HANDLE_FLAG_INHERIT 플래그를 해제한다는 것을 의미합니다.

Python 3.3에서의 상태

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

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

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

이 PEP는 파이썬 3.2에서 subprocess의 변경으로 시작된 작업을 이어받아, subprocess를 사용하는 코드뿐만 아니라 모든 코드에서 이 문제를 해결할 것을 제안합니다.

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

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

TCPServer의 리스닝 소켓은 exec()시 닫히지 않습니다: 자식 프로세스는 새 클라이언트로부터 연결을 받을 수 있으며, 부모가 리스닝 소켓을 닫고 같은 주소에 새 리스닝 소켓을 생성하면 “주소가 이미 사용 중”이라는 오류가 발생하게 됩니다.

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

다음 이슈들도 참조하십시오:

보안

파일 디스크립터 누출은 주요 보안 취약점입니다. 신뢰할 수 없는 자식 프로세스는 누출된 파일 디스크립터를 통해 비밀번호 같은 민감한 데이터를 읽고 부모 프로세스를 장악할 수 있습니다. 예를 들어 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()를 호출하면, 해당 파일 디스크립터는 자식 프로세스에 상속됩니다. 현대 운영체제는 파일 디스크립터 생성 시점에 플래그를 설정하는 함수를 제공하여 경쟁 상태(race condition)를 방지합니다.

이식성

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

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

Note

5.2보다 이전 버전의 OpenBSD에서는 fork()exec()보다 먼저 사용하면 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를 추가합니다.

subprocesspass_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는 fork()없이 exec()를 사용하는 애플리케이션의 문제를 해결하지 않습니다. Python에는 포크 후 호출될 콜백을 등록할 수 있는 범용 프로세스가 필요합니다. #16500: Add an atfork module을 참조하십시오. 이러한 레지스트리를 사용하여 fork()직후 파일 디스크립터를 닫을 수 있습니다.

단점:

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

open(): 모드에 “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>, etc.
  • openssl: -pass fd:<fd>
  • qemu: -add-fd <fd>
  • valgrind: --log-fd=<fd>, --input-fd=<fd>, etc.
  • 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 플래그를 설정하는 데 따른 성능 오버헤드가 낮습니다. Linux 3.6에서 bench_cloexec.py를 실행한 결과는 다음과 같습니다:

  • close-on 플래그를 설정하지 않음: 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보다 선호됩니다.

Note

fcntl(fd, F_SETFD, flags)은 하나의 플래그(FD_CLOEXEC)만 지원하므로 fcntl(fd, F_GETFD)를 생략할 수 있습니다. 그러나 향후 다른 플래그를 삭제할 수 있으므로 두 함수 호출을 유지하는 편이 더 안전합니다.

Note

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

open()

  • Windows: open()O_NOINHERIT플래그를 사용 [원자적]
  • open()O_CLOEXEC flag를 사용 [원자적]
  • 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) [원자적]
  • dup3()O_CLOEXEC플래그를 사용 [원자적]
  • dup2() + os.set_cloexec(fd, True) [최선의 노력]

os.pipe()

  • Windows: SECURITY_ATTRIBUTES.bInheritHandle=TRUE와 함께 CreatePipe()를 사용하거나, O_NOINHERIT플래그와 함께 _pipe()를 사용 [원자적]
  • pipe2()O_CLOEXEC플래그를 사용 [원자적]
  • pipe() + os.set_cloexec(fd, True) [최선의 노력]

socket.socket()

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

socket.socketpair()

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

socket.socket.accept()

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

하위 호환성

하위 호환성을 깨는 변경 사항은 없습니다. 기본 동작은 변경되지 않습니다: 기본적으로 실행 시 닫기 플래그가 설정되지 않습니다.

부록: 운영 체제 지원

Windows

Windows에는 O_NOINHERIT 플래그가 있습니다: “자식 프로세스에서 상속하지 않습니다.”

예를 들어 open()_pipe()에서 지원됩니다.

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

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

ioctl

함수:

  • ioctl(fd, FIOCLEX, 0): 실행 시 닫기 플래그 설정
  • ioctl(fd, FIONCLEX, 0): 실행 시 닫기 플래그 해제

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

fcntl

함수:

  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags | FD_CLOEXEC): 실행 시 닫기 플래그 설정
  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC): 실행 시 닫기 플래그 해제

사용 가능 환경: 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 플래그: Windows 7 SP1, Windows Server 2008 R2 SP1 및 이후 버전에서 지원됩니다.
  • 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에서 사용할 수 있습니다.

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

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

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)에서 사용할 수 있습니다.

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

링크

링크:

Python 이슈:

다른 언어:

각주