ieee_handler(3M)

NAME
ieee_handler - IEEE exception trap handler function

SYNOPSIS

cc [ flag ... ] file ... -lsunmath -lm [ library ... ]

#include <sunmath.h>

int 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 combinations 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 routine for exception cast to an int.

``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) or ieee_handler(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 an int.

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:
    /*
     * 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 long fopshift = 5, frdshift = 25, frs1shift = 14, frs2shift = 0;
    	long	i, j, fop, frd, frs1, frs2;
    	long 	*con = (long *) &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 look 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.

SEE ALSO
sigaction(2), signal(2), abort(3C), siginfo(5), signal(5), ucontext(5).