Skip to content

Commit bb2fc6b

Browse files
committed
Add CPython header file 'pyfpe.h'.
1 parent 804fd2c commit bb2fc6b

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
#include "pylifecycle.h"
103103
#include "pydebug.h"
104104
#include "code.h"
105+
#include "pyfpe.h"
105106

106107
// our impls
107108
#ifdef Py_True
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
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 */

0 commit comments

Comments
 (0)