diff --git a/pep-0446.txt b/pep-0446.txt index 9900c4afc..ff5dac24e 100644 --- a/pep-0446.txt +++ b/pep-0446.txt @@ -24,6 +24,10 @@ fixes also a race condition in multi-threaded applications on operating systems supporting atomic flags to create non-inheritable file descriptors. +We are aware of the code breakage this is likely to cause, and doing it +anyway for the good of mankind. (Details in the section "Backward +Compatibility" below.) + Rationale ========= @@ -79,6 +83,11 @@ the *dwFlags* field of the ``STARTUPINFO`` structure and the ``TRUE``. So when at least one standard stream is replaced, all inheritable handles are inherited by the child process. +The default value of the *close_fds* parameter of ``subprocess`` process +is ``True`` (``bInheritHandles=FALSE``) if *stdin*, *stdout* and +*stderr* parameters are ``None``, ``False`` (``bInheritHandles=TRUE``) +otherwise. + See also: * `Handle Inheritance @@ -430,12 +439,6 @@ MAXFD is the maximum number of file descriptors, even if there are only few open file descriptors. This maximum can be read using: ``os.sysconf("SC_OPEN_MAX")``. -There is no portable nor reliable function to close all open file -descriptors between ``fork()`` and ``execv()``. Another thread may -create an inheritable file descriptors while we are closing existing -file descriptors. Holding the CPython GIL reduces the risk of the race -condition. - The operation can be slow if MAXFD is large. For example, on a FreeBSD buildbot with ``MAXFD=655,000``, the operation took 300 ms: see `issue #11284: slow close file descriptors @@ -445,10 +448,6 @@ On Linux, Python 3.3 gets the list of all open file descriptors from ``/proc//fd/``, and so performances depends on the number of open file descriptors, not on MAXFD. -FreeBSD, OpenBSD and Solaris provide a ``closefrom()`` function. It -cannot be used by the ``subprocess`` module when the *pass_fds* -parameter is a non-empty list of file descriptors. - See also: * `Python issue #1663329 `_: @@ -485,6 +484,8 @@ descriptors non-inheritable by default: * ``socket.socket.fromfd()`` * ``socket.socketpair()`` +``os.dup2()`` still creates inheritable by default, see below. + When available, atomic flags are used to make file descriptors non-inheritable. The atomicity is not guaranteed because a fallback is required when atomic flags are not available. @@ -518,14 +519,20 @@ New methods: Other Changes ------------- -* On UNIX, subprocess makes file descriptors of the *pass_fds* parameter - inheritable. The file descriptor is made inheritable in the child - process after the ``fork()`` and before ``execv()``, so the inheritable - flag of file descriptors is unchanged in the parent process. +On UNIX, subprocess makes file descriptors of the *pass_fds* parameter +inheritable. The file descriptor is made inheritable in the child +process after the ``fork()`` and before ``execv()``, so the inheritable +flag of file descriptors is unchanged in the parent process. -* ``os.dup2()`` has a new optional *inheritable* parameter: - ``os.dup2(fd, fd2, inheritable=True)``. *fd2* is created inheritable - by default, but non-inheritable if *inheritable* is ``False``. +``os.dup2()`` has a new optional *inheritable* parameter: ``os.dup2(fd, +fd2, inheritable=True)``. *fd2* is created inheritable by default, but +non-inheritable if *inheritable* is ``False``. + +``os.dup2()`` behaves differently than ``os.dup()`` because the most +common use case of ``os.dup2()`` is to replace the file descriptors of +the standard streams: ``stdin`` (``0``), ``stdout`` (``1``) and +``stdout`` (``2``). Standard streams are expected to be inherited by +child processes. Since Python should only create non-inheritable file descriptors, it is safe to use subprocess with the *close_fds* parameter set to ``False``.