Man Page ieee_handler.3m


     ieee_handler - IEEE exception trap handler function


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

     #include <sunmath.h>

     long ieee_handler(const char *action, const char *exception,
     sigfpe_handler_type hdl);


     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 :
          ``division''   ... division by zero exception
          ``all''        ... all five exceptions above
          ``common''     ...  invalid,  overflow,  and   division

     Note: ``all'' and ``common'' only make sense with ``set'' or

     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

     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

     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.


     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.


     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

           * 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];

     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;

          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);
               /* 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.


     See attributes(5) for descriptions of the  following  attri-

    | Availability       |  SPROlang       |
    | Interface Stability|  Evolving       |
    | MT-Level           |  MT-Safe        |


     sigaction(2),     signal(3C),     sigfpe(3),      abort(3C),
     fex_set_handling(3M),  ieee_flags(3M),  attributes(5),  sig-
     info(5), signal(5), ucontext(5)


     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.)