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:
Rui Xue
2020-09-02 02:15:39 -05:00
committed by GitHub
parent 0740a4ac7e
commit d9b945f663
9 changed files with 35 additions and 14 deletions

View File

@@ -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.

View File

@@ -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,

View 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),