Mac OS: support Python >= 3.8 by using fork-based multiprocessing (#18124)
As detailed in https://bugs.python.org/issue33725, starting new processes with 'fork' on Mac OS is not guaranteed to work in general. As of Python 3.8 the default process spawning mechanism was changed to avoid this issue. Spack depends on the fork-based method to preserve file descriptors transparently, to preserve global state, and to avoid pickling some objects. An effort is underway to remove dependence on fork-based process spawning (see #18205). In the meantime, this allows Spack to run with Python 3.8 on Mac OS by explicitly choosing to use 'fork'. Co-authored-by: Peter Josef Scheibel <scheibel1@llnl.gov> Co-authored-by: Adam J. Stewart <ajstewart426@gmail.com> Co-authored-by: Todd Gamblin <tgamblin@llnl.gov>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import functools
|
||||
@@ -19,6 +20,23 @@
|
||||
ignore_modules = [r'^\.#', '~$']
|
||||
|
||||
|
||||
# On macOS, Python 3.8 multiprocessing now defaults to the 'spawn' start
|
||||
# method. Spack cannot currently handle this, so force the process to start
|
||||
# using the 'fork' start method.
|
||||
#
|
||||
# TODO: This solution is not ideal, as the 'fork' start method can lead to
|
||||
# crashes of the subprocess. Figure out how to make 'spawn' work.
|
||||
#
|
||||
# See:
|
||||
# * https://github.com/spack/spack/pull/18124
|
||||
# * https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods # noqa: E501
|
||||
# * https://bugs.python.org/issue33725
|
||||
if sys.version_info >= (3,): # novm
|
||||
fork_context = multiprocessing.get_context('fork')
|
||||
else:
|
||||
fork_context = multiprocessing
|
||||
|
||||
|
||||
def index_by(objects, *funcs):
|
||||
"""Create a hierarchy of dictionaries by splitting the supplied
|
||||
set of objects on unique values of the supplied functions.
|
||||
|
@@ -21,6 +21,7 @@
|
||||
from six import StringIO
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import fork_context
|
||||
|
||||
try:
|
||||
import termios
|
||||
@@ -430,7 +431,7 @@ def __enter__(self):
|
||||
except BaseException:
|
||||
input_stream = None # just don't forward input if this fails
|
||||
|
||||
self.process = multiprocessing.Process(
|
||||
self.process = fork_context.Process(
|
||||
target=_writer_daemon,
|
||||
args=(
|
||||
input_stream, read_fd, write_fd, self.echo, self.log_file,
|
||||
|
@@ -24,6 +24,7 @@
|
||||
import traceback
|
||||
|
||||
import llnl.util.tty.log as log
|
||||
from llnl.util.lang import fork_context
|
||||
|
||||
from spack.util.executable import which
|
||||
|
||||
@@ -233,7 +234,7 @@ def start(self, **kwargs):
|
||||
``minion_function``.
|
||||
|
||||
"""
|
||||
self.proc = multiprocessing.Process(
|
||||
self.proc = fork_context.Process(
|
||||
target=PseudoShell._set_up_and_run_controller_function,
|
||||
args=(self.controller_function, self.minion_function,
|
||||
self.controller_timeout, self.sleep_time),
|
||||
|
Reference in New Issue
Block a user