Commits

Victor Stinner committed c73aee6

cloexec

Comments (0)

Files changed (1)

python/pep_cloexec.rst

 Add optional ``cloexec`` argument to:
 
  * ``open()``: ``os.fdopen()`` is indirectly modified
- * ``socket.socket()``, ``socket.socketpair()``
  * ``os.dup()``, ``os.dup2()``
  * ``os.pipe()``
+ * ``socket.socket()``, ``socket.socketpair()`` ``socket.socket.accept()``
  * Maybe also: ``os.open()``, ``os.openpty()``
- * Should be modified later:
+ * TODO:
 
    * ``select.devpoll()``
    * ``select.poll()``
    * ``select.kqueue()``
    * ``socket.socket.recvmsg()``: use ``MSG_CMSG_CLOEXEC``, or ``os.set_cloexec()``
 
-If the ``cloexec`` argument is not set, ``sys.getdefaultcloexec()`` will be used.
+The default value of ``cloexec`` is ``sys.getdefaultcloexec()``.
 
 Impacted modules:
 
     if os.name == 'nt':
         def set_cloexec(fd, cloexec):
             SetHandleInformation(fd, HANDLE_FLAG_INHERIT, int(cloexec))
-    if ioctl is not None and hasattr('FIOCLEX', ioctl):
-        def set_cloexec(fd, cloexec):
-            if cloexec:
-                ioctl.ioctl(fd, ioctl.FIOCLEX)
-            else:
-                ioctl.ioctl(fd, ioctl.FIONCLEX)
-    elif fnctl is not None:
-        def set_cloexec(fd, cloexec):
-            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
-            if cloexec:
-                flags |= FD_CLOEXEC
-            else:
-                flags &= ~FD_CLOEXEC
-            fcntl.fcntl(fd, fcntl.F_SETFD, flags)
     else:
-        def set_cloexec(fd, cloexec):
-            raise NotImplementedError("close-on-exec flag is not supported on your platform")
+        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):
+                if cloexec:
+                    ioctl.ioctl(fd, ioctl.FIOCLEX)
+                else:
+                    ioctl.ioctl(fd, ioctl.FIONCLEX)
+        elif fnctl is not None:
+            def set_cloexec(fd, cloexec):
+                flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+                if cloexec:
+                    flags |= FD_CLOEXEC
+                else:
+                    flags &= ~FD_CLOEXEC
+                fcntl.fcntl(fd, fcntl.F_SETFD, flags)
+        else:
+            def set_cloexec(fd, cloexec):
+                raise NotImplementedError("close-on-exec flag is not supported on your platform")
+
+ioctl is preferred over fcntl because it requires only one syscall, instead of
+two syscalls for fcntl.
+
+XXX Should the ``cloexec`` argument be optional (default: True)? XXX
+
+Note: ``fcntl(fd, F_SETFD, flags)`` only supports one flag, so it would be
+possible to avoid ``fcntl(fd, F_GETFD)``. But it may drop other flags in
+the future, and so it is safer to keep the two functions calls.
 
 open()
 ------
 
+ * Windows: ``open()`` with ``O_NOINHERIT`` flag [atomic]
  * ``open()`` with ``O_CLOEXEC flag`` [atomic]
- * Windows: ``open()`` with ``O_NOINHERIT`` flag [atomic]
  * ``open()`` + ``os.set_cloexec(fd, True)`` [best-effort]
 
-socket.socket()
----------------
-
- * ``socket()`` with ``SOCK_CLOEXEC`` flag [atomic]
- * ``socket()`` + ``os.set_cloexec(fd, True)`` [best-effort]
-
-XXX what is SO_CLOEXEC??? XXX
-
 os.dup()
 --------
 
  * ``dup()`` + ``os.set_cloexec(fd, True)`` [best-effort]
 
 os.dup2()
--------------------
+---------
 
  * ``dup3()`` with ``O_CLOEXEC`` flag [atomic]
  * ``dup2()`` + ``os.set_cloexec(fd, True)`` [best-effort]
  * ``pipe2()`` with ``O_CLOEXEC`` flag [atomic]
  * ``pipe()`` + ``os.set_cloexec(fd, True)`` [best-effort]
 
+socket.socket()
+---------------
+
+ * ``socket()`` with ``SOCK_CLOEXEC`` flag [atomic]
+ * ``socket()`` + ``os.set_cloexec(fd, True)`` [best-effort]
+
+socket.socketpair()
+-------------------
+
+ * ``socketpair()`` with ``SOCK_CLOEXEC`` flag [atomic]
+ * ``socketpair()`` + ``os.set_cloexec(fd, True)`` [best-effort]
+
+socket.socket.accept()
+----------------------
+
+ * ``accept4()`` with ``SOCK_CLOEXEC`` flag [atomic]
+ * ``accept()`` + ``os.set_cloexec(fd, True)`` [best-effort]
+
 
 Backward compatibility
 ======================
 
 There is no backward incompatible change. The default behaviour is unchanged:
-close-on-exec is not set by default.
+the close-on-exec flag is not set by default.
 
 
 Alternatives
 open(): add "e" flag to mode
 ----------------------------
 
-Since its version 2.7, the GNU libc supports "e" flag for fopen(). It uses
-``O_CLOEXEC`` if available, or use ``fcntl(fd, F_SETFD, flags | FD_CLOEXEC)``.
+A new "e" mode would set close-on-exec flag (best-effort).
 
 This API doesn't allow to disable explictly close-on-exec flag if it was
-enabled globally with sys.setdefaultcloexec().
+enabled globally with ``sys.setdefaultcloexec()``.
+
+Note: Since its version 2.7, the GNU libc supports ``"e"`` flag for ``fopen()``.
+It uses ``O_CLOEXEC`` if available, or use ``fcntl(fd, F_SETFD, FD_CLOEXEC)``.
+
 
 
 Appendix: Operating system support
 Windows
 -------
 
-Windows has an ``O_NOINHERIT`` flag: "Don't inherit in child processes".  For
-example, it is supported by ``open()`` and ``_pipe()``. The value of the flag
-can be modified on a file descriptor using:
+Windows has an ``O_NOINHERIT`` flag: "Don't inherit in child processes".
+
+For example, it is supported by ``open()`` and ``_pipe()``.
+
+The value of the flag can be modified using:
 ``SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 1)``.
 
 fcntl
 -----
 
+Functions:
+
  * ``fcntl(fd, F_GETFD)``
  * ``fcntl(fd, F_SETFD, flags | FD_CLOEXEC)``
 
-Available on:
-
- * AIX 4.2
- * Digital UNIX 4.0
- * FreeBSD 8.2
- * HP-UX 11
- * IRIX 6.5
- * Linux 2.0
- * Mac OS X 10.8
- * OpenBSD 4.9
- * Solaris 8
- * SunOS 4.1.1_U1
- * Unicos 9.0
+Availability: AIX, Digital UNIX, FreeBSD, HP-UX, IRIX, Linux, Mac OS X,
+OpenBSD, Solaris, SunOS, Unicos.
 
 Note: OpenBSD older 5.2 does not close the file descriptor if fork() is used
 before exec(), but it works correctly if exec() is called without fork().
 ioctl
 -----
 
- * ``ioctl(fd, FIOCLEX, 0);`` sets close-on-exec flag
- * ``ioctl(fd, FIONCLEX, 0);`` unsets close-on-exec flag
+Functions:
+
+ * ``ioctl(fd, FIOCLEX, 0)`` sets close-on-exec flag
+ * ``ioctl(fd, FIONCLEX, 0)`` unsets close-on-exec flag
 
 Availability: Linux, Mac OS X, QNX, NetBSD, OpenBSD, FreeBSD.
 
 
 New flags:
 
- * ``O_CLOEXEC``: available on Linux (2.6.23+), FreeBSD (8.3+). Part of POSIX.1-2008.
+ * ``O_CLOEXEC``: available on Linux (2.6.23+), FreeBSD (8.3+).
+   The flag is part of POSIX.1-2008.
  * ``socket()``: ``SOCK_CLOEXEC`` flag, available on Linux 2.6.27+
  * ``fcntl()``: ``F_DUPFD_CLOEXEC`` flag, available on Linux ???
  * ``recvmsg()``: ``MSG_CMSG_CLOEXEC``, available on Linux ???