diff -r 259c82332199 Lib/multiprocessing/popen_spawn_posix.py --- a/Lib/multiprocessing/popen_spawn_posix.py Sun Nov 17 16:08:23 2013 -0600 +++ b/Lib/multiprocessing/popen_spawn_posix.py Mon Nov 18 09:58:26 2013 +0100 @@ -30,6 +30,7 @@ class _DupFd(object): class Popen(popen_fork.Popen): method = 'spawn' DupFd = _DupFd + _faulthandler_timeout = None def __init__(self, process_obj): self._fds = [] @@ -57,7 +58,8 @@ class Popen(popen_fork.Popen): parent_r, child_w = os.pipe() child_r, parent_w = os.pipe() cmd = spawn.get_command_line(tracker_fd=tracker_fd, - pipe_handle=child_r) + pipe_handle=child_r, + _faulthandler_timeout=self._faulthandler_timeout) self._fds.extend([child_r, child_w]) self.pid = util.spawnv_passfds(spawn.get_executable(), cmd, self._fds) diff -r 259c82332199 Lib/multiprocessing/popen_spawn_win32.py --- a/Lib/multiprocessing/popen_spawn_win32.py Sun Nov 17 16:08:23 2013 -0600 +++ b/Lib/multiprocessing/popen_spawn_win32.py Mon Nov 18 09:58:26 2013 +0100 @@ -29,6 +29,7 @@ class Popen(object): Start a subprocess to run the code of a process object ''' method = 'spawn' + _faulthandler_timeout = None def __init__(self, process_obj): prep_data = spawn.get_preparation_data(process_obj._name) @@ -38,7 +39,8 @@ class Popen(object): rhandle, whandle = _winapi.CreatePipe(None, 0) wfd = msvcrt.open_osfhandle(whandle, 0) cmd = spawn.get_command_line(parent_pid=os.getpid(), - pipe_handle=rhandle) + pipe_handle=rhandle, + _faulthandler_timeout=self._faulthandler_timeout) cmd = ' '.join('"%s"' % x for x in cmd) with open(wfd, 'wb', closefd=True) as to_child: diff -r 259c82332199 Lib/multiprocessing/spawn.py --- a/Lib/multiprocessing/spawn.py Sun Nov 17 16:08:23 2013 -0600 +++ b/Lib/multiprocessing/spawn.py Mon Nov 18 09:58:26 2013 +0100 @@ -79,7 +79,8 @@ def get_command_line(**kwds): return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork'] -def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None): +def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None, + _faulthandler_timeout=None): ''' Run code specifed by data received over pipe ''' @@ -93,6 +94,9 @@ def spawn_main(pipe_handle, parent_pid=N from . import semaphore_tracker semaphore_tracker._semaphore_tracker._fd = tracker_fd fd = pipe_handle + if _faulthandler_timeout is not None: + import faulthandler + faulthandler.dump_traceback_later(_faulthandler_timeout, exit=True) exitcode = _main(fd) sys.exit(exitcode) diff -r 259c82332199 Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py Sun Nov 17 16:08:23 2013 -0600 +++ b/Lib/test/_test_multiprocessing.py Mon Nov 18 09:58:26 2013 +0100 @@ -87,6 +87,9 @@ HAVE_GETVALUE = not getattr(_multiproces WIN32 = (sys.platform == "win32") +# Kill child processes if they hang more 10 minutes +FAULTHANDLER_TIMEOUT = 10*60 # seconds + from multiprocessing.connection import wait def wait_for_handle(handle, timeout): @@ -1644,9 +1647,15 @@ def mul(x, y): class _TestPool(BaseTestCase): + if os.name == 'nt': + from multiprocessing.popen_spawn_win32 import Popen as _Popen + else: + from multiprocessing.popen_spawn_posix import Popen as _Popen + @classmethod def setUpClass(cls): super().setUpClass() + cls._Popen._faulthandler_timeout = FAULTHANDLER_TIMEOUT cls.pool = cls.Pool(4) @classmethod @@ -1654,6 +1663,7 @@ class _TestPool(BaseTestCase): cls.pool.terminate() cls.pool.join() cls.pool = None + cls._Popen._faulthandler_timeout = None super().tearDownClass() def test_apply(self):