aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/multiprocessing/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/multiprocessing/util.py')
-rw-r--r--Lib/multiprocessing/util.py79
1 files changed, 77 insertions, 2 deletions
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index b7192042b9c..a1a537dd48d 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -19,7 +19,7 @@ from subprocess import _args_from_interpreter_flags # noqa: F401
from . import process
__all__ = [
- 'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
+ 'sub_debug', 'debug', 'info', 'sub_warning', 'warn', 'get_logger',
'log_to_stderr', 'get_temp_dir', 'register_after_fork',
'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING',
@@ -34,6 +34,7 @@ SUBDEBUG = 5
DEBUG = 10
INFO = 20
SUBWARNING = 25
+WARNING = 30
LOGGER_NAME = 'multiprocessing'
DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
@@ -53,6 +54,10 @@ def info(msg, *args):
if _logger:
_logger.log(INFO, msg, *args, stacklevel=2)
+def warn(msg, *args):
+ if _logger:
+ _logger.log(WARNING, msg, *args, stacklevel=2)
+
def sub_warning(msg, *args):
if _logger:
_logger.log(SUBWARNING, msg, *args, stacklevel=2)
@@ -121,6 +126,21 @@ abstract_sockets_supported = _platform_supports_abstract_sockets()
# Function returning a temp directory which will be removed on exit
#
+# Maximum length of a socket file path is usually between 92 and 108 [1],
+# but Linux is known to use a size of 108 [2]. BSD-based systems usually
+# use a size of 104 or 108 and Windows does not create AF_UNIX sockets.
+#
+# [1]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html
+# [2]: https://man7.org/linux/man-pages/man7/unix.7.html.
+
+if sys.platform == 'linux':
+ _SUN_PATH_MAX = 108
+elif sys.platform.startswith(('openbsd', 'freebsd')):
+ _SUN_PATH_MAX = 104
+else:
+ # On Windows platforms, we do not create AF_UNIX sockets.
+ _SUN_PATH_MAX = None if os.name == 'nt' else 92
+
def _remove_temp_dir(rmtree, tempdir):
rmtree(tempdir)
@@ -130,12 +150,67 @@ def _remove_temp_dir(rmtree, tempdir):
if current_process is not None:
current_process._config['tempdir'] = None
+def _get_base_temp_dir(tempfile):
+ """Get a temporary directory where socket files will be created.
+
+ To prevent additional imports, pass a pre-imported 'tempfile' module.
+ """
+ if os.name == 'nt':
+ return None
+ # Most of the time, the default temporary directory is /tmp. Thus,
+ # listener sockets files "$TMPDIR/pymp-XXXXXXXX/sock-XXXXXXXX" do
+ # not have a path length exceeding SUN_PATH_MAX.
+ #
+ # If users specify their own temporary directory, we may be unable
+ # to create those files. Therefore, we fall back to the system-wide
+ # temporary directory /tmp, assumed to exist on POSIX systems.
+ #
+ # See https://github.com/python/cpython/issues/132124.
+ base_tempdir = tempfile.gettempdir()
+ # Files created in a temporary directory are suffixed by a string
+ # generated by tempfile._RandomNameSequence, which, by design,
+ # is 8 characters long.
+ #
+ # Thus, the length of socket filename will be:
+ #
+ # len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX')
+ sun_path_len = len(base_tempdir) + 14 + 14
+ if sun_path_len <= _SUN_PATH_MAX:
+ return base_tempdir
+ # Fallback to the default system-wide temporary directory.
+ # This ignores user-defined environment variables.
+ #
+ # On POSIX systems, /tmp MUST be writable by any application [1].
+ # We however emit a warning if this is not the case to prevent
+ # obscure errors later in the execution.
+ #
+ # On some legacy systems, /var/tmp and /usr/tmp can be present
+ # and will be used instead.
+ #
+ # [1]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s18.html
+ dirlist = ['/tmp', '/var/tmp', '/usr/tmp']
+ try:
+ base_system_tempdir = tempfile._get_default_tempdir(dirlist)
+ except FileNotFoundError:
+ warn("Process-wide temporary directory %s will not be usable for "
+ "creating socket files and no usable system-wide temporary "
+ "directory was found in %s", base_tempdir, dirlist)
+ # At this point, the system-wide temporary directory is not usable
+ # but we may assume that the user-defined one is, even if we will
+ # not be able to write socket files out there.
+ return base_tempdir
+ warn("Ignoring user-defined temporary directory: %s", base_tempdir)
+ # at most max(map(len, dirlist)) + 14 + 14 = 36 characters
+ assert len(base_system_tempdir) + 14 + 14 <= _SUN_PATH_MAX
+ return base_system_tempdir
+
def get_temp_dir():
# get name of a temp directory which will be automatically cleaned up
tempdir = process.current_process()._config.get('tempdir')
if tempdir is None:
import shutil, tempfile
- tempdir = tempfile.mkdtemp(prefix='pymp-')
+ base_tempdir = _get_base_temp_dir(tempfile)
+ tempdir = tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir)
info('created temp directory %s', tempdir)
# keep a strong reference to shutil.rmtree(), since the finalizer
# can be called late during Python shutdown