diff -r d64bb25cf797 Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst Wed Nov 18 02:45:51 2015 +0000 +++ b/Doc/library/multiprocessing.rst Thu Nov 19 12:16:19 2015 +0200 @@ -2670,7 +2670,7 @@ Beware of replacing :data:`sys.stdin` wi in issues with processes-in-processes. This has been changed to:: sys.stdin.close() - sys.stdin = open(os.devnull) + sys.stdin = open(os.open(os.devnull, os.O_RDONLY), closefd=False) Which solves the fundamental issue of processes colliding with each other resulting in a bad file descriptor error, but introduces a potential danger diff -r d64bb25cf797 Lib/multiprocessing/forkserver.py --- a/Lib/multiprocessing/forkserver.py Wed Nov 18 02:45:51 2015 +0000 +++ b/Lib/multiprocessing/forkserver.py Thu Nov 19 12:16:19 2015 +0200 @@ -147,13 +147,7 @@ def main(listener_fd, alive_r, preload, except ImportError: pass - # close sys.stdin - if sys.stdin is not None: - try: - sys.stdin.close() - sys.stdin = open(os.devnull) - except (OSError, ValueError): - pass + util._close_stdin() # ignoring SIGCHLD means no need to reap zombie processes handler = signal.signal(signal.SIGCHLD, signal.SIG_IGN) diff -r d64bb25cf797 Lib/multiprocessing/process.py --- a/Lib/multiprocessing/process.py Wed Nov 18 02:45:51 2015 +0000 +++ b/Lib/multiprocessing/process.py Thu Nov 19 12:16:19 2015 +0200 @@ -234,12 +234,7 @@ class BaseProcess(object): context._force_start_method(self._start_method) _process_counter = itertools.count(1) _children = set() - if sys.stdin is not None: - try: - sys.stdin.close() - sys.stdin = open(os.devnull) - except (OSError, ValueError): - pass + util._close_stdin() old_process = _current_process _current_process = self try: diff -r d64bb25cf797 Lib/multiprocessing/util.py --- a/Lib/multiprocessing/util.py Wed Nov 18 02:45:51 2015 +0000 +++ b/Lib/multiprocessing/util.py Thu Nov 19 12:16:19 2015 +0200 @@ -9,6 +9,7 @@ import os import itertools +import sys import weakref import atexit import threading # we want threading to install it's @@ -356,6 +357,22 @@ def close_all_fds_except(fds): assert fds[-1] == MAXFD, 'fd too large' for i in range(len(fds) - 1): os.closerange(fds[i]+1, fds[i+1]) +# +# Close sys.stdin +# + +def _close_stdin(): + if sys.stdin is not None: + try: + sys.stdin.close() + fd = os.open(os.devnull, os.O_RDONLY) + try: + sys.stdin = open(fd, closefd=False) + except: + os.close(fd) + raise + except (OSError, ValueError): + pass # # Start a program with only specified fds kept open diff -r d64bb25cf797 Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py Wed Nov 18 02:45:51 2015 +0000 +++ b/Lib/test/_test_multiprocessing.py Thu Nov 19 12:16:19 2015 +0200 @@ -455,13 +455,17 @@ class _TestSubclassingProcess(BaseTestCa @classmethod def _test_stderr_flush(cls, testfn): - sys.stderr = open(testfn, 'w') + if not isinstance(testfn, int): + testfn = os.open(testfn, os.O_RDWR|os.O_CREAT) + sys.stderr = open(testfn, 'w', closefd=False) 1/0 # MARKER @classmethod def _test_sys_exit(cls, reason, testfn): - sys.stderr = open(testfn, 'w') + if not isinstance(testfn, int): + testfn = os.open(testfn, os.O_RDWR|os.O_CREAT) + sys.stderr = open(testfn, 'w', closefd=False) sys.exit(reason) def test_sys_exit(self):