Go to main content

man pages section 3: Extended Library Functions, Volume 4

Exit Print View

Updated: Thursday, June 13, 2019
 
 

ieee_handler (3SUNMATH)

Name

ieee_handler - manage floating-point exception trap handlers

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 simultaneously establishes SIGFPE signal handlers and controls floating-point trap enable modes for the five floating-point exceptions defined by ANSI/IEEE Std 754-1985. The action and exception arguments are pointers to case-insensitive strings that specify the operation to perform. Invalid argument strings and invalid combinations of arguments yield undefined results.

There are three valid values for action, “get”, “set”, and “clear”, and seven valid values for exception:

“inexact”
“division”   ... division by zero exception
“underflow”
“overflow”
“invalid”
“all”        ... all five exceptions above
“common”     ... invalid, overflow, and division exceptions

When action is “set”, ieee_handler() establishes the handler hdl for the specified exception(s). hdl may be one of SIGFPE_DEFAULT, SIGFPE_IGNORE, or SIGFPE_ABORT, or the address of a user-defined SIGFPE handler. (The macros SIGFPE_DEFAULT, SIGFPE_IGNORE, and SIGFPE_ABORT and the type sigfpe_handler_type are defined in <floatingpoint.h>.)

If hdl is SIGFPE_DEFAULT or SIGFPE_IGNORE, ieee_handler() disables trapping on the specified exceptions so that subsequent occurrences of those exceptions result in the default behavior specified by IEEE 754.

If hdl is SIGFPE_ABORT, ieee_handler() enables trapping on the specified exceptions; a subsequent occurrence of those exceptions will cause the program to dump core by calling abort(3C).

If hdl is the address of a user-defined SIGFPE handler, ieee_handler() enables trapping on the specified exceptions; subsequent occurrences of those exceptions will cause the handler to be invoked as though it were installed via sigaction(2) with the SA_SIGINFO flag set.

When action is “clear”, ieee_handler() disables trapping on the specified exception(s) and sets the corresponding handler(s) to SIGFPE_DEFAULT.

When action is “get”, ieee_handler() returns the handler associated with the specified exception (cast to type long). The hdl argument is ignored.

For actions other than “get”, ieee_handler() returns 1 if the requested action is not available (e.g., the underlying hardware does not support enabling or disabling trapping on the specified exception) and returns 0 otherwise.

EXAMPLE

To use ieee_handler() to catch a SIGFPE signal caused by a floating point exception, a program must:

  1. Set up a handler with ieee_handler.

  2. Perform a floating-point operation that generates the intended exception.

The following program shows one way to set up a handler for an invalid operation exception and trigger that exception by attempting to compute 0/0. The handler then substitutes the value of a global variable for the default result specified by IEEE 754 for this operation. Note that the handler shown below only works on SPARC systems when the program is compiled for the SPARC V8 instruction set.

 
/*
 * Sample floating point exception handler.  In this example, we trap
 * on the invalid operation exception.  The handler checks that the
 * exception occurred as a result of an attempt to compute 0/0.  If so,
 * it supplies the value of the global variable zero_over_zero_value
 * for the result of the instruction that raised the exception.
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sunmath.h>
#include <siginfo.h>
#include <ucontext.h>

double zero_over_zero_value;

void zero_over_zero_handler(int sig, siginfo_t *sip, ucontext_t *uap) {
     /* see <sys/reg.h> for structure fpregset_t */
     fpregset_t  *uc = &uap->uc_mcontext.fpregs;
     int         i, j, fop, frd, frs1, frs2;
     int         *con = (int *) &zero_over_zero_value;

     /*
      * decode the trapping instruction to determine the
      * operation and source and destination registers
      */
     fop = (uc->fpu_q->FQu.fpq.fpq_instr >> 5) & 0x1ff;
     frd = (uc->fpu_q->FQu.fpq.fpq_instr >> 25) & 0x1f;
     frs1 = (uc->fpu_q->FQu.fpq.fpq_instr >> 14) & 0x1f;
     frs2 = uc->fpu_q->FQu.fpq.fpq_instr & 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];
     if (fop == 0x4e)  /* instruction is fdivd */
          if ((i | j) == 0) {  /* both operands are 0 */
               /* set rd to zero_over_zero_value */
               uc->fpu_fr.fpu_regs[frd] = con[0];
               uc->fpu_fr.fpu_regs[frd+1] = con[1];
          }
     }
}

int main(void) {
     double              x, w;
     int                 i, k;
     sigfpe_handler_type hdl, oldhdl;

     /*
      * save current invalid operation handler
      */
     oldhdl = (sigfpe_handler_type) ieee_handler("get", "invalid",
         (sigfpe_handler_type)0);

     /*
      * set up new 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;
     (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 handler
      */
     (void) ieee_handler("set", "invalid", oldhdl);
     return 0;
}

The output from this program looks like this:

 
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, the evaluation of w results in an attempt to compute 0/0, and an invalid operation exception occurs. The exception handler substitutes the value 2.0 for the result.

Attributes

See attributes(7) for descriptions of the following attributes:

ATTRIBUTE TYPE
ATTRIBUTE VALUE
Interface Stability
Committed
MT-Level
MT-Safe
Availability
system/library/math

See Also

sigaction(2), signal(3C), sigfpe(3C), abort(3C), fex_set_handling(3M), ieee_flags(3SUNMATH), attributes(7), siginfo.h(3HEAD), signal.h(3HEAD), ucontext.h(3HEAD)

Notes

Floating point exception handling routines may be installed using any of sigfpe(3C), ieee_handler(3SUNMATH), or fex_set_handling(3M). These methods may not be mixed within a single program.

On Intel systems, the x87 floating point unit 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 spurious traps, a program should clear the flags corresponding to each exception for which trapping will be enabled before calling ieee_handler(). (The ieee_flags(3SUNMATH) function provides one way to clear exception flags.)

Often, a handler installed via ieee_handler() will simply print some diagnostic information and terminate the program. As the example above shows, however, a handler may instead return normally, so that control is returned to the thread that executed the trapping instruction. On current SPARC systems, execution continues from the instruction following the one that trapped; in this case, the handler must provide a result to the destination of the trapping instruction so that subsequent computations may proceed using that result. On Intel systems, if the trapping instruction is an SSE instruction, execution continues by reissuing the instruction that trapped; in this case, the handler must either modify the operands of the trapping instruction so that it will compute a usable result when it is reissued or provide a usable result to the destination of the trapping instruction and explicitly advance the saved instruction pointer so that execution will instead resume from the next instruction past the trapping instruction. If the trapping instruction is an x87 instruction, execution continues from the next floating point instruction following the one that trapped; in this case, the handler must supply a usable result to the destination of the trapping instruction and adjust the saved x87 register stack as necessary so that the trapping instruction will appear to have completed. See the Intel IA-32 architecture manuals for more information. (Note that fex_set_handling(3M) provides a much simpler interface for handling a floating point exception and continuing execution.)