Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f6243ac

Browse filesBrowse files
authored
bpo-35537: subprocess can use posix_spawn with pipes (GH-11575)
* subprocess.Popen can now also use os.posix_spawn() with pipes, but only if pipe file descriptors are greater than 2. * Fix Popen._posix_spawn(): set '_child_created' attribute to True. * Add Popen._close_pipe_fds() helper function to factorize the code.
1 parent ab67281 commit f6243ac
Copy full SHA for f6243ac

File tree

Expand file treeCollapse file tree

2 files changed

+66
-30
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+66
-30
lines changed

‎Doc/whatsnew/3.8.rst

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.8.rst
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ Optimizations
280280
and Linux (using glibc 2.24 or newer) if all these conditions are met:
281281

282282
* *close_fds* is false;
283-
* *preexec_fn*, *pass_fds*, *cwd*, *stdin*, *stdout*, *stderr* and
284-
*start_new_session* parameters are not set;
283+
* *preexec_fn*, *pass_fds*, *cwd* and *start_new_session* parameters
284+
are not set;
285285
* the *executable* path contains a directory.
286286

287287
* :func:`shutil.copyfile`, :func:`shutil.copy`, :func:`shutil.copy2`,

‎Lib/subprocess.py

Copy file name to clipboardExpand all lines: Lib/subprocess.py
+64-28Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,34 @@ def wait(self, timeout=None):
10661066
pass
10671067
raise # resume the KeyboardInterrupt
10681068

1069+
def _close_pipe_fds(self,
1070+
p2cread, p2cwrite,
1071+
c2pread, c2pwrite,
1072+
errread, errwrite):
1073+
# self._devnull is not always defined.
1074+
devnull_fd = getattr(self, '_devnull', None)
1075+
1076+
if _mswindows:
1077+
if p2cread != -1:
1078+
p2cread.Close()
1079+
if c2pwrite != -1:
1080+
c2pwrite.Close()
1081+
if errwrite != -1:
1082+
errwrite.Close()
1083+
else:
1084+
if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
1085+
os.close(p2cread)
1086+
if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
1087+
os.close(c2pwrite)
1088+
if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
1089+
os.close(errwrite)
1090+
1091+
if devnull_fd is not None:
1092+
os.close(devnull_fd)
1093+
1094+
# Prevent a double close of these handles/fds from __init__ on error.
1095+
self._closed_child_pipe_fds = True
1096+
10691097

10701098
if _mswindows:
10711099
#
@@ -1244,17 +1272,9 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
12441272
# output pipe are maintained in this process or else the
12451273
# pipe will not close when the child process exits and the
12461274
# ReadFile will hang.
1247-
if p2cread != -1:
1248-
p2cread.Close()
1249-
if c2pwrite != -1:
1250-
c2pwrite.Close()
1251-
if errwrite != -1:
1252-
errwrite.Close()
1253-
if hasattr(self, '_devnull'):
1254-
os.close(self._devnull)
1255-
# Prevent a double close of these handles/fds from __init__
1256-
# on error.
1257-
self._closed_child_pipe_fds = True
1275+
self._close_pipe_fds(p2cread, p2cwrite,
1276+
c2pread, c2pwrite,
1277+
errread, errwrite)
12581278

12591279
# Retain the process handle, but close the thread handle
12601280
self._child_created = True
@@ -1441,7 +1461,10 @@ def _get_handles(self, stdin, stdout, stderr):
14411461
errread, errwrite)
14421462

14431463

1444-
def _posix_spawn(self, args, executable, env, restore_signals):
1464+
def _posix_spawn(self, args, executable, env, restore_signals,
1465+
p2cread, p2cwrite,
1466+
c2pread, c2pwrite,
1467+
errread, errwrite):
14451468
"""Execute program using os.posix_spawn()."""
14461469
if env is None:
14471470
env = os.environ
@@ -1456,7 +1479,26 @@ def _posix_spawn(self, args, executable, env, restore_signals):
14561479
sigset.append(signum)
14571480
kwargs['setsigdef'] = sigset
14581481

1482+
file_actions = []
1483+
for fd in (p2cwrite, c2pread, errread):
1484+
if fd != -1:
1485+
file_actions.append((os.POSIX_SPAWN_CLOSE, fd))
1486+
for fd, fd2 in (
1487+
(p2cread, 0),
1488+
(c2pwrite, 1),
1489+
(errwrite, 2),
1490+
):
1491+
if fd != -1:
1492+
file_actions.append((os.POSIX_SPAWN_DUP2, fd, fd2))
1493+
if file_actions:
1494+
kwargs['file_actions'] = file_actions
1495+
14591496
self.pid = os.posix_spawn(executable, args, env, **kwargs)
1497+
self._child_created = True
1498+
1499+
self._close_pipe_fds(p2cread, p2cwrite,
1500+
c2pread, c2pwrite,
1501+
errread, errwrite)
14601502

14611503
def _execute_child(self, args, executable, preexec_fn, close_fds,
14621504
pass_fds, cwd, env,
@@ -1489,11 +1531,14 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14891531
and not close_fds
14901532
and not pass_fds
14911533
and cwd is None
1492-
and p2cread == p2cwrite == -1
1493-
and c2pread == c2pwrite == -1
1494-
and errread == errwrite == -1
1534+
and (p2cread == -1 or p2cread > 2)
1535+
and (c2pwrite == -1 or c2pwrite > 2)
1536+
and (errwrite == -1 or errwrite > 2)
14951537
and not start_new_session):
1496-
self._posix_spawn(args, executable, env, restore_signals)
1538+
self._posix_spawn(args, executable, env, restore_signals,
1539+
p2cread, p2cwrite,
1540+
c2pread, c2pwrite,
1541+
errread, errwrite)
14971542
return
14981543

14991544
orig_executable = executable
@@ -1548,18 +1593,9 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
15481593
# be sure the FD is closed no matter what
15491594
os.close(errpipe_write)
15501595

1551-
# self._devnull is not always defined.
1552-
devnull_fd = getattr(self, '_devnull', None)
1553-
if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
1554-
os.close(p2cread)
1555-
if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
1556-
os.close(c2pwrite)
1557-
if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
1558-
os.close(errwrite)
1559-
if devnull_fd is not None:
1560-
os.close(devnull_fd)
1561-
# Prevent a double close of these fds from __init__ on error.
1562-
self._closed_child_pipe_fds = True
1596+
self._close_pipe_fds(p2cread, p2cwrite,
1597+
c2pread, c2pwrite,
1598+
errread, errwrite)
15631599

15641600
# Wait for exec to fail or succeed; possibly raising an
15651601
# exception (limited in size)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.