'\" t .\" @(#)ieee_handler.3m 1.31 97/09/02 SMI; .\" @(#)ieee_handler.3m 1.15 91/05/20 SMI; .TH ieee_handler 3M "09/02/97" .UC 4 .de Pi \" PI stuff sign .if n \\ \\$2pi\\$1 .if t \\ \\$2\\(*p\\$1 .. .ds up \fIulp\fR .SH NAME ieee_handler \- IEEE exception trap handler function .SH SYNOPSIS .LP .B cc .RI "[ " "flag" " \|.\|.\|. ] " "file" " \|.\|.\|." .B \-lsunmath -lm .RI "[ " "library" " \|.\|.\|. ]" .LP .B #include .LP .BI "long ieee_handler(const char *" "action" , .BI "const char *" "exception" , .BI "sigfpe_handler_type " hdl ); .SH DESCRIPTION .IX "ieee_handler function" "" "\fLieee_handler()\fP function" .LP This function provides easy exception handling to exploit .SM 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 combinations are undefined. .LP There are three types of .I action : ``get'', ``set'', and ``clear''. There are five types of .I exception : .RS .PD 0 .TP 15 ``inexact'' .TP ``division'' \&.\|.\|. division by zero exception .TP ``underflow'' .TP ``overflow'' .TP ``invalid'' .TP ``all'' \&.\|.\|. all five exceptions above .TP ``common'' \&.\|.\|. invalid, overflow, and division exceptions .PD .RE .LP Note: ``all'' and ``common'' only make sense with ``set'' or ``clear''. .LP .I hdl contains the address of a signal-handling routine. .B defines .B sigfpe_handler_type . .LP ``get'' will return the location of the current handler routine for .I exception cast to a long. .LP ``set'' will set the routine pointed at by .I hdl to be the handler routine and at the same time enable the trap on .IR exception , except when .I hdl == .BR \s-1SIGFPE_DEFAULT\s0 or .BR \s-1SIGFPE_IGNORE\s0 ; then .B ieee_handler(\|) will disable the trap on .IR exception . When .I hdl == .BR \s-1SIGFPE_ABORT\s0 , any trap on .I exception will dump core using .BR abort (3). .LP ``clear'' disables trapping on .I exception and sets the handler routine for .I exception to .BR \s-1SIGFPE_DEFAULT\s0 . ``clear'' ``all'' disables trapping on all five exceptions and sets the handler routine for all five exceptions to .BR \s-1SIGFPE_DEFAULT\s0 . .LP Two steps are required to intercept an .SM IEEE\s0-related .BR \s-1SIGFPE\s0 code with .BR ieee_handler : .TP 1) Set up a handler with .BR ieee_handler . .TP 2) Perform a floating-point operation that generates the intended .SM IEEE exception. .LP .B ieee_handler(\|) also adjusts floating-point hardware mode bits affecting .SM IEEE trapping. For ``clear'', ``set'' .BR \s-1SIGFPE_DEFAULT\s0 , or ``set'' .BR \s-1SIGFPE_IGNORE\s0 , the hardware trap is disabled. For any other ``set'', the hardware trap is enabled. .LP .BR \s-1SIGFPE\s0 signals can be handled using .BR sigaction (2) .BR ieee_handler (3M), or .BR fex_set_handling (3M). In a particular program, to avoid confusion, use only one of these interfaces to handle .BR \s-1SIGFPE\s0 signals. .SH DIAGNOSTICS .B 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. .br .ne 25 .vs 11p .SH EXAMPLE .LP 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): .RS .ft B .nf /* * 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 #include #include 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 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; } } .fi .RE .LP and it might be set up like this: .nf .RS .ft B #include #include #include #include #include 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 */ } .fi .RE .LP Here is what the output looks like: .nf .RS .ft B 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 .fi .RE .LP 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. .ft R .SH ATTRIBUTES See .BR attributes (5) for descriptions of the following attributes: .sp .ne 10 .TS box; cbp-1 | cbp-1 l | l . ATTRIBUTE TYPE ATTRIBUTE VALUE = Availability SPROlang Interface Stability Evolving MT-Level MT-Safe .TE .SH "SEE ALSO" .BR sigaction (2), .BR signal (2), .BR sigfpe (3), .BR abort (3C), .BR fex_set_handling (3M), .BR ieee_flags (3M), .BR attributes (5), .BR siginfo (5), .BR signal (5), .BR ucontext (5) .SH 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 .B ieee_handler(\|) will provoke a subsequent trap if the exception's flag is already raised when .B ieee_handler(\|) is called. To avoid such spurious traps, a program should clear the flags corresponding to each exception for which trapping will be enabled before calling .BR ieee_handler(\|) . (The .BR ieee_flags (3M) function provides one way to clear exception flags.)