home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c065 / 2.ddi / MATH.ZIP / FPERR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  6.2 KB  |  183 lines

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