1919from . import process
2020
2121__all__ = [
22- 'sub_debug' , 'debug' , 'info' , 'sub_warning' , 'get_logger' ,
22+ 'sub_debug' , 'debug' , 'info' , 'sub_warning' , 'warn' , ' get_logger' ,
2323 'log_to_stderr' , 'get_temp_dir' , 'register_after_fork' ,
2424 'is_exiting' , 'Finalize' , 'ForkAwareThreadLock' , 'ForkAwareLocal' ,
2525 'close_all_fds_except' , 'SUBDEBUG' , 'SUBWARNING' ,
3434DEBUG = 10
3535INFO = 20
3636SUBWARNING = 25
37+ WARNING = 30
3738
3839LOGGER_NAME = 'multiprocessing'
3940DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
@@ -53,6 +54,10 @@ def info(msg, *args):
5354 if _logger :
5455 _logger .log (INFO , msg , * args , stacklevel = 2 )
5556
57+ def warn (msg , * args ):
58+ if _logger :
59+ _logger .log (WARNING , msg , * args , stacklevel = 2 )
60+
5661def sub_warning (msg , * args ):
5762 if _logger :
5863 _logger .log (SUBWARNING , msg , * args , stacklevel = 2 )
@@ -121,6 +126,21 @@ def is_abstract_socket_namespace(address):
121126# Function returning a temp directory which will be removed on exit
122127#
123128
129+ # Maximum length of a socket file path is usually between 92 and 108 [1],
130+ # but Linux is known to use a size of 108 [2]. BSD-based systems usually
131+ # use a size of 104 or 108 and Windows does not create AF_UNIX sockets.
132+ #
133+ # [1]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html
134+ # [2]: https://man7.org/linux/man-pages/man7/unix.7.html.
135+
136+ if sys .platform == 'linux' :
137+ _SUN_PATH_MAX = 108
138+ elif sys .platform .startswith (('openbsd' , 'freebsd' )):
139+ _SUN_PATH_MAX = 104
140+ else :
141+ # On Windows platforms, we do not create AF_UNIX sockets.
142+ _SUN_PATH_MAX = None if os .name == 'nt' else 92
143+
124144def _remove_temp_dir (rmtree , tempdir ):
125145 rmtree (tempdir )
126146
@@ -130,12 +150,67 @@ def _remove_temp_dir(rmtree, tempdir):
130150 if current_process is not None :
131151 current_process ._config ['tempdir' ] = None
132152
153+ def _get_base_temp_dir (tempfile ):
154+ """Get a temporary directory where socket files will be created.
155+
156+ To prevent additional imports, pass a pre-imported 'tempfile' module.
157+ """
158+ if os .name == 'nt' :
159+ return None
160+ # Most of the time, the default temporary directory is /tmp. Thus,
161+ # listener sockets files "$TMPDIR/pymp-XXXXXXXX/sock-XXXXXXXX" do
162+ # not have a path length exceeding SUN_PATH_MAX.
163+ #
164+ # If users specify their own temporary directory, we may be unable
165+ # to create those files. Therefore, we fall back to the system-wide
166+ # temporary directory /tmp, assumed to exist on POSIX systems.
167+ #
168+ # See https://github.com/python/cpython/issues/132124.
169+ base_tempdir = tempfile .gettempdir ()
170+ # Files created in a temporary directory are suffixed by a string
171+ # generated by tempfile._RandomNameSequence, which, by design,
172+ # is 8 characters long.
173+ #
174+ # Thus, the length of socket filename will be:
175+ #
176+ # len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX')
177+ sun_path_len = len (base_tempdir ) + 14 + 14
178+ if sun_path_len <= _SUN_PATH_MAX :
179+ return base_tempdir
180+ # Fallback to the default system-wide temporary directory.
181+ # This ignores user-defined environment variables.
182+ #
183+ # On POSIX systems, /tmp MUST be writable by any application [1].
184+ # We however emit a warning if this is not the case to prevent
185+ # obscure errors later in the execution.
186+ #
187+ # On some legacy systems, /var/tmp and /usr/tmp can be present
188+ # and will be used instead.
189+ #
190+ # [1]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s18.html
191+ dirlist = ['/tmp' , '/var/tmp' , '/usr/tmp' ]
192+ try :
193+ base_system_tempdir = tempfile ._get_default_tempdir (dirlist )
194+ except FileNotFoundError :
195+ warn ("Process-wide temporary directory %s will not be usable for "
196+ "creating socket files and no usable system-wide temporary "
197+ "directory was found in %s" , base_tempdir , dirlist )
198+ # At this point, the system-wide temporary directory is not usable
199+ # but we may assume that the user-defined one is, even if we will
200+ # not be able to write socket files out there.
201+ return base_tempdir
202+ warn ("Ignoring user-defined temporary directory: %s" , base_tempdir )
203+ # at most max(map(len, dirlist)) + 14 + 14 = 36 characters
204+ assert len (base_system_tempdir ) + 14 + 14 <= _SUN_PATH_MAX
205+ return base_system_tempdir
206+
133207def get_temp_dir ():
134208 # get name of a temp directory which will be automatically cleaned up
135209 tempdir = process .current_process ()._config .get ('tempdir' )
136210 if tempdir is None :
137211 import shutil , tempfile
138- tempdir = tempfile .mkdtemp (prefix = 'pymp-' )
212+ base_tempdir = _get_base_temp_dir (tempfile )
213+ tempdir = tempfile .mkdtemp (prefix = 'pymp-' , dir = base_tempdir )
139214 info ('created temp directory %s' , tempdir )
140215 # keep a strong reference to shutil.rmtree(), since the finalizer
141216 # can be called late during Python shutdown
0 commit comments