Ignore:
Timestamp:
Dec 9, 2000, 8:19:42 PM (25 years ago)
Author:
umoeller
Message:

Major updates; timers, LVM, miscellaneous.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/except.c

    r13 r14  
    33 *@@sourcefile except.c:
    44 *      this file contains powerful exception handlers.
     5 *      except.h also defines easy-to-use macros for them.
    56 *
    67 *      Usage: All OS/2 programs, PM or text mode.
    78 *
    8  *      <B>except.h macros</B>
    9  *
    10  *      except.h declares a few handy macros to easily install
    11  *      exception handling for a section of code.
    12  *
    13  *      These macros automatically insert code for properly
    14  *      registering and deregistering the handlers. You should
    15  *      ALWAYS use these macros instead of directly registering
     9 *      <B>Introduction</B>
     10 *
     11 *      OS/2 exception handlers are a mess to program and,
     12 *      if installed wrongly, almost impossible to debug.
     13 *      The problem is that for any program that does a bit
     14 *      more than showing a message box, using exception
     15 *      handlers is a must to avoid system hangs. This
     16 *      especially applies to multi-thread programs using
     17 *      mutex semaphores (more on that below). The functions
     18 *      and macros in here are designed to make that more simple.
     19 *
     20 *      The macros in except.h automatically insert code for properly
     21 *      registering and deregistering the handlers in except.c. You
     22 *      should ALWAYS use these macros instead of directly registering
    1623 *      the handlers to avoid accidentally forgetting to deregister
    1724 *      them. If you forget to deregister an exception handler, this
     
    2027 *      might get completely messed up.
    2128 *
    22  *      The general idea of these macros is to define
    23  *      TRY / CATCH blocks similar to C++. If an exception
    24  *      occurs in the TRY block, execution is transferred
    25  *      to the CATCH block. (This works in both C and C++,
    26  *      by the way.)
    27  *
    28  *      In addition, with the TRY statement, you may specify
    29  *      an optional "OnKill" function which gets called if
    30  *      the thread gets killed while code in the TRY block is
    31  *      executed (new with V0.9.0). If you need no such
    32  *      function, specify NULL. Details follow.
     29 *      The general idea of these macros is to define TRY / CATCH
     30 *      blocks similar to C++. If an exception occurs in the TRY block,
     31 *      execution is transferred to the CATCH block. (This works in both
     32 *      C and C++, by the way.)
     33 *
     34 *      The "OnKill" function that was added with V0.9.0 has been
     35 *      removed again with V0.9.7. Use DosEnterMustComplete instead.
     36 *      Details follow.
    3337 *
    3438 *      The general usage is like this:
     
    3640 +          int your_protected_func(int ...)
    3741 +          {
    38  +              TRY_LOUD(excptid, OnKillFunc)
    39  +              // or: TRY_QUIET(excptid, OnKillFunc)
    40  +              // OnKillFunc can be NULL
     42 +              TRY_LOUD(excptid)         // or: TRY_QUIET(excptid)
    4143 +              {
    4244 +                  ....        // the stuff in here is protected by
     
    5052 +          } // end of your_func
    5153 *
    52  *      TRY_LOUD  is for excHandlerLoud (see below).
    53  *      TRY_QUIET is for excHandlerQuiet (see below).
     54 *      TRY_LOUD  is for installing excHandlerLoud.
     55 *      TRY_QUIET is for installing excHandlerQuiet.
    5456 *      CATCH / END_CATCH are the same for the two. This
    5557 *      is where the exception handler jumps to if an
     
    5860 *      in there.
    5961 *
    60  *      "excptid" can be any identifier which is not used in
     62 *      "excptid" can be any C identifier which is not used in
    6163 *      your current variable scope, e.g. "excpt1". This
    6264 *      is used for creating an EXCEPTSTRUCT variable of
     
    6567 *      store the exception handler data.
    6668 *
    67  *      It is possible to nest these handlers though. You
    68  *      must use different "excptid"'s only if more than one
    69  *      TRY_* block exists in the same variable scope. Avoid
    70  *      using gotos to jump between the different CATCH blocks,
    71  *      because this might not properly deregister the handlers.
     69 *      These macros may be nested if you use different
     70 *      "excptid"'s for sub-macros.
     71 *
     72 *      Inside the TRY and CATCH blocks, you must not use
     73 *      "goto" (to a location outside the block) or "return",
     74 *      because this will not deregister the handler.
    7275 *
    7376 *      Keep in mind that all the code in the TRY_* block is
     
    7679 *      TRY_* block, your entire application is protected.
    7780 *
    78  *      Your "OnKillFunc" must be declared as
    79  +          VOID APIENTRY YourOnKillFunc(VOID) {...}.
    80  *      This gets called when the thread gets terminated
    81  *      while being executed in the TRY block (that is,
    82  *      if either the thread gets killed explicitly or
    83  *      the entire process ends for some reason). After
    84  *      that function got executed, the thread will _always_
    85  *      be terminated; the CATCH block will not be executed
    86  *      then. You can specify NULL for the "OnKillFunc", if
    87  *      you don't need one.
    88  *
    89  *      To summarize: If an exception occurs in the TRY
    90  *      block,
    91  *
    92  *      a) "OnKillFunc" gets called if the thread got
    93  *         killed, and the thread then terminates;
    94  *
    95  *      b) the CATCH block is executed for other exceptions
    96  *         and execution continues.
     81 *      <B>Asynchronous exceptions</B>
     82 *
     83 *      The exception handlers in this file (which are installed
     84 *      with the TRY/CATCH mechanism) only intercept synchronous
     85 *      exceptions (see excHandlerLoud for a list). They do not
     86 *      protect your code against asynchronous exceptions.
     87 *
     88 *      OS/2 defines asynchronous exceptions to be those that
     89 *      can be delayed. With OS/2, there are only three of these:
     90 *
     91 *      -- XCPT_PROCESS_TERMINATE
     92 *      -- XCPT_ASYNC_PROCESS_TERMINATE
     93 *      -- XCPT_SIGNAL (thread 1 only)
     94 *
     95 *      To protect yourself against these also, put the section
     96 *      in question in a DosEnterMustComplete/DosExitMustComplete
     97 *      block as well.
    9798 *
    9899 *      <B>Mutex semaphores</B>
    99100 *
    100  *      Here's how to deal with mutex semaphores: WHENEVER
    101  *      you request a mutex semaphore, enclose the block
    102  *      with TRY/CATCH in case an error occurs, like this:
     101 *      The problem with OS/2 mutex semaphores is that they are
     102 *      not automatically released when a thread terminates.
     103 *      If the thread owning the mutex died without releasing
     104 *      the mutex, other threads which are blocked on that mutex
     105 *      will wait forever and become zombie threads. Even worse,
     106 *      if this happens to a PM thread, this will hang the system.
     107 *
     108 *      Here's the typical scenario with two threads:
     109 *
     110 *      1)  Thread 2 requests a mutex and does lots of processing.
     111 *
     112 *      2)  Thread 1 requests the mutex. Since it's still owned
     113 *          by thread 2, thread 1 blocks.
     114 *
     115 *      3)  Thread 2 crashes in its processing. Without an
     116 *          exception handler, OS/2 will terminate the process.
     117 *          It will first kill thread 2 and then attempt to
     118 *          kill thread 1. This fails because it is still
     119 *          blocking on the semaphore that thread 2 never
     120 *          released. Boom.
     121 *
     122 *      The same scenario happens when a process gets killed.
     123 *      Since OS/2 will kill secondary threads before thread 1,
     124 *      the same situation can arise.
     125 *
     126 *      As a result, you must protect any section of code which
     127 *      requests a semaphore _both_ against crashes _and_
     128 *      termination.
     129 *
     130 *      So _whenever_ you request a mutex semaphore, enclose
     131 *      the block with TRY/CATCH in case the code crashes.
     132 *      Besides, enclose the TRY/CATCH block in a must-complete
     133 *      section, like this:
    103134 *
    104135 +          HMTX hmtx = ...
    105  +
    106  +          VOID APIENTRY OnKillYourFunc(VOID)
    107  +          {
    108  +              DosReleaseMutexSem(hmtx);
    109  +          }
    110136 +
    111137 +          int your_func(int)
    112138 +          {
    113  +              BOOL fSemOwned = FALSE;
     139 +              BOOL    fSemOwned = FALSE;
     140 +              ULONG   ulNesting = 0;
     141 +
     142 +              DosEnterMustComplete(&ulNesting);
    114143 +              TRY_QUIET(excpt1, OnKillYourFunc) // or TRY_LOUD
    115144 +              {
     
    126155 +                  fSemOwned = FALSE;
    127156 +              }
     157 +              DosExitMustComplete(&ulNesting);
    128158 +          } // end of your_func
    129159 *
    130  *      This way your mutex semaphore gets released even if
    131  *      exceptions occur in your code. If you don't do this,
    132  *      threads waiting for that semaphore will be blocked
    133  *      forever when exceptions occur. As a result, depending
    134  *      on the thread, PM will hang, or the application will
    135  *      never terminate.
     160 *      This way your mutex semaphore gets released in every
     161 *      possible condition.
    136162 *
    137163 *      <B>Customizing</B>
    138164 *
    139  *      Note: As opposed to versions < 0.9.0, this is now
     165 *      As opposed to versions before 0.9.0, this code is now
    140166 *      completely independent of XWorkplace. This file now
    141167 *      contains "pure" exception handlers only.
     
    146172 *      If excRegisterHooks is not called, the following safe
    147173 *      defaults are used:
     174 *
    148175 *          --  the trap log file is TRAP.LOG in the root
    149176 *              directory of your boot drive.
     
    182209 *                                      John Currier,
    183210 *                                      Anthony Cruise.
    184  *      This file is part of the XWorkplace source package.
    185  *      XWorkplace is free software; you can redistribute it and/or modify
     211 *      This file is part of the "XWorkplace helpers" source package.
     212 *      This is free software; you can redistribute it and/or modify
    186213 *      it under the terms of the GNU General Public License as published
    187214 *      by the Free Software Foundation, in version 2 as it comes in the
     
    223250
    224251/* ******************************************************************
    225  *                                                                  *
    226  *   Global variables                                               *
    227  *                                                                  *
     252 *
     253 *   Global variables
     254 *
    228255 ********************************************************************/
    229256
     
    240267
    241268/* ******************************************************************
    242  *                                                                  *
    243  *   Exception helper routines                                      *
    244  *                                                                  *
     269 *
     270 *   Exception helper routines
     271 *
    245272 ********************************************************************/
    246273
     
    490517        case XCPT_ACCESS_VIOLATION:
    491518        {
    492             fprintf(file, "\nAccess violation: ");
     519            fprintf(file, "\nXCPT_ACCESS_VIOLATION: ");
    493520            if (pReportRec->ExceptionInfo[0] & XCPT_READ_ACCESS)
    494521                fprintf(file, "Invalid read access from 0x%04lX:%08lX.\n",
     
    516543        case XCPT_INTEGER_DIVIDE_BY_ZERO:
    517544        {
    518             fprintf(file, "\nInteger division by zero.\n");
     545            fprintf(file, "\nXCPT_INTEGER_DIVIDE_BY_ZERO.\n");
    519546            fprintf(file,
    520547                    "Explanation: An attempt was made to divide an integer value by zero,\n"
     
    525552        case XCPT_ILLEGAL_INSTRUCTION:
    526553        {
    527             fprintf(file, "\nIllegal instruction found.\n");
     554            fprintf(file, "\nXCPT_ILLEGAL_INSTRUCTION.\n");
    528555            fprintf(file,
    529556                    "Explanation: An attempt was made to execute an instruction that\n"
     
    534561        case XCPT_PRIVILEGED_INSTRUCTION:
    535562        {
    536             fprintf(file, "\nPrivileged instruction found.\n");
     563            fprintf(file, "\nXCPT_PRIVILEGED_INSTRUCTION.\n");
    537564            fprintf(file,
    538565                    "Explanation: An attempt was made to execute an instruction that\n"
     
    543570
    544571        case XCPT_INTEGER_OVERFLOW:
    545             fprintf(file, "\nInteger overflow.\n");
     572            fprintf(file, "\nXCPT_INTEGER_OVERFLOW.\n");
    546573            fprintf(file,
    547574                    "Explanation: An integer operation generated a carry-out of the most\n"
    548575                    "             significant bit. This is a sign of an attempt to store\n"
    549576                    "             a value which does not fit into an integer variable.\n");
     577
     578        default:
     579            fprintf(file, "\nUnknown OS/2 exception number %d.\n", pReportRec->ExceptionNum);
     580            fprintf(file, "Look this up in the OS/2 header files.\n");
    550581    }
    551582
     
    700731
    701732/* ******************************************************************
    702  *                                                                  *
    703  *   Exported routines                                              *
    704  *                                                                  *
     733 *
     734 *   Exported routines
     735 *
    705736 ********************************************************************/
    706737
     
    722753 *      The hooks are as follows:
    723754 *
    724  *      pfnExcOpenFileNew gets called to open
     755 *      --  pfnExcOpenFileNew gets called to open
    725756 *          the trap log file. This must return a FILE*
    726757 *          pointer from fopen(). If this is not defined,
     
    729760 *          into it before the actual exception info.
    730761 *
    731  *      pfnExcHookNew gets called while the trap log
     762 *      --  pfnExcHookNew gets called while the trap log
    732763 *          is being written. At this point,
    733764 *          the following info has been written into
     
    743774 *          Use this hook to write additional application
    744775 *          info into the trap log, such as the state
    745  *          of your threads.
    746  *
    747  *      pfnExcHookError gets called when the TRY_* macros
     776 *          of your own threads and mutexes.
     777 *
     778 *      --  pfnExcHookError gets called when the TRY_* macros
    748779 *          fail to install an exception handler (when
    749  *          DosSetExceptionHandler fails).
     780 *          DosSetExceptionHandler fails). I've never seen
     781 *          this happen.
    750782 *
    751783 *@@added V0.9.0 [umoeller]
     
    772804 *      to the thread to continue execution, i.e. the
    773805 *      default OS/2 exception handler will never get
    774  *      called. This requires a setjmp() call on
     806 *      called.
     807 *
     808 *      This requires a setjmp() call on
    775809 *      EXCEPTIONREGISTRATIONRECORD2.jmpThread before
    776  *      being installed.
    777  *
    778  *      This is best registered thru the TRY_LOUD macro
    779  *      (new with V0.84, described in except.c), which
    780  *      does the necessary setup.
    781  *
    782  *      Depending on the type of exception, the following
    783  *      happens:
    784  *
    785  *      <B>a) "real" exceptions</B>
     810 *      being installed. The TRY_LOUD macro will take
     811 *      care of this for you (see except.c).
     812 *
     813 *      This intercepts the following exceptions (see
     814 *      the OS/2 Control Program Reference for details):
    786815 *
    787816 *      --  XCPT_ACCESS_VIOLATION         (traps 0x0d, 0x0e)
     
    795824 *      what source code corresponds to the error.
    796825 *
     826 *      See excRegisterHooks for the default setup of this.
     827 *
    797828 *      Note that to get meaningful debugging information
    798829 *      in this handler's traplog, you need the following:
     830 *
    799831 *      a)  have a MAP file created at link time (/MAP)
     832 *
    800833 *      b)  convert the MAP to a SYM file using MAPSYM
     834 *
    801835 *      c)  put the SYM file in the same directory of
    802  *          the executable. This must have the same
    803  *          filestem as the executable.
    804  *
    805  *      See the "Control Programming Guide and Reference"
    806  *      for details.
     836 *          the module (EXE or DLL). This must have the
     837 *          same filestem as the module.
     838 *
    807839 *      All other exceptions are passed to the next handler
    808840 *      in the exception handler chain. This might be the
    809841 *      C/C++ compiler handler or the default OS/2 handler,
    810842 *      which will probably terminate the process.
    811  *
    812  *      <B>b) thread kills</B>
    813  *
    814  *      -- XCPT_PROCESS_TERMINATE
    815  *      -- XCPT_ASYNC_PROCESS_TERMINATE:
    816  *
    817  *      If EXCEPTIONREGISTRATIONRECORD2.pfnOnKill is != NULL,
    818  *      that function gets called to allow for thread cleanup
    819  *      before the thread really terminates. This should be
    820  *      used for releasing mutex semaphores.
    821843 *
    822844 *@@changed V0.9.0 [umoeller]: added support for thread termination
     
    852874    switch (pReportRec->ExceptionNum)
    853875    {
    854         case XCPT_PROCESS_TERMINATE:
     876        /* case XCPT_PROCESS_TERMINATE:
    855877        case XCPT_ASYNC_PROCESS_TERMINATE:
    856878            // thread terminated:
     
    859881            if (pRegRec2->pfnOnKill)
    860882                // call the "OnKill" function
    861                 pRegRec2->pfnOnKill();
     883                pRegRec2->pfnOnKill(pRegRec2);
    862884            // get outta here, which will kill the thread
    863         break;
     885        break; */
    864886
    865887        case XCPT_ACCESS_VIOLATION:
     
    867889        case XCPT_ILLEGAL_INSTRUCTION:
    868890        case XCPT_PRIVILEGED_INSTRUCTION:
     891        case XCPT_INVALID_LOCK_SEQUENCE:
    869892        case XCPT_INTEGER_OVERFLOW:
    870893        {
     
    924947 *      this is useful for certain error-prone functions, where
    925948 *      exceptions are likely to appear, for example used by
    926  *      cmnCheckObject to implement a fail-safe SOM object check.
     949 *      wpshCheckObject to implement a fail-safe SOM object check.
    927950 *
    928951 *      This does _not_ write an error log and makes _no_ sound.
     
    953976    switch (pReportRec->ExceptionNum)
    954977    {
    955         case XCPT_PROCESS_TERMINATE:
     978        /* case XCPT_PROCESS_TERMINATE:
    956979        case XCPT_ASYNC_PROCESS_TERMINATE:
    957980            // thread terminated:
     
    960983            if (pRegRec2->pfnOnKill)
    961984                // call the "OnKill" function
    962                 pRegRec2->pfnOnKill();
     985                pRegRec2->pfnOnKill(pRegRec2);
    963986            // get outta here, which will kill the thread
    964         break;
     987        break; */
    965988
    966989        case XCPT_ACCESS_VIOLATION:
     
    968991        case XCPT_ILLEGAL_INSTRUCTION:
    969992        case XCPT_PRIVILEGED_INSTRUCTION:
     993        case XCPT_INVALID_LOCK_SEQUENCE:
    970994        case XCPT_INTEGER_OVERFLOW:
    971995            // write excpt explanation only if the
    972             // resp. debugging #define is set (common.h)
     996            // resp. debugging #define is set (setup.h)
    973997            #ifdef DEBUG_WRITEQUIETEXCPT
    974998            {
Note: See TracChangeset for help on using the changeset viewer.