common/trace.c

00001 /*
00002  * Copyright Ian Burnett 2005, 2006.
00003  *
00004  * This file is part of Ian's Interactive LCD controller (IILC).
00005  * 
00006  * IILC is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU General Public License as published by the Free
00008  * Software Foundation; either version 2 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * IILC is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00014  * for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with IILC; if not, write to the Free Software Foundation, Inc.,
00018  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdarg.h>
00023 #include <string.h>
00024 #include <time.h>
00025 
00026 #if defined(_WIN32)
00027 #   include "pthread_w32.h"
00028 #   define vsnprintf _vsnprintf
00029 #else
00030 #   include <pthread.h>
00031 #   include <sys/time.h>
00032 #endif
00033 
00034 #include "trace.h"
00035 
00036 
00041 static void traceData(traceContextData * pContext,
00042                       char symbol,
00043                       char * fmt,
00044                       va_list args);
00045 
00049 static pthread_once_t trace_init = PTHREAD_ONCE_INIT;
00050 
00055 #define TRACE_INITIALISE  (void) pthread_once(&trace_init, traceInitialise);
00056 
00060 static FILE * g_file = NULL;
00061 
00062 /*
00063  * State flags for each type of trace function
00064  */
00065 
00066 unsigned char g_bSev0Enabled = 0; /* Really low-level debugging    */
00067 unsigned char g_bSev1Enabled = 0; /* Low-level debugging           */
00068 unsigned char g_bSev2Enabled = 1; /* Extra info about goings-on    */
00069 unsigned char g_bSev3Enabled = 1; /* Warnings about stuff          */
00070 unsigned char g_bSev4Enabled = 1; /* Internally-recoverable errors */
00071 unsigned char g_bSev5Enabled = 1; /* Catastrophic errors           */
00072 
00073 /*
00074  * Key under which to find the stack depth in TLS
00075  */
00076 
00077 static pthread_key_t g_keyStackDepth;
00078 
00079 
00080 
00081 /********************************************************************************
00082  *      Internal functions                                                      *
00083  ********************************************************************************/
00084 
00085 
00086 void traceInitialise(void)
00087 {
00088     /* Initialise the stack depth TLS key */
00089     (void) pthread_key_create(&g_keyStackDepth, NULL);
00090 
00091     /* Open the file for writing */
00092     g_file = stdout;
00093     /* g_file = fopen("trace.txt", "a"); */
00094 }
00095 
00096 #define TRACE_BUFLEN 1024
00097 
00098 #define FIFTY_SPACES  "                                                  "
00099 
00100 void traceData(traceContextData * pContext, char symbol, char * fmt, va_list args)
00101 {
00102     char    message[TRACE_BUFLEN];
00103     int   * pStackDepth = NULL;
00104     int     nStackDepth = 0;
00105     int     nIndent     = 0;
00106     size_t  nOffset     = 0;
00107     size_t  nBytesAvail = TRACE_BUFLEN;
00108 
00109     /* Clear the buffer */
00110     memset(message, (int) ' ', TRACE_BUFLEN);
00111 
00112     /* Grab the current stack depth */
00113     pStackDepth = (int *) pthread_getspecific(g_keyStackDepth);
00114     if (pStackDepth == NULL) {
00115         pStackDepth = (int *) malloc(sizeof(int));
00116         *pStackDepth = 0;
00117         pthread_setspecific(g_keyStackDepth, (void *) pStackDepth);
00118     }
00119 
00120     /* ----- Time formatting ----- */
00121     {
00122         struct timeval now;
00123         struct tm * nowTM;
00124 
00125         /* Get the current time */
00126         gettimeofday(&now, NULL);
00127 
00128         nowTM = localtime(&(now.tv_sec));
00129 
00130         /* Format the time string */
00131         nOffset += strftime(message + nOffset, nBytesAvail, "%d/%m/%y %H:%M:%S ", nowTM);
00132     }
00133 
00134     /* ----- Thread ID ----- */
00135     {
00136         pthread_t this_thread;
00137 
00138         this_thread = pthread_self();
00139 
00140         sprintf(message + nOffset, "%8lX ", this_thread);
00141 
00142         /* Update counters */
00143         nOffset     += 9;
00144         nBytesAvail -= 9;
00145     }
00146 
00147     /* ----- Data type symbol ----- */
00148     {
00149         sprintf(message + nOffset, "%c ", symbol);
00150         nOffset     += 2;
00151         nBytesAvail -= 2;
00152     }
00153 
00154     /* ----- Data formatting ----- */
00155     {
00156         /* Drop the NUL-terminator */
00157         message[nOffset] = ' ';
00158 
00159         /* Get the current depth for this thread */
00160         nStackDepth = *pStackDepth;
00161 
00162         /* Outdent by 1 if this is an exit point */
00163         if (symbol == '<') { nStackDepth--; }
00164 
00165         /* If we're using entry / exit trace, use indenting */
00166         nIndent = g_bSev1Enabled ? nStackDepth * 2 : 0;
00167 
00168         /* Skip into buffer by sufficient bytes */
00169         nOffset     += nIndent;
00170         nBytesAvail -= nIndent;
00171 
00172         /* Format the message */
00173         vsnprintf(message + nOffset, nBytesAvail, fmt, args);
00174 
00175         /* Indent by 1 if this is an entry point */
00176         if (symbol == '>') { nStackDepth++; }
00177 
00178         /* Save stack depth */
00179         *pStackDepth = nStackDepth;
00180     }
00181 
00182     /* ----- Write out buffer ----- */
00183     fprintf(g_file, "%s\n", message);
00184 }
00185 
00186 
00187 
00188 /********************************************************************************
00189  *      Exported functions                                                      *
00190  ********************************************************************************/
00191 
00192 
00193 void traceEntry(traceContextData * pContext)
00194 {
00195     TRACE_INITIALISE;
00196 
00197     if (g_bSev1Enabled) {
00198         traceData(pContext, '>', &(pContext->pszFunction[2]), NULL);
00199     }
00200 }
00201 
00202 
00203 void traceExit(traceContextData * pContext)
00204 {
00205     TRACE_INITIALISE;
00206 
00207     if (g_bSev1Enabled) {
00208         traceData(pContext, '<', &(pContext->pszFunction[2]), NULL);
00209     }
00210 }
00211 
00212 void traceDebug(traceContextData * pContext, char * fmt, ...)
00213 {
00214     va_list args;
00215 
00216     TRACE_INITIALISE;
00217 
00218     if (g_bSev1Enabled) {
00219         va_start(args, fmt);
00220         traceData(pContext, 'D', fmt, args);
00221         va_end(args);
00222     }
00223 }
00224 
00225 void traceInfo(traceContextData * pContext, char * fmt, ...)
00226 {
00227     va_list args;
00228 
00229     TRACE_INITIALISE;
00230 
00231     if (g_bSev3Enabled) {
00232         va_start(args, fmt);
00233         traceData(pContext, 'I', fmt, args);
00234         va_end(args);
00235     }
00236 }
00237 
00238 void traceWarning(traceContextData * pContext, char * fmt, ...)
00239 {
00240     va_list args;
00241 
00242     TRACE_INITIALISE;
00243 
00244     if (g_bSev4Enabled) {
00245         va_start(args, fmt);
00246         traceData(pContext, 'W', fmt, args);
00247         va_end(args);
00248     }
00249 }
00250 
00251 void traceError(traceContextData * pContext, char * fmt, ...)
00252 {
00253     va_list args;
00254 
00255     TRACE_INITIALISE;
00256 
00257     if (g_bSev5Enabled) {
00258         va_start(args, fmt);
00259         traceData(pContext, 'E', fmt, args);
00260         va_end(args);
00261     }
00262 }
00263 

Generated on Mon Jul 17 01:36:11 2006 for IILC by  doxygen 1.4.6