home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_144 / 1.ddi / MATHSRC.ZIP / FPERR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  6.7 KB  |  181 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - fperr.c
  3.  *
  4.  * Floating point exception handler code.
  5.  *-----------------------------------------------------------------------*/
  6.  
  7. /*
  8.  *      C/C++ Run Time Library - Version 5.0
  9.  *
  10.  *      Copyright (c) 1987, 1992 by Borland International
  11.  *      All Rights Reserved.
  12.  *
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <math.h>       /* for _mexcep */
  17. #include <stdlib.h>
  18. #include <signal.h>
  19. #include <float.h>      /* for FPE types */
  20.  
  21. /* No denormal signal are caught here, but treat it for completeness. */
  22. #define FPE_DENORMAL            130     /* 80x87 denormalized operand   */
  23.  
  24. typedef void cdecl (* CatcherPTR)(); /* Cleaner signal catcher declaration */
  25.  
  26. extern  CatcherPTR (* cdecl __SignalPtr)();
  27.  
  28. /*
  29.         The only exceptions routed through this code are GENUINE floating
  30.         point ones.  The explicitly raised SIGFPE and the integer related
  31.         SIGFPE types DO NOT come this way.
  32. */
  33. static const
  34.         struct f_errors
  35.         {
  36.                 int     FPEtype;
  37.                 char    *string;
  38.         }
  39.         fp_errors[] =
  40.         {
  41.                 { FPE_INVALID,          "Domain" },
  42.                 { FPE_DENORMAL,         "Denormal" },
  43.                 { FPE_ZERODIVIDE,       "Divide by 0" },
  44.                 { FPE_OVERFLOW,         "Overflow" },
  45.                 { FPE_UNDERFLOW,        "Underflow" },
  46.                 { FPE_INEXACT,          "Partial loss of precision" },
  47.                 { FPE_STACKFAULT,       "Stack fault" },
  48.         };
  49.  
  50. /*
  51. This is an fp exception structure.  It describes the info passed
  52. to _fperror, the purpose of which is to give a C interface to
  53. trapping fp exceptions in a style similar to matherr().
  54.  
  55. _fperror() is called directly from the NMI handler.  Portable fp
  56. exception handlers should call signal() instead, as that is an
  57. ANSI function.  _fperror() is for lower level control over the
  58. exception.
  59.  
  60. The default _fperror() only uses the type and subtype fields of
  61. struct fpexcep.  The other fields are correctly filled in if the
  62. coprocessor is present, but not otherwise.  They can be used to
  63. help track down the source of the error, and the circumstances
  64. causing the error.
  65.  
  66. _fperror() is not called for denormal exceptions, as these are
  67. handled by the NMI handler.  The NMI handler also attempts to
  68. correct some invalid operation exceptions, and only calls
  69. _fperror() if it is unsuccessful in curing the problem.
  70.  
  71. _fperror() is also not called for certain Invalid Operation
  72. exceptions.  Some of these are recoverable stack faults.
  73.  
  74. The subtype is always 1.  Future implementations may use this
  75. field to pass more info, such as whether an INVALID exception
  76. came from a FSQRT instruction.
  77.  
  78. Here are the reasonable alternatives for an fp exception handler.
  79.  
  80. 1. Print a suitable message and exit.  This is what the default
  81. handler does.  A program that wants to do the same may still wish
  82. to replace the handler as it may have some additional cleaning up
  83. to do, or may want to print a more informative message.
  84.  
  85. 2. Do a long jump to safe place in the program.  If so, the
  86. program must pay attention to all of the usual hazards of long
  87. jumps, and in addition,
  88.         It should call _fpreset() to reset the coprocessor or emulator.
  89.         Since interrupts occur asynchronously, there is more danger than
  90.         usual that the code will be left in an inconsistent state.
  91.  
  92. 3. Ignore the exception.  In most cases the coprocessor will
  93. generate infinities and NANs which are likely to cause additional
  94. exceptions. These exceptions can be ignored more efficiently by
  95. using _control87() to mask them.  This option does not work if
  96. the coprocessor is being emulated, as the emulator does not support
  97. all of the exception handling that the 8087 does.
  98.  
  99. 4. Set a flag and continue.  As with case 3 above, most programs
  100. may prefer the simpler strategy of masking the exceptions.  The
  101. occurrence of the exception can still be detected by examining
  102. the status word with _status87() and can be cleared with
  103. _clear87().  This option does not work if the coprocessor is being
  104. emulated.
  105.  
  106. 5. Attempt to analyze the damage and repair it. This is nearly
  107. impossible as the 8087 is a very complex chip with many
  108. instructions, data types, registers, and special cases.  Some
  109. info is provided at the _fperror() level for programs to try.
  110.  
  111. Caution: _fperror() is a huge function in all memory models.
  112.  
  113. Bugs:
  114. Currently, only the 'type' field of the struct fpexcep is supported.
  115. Do NOT use any of the others.
  116. */
  117.  
  118. struct fpexcep
  119. {
  120.         _mexcep type;
  121.         int subtype;
  122.         unsigned int opcode;    /* offending instruction */
  123.         void huge *datap;       /* ptr to bad mem operand, if any */
  124.         void (huge *codep)();   /* ptr to bad instruction */
  125. };
  126.  
  127. /*
  128. void huge cdecl _fperror(void)
  129. */
  130. void near cdecl _fperror(void)
  131. {
  132.         struct fpexcep far *a = (struct fpexcep _ss *) _BX;
  133.  
  134.         /*
  135.         If signal() functions are installed, use them. signal() makes
  136.         it's presence known by filling the '__SignalPtr' function pointer
  137.         the first time it's called.
  138.         */
  139.  
  140.         if (__SignalPtr != NULL)                /* signals installed    */
  141.         {
  142.                 CatcherPTR      func;
  143.  
  144. #pragma warn -pro
  145.                 func = (*__SignalPtr)(SIGFPE, SIG_DFL); /* get current  */
  146.                 (*__SignalPtr)(SIGFPE, func);           /* restore it   */
  147.  
  148.                 if (func != SIG_IGN)
  149.                 {
  150.                         if (func == SIG_DFL)
  151.                                 goto default_actions;
  152.  
  153.                         /*
  154.                                 Set a default handler and call the users
  155.                                 handler.  The user handler is responsible for
  156.                                 reenabling itself if it needs to.
  157.                         */
  158.                         (*__SignalPtr)(SIGFPE, SIG_DFL);
  159.                         (* func)(SIGFPE, fp_errors[a->type-1].FPEtype);
  160.                 }
  161.         }
  162. #pragma warn .pro
  163.         else    /* Default actions if signals aren't present    */
  164.         {       /* or are defaulted.                            */
  165. default_actions :
  166.                 /*
  167.                         default handler treats all exceptions as fatal.
  168.                         some won't occur unless the user enables them.
  169.                 */
  170.                 fprintf(stderr, "Floating point error: %s.\n",
  171.                                 fp_errors[a->type-1].string);
  172.  
  173.                 /*
  174.                         Now abort the program.  The exit sequence will
  175.                         clean off the chip and restore interrupts.
  176.                 */
  177.                 abort();
  178.                 /* not reached */
  179.         }
  180. }
  181.