cpython: ef889c3d5dc6 (original) (raw)

--- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -979,6 +979,8 @@ are always available. They are listed h :mod:os.open as opener results in functionality similar to passing None).

@@ -992,10 +994,6 @@ are always available. They are listed h ... >>> os.close(dir_fd) # don't leak a file descriptor

- The type of :term:file object returned by the :func:open function depends on the mode. When :func:open is used to open a file in a text mode ('w', 'r', 'wt', 'rt', etc.), it returns a subclass of @@ -1022,10 +1020,15 @@ are always available. They are listed h and :mod:shutil. .. versionchanged:: 3.3

+ .. XXX works for bytes too, but should it? .. function:: ord(c)

--- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -522,6 +522,8 @@ Raw File I/O :mod:os.open as opener results in functionality similar to passing None).

@@ -529,6 +531,9 @@ Raw File I/O The opener parameter was added. The 'x' mode was added.

+ In addition to the attributes and methods from :class:IOBase and :class:RawIOBase, :class:FileIO provides the following data attributes:

--- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -685,17 +685,30 @@ as internal buffering of data. .. function:: dup(fd)

- -.. function:: dup2(fd, fd2)

+ + +.. function:: dup2(fd, fd2, inheritable=True) Duplicate file descriptor fd to fd2, closing the latter first if necessary.

+ .. function:: fchmod(fd, mode) @@ -848,6 +861,7 @@ as internal buffering of data. Open the file file and set various flags according to flags and possibly its mode according to mode. When computing mode, the current umask value is first masked out. Return the file descriptor for the newly opened file.

+ .. note:: This function is intended for low-level I/O. For normal usage, use the @@ -933,20 +950,28 @@ or `the MSDN <http://msdn.microsoft.com/[](#l3.55) .. index:: module: pty

+ .. function:: pipe()

+ .. function:: pipe2(flags) @@ -1178,6 +1203,50 @@ Querying the size of a terminal Height of the terminal window in characters. +.. _fd_inheritance: + +Inheritance of File Descriptors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A file descriptor has a inheritable flag which indicates if the file descriptor +can be inherited or not in child processes. Since Python 3.4, file descriptors +created by Python are non-inheritable by default. + +On UNIX, non-inheritable file descriptors are closed in child processes at the +execution of a new program, other file descriptors are inherited. + +On Windows, non-inheritable handles and file descriptors are closed in child +processes, except standard streams (file descriptors 0, 1 and 2: stdin, stdout +and stderr) which are always inherited. Using :func:os.spawn* functions, +all inheritable handles and all inheritable file descriptors are inherited. +Using the :mod:subprocess module, all file descriptors except standard +streams are closed, inheritable handles are only inherited if the close_fds +parameter is False. + +.. versionadded:: 3.4 + +.. function:: get_inheritable(fd) +

+.. function:: set_inheritable(fd, inheritable) +

+.. function:: get_handle_inheritable(handle) +

+.. function:: set_handle_inheritable(handle, inheritable) +

+ .. _os-file-dir: Files and Directories

--- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -37,8 +37,13 @@ The module defines the following: increases this value, :c:func:devpoll may return an incomplete list of active file descriptors.

+ .. function:: epoll(sizehint=-1, flags=0) (Only supported on Linux 2.5.44 and newer.) Return an edge polling object, @@ -49,11 +54,14 @@ The module defines the following: :ref:epoll-objects below for the methods supported by epolling objects. They also support the :keyword:with statement.

.. function:: poll() @@ -69,6 +77,11 @@ The module defines the following: (Only supported on BSD.) Returns a kernel queue object; see section :ref:kqueue-objects below for the methods supported by kqueue objects.

+ .. function:: kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0)

--- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -460,7 +460,7 @@ The module :mod:socket exports the fol 'udp', otherwise any protocol will match. -.. function:: socket([family[, type[, proto]]]) +.. function:: socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) Create a new socket using the given address family, socket type and protocol number. The address family should be :const:AF_INET (the default), @@ -471,12 +471,18 @@ The module :mod:socket exports the fol case where the address family is :const:AF_CAN the protocol should be one of :const:CAN_RAW or :const:CAN_BCM.

+

+ .. function:: socketpair([family[, type[, proto]]]) @@ -486,12 +492,17 @@ The module :mod:socket exports the fol if defined on the platform; otherwise, the default is :const:AF_INET. Availability: Unix.

-.. function:: fromfd(fd, family, type[, proto]) + +.. function:: fromfd(fd, family, type, proto=0) Duplicate the file descriptor fd (an integer as returned by a file object's :meth:fileno method) and build a socket object from the result. Address @@ -502,6 +513,11 @@ The module :mod:socket exports the fol a socket passed to a program as standard input or output (such as a server started by the Unix inet daemon). The socket is assumed to be in blocking mode.

+ .. function:: ntohl(x) @@ -730,6 +746,11 @@ correspond to Unix system calls applicab new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.

+ .. method:: socket.bind(address) @@ -775,6 +796,16 @@ correspond to Unix system calls applicab .. versionadded:: 3.2 +.. method:: socket.dup() +

+ + .. method:: socket.fileno() Return the socket's file descriptor (a small integer). This is useful with @@ -785,6 +816,15 @@ correspond to Unix system calls applicab this limitation. +.. method:: socket.get_inheritable() +

+ .. method:: socket.getpeername() Return the remote address to which the socket is connected. This is useful to @@ -1068,6 +1108,14 @@ correspond to Unix system calls applicab .. versionadded:: 3.3 +.. method:: socket.set_inheritable(inheritable) +

+ .. method:: socket.setblocking(flag) Set blocking or non-blocking mode of the socket: if flag is false, the

--- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -96,6 +96,7 @@ New built-in features:

--- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -27,11 +27,19 @@ PyAPI_FUNC(int) _Py_stat( struct stat *statbuf); #endif +PyAPI_FUNC(int) _Py_open(

+ PyAPI_FUNC(FILE *) _Py_wfopen( const wchar_t *path, const wchar_t mode); PyAPI_FUNC(FILE) _Py_fopen(

+ +PyAPI_FUNC(FILE*) _Py_fopen_obj( PyObject *path, const char mode); @@ -53,6 +61,13 @@ PyAPI_FUNC(wchar_t) _Py_wgetcwd( wchar_t *buf, size_t size); +PyAPI_FUNC(int) _Py_get_inheritable(int fd); + +PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable,

+ +PyAPI_FUNC(int) _Py_dup(int fd); + #ifdef __cplusplus } #endif

--- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -129,6 +129,8 @@ def open(file, mode="r", buffering=-1, e be kept open when the file is closed. This does not work when a file name is given and must be True in that case.

+ A custom opener can be used by passing a callable as opener. The underlying file descriptor for the file object is then obtained by calling opener with (file, flags). opener must return an open file

--- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -509,7 +509,7 @@ if sys.platform != 'win32': c1 = Connection(s1.detach()) c2 = Connection(s2.detach()) else:

@@ -536,7 +536,9 @@ else: _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE, _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | _winapi.PIPE_WAIT,

--- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -60,8 +60,8 @@ def connect_to_new_process(fds): raise ValueError('too many fds') with socket.socket(socket.AF_UNIX) as client: client.connect(_forkserver_address)

--- a/Lib/multiprocessing/popen_fork.py +++ b/Lib/multiprocessing/popen_fork.py @@ -66,7 +66,7 @@ class Popen(object): def _launch(self, process_obj): code = 1

--- a/Lib/multiprocessing/popen_spawn_posix.py +++ b/Lib/multiprocessing/popen_spawn_posix.py @@ -54,8 +54,8 @@ class Popen(popen_fork.Popen): parent_r = child_w = child_r = parent_w = None try:

--- a/Lib/multiprocessing/semaphore_tracker.py +++ b/Lib/multiprocessing/semaphore_tracker.py @@ -45,7 +45,7 @@ def ensure_running(): except Exception: pass cmd = 'from multiprocessing.semaphore_tracker import main; main(%d)'

--- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -365,7 +365,7 @@ def spawnv_passfds(path, args, passfds): if flag & fcntl.FD_CLOEXEC: fcntl.fcntl(fd, fcntl.F_SETFD, flag & ~fcntl.FD_CLOEXEC) tmp.append((fd, flag))

@@ -381,7 +381,9 @@ def spawnv_passfds(path, args, passfds): #

Return pipe with CLOEXEC set on fds

# +# Deprecated: os.pipe() creates non-inheritable file descriptors +# since Python 3.4 +# def pipe():

--- a/Lib/socket.py +++ b/Lib/socket.py @@ -137,7 +137,8 @@ class socket(_socket.socket): def dup(self): """dup() -> socket object

@@ -229,6 +230,20 @@ class socket(_socket.socket): self._closed = True return super().detach()

+ + def fromfd(fd, family, type, proto=0): """ fromfd(fd, family, type[, proto]) -> socket object

--- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -405,7 +405,6 @@ else: import select _has_poll = hasattr(select, 'poll') import _posixsubprocess

# When select or poll has indicated that the file is writable, # we can write up to _PIPE_BUF bytes without risk of blocking. @@ -1258,7 +1257,7 @@ class Popen(object): if stdin is None: pass elif stdin == PIPE:

@@ -1270,7 +1269,7 @@ class Popen(object): if stdout is None: pass elif stdout == PIPE:

@@ -1282,7 +1281,7 @@ class Popen(object): if stderr is None: pass elif stderr == PIPE:

@@ -1334,7 +1333,7 @@ class Popen(object): # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation.

--- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -35,33 +35,12 @@ import errno as _errno from random import Random as _Random try:

-except ImportError:

-else:

- - -try: import _thread except ImportError: import _dummy_thread as _thread _allocate_lock = _thread.allocate_lock _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL -if hasattr(_os, 'O_CLOEXEC'):

-if hasattr(_os, 'O_NOINHERIT'):

if hasattr(_os, 'O_NOFOLLOW'): _text_openflags |= _os.O_NOFOLLOW @@ -90,8 +69,8 @@ else: # Fallback. All we need is something that raises OSError if the # file doesn't exist. def _stat(fn):

def _exists(fn): try: @@ -217,7 +196,6 @@ def _mkstemp_inner(dir, pre, suf, flags) file = _os.path.join(dir, pre + name + suf) try: fd = _os.open(file, flags, 0o600)

new file mode 100644 --- /dev/null +++ b/Lib/test/subprocessdata/inherited.py @@ -0,0 +1,22 @@ +"""Similar to fd_status.py, but only checks file descriptors passed on the +command line.""" + +import errno +import os +import sys +import stat + +if name == "main":

--- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -744,7 +744,12 @@ class BaseTestAPI: s.create_socket(self.family) self.assertEqual(s.socket.family, self.family) SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)

def test_bind(self): if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:

--- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1015,6 +1015,11 @@ class BuiltinTest(unittest.TestCase): os.environ.clear() os.environ.update(old_environ)

+ def test_ord(self): self.assertEqual(ord(' '), 32) self.assertEqual(ord('A'), 65)

--- a/Lib/test/test_devpoll.py +++ b/Lib/test/test_devpoll.py @@ -2,7 +2,11 @@

Initial tests are copied as is from "test_poll.py"

-import os, select, random, unittest, sys +import os +import random +import select +import sys +import unittest from test.support import TESTFN, run_unittest try: @@ -111,6 +115,11 @@ class DevPollTests(unittest.TestCase): self.assertRaises(ValueError, devpoll.register, fd, fd, select.POLLIN) self.assertRaises(ValueError, devpoll.unregister, fd)

+ def test_main(): run_unittest(DevPollTests)

--- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -21,10 +21,11 @@ """ Tests for epoll wrapper. """ +import errno +import os +import select import socket -import errno import time -import select import unittest from test import support @@ -249,6 +250,11 @@ class TestEPoll(unittest.TestCase): self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN) self.assertRaises(ValueError, epoll.unregister, fd)

+ def test_main(): support.run_unittest(TestEPoll)

--- a/Lib/test/test_kqueue.py +++ b/Lib/test/test_kqueue.py @@ -206,6 +206,11 @@ class TestKQueue(unittest.TestCase): # operations must fail with ValueError("I/O operation on closed ...") self.assertRaises(ValueError, kqueue.control, None, 4)

+ def test_main(): support.run_unittest(TestKQueue)

--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2298,6 +2298,72 @@ class CPUCountTests(unittest.TestCase): else: self.skipTest("Could not determine the number of CPUs") + +class FDInheritanceTests(unittest.TestCase):

+

+

+

+

+

+

+

+

+

+ + @support.reap_threads def test_main(): support.run_unittest( @@ -2330,6 +2396,7 @@ def test_main(): OSErrorTests, RemoveDirsTests, CPUCountTests,

--- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -23,10 +23,6 @@ import math import pickle import struct try:

-except ImportError:

-try: import multiprocessing except ImportError: multiprocessing = False @@ -1108,9 +1104,15 @@ class GeneralModuleTests(unittest.TestCa def testNewAttributes(self): # testing .family, .type and .protocol + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.assertEqual(sock.family, socket.AF_INET)

@@ -4749,16 +4751,46 @@ class ContextManagersTest(ThreadedTCPSoc self.assertRaises(OSError, sock.sendall, b'foo') -@unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),

-@unittest.skipUnless(fcntl, "module fcntl not available") -class CloexecConstantTest(unittest.TestCase): +class InheritanceTest(unittest.TestCase):

+

+

+

+

+

@unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"), @@ -4927,7 +4959,7 @@ def test_main(): NetworkConnectionAttributesTest, NetworkConnectionBehaviourTest, ContextManagersTest,

--- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1501,16 +1501,28 @@ class POSIXProcessTestCase(BaseTestCase) # Terminating a dead process self._kill_dead_process('terminate')

+

+ def check_close_std_fds(self, fds): # Issue #9905: test that subprocess pipes still work properly with # some standard fds closed stdin = 0

@@ -1525,10 +1537,7 @@ class POSIXProcessTestCase(BaseTestCase) err = support.strip_python_stderr(err) self.assertEqual((out, err), (b'apple', b'orange')) finally:

def test_close_fd_0(self): self.check_close_std_fds([0]) @@ -1568,7 +1577,7 @@ class POSIXProcessTestCase(BaseTestCase) os.lseek(temp_fds[1], 0, 0) # move the standard file descriptors out of the way

@@ -1584,10 +1593,7 @@ class POSIXProcessTestCase(BaseTestCase) stderr=temp_fds[0]) p.wait() finally:

for fd in temp_fds: os.lseek(fd, 0, 0) @@ -1611,7 +1617,7 @@ class POSIXProcessTestCase(BaseTestCase) os.unlink(fname) # save a copy of the standard file descriptors

@@ -1637,9 +1643,7 @@ class POSIXProcessTestCase(BaseTestCase) out = os.read(stdout_no, 1024) err = support.strip_python_stderr(os.read(stderr_no, 1024)) finally:

self.assertEqual(out, b"got STDIN") self.assertEqual(err, b"err") @@ -1810,6 +1814,9 @@ class POSIXProcessTestCase(BaseTestCase) self.addCleanup(os.close, fd) open_fds.add(fd)

+ p = subprocess.Popen([sys.executable, fd_status], stdout=subprocess.PIPE, close_fds=False) output, ignored = p.communicate() @@ -1854,6 +1861,8 @@ class POSIXProcessTestCase(BaseTestCase) fds = os.pipe() self.addCleanup(os.close, fds[0]) self.addCleanup(os.close, fds[1])

for fd in open_fds: @@ -1876,6 +1885,32 @@ class POSIXProcessTestCase(BaseTestCase) close_fds=False, pass_fds=(fd, ))) self.assertIn('overriding close_fds', str(context.warning))

+

+

+

+

+ def test_stdout_stdin_are_single_inout_fd(self): with io.open(os.devnull, "r+") as inout: p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],

--- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -333,6 +333,7 @@ class TestMkstempInner(BaseTestCase): v="q" file = self.do_create()

try:

--- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -584,13 +584,6 @@ class SimpleXMLRPCServer(socketserver.TC SimpleXMLRPCDispatcher.init(self, allow_none, encoding, use_builtin_types) socketserver.TCPServer.init(self, addr, requestHandler, bind_and_activate)

class MultiPathXMLRPCServer(SimpleXMLRPCServer): """Multipath XML-RPC Server

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Projected Release date: 2013-09-08 Core and Builtins ----------------- +- Issue #18571: Implementation of the PEP 446: file descriptors and file

--- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1694,26 +1694,24 @@ PyCursesWindow_PutWin(PyCursesWindowObje /* We have to simulate this by writing to a temporary FILE*, then reading back, then writing to the argument stream. */ char fn[100];

strcpy(fn, "/tmp/py.curses.putwin.XXXXXX"); fd = mkstemp(fn); if (fd < 0) return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);

@@ -1727,7 +1725,12 @@ PyCursesWindow_PutWin(PyCursesWindowObje if (res == NULL) break; }

+ +exit:

PyCursesInitialised; @@ -2265,44 +2269,47 @@ PyCurses_GetWin(PyCursesWindowObject *se fd = mkstemp(fn); if (fd < 0) return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);

+ +error:

} static PyObject *

--- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -202,6 +202,9 @@ check_fd(int fd) return 0; } +#ifdef O_CLOEXEC +extern int _Py_open_cloexec_works; +#endif static int fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) @@ -221,6 +224,11 @@ fileio_init(PyObject *oself, PyObject *a int fd = -1; int closefd = 1; int fd_is_own = 0; +#ifdef O_CLOEXEC

+#elif !defined(MS_WINDOWS)

+#endif assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -345,6 +353,11 @@ fileio_init(PyObject *oself, PyObject *a if (append) flags |= O_APPEND; #endif +#ifdef MS_WINDOWS

+#elif defined(O_CLOEXEC)

+#endif if (fd >= 0) { if (check_fd(fd)) @@ -369,10 +382,18 @@ fileio_init(PyObject *oself, PyObject *a else #endif self->fd = open(name, flags, 0666); + Py_END_ALLOW_THREADS

+ +#ifndef MS_WINDOWS

+#endif +

@@ -394,6 +415,11 @@ fileio_init(PyObject *oself, PyObject *a PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } + +#ifndef MS_WINDOWS

+#endif } if (dircheck(self, nameobj) < 0) goto error;

--- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -35,7 +35,7 @@

define FD_DIR "/proc/self/fd"

#endif -#define POSIX_CALL(call) if ((call) == -1) goto error +#define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0) /* Maximum file descriptor, initialized on module load. */ @@ -87,7 +87,7 @@ static int if (stat("/dev", &dev_stat) != 0) return 0; if (stat(FD_DIR, &dev_fd_stat) != 0)

+

+} + /* Close all file descriptors in the range start_fd inclusive to

-#ifdef O_CLOEXEC

-#else

-#ifdef FD_CLOEXEC

-#endif -#endif +

@@ -356,16 +369,16 @@ child_exec(char const exec_array[], / Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1];

+ /* Close parent's pipe ends. */

+ if (c2pwrite == 1) {

+ if (errwrite == 2) {

/* Close pipe fds. Make sure we don't close the same fd more than / / once, or standard fds. */

if (cwd) POSIX_CALL(chdir(cwd)); @@ -544,7 +553,7 @@ subprocess_fork_exec(PyObject* self, PyO PyObject *result; _Py_IDENTIFIER(isenabled); _Py_IDENTIFIER(disable);

+ gc_module = PyImport_ImportModule("gc"); if (gc_module == NULL) return NULL; @@ -721,52 +730,6 @@ Returns: the child process's PID.\n[](#l32.160) Raises: Only on an error in the parent process.\n[](#l32.161) "); -PyDoc_STRVAR(subprocess_cloexec_pipe_doc, -"cloexec_pipe() -> (read_end, write_end)\n\n[](#l32.165) -Create a pipe whose ends have the cloexec flag set."); - -static PyObject * -subprocess_cloexec_pipe(PyObject *self, PyObject *noargs) -{

-#ifdef HAVE_PIPE2

-#endif

-

-

-

-#ifdef HAVE_PIPE2

-#endif

-} - /* module level code ********************************************************/ PyDoc_STRVAR(module_doc, @@ -775,7 +738,6 @@ PyDoc_STRVAR(module_doc, static PyMethodDef module_methods[] = { {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},

--- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2350,7 +2350,7 @@ load_dh_params(PySSLContext *self, PyObj FILE *f; DH *dh;

--- a/Modules/main.c +++ b/Modules/main.c @@ -143,7 +143,7 @@ static void RunStartupFile(PyCompilerFla { char *startup = Py_GETENV("PYTHONSTARTUP"); if (startup != NULL && startup[0] != '\0') {

--- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1208,18 +1208,18 @@ new_mmap_object(PyTypeObject type, PyOb flags |= MAP_ANONYMOUS; #else / SVR4 method to map anonymous memory is to open /dev/zero */

#endif

--- a/Modules/ossaudiodev.c +++ b/Modules/ossaudiodev.c @@ -115,7 +115,9 @@ newossobject(PyObject *arg) one open at a time. This does not affect later I/O; OSS provides a special ioctl() for non-blocking read/write, which is exposed via oss_nonblock() below. */

+

--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3535,10 +3535,7 @@ static PyObject #ifdef HAVE_FDOPENDIR if (path->fd != -1) { / closedir() closes the FD, so we duplicate it */

-

@@ -5768,7 +5765,7 @@ Open a pseudo-terminal, returning open f static PyObject * posix_openpty(PyObject *self, PyObject *noargs) {

#ifndef HAVE_OPENPTY char * slave_name; #endif @@ -5781,37 +5778,52 @@ posix_openpty(PyObject *self, PyObject * #ifdef HAVE_OPENPTY if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)

+

+ #elif defined(HAVE__GETPTY) slave_name = _getpty(&master_fd, O_RDWR, 0666, 0); if (slave_name == NULL)

-

+

-#else

+ +#else

+ sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL); + /* change permission of slave */ if (grantpt(master_fd) < 0) { PyOS_setsig(SIGCHLD, sig_saved);

+ /* unlock slave */ if (unlockpt(master_fd) < 0) { PyOS_setsig(SIGCHLD, sig_saved);

+ PyOS_setsig(SIGCHLD, sig_saved); + slave_name = ptsname(master_fd); /* get name of slave */ if (slave_name == NULL)

+

#if !defined(CYGWIN) && !defined(HAVE_DEV_PTC) ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem / ioctl(slave_fd, I_PUSH, "ldterm"); / push ldterm */ @@ -5823,6 +5835,14 @@ posix_openpty(PyObject *self, PyObject * return Py_BuildValue("(ii)", master_fd, slave_fd); +posix_error:

+error:

} #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ @@ -7432,6 +7452,10 @@ posix_tcsetpgrp(PyObject self, PyObject / Functions acting on file descriptors */ +#ifdef O_CLOEXEC +extern int Py_open_cloexec_works; +#endif + PyDoc_STRVAR(posix_open__doc_, "open(path, flags, mode=0o777, *, dir_fd=None)\n\n[](#l37.116) Open a file for low level IO. Returns a file handle (integer).\n[](#l37.117) @@ -7451,6 +7475,11 @@ posix_open(PyObject *self, PyObject *arg int fd; PyObject *return_value = NULL; static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL}; +#ifdef O_CLOEXEC

+#elif !defined(MS_WINDOWS)

+#endif memset(&path, 0, sizeof(path)); path.function_name = "open"; @@ -7465,6 +7494,12 @@ posix_open(PyObject *self, PyObject *arg )) return NULL; +#ifdef MS_WINDOWS

+#elif defined(O_CLOEXEC)

+#endif + Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS if (path.wide) @@ -7484,6 +7519,13 @@ posix_open(PyObject *self, PyObject *arg goto exit; } +#ifndef MS_WINDOWS

+#endif + return_value = PyLong_FromLong((long)fd); exit: @@ -7540,13 +7582,14 @@ static PyObject * posix_dup(PyObject *self, PyObject *args) { int fd; + if (!PyArg_ParseTuple(args, "i:dup", &fd)) return NULL;

+ return PyLong_FromLong((long)fd); } @@ -7556,16 +7599,82 @@ PyDoc_STRVAR(posix_dup2__doc__, Duplicate file descriptor."); static PyObject * -posix_dup2(PyObject *self, PyObject *args) -{

+posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs) +{

+#if defined(HAVE_DUP3) && [](#l37.192)

+#endif +

+ if (!_PyVerify_fd_dup2(fd, fd2)) return posix_error(); + +#ifdef MS_WINDOWS

+

+ +#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)

+ +#else + +#ifdef HAVE_DUP3

+

+#endif

+

+#ifdef HAVE_DUP3

+#endif + +#endif + Py_INCREF(Py_None); return Py_None; } @@ -8052,24 +8161,69 @@ Create a pipe."); static PyObject * posix_pipe(PyObject *self, PyObject *noargs) { -#if !defined(MS_WINDOWS) int fds[2]; +#ifdef MS_WINDOWS

+#else int res;

-#else /* MS_WINDOWS */

+#endif + +#ifdef MS_WINDOWS

+

+ if (!ok) return PyErr_SetFromWindowsErr(0);

-#endif /* MS_WINDOWS */ +#else + +#ifdef HAVE_PIPE2

+

+#endif

+

+#ifdef HAVE_PIPE2

+#endif +

+#endif /* !MS_WINDOWS */

} #endif /* HAVE_PIPE */ @@ -10659,6 +10813,102 @@ posix_cpu_count(PyObject *self) Py_RETURN_NONE; } +PyDoc_STRVAR(get_inheritable__doc__,

+ +static PyObject* +posix_get_inheritable(PyObject *self, PyObject *args) +{

+

+

+

+} + +PyDoc_STRVAR(set_inheritable__doc__,

+ +static PyObject* +posix_set_inheritable(PyObject *self, PyObject *args) +{

+

+

+

+} + + +#ifdef MS_WINDOWS +PyDoc_STRVAR(get_handle_inheritable__doc__,

+ +static PyObject* +posix_get_handle_inheritable(PyObject *self, PyObject *args) +{

+

+

+

+} + +PyDoc_STRVAR(set_handle_inheritable__doc__,

+ +static PyObject* +posix_set_handle_inheritable(PyObject *self, PyObject *args) +{

+

+

+} +#endif /* MS_WINDOWS */ + static PyMethodDef posix_methods[] = { {"access", (PyCFunction)posix_access, @@ -10934,7 +11184,8 @@ static PyMethodDef posix_methods[] = { {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__}, {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__}, {"dup", posix_dup, METH_VARARGS, posix_dup__doc__},

#ifdef HAVE_LOCKF {"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__}, #endif @@ -11105,6 +11356,14 @@ static PyMethodDef posix_methods[] = { #endif {"cpu_count", (PyCFunction)posix_cpu_count, METH_NOARGS, posix_cpu_count__doc__},

+#ifdef MS_WINDOWS

+#endif {NULL, NULL} /* Sentinel */ };

--- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1004,7 +1004,7 @@ newDevPollObject(void) */ limit_result = getrlimit(RLIMIT_NOFILE, &limit); if (limit_result != -1)

#ifdef HAVE_EPOLL_CREATE1

@@ -1209,6 +1210,14 @@ newPyEpoll_Object(PyTypeObject *type, in PyErr_SetFromErrno(PyExc_OSError); return NULL; } + +#ifndef HAVE_EPOLL_CREATE1

+#endif + return (PyObject *)self; } @@ -1896,13 +1905,19 @@ newKqueue_Object(PyTypeObject *type, SOC PyErr_SetFromErrno(PyExc_OSError); return NULL; } +

static PyObject * kqueue_queue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - if ((args != NULL && PyObject_Size(args)) || (kwds != NULL && PyObject_Size(kwds))) { PyErr_SetString(PyExc_ValueError,

--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -97,13 +97,14 @@ Local naming conventions: /* Socket object documentation / PyDoc_STRVAR(sock_doc, -"socket([family[, type[, proto]]]) -> socket object\n[](#l39.7) +"socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) -> socket object\n[](#l39.8) \n[](#l39.9) Open a socket of the given type. The family argument specifies the\n[](#l39.10) address family; it defaults to AF_INET. The type argument specifies\n[](#l39.11) whether this is a stream (SOCK_STREAM, this is the default)\n[](#l39.12) or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n[](#l39.13) specifying the default protocol. Keyword arguments are accepted.\n[](#l39.14) +The socket is created as non-inheritable.\n[](#l39.15) \n[](#l39.16) A socket object represents one endpoint of a network connection.\n[](#l39.17) \n[](#l39.18) @@ -114,7 +115,7 @@ bind(addr) -- bind the socket to a local close() -- close the socket\n[](#l39.20) connect(addr) -- connect the socket to a remote address\n[](#l39.21) connect_ex(addr) -- connect, return an error code instead of an exception\n[](#l39.22) -_dup() -- return a new socket fd duplicated from fileno()\n[](#l39.23) +dup() -- return a new socket fd duplicated from fileno()\n[](#l39.24) fileno() -- return underlying file descriptor\n[](#l39.25) getpeername() -- return remote address []\n[](#l39.26) getsockname() -- return local address\n[](#l39.27) @@ -356,22 +357,7 @@ const char inet_ntop(int af, const void #endif #ifdef MS_WINDOWS -/ On Windows a socket is really a handle not an fd */ -static SOCKET -dup_socket(SOCKET handle) -{

-

-

-} #define SOCKETCLOSE closesocket -#else -/* On Unix we can use dup to duplicate the file descriptor of a socket*/ -#define dup_socket(fd) dup(fd) #endif #ifdef MS_WIN32 @@ -499,6 +485,11 @@ select_error(void) (errno == expected) #endif +#ifdef MS_WINDOWS +/* Does WSASocket() support the WSA_FLAG_NO_HANDLE_INHERIT flag? / +static int support_wsa_no_inherit = -1; +#endif + / Convenience function to raise an error according to errno and return a NULL pointer from a function. */ @@ -1955,6 +1946,11 @@ sock_accept(PySocketSockObject *s) PyObject *addr = NULL; PyObject *res = NULL; int timeout; +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)

+#endif + if (!getsockaddrlen(s, &addrlen)) return NULL; memset(&addrbuf, 0, addrlen); @@ -1963,10 +1959,24 @@ sock_accept(PySocketSockObject *s) return select_error(); BEGIN_SELECT_LOOP(s) + Py_BEGIN_ALLOW_THREADS timeout = internal_select_ex(s, 0, interval); if (!timeout) { +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)

+#else newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); +#endif } Py_END_ALLOW_THREADS @@ -1979,6 +1989,25 @@ sock_accept(PySocketSockObject *s) if (newfd == INVALID_SOCKET) return s->errorhandler(); +#ifdef MS_WINDOWS

+#else + +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)

+#endif

+#endif + sock = PyLong_FromSocket_t(newfd); if (sock == NULL) { SOCKETCLOSE(newfd); @@ -3909,6 +3938,12 @@ sock_new(PyTypeObject *type, PyObject a / Initialize a new socket object. / +#ifdef SOCK_CLOEXEC +/ socket() and socketpair() fail with EINVAL on Linux kernel older

+#else

+#endif +#endif if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiO:socket", keywords, @@ -3962,14 +4004,74 @@ sock_initobj(PyObject *self, PyObject *a } } else { +#ifdef MS_WINDOWS

+#ifndef WSA_FLAG_NO_HANDLE_INHERIT +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + Py_BEGIN_ALLOW_THREADS

if (fd == INVALID_SOCKET) { set_error(); return -1; } +

+#else

+#ifdef SOCK_CLOEXEC

+#endif

+

+

+#endif } init_sockobject(s, fd, family, type, proto); @@ -4535,16 +4637,36 @@ socket_dup(PyObject *self, PyObject *fdo { SOCKET_T fd, newfd; PyObject *newfdobj; - +#ifdef MS_WINDOWS

+#endif fd = PyLong_AsSocket_t(fdobj); if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) return NULL;

+#ifdef MS_WINDOWS

+

+#else

+#endif + newfdobj = PyLong_FromSocket_t(newfd); if (newfdobj == NULL) SOCKETCLOSE(newfd); @@ -4572,6 +4694,12 @@ socket_socketpair(PyObject *self, PyObje SOCKET_T sv[2]; int family, type = SOCK_STREAM, proto = 0; PyObject *res = NULL; +#ifdef SOCK_CLOEXEC

+#else

+#endif

#if defined(AF_UNIX) family = AF_UNIX; @@ -4581,9 +4709,38 @@ socket_socketpair(PyObject self, PyObje if (!PyArg_ParseTuple(args, "|iii:socketpair", &family, &type, &proto)) return NULL; + / Create a pair of socket fds */

+#ifdef SOCK_CLOEXEC

+#endif

+

+

+ s0 = new_sockobject(sv[0], family, type, proto); if (s0 == NULL) goto finally; @@ -4605,7 +4762,7 @@ finally: } PyDoc_STRVAR(socketpair_doc, -"socketpair([family[, type[, proto]]]) -> (socket object, socket object)\n[](#l39.325) +"socketpair([family[, type [, proto]]]) -> (socket object, socket object)\n[](#l39.326) \n[](#l39.327) Create a pair of socket objects from the sockets returned by the platform\n[](#l39.328) socketpair() function.\n[](#l39.329) @@ -5539,6 +5696,16 @@ PyInit__socket(void) if (!os_init()) return NULL; +#ifdef MS_WINDOWS

+#endif + Py_TYPE(&sock_type) = &PyType_Type; m = PyModule_Create(&socketmodule); if (m == NULL)

--- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -870,7 +870,7 @@ read_directory(PyObject *archive) const char *charset; int bootstrap;

@@ -1064,7 +1064,7 @@ get_data(PyObject *archive, PyObject *to return NULL; }

--- a/PC/_msi.c +++ b/PC/_msi.c @@ -55,7 +55,7 @@ static FNFCIFREE(cb_free) static FNFCIOPEN(cb_open) {

} static PyObject* fcicreate(PyObject* obj, PyObject* args)

--- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -743,7 +743,7 @@ do_run_installscript(HINSTANCE hPython, if (pathname == NULL || pathname[0] == '\0') return 2;

--- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1730,10 +1730,15 @@ PyTokenizer_FindEncodingFilename(int fd, FILE *fp; char *p_start =NULL , *p_end =NULL , *encoding = NULL; +#ifndef PGEN

+#else fd = dup(fd); +#endif if (fd < 0) { return NULL; } + fp = fdopen(fd, "r"); if (fp == NULL) { return NULL;

--- a/Python/errors.c +++ b/Python/errors.c @@ -1042,7 +1042,7 @@ PyErr_ProgramText(const char *filename, FILE *fp; if (filename == NULL || *filename == '\0' || lineno <= 0) return NULL;

@@ -1052,7 +1052,7 @@ PyErr_ProgramTextObject(PyObject *filena FILE *fp; if (filename == NULL || lineno <= 0) return NULL;

--- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -9,10 +9,29 @@ #include <langinfo.h> #endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H / + #ifdef APPLE extern wchar_t _Py_DecodeUTF8_surrogateescape(const char s, Py_ssize_t size); #endif +#ifdef O_CLOEXEC +/ Does open() supports the O_CLOEXEC flag? Possible values: +

+

PyObject * _Py_device_encoding(int fd) { @@ -547,14 +566,215 @@ int #endif +int +get_inheritable(int fd, int raise) +{ +#ifdef MS_WINDOWS

+

+

+

+

+#else

+

+#endif +} + +/* Get the inheritable flag of the specified file descriptor.

+} + +static int +set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) +{ +#ifdef MS_WINDOWS

+#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)

+#elif defined(HAVE_FCNTL_H)

+#endif +

+

+

+ +#ifdef MS_WINDOWS

+

+

+ +#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)

+ +#else

+

+#endif +} + +/* Make the file descriptor non-inheritable.

+} + +/* Set the inheritable flag of the specified file descriptor.

+

+} + +/* Open a file with the specified flags (wrapper to open() function).

+#ifdef MS_WINDOWS

+#else +

+#ifdef O_CLOEXEC

+#else

+#endif

+

+#endif /* !MS_WINDOWS */

+} + /* Open a file. Use _wfopen() on Windows, encode the path to the locale

#ifndef MS_WINDOWS

+#endif

-#endif } -/* Call _wfopen() on Windows, or encode the path to the filesystem encoding and

+} + +/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem

#ifdef MS_WINDOWS wchar_t wpath; wchar_t wmode[10]; @@ -602,16 +843,21 @@ FILE if (usize == 0) return NULL;

#else

#ifdef HAVE_READLINK @@ -729,3 +975,72 @@ wchar_t* #endif } +/* Duplicate a file descriptor. The new file descriptor is created as

+#endif +

+ +#ifdef MS_WINDOWS

+

+

+

+#elif defined(HAVE_FCNTL_H) && defined(F_DUPFD_CLOEXEC)

+ +#else

+

+#endif

+} +

--- a/Python/import.c +++ b/Python/import.c @@ -1797,7 +1797,7 @@ imp_load_dynamic(PyObject *self, PyObjec &name, PyUnicode_FSDecoder, &pathname, &fob)) return NULL; if (fob != NULL) {

--- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1454,7 +1454,7 @@ PyRun_SimpleFileExFlags(FILE fp, const / Try to run a pyc file. First, re-open in binary */ if (closeit) fclose(fp);

--- a/Python/random.c +++ b/Python/random.c @@ -101,7 +101,7 @@ dev_urandom_noraise(char *buffer, Py_ssi assert (0 < size);

@@ -134,7 +134,7 @@ dev_urandom_python(char *buffer, Py_ssiz return 0; Py_BEGIN_ALLOW_THREADS

--- a/configure +++ b/configure @@ -10275,7 +10275,7 @@ fi

checks for library functions

for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown [](#l49.6)

--- a/configure.ac +++ b/configure.ac @@ -2807,7 +2807,7 @@ fi

checks for library functions

AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown [](#l50.6)

--- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -193,6 +193,9 @@ /* Define to 1 if you have the dup2' function. */[](#l51.4) #undef HAVE_DUP2[](#l51.5) [](#l51.6) +/* Define to 1 if you have the dup3' function. / +#undef HAVE_DUP3 + / Defined when any dynamic module loading is enabled. */ #undef HAVE_DYNAMIC_LOADING