NAME
ieee_handler - IEEE exception trap handler function
SYNOPSIS
cc [ flag ... ] file ... -lsunmath -lm [ library ... ]
#include <sunmath.h>
long ieee_handler(const char *action, const char *exception,
sigfpe_handler_type hdl);
DESCRIPTION
This function provides easy exception handling to exploit
ANSI/IEEE Std 754-1985 arithmetic in a C program. The first
two arguments are pointers to strings. For efficiency,
results arising from invalid arguments and invalid combina-
tions are undefined.
There are three types of action : ``get'', ``set'', and
``clear''. There are five types of exception :
``inexact''
``division'' ... division by zero exception
``underflow''
``overflow''
``invalid''
``all'' ... all five exceptions above
``common'' ... invalid, overflow, and division
exceptions
Note: ``all'' and ``common'' only make sense with ``set'' or
``clear''.
hdl contains the address of a signal-handling routine.
<floatingpoint.h> defines sigfpe_handler_type .
``get'' will return the location of the current handler rou-
tine for exception cast to a long.
``set'' will set the routine pointed at by hdl to be the
handler routine and at the same time enable the trap on
exception, except when hdl == SIGFPE_DEFAULT or
SIGFPE_IGNORE; then ieee_handler() will disable the trap on
exception. When hdl == SIGFPE_ABORT, any trap on exception
will dump core using abort(3).
``clear'' disables trapping on exception and sets the
handler routine for exception to SIGFPE_DEFAULT. ``clear''
``all'' disables trapping on all five exceptions and sets
the handler routine for all five exceptions to
SIGFPE_DEFAULT.
Two steps are required to intercept an IEEE-related SIGFPE
code with ieee_handler:
1) Set up a handler with ieee_handler.
2) Perform a floating-point operation that generates the
intended IEEE exception.
ieee_handler() also adjusts floating-point hardware mode
bits affecting IEEE trapping. For ``clear'', ``set''
SIGFPE_DEFAULT, or ``set'' SIGFPE_IGNORE, the hardware trap
is disabled. For any other ``set'', the hardware trap is
enabled.
SIGFPE signals can be handled using sigaction(2)
ieee_handler(3M), or fex_set_handling(3M).
In a particular program, to avoid confusion, use only one of
these interfaces to handle SIGFPE signals.
DIAGNOSTICS
ieee_handler() normally returns 0 for ``set''; 1 will be
returned if the action is not available (for instance, not
supported in hardware). For ``get'', the address of the
current handler is returned, cast to a long.
EXAMPLE
Here we give an example of how to trap an invalid signal and
change the default output (NaN) to a user given value if the
exception is caused by zero/zero. Following is a user-
specified signal handler (appropriate for SPARC systems
only):
/*
* Sample user exception handler routine. In this example, we trap on the
* invalid signal. Then we check if the exception is of zero/zero type. If
* yes, we set the result = zero_over_zero_value (user given).
*/
#include <sunmath.h>
#include <siginfo.h>
#include <ucontext.h>
extern double zero_over_zero_value;
void zero_over_zero_handler(int sig, siginfo_t *sip, ucontext_t *uap) {
fpregset_t *uc = &uap->uc_mcontext.fpregs; /* see <sys/reg.h> for structure fpregset_t */
const int fopshift = 5, frdshift = 25, frs1shift = 14, frs2shift = 0;
int i, j, fop, frd, frs1, frs2;
int *con = (int *) &zero_over_zero_value;
/*
* find out registers rd, rs1, rs2, and opf
*/
fop = ((uc->fpu_q->FQu.fpq.fpq_instr)>>fopshift) &0x1ff;
frd = ((uc->fpu_q->FQu.fpq.fpq_instr)>>frdshift) &0x1f;
frs1= ((uc->fpu_q->FQu.fpq.fpq_instr)>>frs1shift)&0x1f;
frs2= ((uc->fpu_q->FQu.fpq.fpq_instr)>>frs2shift )&0x1f;
/*
* check if both rs1 and rs2 are zero (0/0 case)
*/
i = (uc->fpu_fr.fpu_regs[frs2]&0x7fffffff)|uc->fpu_fr.fpu_regs[frs2+1];
j = (uc->fpu_fr.fpu_regs[frs1]&0x7fffffff)|uc->fpu_fr.fpu_regs[frs1+1];
switch (fop) {
case 0x4e: /* fdivd */
if((i|j) == 0) { /* 0/0 , set rd to be zero_over_zero_value */
uc->fpu_fr.fpu_regs[frd] = con[0];
uc->fpu_fr.fpu_regs[frd+1] = con[1];
}
break;
}
}
and it might be set up like this:
#include <stdio.h>
#include <stdlib.h>
#include <sunmath.h>
#include <siginfo.h>
#include <ucontext.h>
extern void zero_over_zero_handler(int, siginfo_t *, ucontext_t *);
double zero_over_zero_value;
void
main(void) {
extern double sin(double);
double x, w;
int i, k;
sigfpe_handler_type hdl, old_handler1;
/*
* save current invalid handler
*/
old_handler1 = (sigfpe_handler_type) ieee_handler("get", "invalid", (sigfpe_handler_type)0);
/*
* set up new invalid handler
*/
hdl = (sigfpe_handler_type) zero_over_zero_handler;
(void) ieee_handler("set", "invalid", hdl);
/*
* compute (k*x)/sin(x) for k=2, x=0.5, 0.4, ..., 0.1, 0.0
*/
k = 2.0; /* user specified */
(void) printf("Evaluating f(x) = (k*x)/sin(x)\n\n");
zero_over_zero_value = k;
for (i = 5; i >= 0; i--) {
x = (double) i * 0.1;
w = (k * x) / sin(x);
(void) printf("\tx=%3.3f\t f(x) = % 1.20e\n", x, w);
}
/*
* restore old invalid handler
*/
(void) ieee_handler("set", "invalid", old_handler1);
exit(0);
/* NOTREACHED */
}
Here is what the output looks like:
Evaluating f(x) = (k*x)/sin(x)
x=0.500 f(x) = 2.08582964293348816000e+00
x=0.400 f(x) = 2.05434596443822626000e+00
x=0.300 f(x) = 2.03031801709447368000e+00
x=0.200 f(x) = 2.01339581906893761000e+00
x=0.100 f(x) = 2.00333722632695554000e+00
x=0.000 f(x) = 2.00000000000000000000e+00
Note that when x=0, f(x) = 0/0 and an invalid exception
occurs. The value of 0/0 is set to be 2.0 in this example.
ATTRIBUTES
See attributes(5) for descriptions of the following attri-
butes:
_______________________________________
| ATTRIBUTE TYPE | ATTRIBUTE VALUE|
|____________________|_________________|
| Availability | SPROlang |
| Interface Stability| Evolving |
| MT-Level | MT-Safe |
|____________________|_________________|
SEE ALSO
sigaction(2), signal(3C), sigfpe(3), abort(3C),
fex_set_handling(3M), ieee_flags(3M), attributes(5), sig-
info(5), signal(5), ucontext(5)
NOTES
On Intel systems, the floating point hardware traps whenever
an exception's trap is enabled (i.e., the exception is
"unmasked") and its corresponding flag is raised. Thus,
enabling a trap for an exception via ieee_handler() will
provoke a subsequent trap if the exception's flag is already
raised when ieee_handler() is called. To avoid such spuri-
ous traps, a program should clear the flags corresponding to
each exception for which trapping will be enabled before
calling ieee_handler(). (The ieee_flags(3M) function pro-
vides one way to clear exception flags.)