From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Oct 2025 00:37:04 +0000 (+0200) Subject: [3.14] gh-126631: gh-137996: fix pre-loading of `__main__` (GH-135295) (#138607) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=64f0e2d6fac3729ea1bc7ea3a07934e8b486d608;p=thirdparty%2FPython%2Fcpython.git [3.14] gh-126631: gh-137996: fix pre-loading of `__main__` (GH-135295) (#138607) gh-126631: gh-137996: fix pre-loading of `__main__` (GH-135295) gh-126631: gh-137996: fix pre-loading of `__main__` The `main_path` parameter was renamed `init_main_from_name`, update the forkserver code accordingly. This was leading to slower startup times when people were trying to preload the main module. --------- (cherry picked from commit 0912b3a6dbd226bea79eb8d70d5a06230804d4cb) Co-authored-by: Duane Griffin Co-authored-by: Gregory P. Smith Co-authored-by: Petr Viktorin Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index c91891ff162c..cc8947c5e04f 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -145,12 +145,13 @@ class ForkServer(object): cmd = ('from multiprocessing.forkserver import main; ' + 'main(%d, %d, %r, **%r)') + main_kws = {} if self._preload_modules: - desired_keys = {'main_path', 'sys_path'} data = spawn.get_preparation_data('ignore') - main_kws = {x: y for x, y in data.items() if x in desired_keys} - else: - main_kws = {} + if 'sys_path' in data: + main_kws['sys_path'] = data['sys_path'] + if 'init_main_from_path' in data: + main_kws['main_path'] = data['init_main_from_path'] with socket.socket(socket.AF_UNIX) as listener: address = connection.arbitrary_address('AF_UNIX') diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 9a72362c0223..a7fa862d4cf1 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6883,6 +6883,18 @@ class MiscTestCase(unittest.TestCase): self.assertEqual(q.get_nowait(), "done") close_queue(q) + def test_preload_main(self): + # gh-126631: Check that __main__ can be pre-loaded + if multiprocessing.get_start_method() != "forkserver": + self.skipTest("forkserver specific test") + + name = os.path.join(os.path.dirname(__file__), 'mp_preload_main.py') + _, out, err = test.support.script_helper.assert_python_ok(name) + self.assertEqual(err, b'') + + # The trailing empty string comes from split() on output ending with \n + out = out.decode().split("\n") + self.assertEqual(out, ['__main__', '__mp_main__', 'f', 'f', '']) # # Mixins diff --git a/Lib/test/mp_preload_main.py b/Lib/test/mp_preload_main.py new file mode 100644 index 000000000000..acb342822ecc --- /dev/null +++ b/Lib/test/mp_preload_main.py @@ -0,0 +1,14 @@ +import multiprocessing + +print(f"{__name__}") + +def f(): + print("f") + +if __name__ == "__main__": + ctx = multiprocessing.get_context("forkserver") + ctx.set_forkserver_preload(['__main__']) + for _ in range(2): + p = ctx.Process(target=f) + p.start() + p.join() diff --git a/Misc/NEWS.d/next/Library/2025-06-10-21-00-48.gh-issue-126631.eITVJd.rst b/Misc/NEWS.d/next/Library/2025-06-10-21-00-48.gh-issue-126631.eITVJd.rst new file mode 100644 index 000000000000..195253b1ec1e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-10-21-00-48.gh-issue-126631.eITVJd.rst @@ -0,0 +1,2 @@ +Fix :mod:`multiprocessing` ``forkserver`` bug which prevented ``__main__`` +from being preloaded.