File: /Users/paulross/dev/Python-3.6.2/Include/pyfpe.h

Green shading in the line number column means the source is part of the translation unit, red means it is conditionally excluded. Highlighted line numbers link to the translation unit page. Highlighted macros link to the macro page.

       1: #ifndef Py_PYFPE_H
       2: #define Py_PYFPE_H
       3: #ifdef __cplusplus
       4: extern "C" {
       5: #endif
       6: /*
       7:      ---------------------------------------------------------------------
       8:     /                       Copyright (c) 1996.                           \
       9:    |          The Regents of the University of California.                 |
      10:    |                        All rights reserved.                           |
      11:    |                                                                       |
      12:    |   Permission to use, copy, modify, and distribute this software for   |
      13:    |   any purpose without fee is hereby granted, provided that this en-   |
      14:    |   tire notice is included in all copies of any software which is or   |
      15:    |   includes  a  copy  or  modification  of  this software and in all   |
      16:    |   copies of the supporting documentation for such software.           |
      17:    |                                                                       |
      18:    |   This  work was produced at the University of California, Lawrence   |
      19:    |   Livermore National Laboratory under  contract  no.  W-7405-ENG-48   |
      20:    |   between  the  U.S.  Department  of  Energy and The Regents of the   |
      21:    |   University of California for the operation of UC LLNL.              |
      22:    |                                                                       |
      23:    |                              DISCLAIMER                               |
      24:    |                                                                       |
      25:    |   This  software was prepared as an account of work sponsored by an   |
      26:    |   agency of the United States Government. Neither the United States   |
      27:    |   Government  nor the University of California nor any of their em-   |
      28:    |   ployees, makes any warranty, express or implied, or  assumes  any   |
      29:    |   liability  or  responsibility  for the accuracy, completeness, or   |
      30:    |   usefulness of any information,  apparatus,  product,  or  process   |
      31:    |   disclosed,   or  represents  that  its  use  would  not  infringe   |
      32:    |   privately-owned rights. Reference herein to any specific  commer-   |
      33:    |   cial  products,  process,  or  service  by trade name, trademark,   |
      34:    |   manufacturer, or otherwise, does not  necessarily  constitute  or   |
      35:    |   imply  its endorsement, recommendation, or favoring by the United   |
      36:    |   States Government or the University of California. The views  and   |
      37:    |   opinions  of authors expressed herein do not necessarily state or   |
      38:    |   reflect those of the United States Government or  the  University   |
      39:    |   of  California,  and shall not be used for advertising or product   |
      40:     \  endorsement purposes.                                              /
      41:      ---------------------------------------------------------------------
      42: */
      43: 
      44: /*
      45:  *       Define macros for handling SIGFPE.
      46:  *       Lee Busby, LLNL, November, 1996
      47:  *       busby1@llnl.gov
      48:  *
      49:  *********************************************
      50:  * Overview of the system for handling SIGFPE:
      51:  *
      52:  * This file (Include/pyfpe.h) defines a couple of "wrapper" macros for
      53:  * insertion into your Python C code of choice. Their proper use is
      54:  * discussed below. The file Python/pyfpe.c defines a pair of global
      55:  * variables PyFPE_jbuf and PyFPE_counter which are used by the signal
      56:  * handler for SIGFPE to decide if a particular exception was protected
      57:  * by the macros. The signal handler itself, and code for enabling the
      58:  * generation of SIGFPE in the first place, is in a (new) Python module
      59:  * named fpectl. This module is standard in every respect. It can be loaded
      60:  * either statically or dynamically as you choose, and like any other
      61:  * Python module, has no effect until you import it.
      62:  *
      63:  * In the general case, there are three steps toward handling SIGFPE in any
      64:  * Python code:
      65:  *
      66:  * 1) Add the *_PROTECT macros to your C code as required to protect
      67:  *    dangerous floating point sections.
      68:  *
      69:  * 2) Turn on the inclusion of the code by adding the ``--with-fpectl''
      70:  *    flag at the time you run configure.  If the fpectl or other modules
      71:  *    which use the *_PROTECT macros are to be dynamically loaded, be
      72:  *    sure they are compiled with WANT_SIGFPE_HANDLER defined.
      73:  *
      74:  * 3) When python is built and running, import fpectl, and execute
      75:  *    fpectl.turnon_sigfpe(). This sets up the signal handler and enables
      76:  *    generation of SIGFPE whenever an exception occurs. From this point
      77:  *    on, any properly trapped SIGFPE should result in the Python
      78:  *    FloatingPointError exception.
      79:  *
      80:  * Step 1 has been done already for the Python kernel code, and should be
      81:  * done soon for the NumPy array package.  Step 2 is usually done once at
      82:  * python install time. Python's behavior with respect to SIGFPE is not
      83:  * changed unless you also do step 3. Thus you can control this new
      84:  * facility at compile time, or run time, or both.
      85:  *
      86:  ********************************
      87:  * Using the macros in your code:
      88:  *
      89:  * static PyObject *foobar(PyObject *self,PyObject *args)
      90:  * {
      91:  *     ....
      92:  *     PyFPE_START_PROTECT("Error in foobar", return 0)
      93:  *     result = dangerous_op(somearg1, somearg2, ...);
      94:  *     PyFPE_END_PROTECT(result)
      95:  *     ....
      96:  * }
      97:  *
      98:  * If a floating point error occurs in dangerous_op, foobar returns 0 (NULL),
      99:  * after setting the associated value of the FloatingPointError exception to
     100:  * "Error in foobar". ``Dangerous_op'' can be a single operation, or a block
     101:  * of code, function calls, or any combination, so long as no alternate
     102:  * return is possible before the PyFPE_END_PROTECT macro is reached.
     103:  *
     104:  * The macros can only be used in a function context where an error return
     105:  * can be recognized as signaling a Python exception. (Generally, most
     106:  * functions that return a PyObject * will qualify.)
     107:  *
     108:  * Guido's original design suggestion for PyFPE_START_PROTECT and
     109:  * PyFPE_END_PROTECT had them open and close a local block, with a locally
     110:  * defined jmp_buf and jmp_buf pointer. This would allow recursive nesting
     111:  * of the macros. The Ansi C standard makes it clear that such local
     112:  * variables need to be declared with the "volatile" type qualifier to keep
     113:  * setjmp from corrupting their values. Some current implementations seem
     114:  * to be more restrictive. For example, the HPUX man page for setjmp says
     115:  *
     116:  *   Upon the return from a setjmp() call caused by a longjmp(), the
     117:  *   values of any non-static local variables belonging to the routine
     118:  *   from which setjmp() was called are undefined. Code which depends on
     119:  *   such values is not guaranteed to be portable.
     120:  *
     121:  * I therefore decided on a more limited form of nesting, using a counter
     122:  * variable (PyFPE_counter) to keep track of any recursion.  If an exception
     123:  * occurs in an ``inner'' pair of macros, the return will apparently
     124:  * come from the outermost level.
     125:  *
     126:  */
     127: 
     128: #ifdef WANT_SIGFPE_HANDLER
     129: #include <signal.h>
     130: #include <setjmp.h>
     131: #include <math.h>
     132: extern jmp_buf PyFPE_jbuf;
     133: extern int PyFPE_counter;
     134: extern double PyFPE_dummy(void *);
     135: 
     136: #define PyFPE_START_PROTECT(err_string, leave_stmt) \
     137: if (!PyFPE_counter++ && setjmp(PyFPE_jbuf)) { \
     138:     PyErr_SetString(PyExc_FloatingPointError, err_string); \
     139:     PyFPE_counter = 0; \
     140:     leave_stmt; \
     141: }
     142: 
     143: /*
     144:  * This (following) is a heck of a way to decrement a counter. However,
     145:  * unless the macro argument is provided, code optimizers will sometimes move
     146:  * this statement so that it gets executed *before* the unsafe expression
     147:  * which we're trying to protect.  That pretty well messes things up,
     148:  * of course.
     149:  *
     150:  * If the expression(s) you're trying to protect don't happen to return a
     151:  * value, you will need to manufacture a dummy result just to preserve the
     152:  * correct ordering of statements.  Note that the macro passes the address
     153:  * of its argument (so you need to give it something which is addressable).
     154:  * If your expression returns multiple results, pass the last such result
     155:  * to PyFPE_END_PROTECT.
     156:  *
     157:  * Note that PyFPE_dummy returns a double, which is cast to int.
     158:  * This seeming insanity is to tickle the Floating Point Unit (FPU).
     159:  * If an exception has occurred in a preceding floating point operation,
     160:  * some architectures (notably Intel 80x86) will not deliver the interrupt
     161:  * until the *next* floating point operation.  This is painful if you've
     162:  * already decremented PyFPE_counter.
     163:  */
     164: #define PyFPE_END_PROTECT(v) PyFPE_counter -= (int)PyFPE_dummy(&(v));
     165: 
     166: #else
     167: 
     168: #define PyFPE_START_PROTECT(err_string, leave_stmt)
     169: #define PyFPE_END_PROTECT(v)
     170: 
     171: #endif
     172: 
     173: #ifdef __cplusplus
     174: }
     175: #endif
     176: #endif /* !Py_PYFPE_H */
     177: