FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-135335: flush stdout/stderr in forkserver after preloading modules by duaneg · Pull Request #135338 · python/cpython · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension .py  (3) .rst  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
4 changes: 4 additions & 0 deletions Lib/multiprocessing/forkserver.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
except ImportError:
pass

# gh-135335: flush stdout/stderr in case any of the preloaded modules
# wrote to them, otherwise children might inherit buffered data
util._flush_std_streams()

util._close_stdin()

sig_r, sig_w = os.pipe()
Expand Down
33 changes: 33 additions & 0 deletions Lib/test/_test_multiprocessing.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -6801,6 +6801,39 @@ def test_child_sys_path(self):
self.assertEqual(child_sys_path[1:], sys.path[1:])
self.assertIsNone(import_error, msg=f"child could not import {self._mod_name}")

def test_std_streams_flushed_after_preload(self):
# gh-135335: Check fork server flushes standard streams after
# preloading modules
if multiprocessing.get_start_method() != "forkserver":
self.skipTest("forkserver specific test")

# Create a test module in the temporary directory on the child's path
# TODO: This can all be simplified once gh-126631 is fixed and we can
# use __main__ instead of a module.
dirname = os.path.join(self._temp_dir, 'preloaded_module')
init_name = os.path.join(dirname, '__init__.py')
os.mkdir(dirname)
with open(os.path.join(init_name), "w") as f:
Comment thread
duaneg marked this conversation as resolved.
Resolved
cmd = '''if 1:
import sys
print('stderr', file=sys.stderr)
print('stdout', file=sys.stdout)
Comment thread
duaneg marked this conversation as resolved.
Resolved
'''
f.write(cmd)

name = os.path.join(os.path.dirname(__file__), 'mp_preload_flush.py')
env = {'PYTHONPATH': self._temp_dir}
rc, out, err = test.support.script_helper.assert_python_ok(name, **env)
if rc:
support.print_warning("preload flush test failed with stderr:")
support.print_warning(err.decode())
self.assertEqual(rc, 0)
Comment thread
duaneg marked this conversation as resolved.
Resolved

# Check stderr first, as it is more likely to be useful to see in the
# event of a failure.
self.assertEqual(err.decode().rstrip(), 'stderr')
self.assertEqual(out.decode().rstrip(), 'stdout')
Comment thread
duaneg marked this conversation as resolved.
Resolved


class MiscTestCase(unittest.TestCase):
def test__all__(self):
Expand Down
14 changes: 14 additions & 0 deletions Lib/test/mp_preload_flush.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import multiprocessing
import sys

modname = 'preloaded_module'
if __name__ == '__main__':
assert modname not in sys.modules
Comment thread
duaneg marked this conversation as resolved.
Resolved
multiprocessing.set_start_method('forkserver')
multiprocessing.set_forkserver_preload([modname])
for _ in range(2):
p = multiprocessing.Process()
p.start()
p.join()
elif modname not in sys.modules:
raise AssertionError(f'{modname!r} is not in sys.modules')
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Flush ``stdout`` and ``stderr`` after preloading modules in the
:mod:`multiprocessing` ``forkserver``.
Comment thread
duaneg marked this conversation as resolved.
Resolved

Back | FazBrowse Home | New Git URL