/*1Interrupt and signal handling for Sage.23For documentation about how to use these, see the Developer's Guide.456AUTHORS:78- William Stein, Martin Albrecht (2006): initial version910- Jeroen Demeyer (2010-10-03): almost complete rewrite (#9678)1112*/1314/*****************************************************************************15* Copyright (C) 2006 William Stein <[email protected]>16* 2006 Martin Albrecht <[email protected]>17* 2010 Jeroen Demeyer <[email protected]>18*19* Distributed under the terms of the GNU General Public License (GPL)20* as published by the Free Software Foundation; either version 2 of21* the License, or (at your option) any later version.22* http://www.gnu.org/licenses/23****************************************************************************/2425/* Whether or not to enable interrupt debugging (0: disable, 1: enable) */26#define ENABLE_DEBUG_INTERRUPT 0272829#ifndef C_LIB_INCLUDE_INTERRUPT_H30#define C_LIB_INCLUDE_INTERRUPT_H31#include <Python.h>32#include <setjmp.h>33#include <signal.h>3435#ifdef __cplusplus36extern "C" {37#endif383940/* Declare likely() and unlikely() as in Cython */41#ifdef __GNUC__42/* Test for GCC > 2.95 */43#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))44#define HAVE_BUILTIN_EXPECT 145#endif46#endif4748#if HAVE_BUILTIN_EXPECT49#define likely(x) __builtin_expect(!!(x), 1)50#define unlikely(x) __builtin_expect(!!(x), 0)51#else52#define likely(x) (x)53#define unlikely(x) (x)54#endif55565758/* Print a C backtrace if supported by libc */59void print_backtrace(void);6061/* Print a message s and kill ourselves with signal sig */62void sigdie(int sig, const char* s);636465/*66* The signal handlers for Sage, one for SIGINT and one for other67* signals.68* Inside sig_on() (i.e. when _signals.sig_on_count is positive), this69* raises an exception and jumps back to sig_on().70* Outside of sig_on(), sage_interrupt_handler() sets Python's71* interrupt flag using PyErr_SetInterrupt(); sage_signal_handler()72* terminates Sage.73*/74void sage_interrupt_handler(int sig); /* SIGINT */75void sage_signal_handler(int sig); /* Other signals */7677/* Wrapper to call sage_interrupt_handler() "by hand". */78void call_sage_interrupt_handler(int sig);7980/*81* Setup the signal handlers for SIGINT, SIGILL, SIGABRT, SIGFPE82* SIGBUS, SIGSEGV. It is safe to call this more than once.83*84* We do not handle SIGALRM since there is code to deal with85* alarms in sage/misc/misc.py86*/87void setup_sage_signal_handler(void);888990/**********************************************************************91* SAGE_SIGNALS_T STRUCTURE *92**********************************************************************/9394/* All the state of the signal handler is in this struct. */95struct sage_signals_t96{97/* Reference counter for sig_on().98* If this is strictly positive, we are inside a sig_on(). */99volatile sig_atomic_t sig_on_count;100101/* If this is nonzero, check for interrupts using PyErr_Occured()102* during sig_on() and sig_unblock(). This value is increased103* whenever an interrupt happens outside of sig_on() or inside104* sig_block(). */105volatile sig_atomic_t interrupt_received;106107/* Are we currently handling a signal inside sage_signal_handler()?108* This is set to 1 on entry in sage_signal_handler (not in109* sage_interrupt_handler) and 0 in _sig_on_postjmp. This is110* needed to check for signals raised within the signal handler. */111volatile sig_atomic_t inside_signal_handler;112113/* Non-zero if we currently are in a function which blocks SIGINT,114* zero normally. See sig_block(), sig_unblock(). */115volatile sig_atomic_t block_sigint;116117/* A jump buffer holding where to siglongjmp() after a signal has118* been received. This is set by sig_on(). */119sigjmp_buf env;120121/* An optional string may be passed to the signal handler which122* will be used as the text for the exception. This can be set123* using sig_str() instead of sig_on() or it can be changed by124* set_sage_signal_handler_message() declared below.125*/126const char* s;127};128129/*130* The actual object (there is a unique copy of this throughout Sage).131*/132extern struct sage_signals_t _signals;133134135/**********************************************************************136* IMPLEMENTATION OF SIG_ON/SIG_OFF *137**********************************************************************/138139/*140* Implementation of sig_on(). Applications should not use this141* directly, use sig_on() or sig_str() instead.142*143* _sig_on_(message) is a macro which pretends to be a function.144* Since this is declared as "cdef except 0", Cython will know that an145* exception occured if the value of _sig_on_() is 0 (false).146*147* INPUT:148*149* - message -- a string to be displayed as error message when the code150* between sig_on() and sig_off() fails and raises an exception.151*152* OUTPUT: zero if an exception occured, non-zero otherwise.153*154* The function sigsetjmp() in the _sig_on_() macro can return:155* - zero: this happens in the actual sig_on() call. sigsetjmp() sets156* up the address for the Sage signal handler to jump to. The157* program continues normally.158* - a signal number (e.g. 2 for SIGINT), assumed to be strictly159* positive: the Sage signal handler handled a signal. Since160* _sig_on_() will return 0 in this case, the Exception (raised by161* sage_signal_handler) will be detected by Cython.162* - a negative number: this is assumed to come from sig_retry(). In163* this case, the program continues as if nothing happened between164* sig_on() and sig_retry().165*166* We cannot simply put sigsetjmp() in a function, because when that167* function returns, we would lose the stack frame to siglongjmp() to.168* That's why we need this hackish macro. We use the fact that || is169* a short-circuiting operator (the second argument is only evaluated170* if the first returns 0).171*/172#define _sig_on_(message) ( unlikely(_sig_on_prejmp(message, __FILE__, __LINE__)) || _sig_on_postjmp(sigsetjmp(_signals.env,0)) )173174/* This will be called during _sig_on_postjmp() when a SIGINT was175* received *before* the call to sig_on().176* Return 0 if there was an interrupt, 1 otherwise. */177int _sig_on_interrupt_received(void);178179/*180* Set message, return 0 if we need to sigsetjmp(), return 1 otherwise.181*/182static inline int _sig_on_prejmp(const char* message, const char* file, int line)183{184_signals.s = message;185#if ENABLE_DEBUG_INTERRUPT186fprintf(stderr, "sig_on (counter = %i) at %s:%i\n", _signals.sig_on_count+1, file, line);187fflush(stderr);188#endif189if (_signals.sig_on_count > 0)190{191_signals.sig_on_count++;192return 1;193}194195/* At this point, _signals.sig_on_count == 0 */196return 0;197}198199200/* Cleanup after siglongjmp() (reset signal mask to the default, set201* sig_on_count to zero) */202void _sig_on_recover(void);203204/*205* Process the return value of sigsetjmp().206* Return 0 if there was an exception, 1 otherwise.207*/208static inline int _sig_on_postjmp(int jmpret)209{210if (unlikely(jmpret > 0))211{212/* An exception occured */213_sig_on_recover();214return 0;215}216217/* When we are here, it's either the original sig_on() call or we218* got here after sig_retry(). */219_signals.sig_on_count = 1;220221/* Check whether we received an interrupt before this point.222* _signals.interrupt_received can only be set by the interrupt223* handler if _signals.sig_on_count is zero. Because of that and224* because _signals.sig_on_count and _signals.interrupt_received are225* volatile, we can safely evaluate _signals.interrupt_received here226* without race conditions. */227if (unlikely(_signals.interrupt_received))228return _sig_on_interrupt_received();229230return 1;231}232233/* Give a warning that sig_off() was called without sig_on() */234void _sig_off_warning(const char* file, int line);235236/*237* Implementation of sig_off(). Applications should not use this238* directly, use sig_off() instead.239*/240static inline void _sig_off_(const char* file, int line)241{242#if ENABLE_DEBUG_INTERRUPT243fprintf(stderr, "sig_off (counter = %i) at %s:%i\n", _signals.sig_on_count, file, line);244fflush(stderr);245#endif246if (unlikely(_signals.sig_on_count <= 0))247{248_sig_off_warning(file, line);249}250else251{252--_signals.sig_on_count;253}254}255256257258/**********************************************************************259* USER MACROS/FUNCTIONS *260**********************************************************************/261262/* The actual macros which should be used in a program. */263#define sig_on() _sig_on_(NULL)264#define sig_str(message) _sig_on_(message)265#define sig_off() _sig_off_(__FILE__, __LINE__)266267/* These deprecated macros provide backwards compatibility with268* sage-4.6 and earlier */269#define _sig_on {if (!_sig_on_(NULL)) return 0;}270#define _sig_str(s) {if (!_sig_on_(s)) return 0;}271#define _sig_off {_sig_off_(__FILE__, __LINE__);}272273274/* sig_check() should be functionally equivalent to sig_on(); sig_off();275* but much faster. Essentially, it checks whether we missed any276* interrupts.277*278* OUTPUT: zero if an interrupt occured, non-zero otherwise.279*/280static inline int sig_check()281{282if (unlikely(_signals.interrupt_received) && _signals.sig_on_count == 0)283return _sig_on_interrupt_received();284285return 1;286}287288/* Macros behaving exactly like sig_on, sig_str and sig_check289* but which are *not* declared cdef except 0. This is useful if some290* Cython code wants to do its own exception handling. */291#define sig_on_no_except() sig_on()292#define sig_str_no_except(message) sig_str(message)293#define sig_check_no_except() sig_check()294295296/*297* Temporarily block interrupts from happening inside sig_on(). This298* is meant to wrap malloc() for example. sig_unblock() checks whether299* an interrupt happened in the mean time. If yes, the interrupt is300* re-raised.301*302* NOTES:303* - This only works inside sig_on()/sig_off(). Outside of sig_on(),304* interrupts behave as usual. This is because we can't propagate305* Python exceptions from low-level C code.306* - Other signals still go through, because we can't really ignore307* SIGSEGV for example.308* - For efficiency reasons, currently these may NOT be nested.309* Nesting could be implemented like src/headers/pariinl.h in PARI.310*/311static inline void sig_block()312{313_signals.block_sigint = 1;314}315316static inline void sig_unblock()317{318_signals.block_sigint = 0;319320if (unlikely(_signals.interrupt_received) && _signals.sig_on_count > 0)321kill(getpid(), SIGINT); /* Re-raise the interrupt */322}323324325/*326* Call this before raising an exception to set _signals.s. The string327* s will be used as the text for the exception. Note that s is not328* copied, we just store the pointer.329*/330void set_sage_signal_handler_message(const char* s);331332333/*334* Retry a failed computation starting from sig_on(). This is useful335* for PARI: if PARI complains that it doesn't have enough memory, we336* allocate a larger stack and retry the computation.337*/338static inline void sig_retry()339{340/* If we're outside of sig_on(), we can't jump, so we can only bail341* out */342if (unlikely(_signals.sig_on_count <= 0))343{344fprintf(stderr, "sig_retry() without sig_on()\n");345abort();346}347siglongjmp(_signals.env, -1);348}349350351/*352* This function does nothing, but it is declared cdef except *, so it353* can be used to make Cython check whether there is a pending exception354* (PyErr_Occurred() is non-NULL).355* To Cython, it will look like cython_check_exception() actually356* raised the exception.357*/358static inline void cython_check_exception() {return;}359360361#ifdef __cplusplus362} /* extern "C" */363#endif364#endif /* C_LIB_INCLUDE_INTERRUPT_H */365366367