Ticket #9640: 9640-pari_error_handling.patch

File 9640-pari_error_handling.patch, 11.9 KB (added by pbruin, 8 years ago)

based on 5.12.beta4 + #15124

  • c_lib/include/interrupt.h

    # HG changeset patch
    # User Peter Bruin <P.Bruin@warwick.ac.uk>
    # Date 1378912641 -3600
    # Node ID c986f602233bb76cab13eccbc3970157963cdd2c
    # Parent  4275212b576c16066ba6d5e9574e057c7f558bc8
    Trac 9640: change PARI error catching mechanism
    
    diff --git a/c_lib/include/interrupt.h b/c_lib/include/interrupt.h
    a b  
    291291    }
    292292}
    293293
     294extern void sage_siglongjmp(int err);
    294295
    295296
    296297/**********************************************************************
  • c_lib/src/interrupt.c

    diff --git a/c_lib/src/interrupt.c b/c_lib/src/interrupt.c
    a b  
    9393#endif
    9494}
    9595
     96inline void sage_siglongjmp(int err) {
     97  reset_CPU();
     98  siglongjmp(_signals.env, err);
     99}
    96100
    97101/* Handler for SIGHUP, SIGINT */
    98102void sage_interrupt_handler(int sig)
     
    116120            sig_raise_exception(sig);
    117121
    118122            /* Jump back to sig_on() (the first one if there is a stack) */
    119             reset_CPU();
    120             siglongjmp(_signals.env, sig);
     123            sage_siglongjmp(sig);
    121124        }
    122125    }
    123126    else
     
    157160        sig_raise_exception(sig);
    158161
    159162        /* Jump back to sig_on() (the first one if there is a stack) */
    160         reset_CPU();
    161         siglongjmp(_signals.env, sig);
     163        sage_siglongjmp(sig);
    162164    }
    163165    else
    164166    {
  • sage/libs/pari/decl.pxi

    diff --git a/sage/libs/pari/decl.pxi b/sage/libs/pari/decl.pxi
    a b  
    4747    ctypedef unsigned long pari_sp
    4848    extern pari_sp avma, bot, top
    4949
     50    # parierr.h
     51
     52    int talker2, bugparier, alarmer, openfiler, talker, flagerr, impl, \
     53        archer, notfuncer, precer, typeer, consister, user, errpile, \
     54        overflower, matinv1, mattype1, arither1, primer1, invmoder, \
     55        constpoler, notpoler, redpoler, zeropoler, operi, operf, gdiver, \
     56        memer, negexper, sqrter5, noer
     57
     58    int warner, warnprec, warnfile, warnmem
    5059
    5160    # parigen.h
    5261
     
    19091918        void (*putch)(char)
    19101919        void (*puts)(char*)
    19111920        void (*flush)()
    1912     extern PariOUT* pariOut
     1921    extern PariOUT *pariOut, *pariErr
    19131922
    19141923
    19151924cdef extern from 'pari/paripriv.h':
  • sage/libs/pari/gen.pxd

    diff --git a/sage/libs/pari/gen.pxd b/sage/libs/pari/gen.pxd
    a b  
    33cimport sage.structure.element
    44cimport sage.structure.parent_base
    55
    6 cdef void _pari_trap "_pari_trap"(long errno, long retries) except *
    7 
    86cdef class gen(sage.structure.element.RingElement):
    97    cdef GEN g
    108    cdef object _refers_to
     
    2018
    2119cdef class PariInstance(sage.structure.parent_base.ParentWithBase):
    2220    cdef gen PARI_ZERO, PARI_ONE, PARI_TWO
     21    cdef str error_string
    2322    cdef gen new_gen(self, GEN x)
    2423    cdef object new_gen_to_string(self, GEN x)
    2524    cdef gen new_gen_noclear(self, GEN x)
  • sage/libs/pari/gen.pyx

    diff --git a/sage/libs/pari/gen.pyx b/sage/libs/pari/gen.pyx
    a b  
    92469246    return
    92479247
    92489248
     9249cdef PariOUT sage_pariErr
     9250
     9251cdef void sage_pariErr_putchar(char c):
     9252    cdef char s[2]
     9253    s[0] = c
     9254    s[1] = 0
     9255    pari_instance.error_string += str(s)
     9256    return
     9257
     9258cdef void sage_pariErr_puts(char *s):
     9259    pari_instance.error_string += str(s)
     9260    return
     9261
     9262cdef void sage_pariErr_flush():
     9263    return
     9264
     9265
    92499266cdef class PariInstance(sage.structure.parent_base.ParentWithBase):
    92509267    def __init__(self, long size=16000000, unsigned long maxprime=500000):
    92519268        """
     
    92919308        global num_primes, avma, top, bot, prec
    92929309
    92939310        # The size here doesn't really matter, because we will allocate
    9294         # our own stack anyway. We ask PARI not to set up signal handlers.
    9295         pari_init_opts(10000, maxprime, INIT_JMPm | INIT_DFTm)
     9311        # our own stack anyway. We ask PARI not to set up signal and
     9312        # error handlers.
     9313        pari_init_opts(10000, maxprime, INIT_DFTm)
     9314        _pari_init_err()
    92969315        num_primes = maxprime
    92979316
    92989317        # NOTE: pari_catch_sig_on() can only come AFTER pari_init_opts()!
     
    93119330        GP_DATA.fmt.sigd = prec_bits_to_dec(53)
    93129331
    93139332        # Set printing functions
    9314         global pariOut
     9333        global pariOut, pariErr
     9334
    93159335        pariOut = &sage_pariOut
    93169336        pariOut.putch = sage_putchar
    93179337        pariOut.puts = sage_puts
    93189338        pariOut.flush = sage_flush
     9339
     9340        pariErr = &sage_pariErr
     9341        pariErr.putch = sage_pariErr_putchar
     9342        pariErr.puts = sage_pariErr_puts
     9343        pariErr.flush = sage_pariErr_flush
     9344
     9345        self.error_string = ''
     9346
    93199347        pari_catch_sig_off()
    93209348
    93219349    def __dealloc__(self):
     
    97729800            return v
    97739801
    97749802        t = str(s)
    9775         pari_catch_sig_str('evaluating PARI string')
     9803        pari_catch_sig_on()
    97769804        g = gp_read_str(t)
    97779805        if g == gnil:
    97789806            pari_catch_sig_off()
     
    98929920            return fetch_user_var(s)
    98939921        return -1
    98949922
     9923    def get_error_string(self):
     9924        return self.error_string
     9925
     9926
    98959927    ############################################################
    98969928    # Initialization
    98979929    ############################################################
     
    1051610548
    1051710549cdef extern from "pari/pari.h":
    1051810550    char *errmessage[]
    10519     int talker2, bugparier, alarmer, openfiler, talker, flagerr, impl, \
    10520         archer, notfuncer, precer, typeer, consister, user, errpile, \
    10521         overflower, matinv1, mattype1, arither1, primer1, invmoder, \
    10522         constpoler, notpoler, redpoler, zeropoler, operi, operf, gdiver, \
    10523         memer, negexper, sqrter5, noer
    10524     int warner, warnprec, warnfile, warnmem
    1052510551
    1052610552cdef extern from "misc.h":
    1052710553    int     factorint_withproof_sage(GEN* ans, GEN x, GEN cutoff)
     
    1058010606        return "%s (%d)"%(self.errmessage(self.errnum()), self.errnum())
    1058110607
    1058210608
    10583 # We expose a trap function to C.
    10584 # If this function returns without raising an exception,
    10585 # the code is retried.
    10586 # This is a proof-of-concept example.
    10587 # THE TRY CODE IS NOT REENTRANT -- NO CALLS TO PARI FROM HERE !!!
    10588 #              - Gonzalo Tornario
    10589 
    10590 cdef void _pari_trap "_pari_trap"(long errno, long retries) except *:
    10591     if retries > 100:
    10592         pari_catch_sig_off()
    10593         raise RuntimeError("_pari_trap recursion too deep")
    10594     if errno == errpile:
    10595         P.allocatemem(silent=True)
    10596     elif errno == user:
    10597         pari_catch_sig_off()
    10598         raise RuntimeError("PARI user exception")
    10599     else:
    10600         pari_catch_sig_off()
    10601         raise PariError(errno)
    10602 
    10603 
    1060410609def vecsmall_to_intlist(gen v):
    1060510610    """
    1060610611    INPUT:
  • sage/libs/pari/pari_err.h

    diff --git a/sage/libs/pari/pari_err.h b/sage/libs/pari/pari_err.h
    a b  
    55/*****************************************
    66   Interrupts and PARI exception handling
    77 *****************************************/
    8 #define pari_catch_sig_on() sig_on(); _pari_catch;
    9 #define pari_catch_sig_str(s) sig_str(s); _pari_catch;
    10 #define pari_catch_sig_off() _pari_endcatch; sig_off();
    118
     9static PyObject *__pyx_d;  /* Cython pointer to dictionary of this module */
     10static PyObject *__pyx_empty_tuple;
    1211
    13 // global catch variable !
    14 // this means that the code is not reentrant -- beware !
    15 // THAT MEANS NO CALLING TO PARI from inside the trap....
    16 // Should replace by a stack, that would work.
    17 static volatile long sage_pari_catcherr = 0;
     12static int _pari_handle_exception(long err);
     13static void _pari_err_recover(long err);
    1814
    19 /* Careful with pari_retries, it must be declared volatile!
    20  * Also note that "pari_errno = setjmp(...)" is not legal C.
    21  */
    22 #define _pari_catch                                                           \
    23     jmp_buf _pari_catch_env;                                                  \
    24     {                                                                         \
    25         volatile long pari_retries = 0;                                       \
    26         sage_pari_catcherr = 0;                                               \
    27         long pari_errno = setjmp(_pari_catch_env);                            \
    28         if (pari_errno) {                                                     \
    29             _pari_trap(pari_errno, pari_retries);                             \
    30             if(PyErr_Occurred()) {                                            \
    31                 _pari_endcatch;                                               \
    32                 return NULL;                                                  \
    33             }                                                                 \
    34             pari_retries++;                                                   \
    35         }                                                                     \
    36         sage_pari_catcherr = err_catch(CATCH_ALL, &_pari_catch_env);          \
     15static void _pari_init_err(void) {
     16  cb_pari_err_recover = &_pari_err_recover;
     17  /* disable_color = 1; */
     18}
     19
     20#define _pari_sig_on_(message) (unlikely(_pari_sig_on_prejmp(message, __FILE__, __LINE__))    \
     21                                || _sig_on_postjmp(sigsetjmp(_signals.env, 0)))
     22
     23static inline int _pari_sig_on_prejmp(const char* message, const char* file, int line)
     24{
     25  int i = _sig_on_prejmp(message, file, line);
     26  if (!i)
     27    cb_pari_handle_exception = &_pari_handle_exception;
     28  return i;
     29}
     30
     31static inline void _pari_sig_off_(const char *file, int line)
     32{
     33  _sig_off_(file, line);
     34  if(_signals.sig_on_count == 0)
     35    cb_pari_handle_exception = NULL;
     36}
     37
     38static int _pari_handle_exception(long err)
     39{
     40  if(err == errpile)
     41    {
     42      /* pari.allocatemem(silent=True) */
     43      PyObject *gen, *pari, *allocatemem, *kwds, *result;
     44      gen = PyImport_ImportModule("sage.libs.pari.gen");
     45      pari = PyObject_GetAttrString(gen, "pari");
     46      Py_DECREF(gen);
     47      allocatemem = PyObject_GetAttrString(pari, "allocatemem");
     48      Py_DECREF(pari);
     49      kwds = PyDict_New();
     50      Py_INCREF(Py_True);
     51      PyDict_SetItemString(kwds, "silent", Py_True);  /* steals reference to PyTrue */
     52      result = PyObject_Call(allocatemem, __pyx_empty_tuple, kwds);
     53      Py_DECREF(allocatemem);
     54      Py_DECREF(kwds);
     55      /* We do not use the result, but check in _pari_err_recover()
     56         whether an exception was raised.  */
     57      Py_XDECREF(result);
     58    }
     59  else if(err == user)
     60    {
     61      /* raise RuntimeError("PARI user exception") */
     62      PyErr_SetString(PyExc_RuntimeError, "PARI user exception");
     63    }
     64  else
     65    {
     66      /* raise PariError(err) */
     67      PyObject *PariError, *s, *n;
     68      s = PyString_FromString("PariError");
     69      PariError = PyDict_GetItem(__pyx_d, s);  /* borrowed reference */
     70      Py_DECREF(s);
     71      n = PyInt_FromLong(err);
     72      PyErr_SetObject(PariError, n);
     73      Py_DECREF(n);
     74    }
     75  return 0;
     76}
     77
     78static void _pari_err_recover(long err)
     79{
     80  if((err == errpile) && !PyErr_Occurred())
     81    {
     82      /* We successfully enlarged the PARI stack.  */
     83      sig_retry();
    3784    }
    3885
    39 #define _pari_endcatch {                                                      \
    40          err_leave(sage_pari_catcherr);                                       \
    41     }
     86  /*
     87    An exception was raised.  We disable PARI error catching and call
     88    sage_siglongjmp() with a more or less arbitrary value; the only
     89    important thing is that it is positive.
     90  */
     91  cb_pari_handle_exception = NULL;
     92  sage_siglongjmp(SIGUSR1);
     93}
    4294
     95#define pari_catch_sig_on() _pari_sig_on_(NULL)
     96#define pari_catch_sig_str(s) _pari_sig_on_(s)
     97#define pari_catch_sig_off() _pari_sig_off_(__FILE__, __LINE__)
  • sage/libs/pari/pari_err.pxi

    diff --git a/sage/libs/pari/pari_err.pxi b/sage/libs/pari/pari_err.pxi
    a b  
    1 # We don't need anything from here, as we have PARI-specific signal
    2 # handling.  We still include this such that Cython detects the
    3 # dependency on interrupt.h for recompiling gen.pyx.
     1# Let Cython know that pari_err.h includes interrupt.h
    42cdef extern from 'interrupt.h':
    53    pass
    64
     
    86    int pari_catch_sig_on() except 0
    97    int pari_catch_sig_str(char *) except 0
    108    void pari_catch_sig_off()
    11 
    12 from sage.libs.pari.gen cimport _pari_trap
     9    void _pari_init_err()