Ignore:
Timestamp:
Apr 6, 2001, 7:12:11 PM (24 years ago)
Author:
umoeller
Message:

misc changes

File:
1 edited

Legend:

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

    r32 r55  
    1616 *      especially applies to multi-thread programs using
    1717 *      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
    23  *      the handlers to avoid accidentally forgetting to deregister
    24  *      them. If you forget to deregister an exception handler, this
    25  *      can lead to really strange errors (crashes, hangs) which are
    26  *      nearly impossible to debug because the thread's stack space
    27  *      might get completely messed up.
    28  *
    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.
     18 *      and macros in here are designed to make that more
     19 *      simple.
     20 *
     21 *      The macros in except.h automatically insert code for
     22 *      properly registering and deregistering the handlers
     23 *      in except.c. You should ALWAYS use these macros
     24 *      instead  of directly registering the handlers to avoid
     25 *      accidentally  forgetting to deregister them. If you
     26 *      forget to deregister an exception handler, this can
     27 *      lead to really strange errors (crashes, hangs) which
     28 *      are nearly impossible to debug because the thread's
     29 *      stack probably got completely messed up.
     30 *
     31 *      The general idea of these macros is to define
     32 *      TRY / CATCH blocks similar to C++. If an exception
     33 *      occurs in the TRY block, execution is transferred to
     34 *      the CATCH block. (This works in both C and C++, by the
     35 *      way.)
     36 *
     37 *      The "OnKill" function that was added with V0.9.0 has
     38 *      been removed again with V0.9.7.
    3739 *
    3840 *      The general usage is like this:
     
    4244 +              TRY_LOUD(excptid)         // or: TRY_QUIET(excptid)
    4345 +              {
     46 +                  char *p = NULL;
     47 +
    4448 +                  ....        // the stuff in here is protected by
    4549 +                              // the excHandlerLoud or excHandlerQuiet
    4650 +                              // exception handler
     51 +                  *p = "A";
    4752 +              }
    4853 +              CATCH(excptid)
     
    5863 *      exception occurs.
    5964 *      The CATCH block is _required_ even if you do nothing
    60  *      in there.
     65 *      in there, because the CATCH() macro will deregister
     66 *      the handler.
    6167 *
    6268 *      "excptid" can be any C identifier which is not used in
     
    7884 *      get called. So if you enclose your main() code in a
    7985 *      TRY_* block, your entire application is protected.
     86 *      If any subfunction fails, execution is transferred to
     87 *      the closest CATCH() that was installed (as with C++
     88 *      try and catch).
    8089 *
    8190 *      <B>Asynchronous exceptions</B>
     
    8392 *      The exception handlers in this file (which are installed
    8493 *      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.
     94 *      exceptions, most importantly, XCPT_ACCESS_VIOLATION (see
     95 *      excHandlerLoud for a list). They do not protect your code
     96 *      against asynchronous exceptions.
    8797 *
    8898 *      OS/2 defines asynchronous exceptions to be those that
     
    100110 *
    101111 *      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.
     112 *      sometimes not automatically released when a thread terminates.
     113 *      If there are several mutexes involved and they are released
     114 *      in improper order, you can get zombie threads on exit.
     115 *      Even worse, if this happens to a PM thread, this will hang
     116 *      the system.
     117 *
     118 *      As a result, you should protect any section of code which
     119 *      requests a semaphore with the exception handlers. To protect
     120 *      yourself against thread termination, use must-complete
     121 *      sections as well (but be careful with those if your code
     122 *      takes a long time to execute... but then you shouldn't
     123 *      request a mutex in the first place).
    129124 *
    130125 *      So _whenever_ you request a mutex semaphore, enclose
     
    141136 +
    142137 +              DosEnterMustComplete(&ulNesting);
    143  +              TRY_QUIET(excpt1, OnKillYourFunc) // or TRY_LOUD
     138 +              TRY_QUIET(excpt1)          // or TRY_LOUD
    144139 +              {
    145  +                  fSemOwned = (WinRequestMutexSem(hmtx, ...) == NO_ERROR);
     140 +                  fSemOwned = !WinRequestMutexSem(hmtx, ...);
    146141 +                  if (fSemOwned)
    147142 +                  {       ... // work on your protected data
    148143 +                  }
     144 +                  // mutex gets released below
    149145 +              }
    150146 +              CATCH(excpt1) { } END_CATCH();    // always needed!
    151147 +
    152  +              if (fSemOwned) {
     148 +              if (fSemOwned)
     149 +              {
    153150 +                  // this gets executed always, even if an exception occured
    154151 +                  DosReleaseMutexSem(hmtx);
Note: See TracChangeset for help on using the changeset viewer.