99#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr()
1010#include "pycore_time.h" // _PyTime_FromSecondsObject()
1111#include "pycore_traceback.h" // _Py_DumpTracebackThreads
12-
1312#ifdef HAVE_UNISTD_H
1413# include <unistd.h> // _exit()
1514#endif
15+
1616#include <signal.h> // sigaction()
1717#include <stdlib.h> // abort()
1818#if defined(HAVE_PTHREAD_SIGMASK ) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK ) && defined(HAVE_PTHREAD_H )
@@ -210,6 +210,25 @@ faulthandler_dump_traceback(int fd, int all_threads,
210210 reentrant = 0 ;
211211}
212212
213+ static void
214+ faulthandler_dump_c_stack (int fd )
215+ {
216+ static volatile int reentrant = 0 ;
217+
218+ if (reentrant ) {
219+ return ;
220+ }
221+
222+ reentrant = 1 ;
223+
224+ if (fatal_error .c_stack ) {
225+ PUTS (fd , "\n" );
226+ _Py_DumpStack (fd );
227+ }
228+
229+ reentrant = 0 ;
230+ }
231+
213232static PyObject *
214233faulthandler_dump_traceback_py (PyObject * self ,
215234 PyObject * args , PyObject * kwargs )
@@ -260,6 +279,33 @@ faulthandler_dump_traceback_py(PyObject *self,
260279 Py_RETURN_NONE ;
261280}
262281
282+ static PyObject *
283+ faulthandler_dump_c_stack_py (PyObject * self ,
284+ PyObject * args , PyObject * kwargs )
285+ {
286+ static char * kwlist [] = {"file" , NULL };
287+ PyObject * file = NULL ;
288+
289+ if (!PyArg_ParseTupleAndKeywords (args , kwargs ,
290+ "|O:dump_c_stack" , kwlist ,
291+ & file )) {
292+ return NULL ;
293+ }
294+
295+ int fd = faulthandler_get_fileno (& file );
296+ if (fd < 0 ) {
297+ return NULL ;
298+ }
299+
300+ _Py_DumpStack (fd );
301+
302+ if (PyErr_CheckSignals ()) {
303+ return NULL ;
304+ }
305+
306+ Py_RETURN_NONE ;
307+ }
308+
263309static void
264310faulthandler_disable_fatal_handler (fault_handler_t * handler )
265311{
@@ -350,6 +396,7 @@ faulthandler_fatal_error(int signum)
350396
351397 faulthandler_dump_traceback (fd , deduce_all_threads (),
352398 fatal_error .interp );
399+ faulthandler_dump_c_stack (fd );
353400
354401 _Py_DumpExtensionModules (fd , fatal_error .interp );
355402
@@ -425,6 +472,7 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
425472
426473 faulthandler_dump_traceback (fd , deduce_all_threads (),
427474 fatal_error .interp );
475+ faulthandler_dump_c_stack (fd );
428476
429477 /* call the next exception handler */
430478 return EXCEPTION_CONTINUE_SEARCH ;
@@ -519,14 +567,15 @@ faulthandler_enable(void)
519567static PyObject *
520568faulthandler_py_enable (PyObject * self , PyObject * args , PyObject * kwargs )
521569{
522- static char * kwlist [] = {"file" , "all_threads" , NULL };
570+ static char * kwlist [] = {"file" , "all_threads" , "c_stack" , NULL };
523571 PyObject * file = NULL ;
524572 int all_threads = 1 ;
525573 int fd ;
574+ int c_stack = 1 ;
526575 PyThreadState * tstate ;
527576
528577 if (!PyArg_ParseTupleAndKeywords (args , kwargs ,
529- "|Op :enable" , kwlist , & file , & all_threads ))
578+ "|Opp :enable" , kwlist , & file , & all_threads , & c_stack ))
530579 return NULL ;
531580
532581 fd = faulthandler_get_fileno (& file );
@@ -543,6 +592,7 @@ faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
543592 fatal_error .fd = fd ;
544593 fatal_error .all_threads = all_threads ;
545594 fatal_error .interp = PyThreadState_GetInterpreter (tstate );
595+ fatal_error .c_stack = c_stack ;
546596
547597 if (faulthandler_enable () < 0 ) {
548598 return NULL ;
@@ -1238,6 +1288,10 @@ static PyMethodDef module_methods[] = {
12381288 PyDoc_STR ("dump_traceback($module, /, file=sys.stderr, all_threads=True)\n--\n\n"
12391289 "Dump the traceback of the current thread, or of all threads "
12401290 "if all_threads is True, into file." )},
1291+ {"dump_c_stack" ,
1292+ _PyCFunction_CAST (faulthandler_dump_c_stack_py ), METH_VARARGS |METH_KEYWORDS ,
1293+ PyDoc_STR ("dump_c_stack($module, /, file=sys.stderr)\n--\n\n"
1294+ "Dump the C stack of the current thread." )},
12411295 {"dump_traceback_later" ,
12421296 _PyCFunction_CAST (faulthandler_dump_traceback_later ), METH_VARARGS |METH_KEYWORDS ,
12431297 PyDoc_STR ("dump_traceback_later($module, /, timeout, repeat=False, file=sys.stderr, exit=False)\n--\n\n"
0 commit comments