//============================================================================= // drt/sys/sdebugf.cpp // Debugging trace classes. // These are definitions for members of class DrtTrace. // // History // 0.01, 1998-04-17, David R Tribble. // First cut. // // 0.02, 1998-04-24, David R Tribble. // Renamed from "scdebug.cpp" to "jdebug.cpp". // // 0.03, 1998-05-30, David R Tribble. // Changed filename prefix from "j" to "s". // // 0.04, 1998-06-23, David R Tribble. // Changed prototype for .enter(). // // 0.05, 1999-02-26, David R Tribble. // Moved to drt/sys/. // // Copyright ©1998-1999, by David R. Tribble, all rights reserved. // See "drt/sys/copyr.txt" for more information. //----------------------------------------------------------------------------- // Identification static const char id[] = "@(#)drt/sys/sdebugf.cpp 0.05"; // Special includes #include "sdefs.hpp" #include "sdebug.hpp" // System includes #include #define drt_std_stdarg_h 1 #include #define drt_std_stdio_h 1 // Local wrappers drt_namespace_begin //----------------------------------------------------------------------------- // Shared class constants //----------------------------------------------------------------------------- #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif /*static*/ const int DrtTrace::VS = DrtTrace_VS; // Class version /*static*/ const unsigned int DrtTrace::MAGIC = 0xD2D00B1E; // Class magic number //----------------------------------------------------------------------------- // Shared class variables //----------------------------------------------------------------------------- #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif /*static*/ FILE * DrtTrace::s_outf = null; // Debugging output stream /*static*/ FILE * DrtTrace::s_savef = null; // Suspended output stream /*static*/ int DrtTrace::s_depth = 0; // Func nesting depth /*static*/ DrtTraceInfo * DrtTrace::s_stack = null; // Nested func call info //----------------------------------------------------------------------------- // Class member functions //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // DrtTrace::suspend() // Suspend output to the debugging output stream. // // See also // resume() // // Caveats // Multiple calls to this function without intervening calls to resume() // are benign. //----------------------------------------------------------------------------- /*static*/ void DrtTrace::suspend() { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire mutex lock(); // Save the current debug output stream if (s_outf != null) s_savef = s_outf; // Disable debugging output s_outf = null; // Release the mutex unlock(); } //----------------------------------------------------------------------------- // DrtTrace::resume() // Resume output to the debugging output stream. // // See also // suspend() // // Caveats // Multiple calls to this function without intervening calls to suspend() // are benign. //----------------------------------------------------------------------------- /*static*/ void DrtTrace::resume() { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire a mutex lock(); // Restore the current debug output stream if (s_outf == null and s_savef != null) s_outf = s_savef; s_savef = null; // Release the mutex unlock(); } //----------------------------------------------------------------------------- // DrtTrace::enterContext() // Enter and lock the debug output context for a while. // // Acquires a mutex lock on the debug tracing output, which may cause this // thread to block momentarily, forcing all other thread's debug tracing // output to block. // This then allows this thread to perform debug tracing output without // fear of the output being intermingled with the debug tracing output // from other threads. // // Caveats // This will block indefinitely while the debug tracing context is locked // by another thread. // It is therefore very important that every thread that calls this // function to eventually call leaveContext(). //----------------------------------------------------------------------------- /*static*/ void DrtTrace::enterContext() { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire a mutex lock(); } //----------------------------------------------------------------------------- // DrtTrace::leaveContext() // Unlock and leave the debug output context. // // Releases the mutex lock on the debug tracing output, which allows other // waiting threads to unblock. // This then reliquishes this thread's lock on the debug tracing output. // // Caveats // Other threads will block indefinitely while the debug tracing context // is locked by another thread. // It is therefore very important that every thread call this function // after it has called enterContext(). //----------------------------------------------------------------------------- /*static*/ void DrtTrace::leaveContext() { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Release the mutex unlock(); } //----------------------------------------------------------------------------- // DrtTrace::enter() // Trace an entry into a function. // // Writes a line to the debug output stream indicating the entry (call) // into the function named 'name' for object pointer 'thisp' within // debug group 'g'. // // Caveats // This adjusts the function tracing stack regardless of whether the // debugging output file (.s_outf) is open or not. //----------------------------------------------------------------------------- /*static*/ int DrtTrace::enter(const char *name, const void *thisp, DrtTraceGroup *g) { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire a mutex lock(); // Check the arguments if (name == null) name = "?"; // Push the debugging call stack s_depth++; // Push a new func call entry onto the debugging call stack if (s_depth < MAX_DEPTH) { int d = s_depth-1; s_stack[d].m_func = name; s_stack[d].m_thisp = thisp; s_stack[d].m_group = g; } // Check for an open debug stream if (s_outf != null and (g == null or g->isEnabled())) { char buf[250]; // Write a debug line sprintf(buf, "%s%s%s", (g == null ? "" : g->m_name), (g == null ? "" : "."), name); fprintf(s_outf, "%-16s: {", buf); if (thisp != null) fprintf(s_outf, " %08p", thisp); fprintf(s_outf, "\n"); fflush(s_outf); } // Release the mutex unlock(); // Done return (s_depth); } //----------------------------------------------------------------------------- // DrtTrace::leave() // Trace an exit from a function. // // Writes a line to the debug output stream indicating the return from // the last function previously entered (and registered by a call to // enter()). // // Caveats // This adjusts the function tracing stack regardless of whether the // debugging output file (.s_outf) is open or not. //----------------------------------------------------------------------------- /*static*/ void DrtTrace::leave() { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire a mutex lock(); // Pop the debugging call stack s_depth--; // Check for an open debug stream if (s_outf != null and s_depth >= 0 and s_depth < MAX_DEPTH) { const DrtTraceGroup * g; const void * thisp; const char * name; char buf[250]; // Write a debug line name = s_stack[s_depth].m_func; thisp = s_stack[s_depth].m_thisp; g = s_stack[s_depth].m_group; sprintf(buf, "%s%s%s", (g == null ? "" : g->m_name), (g == null ? "" : "."), name); fprintf(s_outf, "%-16s: }", buf); if (thisp != null) fprintf(s_outf, " %08p", thisp); fprintf(s_outf, "\n"); fflush(s_outf); } // Reset old pointers if (s_depth+1 >= 0 and s_depth+1 < MAX_DEPTH) { int d; d = s_depth+1; s_stack[d].m_func = null; s_stack[d].m_thisp = null; s_stack[d].m_group = null; } // Release the mutex unlock(); } //----------------------------------------------------------------------------- // DrtTrace::print() // Write formatted output to the debug output stream. // String 'fmt' is the format control string (ala ::printf()), followed by // zero or more arguments. // // Returns // The number of characters written, or -1 on error. //----------------------------------------------------------------------------- /*static*/ int DrtTrace::print(const char *fmt, ...) { #if DrtTrace_VS/100 != 1 #error DrtTrace_VS has changed #endif // Acquire a mutex lock(); // Retrieve the varargs va_list ap; int nc = 0; va_start(ap, fmt); // Check for an open debug stream if (s_outf != null and fmt != null) { // Write formatted debugging output nc = vfprintf(s_outf, fmt, ap); fflush(s_outf); } else { // No output va_end(ap); } // Release the mutex unlock(); return (nc == EOF ? -1 : nc); } drt_namespace_end // End sdebugf.cpp