home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_11_12 / winroth / xception.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  18.1 KB  |  702 lines

  1. /*
  2. ** Exception Library -- General exception handling for ANSI C programs
  3. ** 
  4. ** Copyright (C) 1992 Computational Vision and Active Perception Lab. (CVAP),
  5. **                    Royal Institute of Technology, Stockholm.
  6. **
  7. ** This library is free software; you can redistribute it and/or
  8. ** modify it under the terms of the GNU Library General Public
  9. ** License as published by the Free Software Foundation; either
  10. ** version 2 of the License, or (at your option) any later version.
  11. ** 
  12. ** This library is distributed in the hope that it will be useful,
  13. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. ** Library General Public License for more details.
  16. ** 
  17. ** You should have received a copy of the GNU Library General Public
  18. ** License along with this library (see COPYING-LIB); if not, write to 
  19. ** the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
  20. ** USA.
  21. ** 
  22. **                            Written by
  23. **
  24. **                   Harald Winroth, Matti Rendahl
  25. **         Computational Vision and Active Perception Laboratory
  26. **            Royal Institute of Technology
  27. **              S-100 44 Stockholm
  28. **                Sweden
  29. **
  30. ** Report bugs to candela-bug@bion.kth.se, and direct all inquiries to 
  31. ** candela@bion.kth.se.
  32. **
  33. */
  34.  
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <signal.h>
  39.  
  40. #include <exception/exception.h>
  41.  
  42. /* Place holders (to generate unique addresses) */
  43. int exc_any;
  44. int exc_undefined;
  45.  
  46. /* Data associated with the current (pending) exception */
  47. static void *current_exception = EXC_UNDEFINED;
  48. static void *current_type = EXC_UNDEFINED;
  49.  
  50. /* Pointer to current jump buffer */
  51. volatile excBuf *exc_current_buf = NULL;
  52.  
  53. /* Dummy variables */
  54. volatile excBuf exc_buf;  /* Not used, but must exist     */
  55. char exc_in_try = 0;      /* Must have size 1 and value 0 */
  56. char exc_in_tret = 0;     /* Must have size 1 and value 0 */
  57. char exc_in_unwind = 0;   /* Must have size 1 and value 0 */
  58. char exception;           /* Not used, but must exist     */
  59.     
  60. /* Callback list */
  61. typedef struct
  62. {
  63.     excCallback cb;       /* registered callback           */
  64.     excCallbackTag tags;  /* mask                          */
  65.     void *cb_data;        /* data assoc. with the callback */
  66.  
  67. } excCallbackRec;
  68.  
  69. static excCallbackRec cb_list[EXC_MAX_CALLBACKS];
  70. static unsigned int cb_list_len = 0;
  71.  
  72. /* Handler list */
  73. typedef struct
  74. {
  75.     void *e;                 /* & SOME_EXCEPTION (or NULL)      */
  76.     unsigned long e_sz;      /* sizeof (SOME_EXCEPTION)         */
  77.     excHandler h;            /* registered handler              */
  78.     void *h_data;            /* user data                       */
  79.     
  80. } excHandlerRec;
  81.  
  82. static excHandlerRec h_list[EXC_MAX_HANDLERS];
  83. static unsigned int h_list_len = 0;
  84.  
  85. /*
  86.  * Private functions
  87.  */
  88.  
  89. static void check_recovered (volatile excBuf *buf);
  90. static void call_callbacks (volatile excBuf *buf, excCallbackTag tag);
  91. static void call_handlers (void *e, void *e_type);
  92.  
  93. /*
  94.  * Functions for internal error handling. These are private, but since they
  95.  * are used in macro expansions, they must be exported.
  96.  */
  97.  
  98. void exc_vfatal (char *format, va_list list)
  99. {
  100.     fprintf (stderr, "exception: ");
  101.     vfprintf (stderr, format, list);
  102.     fprintf (stderr, "\n");
  103.  
  104.     exit (1);
  105. }
  106.  
  107. void exc_fatal (char *format, ...)
  108. {
  109.     va_list list;
  110.  
  111.     if (format) 
  112.     {
  113.         va_start (list, format);
  114.         exc_vfatal (format, list);
  115.         va_end (list);
  116.     }
  117.  
  118.     exit (1);
  119. }
  120.  
  121. void exc_panic (void)
  122. {
  123.     fprintf (stderr, "exception: exception system panicked--aborting \
  124. (core dumped).\n");
  125.  
  126.     abort ();
  127. }    
  128.  
  129. void exc_assertion_failed (char *file, int line)
  130. {
  131.     exc_fatal ("%s:%d: assertion failed", file, line);
  132. }    
  133.  
  134. /*
  135.  * Memory management. Also used in other exception lib source files,
  136.  * and therefore exported.
  137.  */
  138.  
  139. void *exc_malloc (unsigned long size)
  140. {
  141.     void *s = malloc (size);
  142.     if (!s) exc_fatal ("exc_malloc: cannot allocated %lu bytes", size);
  143.     return s;
  144. }
  145.  
  146. void *exc_calloc (unsigned long count, unsigned long size)
  147. {
  148.     void *s = calloc (count, size);
  149.     if (!s) exc_fatal ("exc_calloc: cannot allocated %lu bytes", count*size);
  150.     return s;
  151. }
  152.  
  153. void *exc_realloc (void *s, unsigned long size)
  154. {
  155.     s = s ? realloc (s, size) : malloc (size);
  156.     if (!s) exc_fatal ("exc_realloc: cannot allocated %lu bytes", size);
  157.     return s;
  158. }
  159.  
  160. void exc_free (void *s)
  161. {
  162.     if (s) free (s);
  163. }
  164.  
  165. char *exc_strdup (char *s)
  166. {
  167.     return strcpy (exc_malloc (strlen (s) + 1), s);
  168. }
  169.  
  170. /*
  171.  * Signals
  172.  */
  173.  
  174. #if defined(SVR4) || defined(SYSV) || defined(_SYSV_)
  175.  
  176. static sigset_t saved_mask;
  177.  
  178. int exc_sigemptyset (void)
  179. {
  180.     return sigemptyset (&saved_mask);
  181. }
  182.  
  183. int exc_sigfillset (void)
  184. {
  185.     return sigfillset (&saved_mask);
  186. }
  187.  
  188. int exc_sigaddset (int signo)
  189. {
  190.     return sigaddset (&saved_mask, signo);
  191. }
  192.  
  193. int exc_sigdelset (int signo)
  194. {
  195.     return sigdelset (&saved_mask, signo);
  196. }
  197.  
  198. int exc_sigismember (int signo)
  199. {
  200.     return sigismember (&saved_mask, signo);
  201. }
  202.  
  203. #else
  204.  
  205. static int saved_mask;
  206.  
  207. int exc_sigemptyset (void)
  208. {
  209.     saved_mask = 0;
  210.     return 0;
  211. }
  212.  
  213. int exc_sigfillset (void)
  214. {
  215.     saved_mask = ~(int)0;
  216.     return 0;
  217. }
  218.  
  219. int exc_sigaddset (int signo)
  220. {
  221.     saved_mask |= sigmask (signo);
  222.     return 0;
  223. }
  224.  
  225. int exc_sigdelset (int signo)
  226. {
  227.     saved_mask &= ~sigmask (signo);
  228.     return 0;
  229. }
  230.  
  231. int exc_sigismember (int signo)
  232. {
  233.     return (saved_mask & sigmask (signo)) ? 1 : 0;
  234. }
  235.  
  236. #endif
  237.  
  238. /*
  239.  * Macros for blocking all signal temporarily
  240.  */
  241.  
  242. #if defined(SVR4) || defined(SYSV) || defined(_SYSV_)
  243.  
  244. #define BLOCK_SIGNALS(VAR)                              \
  245.     sigset_t _filled_mask;                              \
  246.     sigset_t VAR;                                  \
  247.     sigfillset (&_filled_mask);                                  \
  248.     if (sigprocmask (SIG_SETMASK, &_filled_mask, &VAR))                  \
  249.     exc_fatal ("BLOCK_SIGNALS: sigprocmask() failed.")
  250.  
  251. #define UNBLOCK_SIGNALS(VAR)                              \
  252.     if (sigprocmask (SIG_SETMASK, &VAR, 0))                        \
  253.     exc_fatal ("UNBLOCK_SIGNALS: sigprocmask() failed.")
  254.  
  255. #else
  256.  
  257. #define BLOCK_SIGNALS(VAR)                              \
  258.     int VAR = sigsetmask (~(int)0)
  259.     
  260. #define UNBLOCK_SIGNALS(VAR)                              \
  261.     sigsetmask (VAR)
  262.  
  263. #endif
  264.  
  265. /*
  266.  * Stack of data for callbacks.
  267.  *
  268.  * Note: The list of blocks and the blocks it contains are never reallocated.
  269.  * This is important because signals may cause pointer addresses to be invalid
  270.  * between any two machine instructions.
  271.  */
  272.  
  273. #define MAX_BLOCKS (8 * sizeof (unsigned int))
  274.  
  275. static void **try_data_stack[MAX_BLOCKS]; /* Note: Inited to NULL */
  276. static unsigned int try_data_sp = 0;
  277.  
  278. /* acc requires the (void **) cast below, it should not be necessary */
  279. #define TRY_DATA_ADDR(buf, i)                              \
  280.     (((i) < (EXC_LOCAL_TRY_DATA_SIZE)) ?                       \
  281.      (void **) &(buf)->local_try_data[i] :                      \
  282.      try_data_stack_addr ((buf)->try_data_sp+(i)-(EXC_LOCAL_TRY_DATA_SIZE)))
  283.  
  284. static void try_data_stack_alloc (unsigned int b)
  285. {
  286.     BLOCK_SIGNALS(tmp_mask);
  287.  
  288.     if (!try_data_stack[b])
  289.     try_data_stack[b] = (void **) 
  290.         exc_malloc ((((unsigned int) 1) << b) * sizeof(void *));
  291.     
  292.     UNBLOCK_SIGNALS (tmp_mask);
  293. }
  294.  
  295. static void **try_data_stack_addr (unsigned int i)
  296. {
  297.     unsigned int block, offs, mask;
  298.     void **bptr;
  299.  
  300.     for (i++, block=MAX_BLOCKS-1, mask=((unsigned int) 1)<<block;
  301.      (i & mask) == 0; 
  302.      mask >>= 1, block--);
  303.     offs = i & ~mask;
  304.  
  305.     if ((bptr = try_data_stack[block]) == NULL)
  306.     {
  307.     try_data_stack_alloc (block);
  308.     bptr = try_data_stack[block];
  309.     }
  310.  
  311.     return bptr+offs;
  312. }
  313.  
  314. /*
  315.  * Public 
  316.  */
  317.  
  318. void exc_breakpoint (void)
  319. {
  320.     /*
  321.      * Users can place breakpoints in this dummy function to break before
  322.      * the longjmp is taken, no matter which exc_*() function actually 
  323.      * contains the longjmp.
  324.      */
  325.     
  326.     return; 
  327. }
  328.  
  329. void exc_throw_typed (void *e, void *e_type)
  330. {
  331.     volatile excBuf *buf;
  332.  
  333. #if defined(SVR4) || defined(SYSV) || defined(_SYSV_)
  334.     sigset_t filled_mask;
  335.     sigset_t cur_mask;
  336.     if (sigfillset (&filled_mask)) 
  337.     exc_fatal ("exc_throw_typed: sigfillmask() failed.");
  338.     if (sigprocmask (SIG_SETMASK, &filled_mask, &cur_mask))
  339.     exc_fatal ("exc_throw_typed: sigprocmask() failed.");
  340. #else
  341.     int filled_mask = ~(int)0;
  342.     int cur_mask = sigsetmask (filled_mask);
  343. #endif
  344.     
  345.     exc_breakpoint (); /* Dummy function */
  346.  
  347.     if (e == EXC_UNDEFINED)
  348.     exc_fatal ("exc_throw_typed: no exception specified");
  349.     if (e_type == EXC_UNDEFINED)
  350.     exc_fatal ("exc_throw_typed: no exception type specified");
  351.  
  352.     if (current_exception == EXC_UNDEFINED)
  353.     saved_mask = cur_mask;
  354.  
  355.     current_exception = e;
  356.     current_type = e_type;
  357.  
  358.     /* Find first unused jump buffer (target TRY-block) */
  359.     for (buf=exc_current_buf; buf && buf->in_unwind; buf=buf->prev);
  360.  
  361.     if (!buf)
  362.         call_handlers (e, e_type);
  363.     
  364.     /* Execute throw callbacks outside the current TRY scope */
  365.     buf->in_unwind = 1;
  366.     call_callbacks (buf, excThrowCallback);
  367.  
  368.     exc_current_buf = buf;
  369.     try_data_sp = buf->try_data_sp;
  370.     EXC_LONGJMP (buf->buf, 1);
  371. }
  372.  
  373. void exc_throw (void *e)
  374. {
  375.     exc_throw_typed (e, e); /* Let `e` be its own (unique) type */
  376. }
  377.  
  378. void exc_rethrow (void)
  379. {
  380.     if (current_exception == EXC_UNDEFINED)
  381.     exc_fatal ("exc_rethrow: no pending exception");
  382.  
  383.     exc_throw_typed (current_exception, current_type);
  384. }
  385.  
  386. void *exc_exception (void)
  387. {
  388.     if (current_exception == EXC_UNDEFINED)
  389.         exc_fatal ("exc_exception: no exception thrown");
  390.  
  391.     return current_exception;
  392. }
  393.  
  394. void *exc_type (void)
  395. {
  396.     if (current_type == EXC_UNDEFINED)
  397.         exc_fatal ("exc_exception: no exception thrown");
  398.  
  399.     return current_type;
  400. }
  401.  
  402. int exc_in_domain (void *e, void *domain, unsigned long sizeof_domain)
  403. {
  404.     return (e >= domain && e < (void *) (((char *) domain) + sizeof_domain));
  405. }
  406.  
  407. int exc_equal (void *e1, void *e2)
  408. {
  409.     return e1 == e2;
  410. }
  411.  
  412. /*
  413.  * Functions used in macro expansions and therefore exported. Must not be 
  414.  * called explicitly from application programs.
  415.  */
  416.  
  417. void exc_begin (volatile excBuf *buf, int inside_try)
  418. {
  419.     EXC_ASSERT (exc_current_buf != buf && (exc_current_buf || !inside_try));
  420.     
  421.     buf->prev = exc_current_buf;
  422.     buf->prev_dynamic = inside_try ? exc_current_buf->prev_dynamic 
  423.                                : exc_current_buf;
  424.  
  425.     buf->level = exc_current_buf ? exc_current_buf->level+1 : 0;
  426.     buf->cb_list_len = cb_list_len;
  427.     buf->try_data_sp = try_data_sp;
  428.     buf->in_unwind = 0;
  429.  
  430.     if (buf->cb_list_len > (EXC_LOCAL_TRY_DATA_SIZE))
  431.     try_data_sp = buf->try_data_sp + buf->cb_list_len - 
  432.         (EXC_LOCAL_TRY_DATA_SIZE);
  433.     
  434.     call_callbacks (buf, excBeginCallback);
  435. }                                                                    
  436.  
  437. void exc_end (volatile excBuf *buf)
  438. {
  439.     EXC_ASSERT (exc_current_buf == buf);
  440.     
  441.     if (buf->in_unwind)
  442.     check_recovered (buf->prev);
  443.     else
  444.     call_callbacks (buf, excEndCallback);
  445.  
  446.     exc_current_buf = buf->prev;
  447.     try_data_sp = buf->try_data_sp; /* Must be reset *after* exc_current_buf */
  448. }
  449.  
  450. int exc_tret (volatile excBuf *buf, int in_tret, char *file, int line)
  451. {
  452.     if (!in_tret)
  453.     exc_ret_in_try_err (file, line);
  454.  
  455.     EXC_ASSERT (exc_current_buf == buf);
  456.  
  457.     while (exc_current_buf != buf->prev_dynamic)
  458.     exc_end (exc_current_buf);
  459.  
  460.     return 0;
  461. }
  462.  
  463. static void check_recovered (volatile excBuf *buf)
  464. {
  465.     for (; buf; buf=buf->prev)
  466.     if (buf->in_unwind)
  467.         return;
  468.  
  469.     /* The program has recovered from the pending exception */
  470.     current_exception = EXC_UNDEFINED;
  471.     current_type = EXC_UNDEFINED;
  472.  
  473.     call_callbacks (buf, excRecoverCallback);
  474.  
  475. #if defined(SVR4) || defined(SYSV) || defined(_SYSV_)
  476.     if (sigprocmask (SIG_SETMASK, &saved_mask, 0))
  477.     exc_fatal ("exc_end: check_recovered: sigprocmask() failed.");
  478. #else
  479.     sigsetmask (saved_mask);
  480. #endif
  481. }
  482.  
  483. /*
  484.  * Error functions used in macro expansions and therefore exported. Must not 
  485.  * be called explicitly from application programs.
  486.  */
  487.  
  488. void exc_break_in_try_err (char *file, int line)
  489. {
  490.     exc_fatal ("%s:%d: illegal break statement in TRY", file, line);
  491. }
  492.  
  493. void exc_rethrow_err (char *file, int line)
  494. {
  495.     exc_fatal ("%s:%d: THROW(exception) used outside unwind form",
  496.            file, line);
  497. }
  498.  
  499. int exc_catch_outside_unwind_err (char *file, int line)
  500. {
  501.     exc_fatal ("%s:%d: CATCH outside unwind form", file, line);
  502.     return 0; /* Not reached */
  503. }
  504.  
  505. void exc_ret_in_try_err (char *file, int line)
  506. {
  507.     exc_fatal ("%s:%d: illegal return statement in TRY", file, line);
  508. }
  509.  
  510. int exc_tret_err (char *file, int line)
  511. {
  512.     exc_fatal ("%s:%d: tryreturn() used outside TRY", file, line);
  513.     return 0; /* Not reached */
  514. }
  515.  
  516. /*
  517.  * Callbacks
  518.  */
  519.  
  520. void exc_install_callback (excCallbackTag tags, excCallback cb, void *cb_data) 
  521. {
  522.     BLOCK_SIGNALS (tmp_mask);
  523.  
  524.     if (cb_list_len == EXC_MAX_CALLBACKS) 
  525.     exc_fatal ("exc_install_callback: Too many (>%d) callbacks installed",
  526.            EXC_MAX_CALLBACKS);
  527.  
  528.     cb_list[cb_list_len].cb = cb;
  529.     cb_list[cb_list_len].tags = tags;
  530.     cb_list[cb_list_len].cb_data = cb_data;
  531.     cb_list_len++;
  532.  
  533.     UNBLOCK_SIGNALS (tmp_mask);
  534. }
  535.  
  536. void exc_remove_callback (excCallbackTag tags, excCallback cb, void *cb_data) 
  537. {
  538.     unsigned int i;
  539.  
  540.     for (i=cb_list_len; i-- > 0;)
  541.     if (cb_list[i].cb == cb && cb_list[i].tags == tags &&
  542.         cb_list[i].cb_data == cb_data) 
  543.     {
  544.         cb_list[i].tags = excNoCallback;
  545.         return;
  546.     }
  547.  
  548.     exc_fatal ("exc_remove_callback: no such callback installed");
  549. }
  550.  
  551. static void call_callbacks (volatile excBuf *buf, excCallbackTag tag)
  552. {
  553.     /* 
  554.       Careful here: Avoid infinite loops--a callback may do THROW or TRY. 
  555.       Also, excBeginCallback and excEndCallback calls are not protected from
  556.       async. THROWS (caused by signals).
  557.     */
  558.  
  559.     unsigned int i;
  560.  
  561.     switch (tag) 
  562.     {
  563.     case excBeginCallback:
  564.     for (i=0; i<buf->cb_list_len; i++)
  565.         if (cb_list[i].tags & tag)
  566.         (*(cb_list[i].cb)) (tag, cb_list[i].cb_data, 
  567.                     TRY_DATA_ADDR (buf, i));
  568.     return;
  569.  
  570.     case excEndCallback: 
  571.     case excThrowCallback:
  572.     /* 
  573.       For excEndCallback calls:
  574.           No try-data are discarded until all excEndCallback calls have 
  575.           completed successfully. An explicit or async THROW() should
  576.           trigger excThrowCallback calls for the same try-data. 
  577.  
  578.           Watch out for destructive effects in excEndCallback calls which 
  579.           may cause a subsequent excThrowCallback call with the same 
  580.           try-data to crash.
  581.  
  582.       For excThrowCallback calls:
  583.           Async throws are disabled here (blocked in exc_throw_typed()). 
  584.           Explicit throws are allowed and will cause execution to continue 
  585.           in the unwind-block of the enclosing TRY() (thus skipping the 
  586.           rest of the callbacks).
  587.         */
  588.  
  589.     for (i = cb_list_len; i-- > buf->cb_list_len;)
  590.         if (cb_list[i].tags & tag)
  591.         (*(cb_list[i].cb))(tag, cb_list[i].cb_data, (void **)NULL);
  592.  
  593.     for (i = buf->cb_list_len; i-- > 0;)
  594.         if (cb_list[i].tags & tag)
  595.         (*(cb_list[i].cb))(tag, cb_list[i].cb_data, 
  596.                    TRY_DATA_ADDR (buf, i));
  597.     return;
  598.  
  599.     case excRecoverCallback:
  600.     for (i=0; i<cb_list_len; i++)
  601.         if (cb_list[i].tags & tag)
  602.         (*(cb_list[i].cb))(tag, cb_list[i].cb_data, (void **)NULL);
  603.  
  604.     return;
  605.  
  606.     default:
  607.     exc_fatal ("call_callbacks: illegal tag or combination of tags");
  608.     }
  609. }
  610.  
  611. /*
  612.  * Handlers
  613.  */
  614.  
  615. void exc_install_handler (void *e, unsigned long e_sz, excHandler h, 
  616.               void *h_data)
  617. {
  618.     BLOCK_SIGNALS (tmp_mask);
  619.  
  620.     if (h_list_len == EXC_MAX_HANDLERS) 
  621.     exc_fatal ("exc_install_handler: Too many (>%d) handlers installed",
  622.            EXC_MAX_HANDLERS);
  623.  
  624.     /* Note: Users are allowed to use NULL instead of EXC_ANY */
  625.     h_list[h_list_len].e = e ? e : EXC_ANY; 
  626.     h_list[h_list_len].e_sz = e_sz;
  627.     h_list[h_list_len].h = h;
  628.     h_list[h_list_len].h_data = h_data;
  629.     h_list_len++;
  630.  
  631.     UNBLOCK_SIGNALS (tmp_mask);
  632. }
  633.  
  634. void exc_remove_handler (void *e, unsigned long e_sz, excHandler h, 
  635.               void *h_data)
  636. {
  637.     unsigned int i;
  638.     static char slot_not_used; /* Generates a unique, private address */
  639.     
  640.     for (i=h_list_len; i>0; i--)
  641.         if (h_list[i-1].e != &slot_not_used
  642.             && h_list[i-1].e == e 
  643.             && h_list[i-1].e_sz == e_sz
  644.             && h_list[i-1].h == h
  645.             && h_list[i-1].h_data == h_data)
  646.     {
  647.         BLOCK_SIGNALS (tmp_mask);
  648.  
  649.         h_list[i-1].e = &slot_not_used;
  650.         h_list[i-1].e_sz = 0;
  651.         h_list[i-1].h = NULL;
  652.         h_list[i-1].h_data = NULL;
  653.  
  654.         UNBLOCK_SIGNALS (tmp_mask);
  655.         return;
  656.     }
  657.     
  658.     exc_fatal ("exc_remove_handler: no such handler installed");
  659. }
  660.  
  661. static void call_handlers (void *e, void *e_type)
  662. {
  663.     /* 
  664.       The list of handlers is search (in reversed installation order) for 
  665.       a matching handler, say H, and calls it. If H returns, we exit with 
  666.       exc_fatal(NULL) (i.e. exit(1)). If H throws, the list of handlers will 
  667.       be search again, starting with the handler installed before H. If no 
  668.       matching handler can be found, we call exc_fatal() with an informative(?)
  669.       text.
  670.  
  671.       Note: Since handlers may throw, we must remove them from the list BEFORE
  672.       calling them, to prevent infinite loops.
  673.     */
  674.  
  675.     /* 
  676.       Should signals be blocked when the handlers are executed? If not, error
  677.       message print-outs could be terminated with (e.g.) ctrl-c, causing the
  678.       previously installed handler to be called. Have to think about this...
  679.     */
  680.  
  681.     BLOCK_SIGNALS (tmp_mask);
  682.  
  683.     EXC_ASSERT (e != EXC_UNDEFINED && e_type != EXC_UNDEFINED);
  684.  
  685.     while (h_list_len > 0)
  686.     {
  687.         unsigned int i = --h_list_len;
  688.  
  689.         if ((exc_in_domain (e, h_list[i].e, h_list[i].e_sz) 
  690.          || h_list[i].e == EXC_ANY)
  691.             && h_list[i].h)
  692.         {
  693.             int ret_status = (*h_list[i].h) (e, e_type, h_list[i].h_data);
  694.         UNBLOCK_SIGNALS (tmp_mask);
  695.         exit (ret_status);
  696.         }
  697.     }
  698.  
  699.     UNBLOCK_SIGNALS (tmp_mask);
  700.     exc_fatal ("exception not catched and no handler to call, terminating...");
  701. }
  702.