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: