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(2), 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.)
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |