We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Multiprocessing "spawn" not thread-safe on Linux.
<!--
Welcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller
    - For questions and general support, use the discussions forum.
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
-->

<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->

## Description of the issue

When using multiprocessing with the "spawn" method on Linux, processes sometimes fail to start with the message: `FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIOchafX/multiprocessing_bug.py'` This happens if different threads try to launch processes concurrently. It would appear that the "spawn" method is not thread-safe when used with freeze support.

As mentioned below, this bug does not manifest when built with `--onedir`.

[debug.log](https://github.com/pyinstaller/pyinstaller/files/10560051/debug.log) contains import and bootloader logging for a failure case. 


Q: Does this happen with "fork"? 
A: No

Q: Does this happen when running from source?
A: No, only when packaged as a pyinstaller executable with `--onefile`.

Q: Does this happen on Windows?
A: Unknown

### Context information (for bug reports)

* Output of `pyinstaller --version`: ```5.7.0```
* Version of Python: Python 3.10.6
* Platform: Ubuntu 22.04.1 LTS
* How you installed Python: apt
* Did you also try this on another platform?
    * Ubuntu 18.04.6 LTS, pyinstaller 4.7, Python 3.7 - Bug is present
    * WSL2 pyinstaller 4.7, Python 3.7 - Bug is present


* try the latest development version, using the following command:

```shell
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
```

* follow *all* the instructions in our "If Things Go Wrong" Guide
  (https://github.com/pyinstaller/pyinstaller/wiki/If-Things-Go-Wrong) and

### Make sure [everything is packaged correctly](https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs#make-sure-everything-is-packaged-correctly)

  * [x] start with clean installation
  * [x] use the latest development version
  * [x] Run your frozen program **from a command window (shell)** — instead of double-clicking on it
  * [x] Package your program in **--onedir mode** - **BUG DOES NOT MANIFEST**
  * [x] Package **without UPX**, say: use the option `--noupx` or set `upx=False` in your .spec-file -  - **BUG DOES NOT MANIFEST**
  * [x] Repackage you application in **verbose/debug mode**. For this, pass the option `--debug` to `pyi-makespec` or `pyinstaller` or use `EXE(..., debug=1, ...)` in your .spec file.


### A minimal example program which shows the error

```python
import multiprocessing
import sys
from threading import Thread

DEFAULT_N = 3

def main():
    try:
        n = int(sys.argv[1])
    except IndexError:
        n=DEFAULT_N

    threads = []
    for i in range(n):
        threads.append(Thread(target=foo, args=(i, )))
    for i in range(n):
        threads[i].start()
    for i in range(n):
        threads[i].join()

def foo(i):
    multiprocessing_context = multiprocessing.get_context(method="spawn")
    q = multiprocessing_context.Queue()
    p = multiprocessing_context.Process(target=bar, args=(q, i), daemon=True)
    p.start()
    p.join()


def bar(q, i):
    q.put('hello')
    print(f"{i} Added to queue")

if __name__ == "__main__":
    multiprocessing.freeze_support()
    main()

```

### Stacktrace / full error message

Note: If you can't reproduce the bug, try increasing the parameter from 2 to 5 (or higher).

```
$> dist/multiprocessing_bug 2
0 Added to queue
Traceback (most recent call last):
  File "multiprocessing_bug.py", line 34, in <module>
    multiprocessing.freeze_support()
  File "PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py", line 49, in _freeze_support
  File "multiprocessing/spawn.py", line 116, in spawn_main
  File "multiprocessing/spawn.py", line 125, in _main
  File "multiprocessing/spawn.py", line 236, in prepare
  File "multiprocessing/spawn.py", line 287, in _fixup_main_from_path
  File "runpy.py", line 288, in run_path
  File "runpy.py", line 252, in _get_code_from_file
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIOchafX/multiprocessing_bug.py'
[8216] Failed to execute script 'multiprocessing_bug' due to unhandled exception!

```

### Workaround

As shown below, adding a lock around the call to `process.start()` seems to resolve the issue.

```python
import multiprocessing
import sys
from threading import Thread, Lock

DEFAULT_N = 3

def main():
    try:
        n = int(sys.argv[1])
    except IndexError:
        n=DEFAULT_N

    threads = []
    for i in range(n):
        threads.append(Thread(target=foo, args=(i, )))
    for i in range(n):
        threads[i].start()
    for i in range(n):
        threads[i].join()

lock = Lock()
def foo(i):
    multiprocessing_context = multiprocessing.get_context(method="spawn")
    q = multiprocessing_context.Queue()
    p = multiprocessing_context.Process(target=bar, args=(q, i), daemon=True)

    with lock:
        p.start()

    p.join()


def bar(q, i):
    q.put('hello')
    print(f"{i} Added to queue")

if __name__ == "__main__":
    multiprocessing.freeze_support()
    main()

```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2017-2023, PyInstaller Development Team.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #
9 # SPDX-License-Identifier: Apache-2.0
10 #-----------------------------------------------------------------------------
11 
12 import multiprocessing
13 import multiprocessing.spawn as spawn
14 # 'spawn' multiprocessing needs some adjustments on osx
15 import os
16 import sys
17 from subprocess import _args_from_interpreter_flags
18 
19 # prevent spawn from trying to read __main__ in from the main script
20 multiprocessing.process.ORIGINAL_DIR = None
21 
22 
23 def _freeze_support():
24     # We want to catch the two processes that are spawned by the multiprocessing code:
25     # - the semaphore tracker, which cleans up named semaphores in the spawn multiprocessing mode
26     # - the fork server, which keeps track of worker processes in forkserver mode.
27     # both of these processes are started by spawning a new copy of the running executable, passing it the flags from
28     # _args_from_interpreter_flags and then "-c" and an import statement.
29     # Look for those flags and the import statement, then exec() the code ourselves.
30 
31     if (
32         len(sys.argv) >= 2 and sys.argv[-2] == '-c' and sys.argv[-1].startswith((
33             'from multiprocessing.semaphore_tracker import main',  # Py<3.8
34             'from multiprocessing.resource_tracker import main',  # Py>=3.8
35             'from multiprocessing.forkserver import main'
36         )) and set(sys.argv[1:-2]) == set(_args_from_interpreter_flags())
37     ):
38         exec(sys.argv[-1])
39         sys.exit()
40 
41     if spawn.is_forking(sys.argv):
42         kwds = {}
43         for arg in sys.argv[2:]:
44             name, value = arg.split('=')
45             if value == 'None':
46                 kwds[name] = None
47             else:
48                 kwds[name] = int(value)
49         spawn.spawn_main(**kwds)
50         sys.exit()
51 
52 
53 multiprocessing.freeze_support = spawn.freeze_support = _freeze_support
54 
55 # Bootloader unsets _MEIPASS2 for child processes to allow running PyInstaller binaries inside pyinstaller binaries.
56 # This is ok for mac or unix with fork() system call. But on Windows we need to overcome missing fork() function.
57 
58 if sys.platform.startswith('win'):
59     import multiprocessing.popen_spawn_win32 as forking
60 else:
61     import multiprocessing.popen_fork as forking
62     import multiprocessing.popen_spawn_posix as spawning
63 
64 
65 # Mix-in to re-set _MEIPASS2 from sys._MEIPASS.
66 class FrozenSupportMixIn:
67     def __init__(self, *args, **kw):
68         if hasattr(sys, 'frozen'):
69             # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working.
70             os.putenv('_MEIPASS2', sys._MEIPASS)  # @UndefinedVariable
71         try:
72             super().__init__(*args, **kw)
73         finally:
74             if hasattr(sys, 'frozen'):
75                 # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the
76                 # variable but only set it to the empty string. The bootloader can handle this case.
77                 if hasattr(os, 'unsetenv'):
78                     os.unsetenv('_MEIPASS2')
79                 else:
80                     os.putenv('_MEIPASS2', '')
81 
82 
83 # Patch forking.Popen to re-set _MEIPASS2 from sys._MEIPASS.
84 class _Popen(FrozenSupportMixIn, forking.Popen):
85     pass
86 
87 
88 forking.Popen = _Popen
89 
90 if not sys.platform.startswith('win'):
91     # Patch spawning.Popen to re-set _MEIPASS2 from sys._MEIPASS.
92     class _Spawning_Popen(FrozenSupportMixIn, spawning.Popen):
93         pass
94 
95     spawning.Popen = _Spawning_Popen
96
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py b/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py
--- a/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py
+++ b/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py
@@ -9,6 +9,7 @@
 # SPDX-License-Identifier: Apache-2.0
 #-----------------------------------------------------------------------------
 
+import threading
 import multiprocessing
 import multiprocessing.spawn as spawn
 # 'spawn' multiprocessing needs some adjustments on osx
@@ -64,14 +65,17 @@
 
 # Mix-in to re-set _MEIPASS2 from sys._MEIPASS.
 class FrozenSupportMixIn:
+    _lock = threading.Lock()
+
     def __init__(self, *args, **kw):
-        if hasattr(sys, 'frozen'):
+        # The whole code block needs be executed under a lock to prevent race conditions between `os.putenv` and
+        # `os.unsetenv` calls when processes are spawned concurrently from multiple threads. See #7410.
+        with self._lock:
             # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working.
             os.putenv('_MEIPASS2', sys._MEIPASS)  # @UndefinedVariable
-        try:
-            super().__init__(*args, **kw)
-        finally:
-            if hasattr(sys, 'frozen'):
+            try:
+                super().__init__(*args, **kw)
+            finally:
                 # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the
                 # variable but only set it to the empty string. The bootloader can handle this case.
                 if hasattr(os, 'unsetenv'):

{"golden_diff": "diff --git a/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py b/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py\n--- a/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py\n+++ b/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py\n@@ -9,6 +9,7 @@\n # SPDX-License-Identifier: Apache-2.0\n #-----------------------------------------------------------------------------\n \n+import threading\n import multiprocessing\n import multiprocessing.spawn as spawn\n # 'spawn' multiprocessing needs some adjustments on osx\n@@ -64,14 +65,17 @@\n \n # Mix-in to re-set _MEIPASS2 from sys._MEIPASS.\n class FrozenSupportMixIn:\n+    _lock = threading.Lock()\n+\n     def __init__(self, *args, **kw):\n-        if hasattr(sys, 'frozen'):\n+        # The whole code block needs be executed under a lock to prevent race conditions between `os.putenv` and\n+        # `os.unsetenv` calls when processes are spawned concurrently from multiple threads. See #7410.\n+        with self._lock:\n             # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working.\n             os.putenv('_MEIPASS2', sys._MEIPASS)  # @UndefinedVariable\n-        try:\n-            super().__init__(*args, **kw)\n-        finally:\n-            if hasattr(sys, 'frozen'):\n+            try:\n+                super().__init__(*args, **kw)\n+            finally:\n                 # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the\n                 # variable but only set it to the empty string. The bootloader can handle this case.\n                 if hasattr(os, 'unsetenv'):\n", "issue": "Multiprocessing \"spawn\" not thread-safe on Linux.\n<!--\r\nWelcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:\r\n\r\n1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller\r\n    - For questions and general support, use the discussions forum.\r\n2. Use the search function before creating a new issue. Duplicates will be closed and directed to\r\n   the original discussion.\r\n3. When making a bug report, make sure you provide all required information. The easier it is for\r\n   maintainers to reproduce, the faster it'll be fixed.\r\n-->\r\n\r\n<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->\r\n\r\n## Description of the issue\r\n\r\nWhen using multiprocessing with the \"spawn\" method on Linux, processes sometimes fail to start with the message: `FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIOchafX/multiprocessing_bug.py'` This happens if different threads try to launch processes concurrently. It would appear that the \"spawn\" method is not thread-safe when used with freeze support.\r\n\r\nAs mentioned below, this bug does not manifest when built with `--onedir`.\r\n\r\n[debug.log](https://github.com/pyinstaller/pyinstaller/files/10560051/debug.log) contains import and bootloader logging for a failure case. \r\n\r\n\r\nQ: Does this happen with \"fork\"? \r\nA: No\r\n\r\nQ: Does this happen when running from source?\r\nA: No, only when packaged as a pyinstaller executable with `--onefile`.\r\n\r\nQ: Does this happen on Windows?\r\nA: Unknown\r\n\r\n### Context information (for bug reports)\r\n\r\n* Output of `pyinstaller --version`: ```5.7.0```\r\n* Version of Python: Python 3.10.6\r\n* Platform: Ubuntu 22.04.1 LTS\r\n* How you installed Python: apt\r\n* Did you also try this on another platform?\r\n    * Ubuntu 18.04.6 LTS, pyinstaller 4.7, Python 3.7 - Bug is present\r\n    * WSL2 pyinstaller 4.7, Python 3.7 - Bug is present\r\n\r\n\r\n* try the latest development version, using the following command:\r\n\r\n```shell\r\npip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip\r\n```\r\n\r\n* follow *all* the instructions in our \"If Things Go Wrong\" Guide\r\n  (https://github.com/pyinstaller/pyinstaller/wiki/If-Things-Go-Wrong) and\r\n\r\n### Make sure [everything is packaged correctly](https://github.com/pyinstaller/pyinstaller/wiki/How-to-Report-Bugs#make-sure-everything-is-packaged-correctly)\r\n\r\n  * [x] start with clean installation\r\n  * [x] use the latest development version\r\n  * [x] Run your frozen program **from a command window (shell)** \u2014 instead of double-clicking on it\r\n  * [x] Package your program in **--onedir mode** - **BUG DOES NOT MANIFEST**\r\n  * [x] Package **without UPX**, say: use the option `--noupx` or set `upx=False` in your .spec-file -  - **BUG DOES NOT MANIFEST**\r\n  * [x] Repackage you application in **verbose/debug mode**. For this, pass the option `--debug` to `pyi-makespec` or `pyinstaller` or use `EXE(..., debug=1, ...)` in your .spec file.\r\n\r\n\r\n### A minimal example program which shows the error\r\n\r\n```python\r\nimport multiprocessing\r\nimport sys\r\nfrom threading import Thread\r\n\r\nDEFAULT_N = 3\r\n\r\ndef main():\r\n    try:\r\n        n = int(sys.argv[1])\r\n    except IndexError:\r\n        n=DEFAULT_N\r\n\r\n    threads = []\r\n    for i in range(n):\r\n        threads.append(Thread(target=foo, args=(i, )))\r\n    for i in range(n):\r\n        threads[i].start()\r\n    for i in range(n):\r\n        threads[i].join()\r\n\r\ndef foo(i):\r\n    multiprocessing_context = multiprocessing.get_context(method=\"spawn\")\r\n    q = multiprocessing_context.Queue()\r\n    p = multiprocessing_context.Process(target=bar, args=(q, i), daemon=True)\r\n    p.start()\r\n    p.join()\r\n\r\n\r\ndef bar(q, i):\r\n    q.put('hello')\r\n    print(f\"{i} Added to queue\")\r\n\r\nif __name__ == \"__main__\":\r\n    multiprocessing.freeze_support()\r\n    main()\r\n\r\n```\r\n\r\n### Stacktrace / full error message\r\n\r\nNote: If you can't reproduce the bug, try increasing the parameter from 2 to 5 (or higher).\r\n\r\n```\r\n$> dist/multiprocessing_bug 2\r\n0 Added to queue\r\nTraceback (most recent call last):\r\n  File \"multiprocessing_bug.py\", line 34, in <module>\r\n    multiprocessing.freeze_support()\r\n  File \"PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py\", line 49, in _freeze_support\r\n  File \"multiprocessing/spawn.py\", line 116, in spawn_main\r\n  File \"multiprocessing/spawn.py\", line 125, in _main\r\n  File \"multiprocessing/spawn.py\", line 236, in prepare\r\n  File \"multiprocessing/spawn.py\", line 287, in _fixup_main_from_path\r\n  File \"runpy.py\", line 288, in run_path\r\n  File \"runpy.py\", line 252, in _get_code_from_file\r\nFileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIOchafX/multiprocessing_bug.py'\r\n[8216] Failed to execute script 'multiprocessing_bug' due to unhandled exception!\r\n\r\n```\r\n\r\n### Workaround\r\n\r\nAs shown below, adding a lock around the call to `process.start()` seems to resolve the issue.\r\n\r\n```python\r\nimport multiprocessing\r\nimport sys\r\nfrom threading import Thread, Lock\r\n\r\nDEFAULT_N = 3\r\n\r\ndef main():\r\n    try:\r\n        n = int(sys.argv[1])\r\n    except IndexError:\r\n        n=DEFAULT_N\r\n\r\n    threads = []\r\n    for i in range(n):\r\n        threads.append(Thread(target=foo, args=(i, )))\r\n    for i in range(n):\r\n        threads[i].start()\r\n    for i in range(n):\r\n        threads[i].join()\r\n\r\nlock = Lock()\r\ndef foo(i):\r\n    multiprocessing_context = multiprocessing.get_context(method=\"spawn\")\r\n    q = multiprocessing_context.Queue()\r\n    p = multiprocessing_context.Process(target=bar, args=(q, i), daemon=True)\r\n\r\n    with lock:\r\n        p.start()\r\n\r\n    p.join()\r\n\r\n\r\ndef bar(q, i):\r\n    q.put('hello')\r\n    print(f\"{i} Added to queue\")\r\n\r\nif __name__ == \"__main__\":\r\n    multiprocessing.freeze_support()\r\n    main()\r\n\r\n```\r\n\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2017-2023, PyInstaller Development Team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: Apache-2.0\n#-----------------------------------------------------------------------------\n\nimport multiprocessing\nimport multiprocessing.spawn as spawn\n# 'spawn' multiprocessing needs some adjustments on osx\nimport os\nimport sys\nfrom subprocess import _args_from_interpreter_flags\n\n# prevent spawn from trying to read __main__ in from the main script\nmultiprocessing.process.ORIGINAL_DIR = None\n\n\ndef _freeze_support():\n    # We want to catch the two processes that are spawned by the multiprocessing code:\n    # - the semaphore tracker, which cleans up named semaphores in the spawn multiprocessing mode\n    # - the fork server, which keeps track of worker processes in forkserver mode.\n    # both of these processes are started by spawning a new copy of the running executable, passing it the flags from\n    # _args_from_interpreter_flags and then \"-c\" and an import statement.\n    # Look for those flags and the import statement, then exec() the code ourselves.\n\n    if (\n        len(sys.argv) >= 2 and sys.argv[-2] == '-c' and sys.argv[-1].startswith((\n            'from multiprocessing.semaphore_tracker import main',  # Py<3.8\n            'from multiprocessing.resource_tracker import main',  # Py>=3.8\n            'from multiprocessing.forkserver import main'\n        )) and set(sys.argv[1:-2]) == set(_args_from_interpreter_flags())\n    ):\n        exec(sys.argv[-1])\n        sys.exit()\n\n    if spawn.is_forking(sys.argv):\n        kwds = {}\n        for arg in sys.argv[2:]:\n            name, value = arg.split('=')\n            if value == 'None':\n                kwds[name] = None\n            else:\n                kwds[name] = int(value)\n        spawn.spawn_main(**kwds)\n        sys.exit()\n\n\nmultiprocessing.freeze_support = spawn.freeze_support = _freeze_support\n\n# Bootloader unsets _MEIPASS2 for child processes to allow running PyInstaller binaries inside pyinstaller binaries.\n# This is ok for mac or unix with fork() system call. But on Windows we need to overcome missing fork() function.\n\nif sys.platform.startswith('win'):\n    import multiprocessing.popen_spawn_win32 as forking\nelse:\n    import multiprocessing.popen_fork as forking\n    import multiprocessing.popen_spawn_posix as spawning\n\n\n# Mix-in to re-set _MEIPASS2 from sys._MEIPASS.\nclass FrozenSupportMixIn:\n    def __init__(self, *args, **kw):\n        if hasattr(sys, 'frozen'):\n            # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working.\n            os.putenv('_MEIPASS2', sys._MEIPASS)  # @UndefinedVariable\n        try:\n            super().__init__(*args, **kw)\n        finally:\n            if hasattr(sys, 'frozen'):\n                # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the\n                # variable but only set it to the empty string. The bootloader can handle this case.\n                if hasattr(os, 'unsetenv'):\n                    os.unsetenv('_MEIPASS2')\n                else:\n                    os.putenv('_MEIPASS2', '')\n\n\n# Patch forking.Popen to re-set _MEIPASS2 from sys._MEIPASS.\nclass _Popen(FrozenSupportMixIn, forking.Popen):\n    pass\n\n\nforking.Popen = _Popen\n\nif not sys.platform.startswith('win'):\n    # Patch spawning.Popen to re-set _MEIPASS2 from sys._MEIPASS.\n    class _Spawning_Popen(FrozenSupportMixIn, spawning.Popen):\n        pass\n\n    spawning.Popen = _Spawning_Popen\n", "path": "PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2017-2023, PyInstaller Development Team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: Apache-2.0\n#-----------------------------------------------------------------------------\n\nimport threading\nimport multiprocessing\nimport multiprocessing.spawn as spawn\n# 'spawn' multiprocessing needs some adjustments on osx\nimport os\nimport sys\nfrom subprocess import _args_from_interpreter_flags\n\n# prevent spawn from trying to read __main__ in from the main script\nmultiprocessing.process.ORIGINAL_DIR = None\n\n\ndef _freeze_support():\n    # We want to catch the two processes that are spawned by the multiprocessing code:\n    # - the semaphore tracker, which cleans up named semaphores in the spawn multiprocessing mode\n    # - the fork server, which keeps track of worker processes in forkserver mode.\n    # both of these processes are started by spawning a new copy of the running executable, passing it the flags from\n    # _args_from_interpreter_flags and then \"-c\" and an import statement.\n    # Look for those flags and the import statement, then exec() the code ourselves.\n\n    if (\n        len(sys.argv) >= 2 and sys.argv[-2] == '-c' and sys.argv[-1].startswith((\n            'from multiprocessing.semaphore_tracker import main',  # Py<3.8\n            'from multiprocessing.resource_tracker import main',  # Py>=3.8\n            'from multiprocessing.forkserver import main'\n        )) and set(sys.argv[1:-2]) == set(_args_from_interpreter_flags())\n    ):\n        exec(sys.argv[-1])\n        sys.exit()\n\n    if spawn.is_forking(sys.argv):\n        kwds = {}\n        for arg in sys.argv[2:]:\n            name, value = arg.split('=')\n            if value == 'None':\n                kwds[name] = None\n            else:\n                kwds[name] = int(value)\n        spawn.spawn_main(**kwds)\n        sys.exit()\n\n\nmultiprocessing.freeze_support = spawn.freeze_support = _freeze_support\n\n# Bootloader unsets _MEIPASS2 for child processes to allow running PyInstaller binaries inside pyinstaller binaries.\n# This is ok for mac or unix with fork() system call. But on Windows we need to overcome missing fork() function.\n\nif sys.platform.startswith('win'):\n    import multiprocessing.popen_spawn_win32 as forking\nelse:\n    import multiprocessing.popen_fork as forking\n    import multiprocessing.popen_spawn_posix as spawning\n\n\n# Mix-in to re-set _MEIPASS2 from sys._MEIPASS.\nclass FrozenSupportMixIn:\n    _lock = threading.Lock()\n\n    def __init__(self, *args, **kw):\n        # The whole code block needs be executed under a lock to prevent race conditions between `os.putenv` and\n        # `os.unsetenv` calls when processes are spawned concurrently from multiple threads. See #7410.\n        with self._lock:\n            # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working.\n            os.putenv('_MEIPASS2', sys._MEIPASS)  # @UndefinedVariable\n            try:\n                super().__init__(*args, **kw)\n            finally:\n                # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the\n                # variable but only set it to the empty string. The bootloader can handle this case.\n                if hasattr(os, 'unsetenv'):\n                    os.unsetenv('_MEIPASS2')\n                else:\n                    os.putenv('_MEIPASS2', '')\n\n\n# Patch forking.Popen to re-set _MEIPASS2 from sys._MEIPASS.\nclass _Popen(FrozenSupportMixIn, forking.Popen):\n    pass\n\n\nforking.Popen = _Popen\n\nif not sys.platform.startswith('win'):\n    # Patch spawning.Popen to re-set _MEIPASS2 from sys._MEIPASS.\n    class _Spawning_Popen(FrozenSupportMixIn, spawning.Popen):\n        pass\n\n    spawning.Popen = _Spawning_Popen\n", "path": "PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py"}]}