88#include <pthread.h>
99#endif
1010
11-
1211/* Allocate at maximum 100 MB of the stack to raise the stack overflow */
1312#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024)
1413
@@ -72,6 +71,7 @@ typedef struct {
7271 PyObject * file ;
7372 int fd ;
7473 int all_threads ;
74+ int chain ;
7575 _Py_sighandler_t previous ;
7676 PyInterpreterState * interp ;
7777} user_signal_t ;
@@ -94,6 +94,7 @@ static user_signal_t *user_signals;
9494# endif
9595#endif
9696
97+ static void faulthandler_user (int signum );
9798#endif /* FAULTHANDLER_USER */
9899
99100
@@ -259,9 +260,9 @@ faulthandler_fatal_error(int signum)
259260
260261 /* restore the previous handler */
261262#ifdef HAVE_SIGACTION
262- (void )sigaction (handler -> signum , & handler -> previous , NULL );
263+ (void )sigaction (signum , & handler -> previous , NULL );
263264#else
264- (void )signal (handler -> signum , handler -> previous );
265+ (void )signal (signum , handler -> previous );
265266#endif
266267 handler -> enabled = 0 ;
267268
@@ -587,6 +588,39 @@ faulthandler_cancel_dump_tracebacks_later_py(PyObject *self)
587588#endif /* FAULTHANDLER_LATER */
588589
589590#ifdef FAULTHANDLER_USER
591+ static int
592+ faulthandler_register (int signum , int chain , _Py_sighandler_t * p_previous )
593+ {
594+ #ifdef HAVE_SIGACTION
595+ struct sigaction action ;
596+ action .sa_handler = faulthandler_user ;
597+ sigemptyset (& action .sa_mask );
598+ /* if the signal is received while the kernel is executing a system
599+ call, try to restart the system call instead of interrupting it and
600+ return EINTR. */
601+ action .sa_flags = SA_RESTART ;
602+ if (chain ) {
603+ /* do not prevent the signal from being received from within its
604+ own signal handler */
605+ action .sa_flags = SA_NODEFER ;
606+ }
607+ #ifdef HAVE_SIGALTSTACK
608+ if (stack .ss_sp != NULL ) {
609+ /* Call the signal handler on an alternate signal stack
610+ provided by sigaltstack() */
611+ action .sa_flags |= SA_ONSTACK ;
612+ }
613+ #endif
614+ return sigaction (signum , & action , p_previous );
615+ #else
616+ _Py_sighandler_t previous ;
617+ previous = signal (signum , faulthandler_user );
618+ if (p_previous != NULL )
619+ * p_previous = previous ;
620+ return (previous == SIG_ERR );
621+ #endif
622+ }
623+
590624/* Handler of user signals (e.g. SIGUSR1).
591625
592626 Dump the traceback of the current thread, or of all threads if
@@ -621,6 +655,19 @@ faulthandler_user(int signum)
621655 return ;
622656 _Py_DumpTraceback (user -> fd , tstate );
623657 }
658+ #ifdef HAVE_SIGACTION
659+ if (user -> chain ) {
660+ (void )sigaction (signum , & user -> previous , NULL );
661+ /* call the previous signal handler */
662+ raise (signum );
663+ (void )faulthandler_register (signum , user -> chain , NULL );
664+ }
665+ #else
666+ if (user -> chain ) {
667+ /* call the previous signal handler */
668+ user -> previous (signum );
669+ }
670+ #endif
624671 errno = save_errno ;
625672}
626673
@@ -646,25 +693,23 @@ check_signum(int signum)
646693}
647694
648695static PyObject *
649- faulthandler_register (PyObject * self ,
650- PyObject * args , PyObject * kwargs )
696+ faulthandler_register_py (PyObject * self ,
697+ PyObject * args , PyObject * kwargs )
651698{
652- static char * kwlist [] = {"signum" , "file" , "all_threads" , NULL };
699+ static char * kwlist [] = {"signum" , "file" , "all_threads" , "chain" , NULL };
653700 int signum ;
654701 PyObject * file = NULL ;
655702 int all_threads = 1 ;
703+ int chain = 0 ;
656704 int fd ;
657705 user_signal_t * user ;
658706 _Py_sighandler_t previous ;
659- #ifdef HAVE_SIGACTION
660- struct sigaction action ;
661- #endif
662707 PyThreadState * tstate ;
663708 int err ;
664709
665710 if (!PyArg_ParseTupleAndKeywords (args , kwargs ,
666- "i|Oi :register" , kwlist ,
667- & signum , & file , & all_threads ))
711+ "i|Oii :register" , kwlist ,
712+ & signum , & file , & all_threads , & chain ))
668713 return NULL ;
669714
670715 if (!check_signum (signum ))
@@ -686,25 +731,7 @@ faulthandler_register(PyObject *self,
686731 user = & user_signals [signum ];
687732
688733 if (!user -> enabled ) {
689- #ifdef HAVE_SIGACTION
690- action .sa_handler = faulthandler_user ;
691- sigemptyset (& action .sa_mask );
692- /* if the signal is received while the kernel is executing a system
693- call, try to restart the system call instead of interrupting it and
694- return EINTR */
695- action .sa_flags = SA_RESTART ;
696- #ifdef HAVE_SIGALTSTACK
697- if (stack .ss_sp != NULL ) {
698- /* Call the signal handler on an alternate signal stack
699- provided by sigaltstack() */
700- action .sa_flags |= SA_ONSTACK ;
701- }
702- #endif
703- err = sigaction (signum , & action , & previous );
704- #else
705- previous = signal (signum , faulthandler_user );
706- err = (previous == SIG_ERR );
707- #endif
734+ err = faulthandler_register (signum , chain , & previous );
708735 if (err ) {
709736 PyErr_SetFromErrno (PyExc_OSError );
710737 return NULL ;
@@ -716,6 +743,7 @@ faulthandler_register(PyObject *self,
716743 user -> file = file ;
717744 user -> fd = fd ;
718745 user -> all_threads = all_threads ;
746+ user -> chain = chain ;
719747 user -> previous = previous ;
720748 user -> interp = tstate -> interp ;
721749 user -> enabled = 1 ;
@@ -947,8 +975,8 @@ static PyMethodDef module_methods[] = {
947975
948976#ifdef FAULTHANDLER_USER
949977 {"register" ,
950- (PyCFunction )faulthandler_register , METH_VARARGS |METH_KEYWORDS ,
951- PyDoc_STR ("register(signum, file=sys.stderr, all_threads=True): "
978+ (PyCFunction )faulthandler_register_py , METH_VARARGS |METH_KEYWORDS ,
979+ PyDoc_STR ("register(signum, file=sys.stderr, all_threads=True, chain=False ): "
952980 "register an handler for the signal 'signum': dump the "
953981 "traceback of the current thread, or of all threads if "
954982 "all_threads is True, into file" )},
0 commit comments