©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

common/ec.c

Go to the documentation of this file.
00001 /*
00002     Error-checking support functions
00003     AUP2, Sec. 1.04.2
00004 
00005     Copyright 2003 by Marc J. Rochkind. All rights reserved.
00006     May be copied only for purposes and under conditions described
00007     on the Web page www.basepath.com/aup/copyright.htm.
00008 
00009     The Example Files are provided "as is," without any warranty;
00010     without even the implied warranty of merchantability or fitness
00011     for a particular purpose. The author and his publisher are not
00012     responsible for any damages, direct or incidental, resulting
00013     from the use or non-use of these Example Files.
00014 
00015     The Example Files may contain defects, and some contain deliberate
00016     coding mistakes that were included for educational reasons.
00017     You are responsible for determining if and how the Example Files
00018     are to be used.
00019 
00020 */
00021 #include "defs.h"
00022 #include <pthread.h>
00023 
00024 static void ec_mutex(bool lock)
00025 {
00026     static pthread_mutex_t ec_mtx = PTHREAD_MUTEX_INITIALIZER;
00027     int errnum;
00028     char *msg;
00029 
00030     if (lock) {
00031         if ((errnum = pthread_mutex_lock(&ec_mtx)) == 0)
00032             return;
00033     }
00034     else {
00035         if ((errnum = pthread_mutex_unlock(&ec_mtx)) == 0)
00036             return;
00037     }
00038     if ((msg = strerror(errnum)) == NULL)
00039         fprintf(stderr, "Mutex error in ec_* function: %d\n", errnum);
00040     else
00041         fprintf(stderr, "Mutex error in ec_* function: %s\n", msg);
00042     exit(EXIT_FAILURE);
00043 }
00044 
00045 /*[ec_atexit_fcn]*/
00046 static void ec_atexit_fcn(void)
00047 {
00048     ec_print();
00049 }
00050 /*[ec_node]*/
00051 static struct ec_node {
00052     struct ec_node *ec_next;
00053     int ec_errno;
00054     EC_ERRTYPE ec_type;
00055     char *ec_context;
00056 } *ec_head, ec_node_emergency;
00057 static char ec_s_emergency[100];
00058 
00059 const bool ec_in_cleanup = false;
00060 /*[ec_push]*/
00061 #define SEP1 " ["
00062 #define SEP2 ":"
00063 #define SEP3 "] "
00064 
00065 void ec_push(const char *fcn, const char *file, int line,
00066   const char *str, int errno_arg, EC_ERRTYPE type)
00067 {
00068     struct ec_node node, *p;
00069     size_t len;
00070     static bool attexit_called = false;
00071 
00072     ec_mutex(true);
00073     node.ec_errno = errno_arg;
00074     node.ec_type = type;
00075     if (str == NULL)
00076         str = "";
00077     len = strlen(fcn) + strlen(SEP1) + strlen(file) + strlen(SEP2) +
00078       6 + strlen(SEP3) + strlen(str) + 1;
00079     node.ec_context = (char *)calloc(1, len);
00080     if (node.ec_context == NULL) {
00081         if (ec_s_emergency[0] == '\0')
00082             node.ec_context = ec_s_emergency;
00083         else
00084             node.ec_context = "?";
00085         len = sizeof(ec_s_emergency);
00086     }
00087     if (node.ec_context != NULL)
00088         snprintf(node.ec_context, len, "%s%s%s%s%d%s%s", fcn, SEP1,
00089           file, SEP2, line, SEP3, str);
00090     p = (struct ec_node *)calloc(1, sizeof(struct ec_node));
00091     if (p == NULL && ec_node_emergency.ec_context == NULL)
00092         p = &ec_node_emergency; /* use just once */
00093     if (p != NULL) {
00094         node.ec_next = ec_head;
00095         ec_head = p;
00096         *ec_head = node;
00097     }
00098     if (!attexit_called) {
00099         attexit_called = true;
00100         ec_mutex(false);
00101         if (atexit(ec_atexit_fcn) != 0) {
00102             ec_push(fcn, file, line, "atexit failed", errno, EC_ERRNO);
00103             ec_print(); /* so at least the error gets shown */
00104         }
00105     }
00106     else
00107         ec_mutex(false);
00108 }
00109 /*[ec_print]*/
00110 void ec_print(void)
00111 {
00112     struct ec_node *e;
00113     int level = 0;
00114 
00115     ec_mutex(true);
00116     for (e = ec_head; e != NULL; e = e->ec_next, level++) {
00117         char buf[200], buf2[25 + sizeof(buf)];
00118 
00119         if (e == &ec_node_emergency)
00120             fprintf(stderr, "\t*** Trace may be incomplete ***\n");
00121         syserrmsgtype(buf, sizeof(buf), e->ec_context,
00122           e->ec_next == NULL ? e->ec_errno : 0, e->ec_type);
00123         snprintf(buf2, sizeof(buf2), "%s\t%d: %s",
00124           (level == 0? "ERROR:" : ""), level, buf);
00125         fprintf(stderr, "%s\n", buf2);
00126         logfmt(buf2);
00127     }
00128     ec_mutex(false);
00129 }
00130 /*[ec_reinit]*/
00131 void ec_reinit(void)
00132 {
00133     struct ec_node *e, *e_next;
00134 
00135     ec_mutex(true);
00136     for (e = ec_head; e != NULL; e = e_next) {
00137         e_next = e->ec_next;
00138         if (e->ec_context != ec_s_emergency)
00139             free(e->ec_context);
00140         if (e != &ec_node_emergency)
00141             free(e);
00142     }
00143     ec_head = NULL;
00144     memset(&ec_node_emergency, 0, sizeof(ec_node_emergency));
00145     memset(&ec_s_emergency, 0, sizeof(ec_s_emergency));
00146     ec_mutex(false);
00147 }
00148 /*[ec_warn]*/
00149 void ec_warn(void)
00150 {
00151     fprintf(stderr, "***WARNING: Control flowed into EC_CLEANUP_BGN\n");
00152 }
00153 /*[]*/

Generated on Fri Apr 23 10:57:03 2004 for AUP2 Example Source by doxygen 1.3.1