diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst index 94ebd87639c..b588dfa18db 100644 --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -100,8 +100,10 @@ Dumping the tracebacks after a timeout :func:`cancel_dump_traceback_later` is called: see :ref:`issue with file descriptors `. - This function is implemented using a watchdog thread and therefore is not - available if Python is compiled with threads disabled. + This function is implemented using a watchdog thread. + + .. versionchanged:: 3.7 + This function is now always available. .. versionchanged:: 3.5 Added support for passing file descriptor to this function. diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py index 404934ce97a..4e0e30596f5 100644 --- a/Lib/test/eintrdata/eintr_tester.py +++ b/Lib/test/eintrdata/eintr_tester.py @@ -57,9 +57,8 @@ class EINTRBaseTest(unittest.TestCase): # Use faulthandler as watchdog to debug when a test hangs # (timeout of 10 minutes) - if hasattr(faulthandler, 'dump_traceback_later'): - faulthandler.dump_traceback_later(10 * 60, exit=True, - file=sys.__stderr__) + faulthandler.dump_traceback_later(10 * 60, exit=True, + file=sys.__stderr__) @staticmethod def stop_alarm(): @@ -68,8 +67,7 @@ class EINTRBaseTest(unittest.TestCase): def tearDown(self): self.stop_alarm() signal.signal(signal.SIGALRM, self.orig_handler) - if hasattr(faulthandler, 'cancel_dump_traceback_later'): - faulthandler.cancel_dump_traceback_later() + faulthandler.cancel_dump_traceback_later() def subprocess(self, *args, **kw): cmd_args = (sys.executable, '-c') + args diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 47c60126ea6..29970068692 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -164,11 +164,6 @@ class Regrtest: def parse_args(self, kwargs): ns = _parse_args(sys.argv[1:], **kwargs) - if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'): - print("Warning: The timeout option requires " - "faulthandler.dump_traceback_later", file=sys.stderr) - ns.timeout = None - if ns.xmlpath: support.junit_xml_list = self.testsuite_xml = [] diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 24487446f25..a4427a537d1 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -535,8 +535,6 @@ class FaultHandlerTests(unittest.TestCase): with temporary_filename() as filename: self.check_dump_traceback_threads(filename) - @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'), - 'need faulthandler.dump_traceback_later()') def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1, *, filename=None, fd=None): """ @@ -744,9 +742,8 @@ class FaultHandlerTests(unittest.TestCase): faulthandler.enable() with self.check_stderr_none(): faulthandler.dump_traceback() - if hasattr(faulthandler, 'dump_traceback_later'): - with self.check_stderr_none(): - faulthandler.dump_traceback_later(1e-3) + with self.check_stderr_none(): + faulthandler.dump_traceback_later(1e-3) if hasattr(faulthandler, "register"): with self.check_stderr_none(): faulthandler.register(signal.SIGUSR1) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index ef2ee90d2a0..50911995ad1 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -54,8 +54,6 @@ class ParseArgsTestCase(unittest.TestCase): libregrtest._parse_args([opt]) self.assertIn('Run Python regression tests.', out.getvalue()) - @unittest.skipUnless(hasattr(faulthandler, 'dump_traceback_later'), - "faulthandler.dump_traceback_later() required") def test_timeout(self): ns = libregrtest._parse_args(['--timeout', '4.2']) self.assertEqual(ns.timeout, 4.2) @@ -572,8 +570,7 @@ class ProgramsTestCase(BaseTestCase): self.python_args = ['-Wd', '-E', '-bb'] self.regrtest_args = ['-uall', '-rwW', '--testdir=%s' % self.tmptestdir] - if hasattr(faulthandler, 'dump_traceback_later'): - self.regrtest_args.extend(('--timeout', '3600', '-j4')) + self.regrtest_args.extend(('--timeout', '3600', '-j4')) if sys.platform == 'win32': self.regrtest_args.append('-n') diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 011ab5fa28f..129a104dba3 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -19,8 +19,6 @@ /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024) -#define FAULTHANDLER_LATER - #ifndef MS_WINDOWS /* register() is useless on Windows, because only SIGSEGV, SIGABRT and SIGILL can be handled by the process, and these signals can only be used @@ -60,7 +58,6 @@ static struct { #endif } fatal_error = {0, NULL, -1, 0}; -#ifdef FAULTHANDLER_LATER static struct { PyObject *file; int fd; @@ -77,7 +74,6 @@ static struct { /* released by child thread when joined */ PyThread_type_lock running; } thread; -#endif #ifdef FAULTHANDLER_USER typedef struct { @@ -589,8 +585,6 @@ faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored)) return PyBool_FromLong(fatal_error.enabled); } -#ifdef FAULTHANDLER_LATER - static void faulthandler_thread(void *unused) { @@ -790,7 +784,6 @@ faulthandler_cancel_dump_traceback_later_py(PyObject *self, cancel_dump_traceback_later(); Py_RETURN_NONE; } -#endif /* FAULTHANDLER_LATER */ #ifdef FAULTHANDLER_USER @@ -1230,9 +1223,7 @@ faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) static int faulthandler_traverse(PyObject *module, visitproc visit, void *arg) { -#ifdef FAULTHANDLER_LATER Py_VISIT(thread.file); -#endif #ifdef FAULTHANDLER_USER if (user_signals != NULL) { for (size_t signum=0; signum < NSIG; signum++) @@ -1273,7 +1264,6 @@ static PyMethodDef module_methods[] = { PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=True): " "dump the traceback of the current thread, or of all threads " "if all_threads is True, into file")}, -#ifdef FAULTHANDLER_LATER {"dump_traceback_later", (PyCFunction)(void(*)(void))faulthandler_dump_traceback_later, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("dump_traceback_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n" @@ -1284,8 +1274,6 @@ static PyMethodDef module_methods[] = { faulthandler_cancel_dump_traceback_later_py, METH_NOARGS, PyDoc_STR("cancel_dump_traceback_later():\ncancel the previous call " "to dump_traceback_later().")}, -#endif - #ifdef FAULTHANDLER_USER {"register", (PyCFunction)(void(*)(void))faulthandler_register_py, METH_VARARGS|METH_KEYWORDS, @@ -1298,7 +1286,6 @@ static PyMethodDef module_methods[] = { PyDoc_STR("unregister(signum): unregister the handler of the signal " "'signum' registered by register()")}, #endif - {"_read_null", faulthandler_read_null, METH_NOARGS, PyDoc_STR("_read_null(): read from NULL, raise " "a SIGSEGV or SIGBUS signal depending on the platform")}, @@ -1399,9 +1386,7 @@ _PyFaulthandler_Init(int enable) stack.ss_size = SIGSTKSZ * 2; #endif -#ifdef FAULTHANDLER_LATER memset(&thread, 0, sizeof(thread)); -#endif if (enable) { if (faulthandler_init_enable() < 0) { @@ -1413,7 +1398,6 @@ _PyFaulthandler_Init(int enable) void _PyFaulthandler_Fini(void) { -#ifdef FAULTHANDLER_LATER /* later */ if (thread.cancel_event) { cancel_dump_traceback_later(); @@ -1425,7 +1409,6 @@ void _PyFaulthandler_Fini(void) PyThread_free_lock(thread.running); thread.running = NULL; } -#endif #ifdef FAULTHANDLER_USER /* user */