Debug.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005 Palmsource, Inc.
00003  * 
00004  * This software is licensed as described in the file LICENSE, which
00005  * you should have received as part of this distribution. The terms
00006  * are also available at http://www.openbinder.org/license.html.
00007  * 
00008  * This software consists of voluntary contributions made by many
00009  * individuals. For the exact contribution history, see the revision
00010  * history and logs, available at http://www.openbinder.org
00011  */
00012 
00013 #ifndef _SUPPORT_DEBUG_H
00014 #define _SUPPORT_DEBUG_H
00015 
00021 #include <stdarg.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <support/atomic.h>
00025 #include <support/SupportDefs.h>
00026 #include <ErrorMgr.h>
00027 
00028 #ifndef DEBUG
00029 #define DEBUG 0
00030 #endif
00031 
00032 #ifdef __cplusplus
00033 #if _SUPPORTS_NAMESPACE
00034 namespace palmos {
00035 namespace support {
00036 #endif
00037 class SString;
00038 #if _SUPPORTS_NAMESPACE
00039 } } // namespace palmos::support
00040 #endif
00041 #endif  /* __cplusplus */
00042 
00043 /*------------------------------*/
00044 /*----- Private... -------------*/
00045 #ifdef __cplusplus
00046 extern "C" {
00047 #endif
00048 #if TARGET_HOST != TARGET_HOST_PALMOS
00049     extern int _rtDebugFlag;
00050 #else
00051     #define _rtDebugFlag true
00052 #endif
00053 
00054     int _debugFlag(void);
00055     int _setDebugFlag(int);
00056 
00057 #if TARGET_HOST == TARGET_HOST_BEOS
00058     int _debugPrintf(const char *, ...);
00059     int _sPrintf(const char *, ...);
00060     int _xdebugPrintf(const char *, ...);
00061 #else
00062     #define _debugPrintf printf
00063     #define _sPrintf sprintf
00064     #define _xdebugPrintf printf
00065 #endif
00066     
00067     typedef void (*b_debug_action)(void* data);
00068     void _exec_debug_action(b_debug_action action, void* data);
00069 
00070 #ifdef __cplusplus
00071 }
00072 #endif  // __cplusplus
00073 /*-------- ...to here ----------*/
00074 
00079 /*-------------------------------------------------------------*/
00082 
00083 #ifdef __cplusplus
00084 #include <support/Atom.h>
00085     _IMPEXP_SUPPORT void add_debug_atom(BNS(palmos::support::) SAtom * atom, const char *name); // If it's really a pointer you're giving, don't mess with the ref count, so it's safe to call this from inside a constructor
00086     _IMPEXP_SUPPORT void add_debug_atom(const BNS(::palmos::support::)sptr<BNS(palmos::support::) SAtom>& atom, const char *name);
00087     _IMPEXP_SUPPORT void add_debug_sized(const void *key, size_t size, const char *name);
00088     _IMPEXP_SUPPORT void set_debug_fieldwidth(int width);
00089     _IMPEXP_SUPPORT BNS(palmos::support::)SString lookup_debug(const BNS(::palmos::support::)sptr<BNS(palmos::support::) SAtom>& atom, bool padding = true);
00090     _IMPEXP_SUPPORT BNS(palmos::support::)SString lookup_debug(const void *key, bool padding = true);
00091 #endif  // __cplusplus
00092 
00094 
00095 /*-------------------------------------------------------------*/
00098 
00099 #if DEBUG
00100     #define SET_DEBUG_ENABLED(FLAG) _setDebugFlag(FLAG)
00101     #define IS_DEBUG_ENABLED()      _debugFlag()
00102     
00103     #define SERIAL_PRINT(ARGS)      _sPrintf ARGS
00104     #define PRINT(ARGS)             _debugPrintf ARGS
00105     #define PRINT_OBJECT(OBJ)       if (_rtDebugFlag) {     \
00106                                         PRINT(("%s\t", #OBJ));  \
00107                                         (OBJ).PrintToStream();  \
00108                                         } ((void) 0)
00109     #define TRACE()                 _debugPrintf("File: %s, Line: %d, Thread: %d\n", \
00110                                         __FILE__, __LINE__, SysCurrentThread())
00111         
00112     #define SERIAL_TRACE()          _sPrintf("File: %s, Line: %d, Thread: %d\n", \
00113                                         __FILE__, __LINE__, SysCurrentThread())
00114     
00115     #define DEBUGGER(MSG)           if (_rtDebugFlag) ErrFatalError(MSG);
00116     #if !defined(ASSERT)
00117         #define ASSERT(E)           (!(E) ? ErrFatalError(#E) : (int)0)
00118     #endif
00119 
00120     #define ASSERT_WITH_MESSAGE(expr, msg) \
00121                                     (!(expr) ? ErrFatalError(msg) : (int)0) 
00122     
00123     #define VALIDATE(x, recover)    if (!(x)) { ASSERT(x); recover; }
00124     
00125     #define TRESPASS()              if (1) { _debugPrintf("Should not be here at File: %s, Line: %d, Thread: %d\n",__FILE__,__LINE__,SysCurrentThread()); DEBUGGER("DO SOMETHING"); }
00126     
00127     #define DEBUG_ONLY(arg)         arg
00128 
00129     #define EXEC_DEBUG_ACTION(action, data) \
00130                                     _exec_debug_action(actiom data)
00131     
00132 #else /* DEBUG == 0 */
00133     #define SET_DEBUG_ENABLED(FLAG) (void)0
00134     #define IS_DEBUG_ENABLED()      (void)0
00135     
00136     #define SERIAL_PRINT(ARGS)      (void)0
00137     #define PRINT(ARGS)             (void)0
00138     #define PRINT_OBJECT(OBJ)       (void)0
00139     #define TRACE()                 (void)0
00140     #define SERIAL_TRACE()          (void)0
00141     
00142     #define DEBUGGER(MSG)           (void)0
00143     #if !defined(ASSERT)
00144         #define ASSERT(E)               (void)0
00145     #endif
00146     #define ASSERT_WITH_MESSAGE(expr, msg) \
00147                                     (void)0
00148     #define VALIDATE(x, recover)    if (!(x)) { recover; }
00149     #define TRESPASS()              (void)0
00150     #define DEBUG_ONLY(x)
00151     #define EXEC_DEBUG_ACTION(action, data) \
00152                                     (void)0
00153 #endif
00154 
00155 
00156 #ifdef __cplusplus
00157 
00158 template<bool> struct CompileTimeAssert;
00159 template<> struct CompileTimeAssert<true> {};
00160 #define STATIC_ASSERT(x)        CompileTimeAssert< (x) >()
00161 
00162 #else   /* __cplusplus */
00163 
00164 #if !defined(__MWERKS__)
00165     // STATIC_ASSERT is a compile-time check that can be used to
00166     // verify static expressions such as: STATIC_ASSERT(sizeof(int64_t) == 8);
00167     #define STATIC_ASSERT(x)                                \
00168         do {                                                \
00169             enum { __ASSERT_EXPRESSION__ = 2*(x) - 1 };         \
00170             struct __staticAssertStruct__ {                 \
00171                 char __static_assert_failed__[__ASSERT_EXPRESSION__];   \
00172             };                                              \
00173         } while (false)
00174 #else
00175     #define STATIC_ASSERT(x) 
00176     // the STATIC_ASSERT above doesn't work too well with mwcc because
00177     // of scoping bugs; for now make it do nothing
00178 #endif
00179 
00180 #endif /* __cplusplus */
00181 
00183 
00184 /*-------------------------------------------------------------*/
00185 /*----- Conditionals (only for C++) ---------------------------*/
00186 
00187 #ifdef __cplusplus
00188 
00189     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00190     class BDebugCondition
00191     {
00192     public:
00193         static inline int32_t Get() {
00194             // The four lines below are courtesy of ADS.  Don't ask.
00195             (void)ENVNAME;
00196             (void)DEFVAL;
00197             (void)MINVAL;
00198             (void)MAXVAL;
00199             if (m_hasLevel > 2) return m_level;
00200             return GetSlow();
00201         }
00202         
00203         static int32_t GetSlow() {
00204             if (atomic_or(&m_hasLevel, 1) == 0) {
00205 #if TARGET_HOST == TARGET_HOST_PALMOS
00206                 char envBuffer[128];
00207                 const char* env = NULL;
00208                 if (SysIsInstrumentationAllowed()) {
00209                     if (HostGetPreference(ENVNAME, envBuffer)) env = envBuffer;
00210                 }
00211 #else
00212                 const char* env = getenv(ENVNAME);
00213 #endif
00214                 if (env) {
00215                     m_level = atoi(env);
00216                     if (m_level < MINVAL) m_level = MINVAL;
00217                     if (m_level > MAXVAL) m_level = MAXVAL;
00218                 } else {
00219                     m_level = DEFVAL;
00220                 }
00221                 atomic_or(&m_hasLevel, 2);
00222                 if (m_level > 0)
00223                     fprintf(stderr, "%s ENABLED!  %s=%d\n", ENVNAME, ENVNAME, m_level);
00224             } else {
00225                 while ((m_hasLevel&2) == 0) 
00226                     SysThreadDelay(B_MICROSECONDS(2), B_RELATIVE_TIMEOUT);
00227             }
00228             return m_level;
00229         }
00230     
00231     private:
00232         static int32_t m_hasLevel;
00233         static int32_t m_level;
00234     };
00235     
00236     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00237     int32_t BDebugCondition<ENVNAME, DEFVAL, MINVAL, MAXVAL>::m_hasLevel = 0;
00238     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00239     int32_t BDebugCondition<ENVNAME, DEFVAL, MINVAL, MAXVAL>::m_level = 0;
00240 
00241     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00242     class BDebugInteger
00243     {
00244     public:
00245         static inline int32_t Get() {
00246             // The four lines below are courtesy of ADS.  Don't ask.
00247             (void)ENVNAME;
00248             (void)DEFVAL;
00249             (void)MINVAL;
00250             (void)MAXVAL;
00251             if (m_hasLevel > 2) return m_level;
00252             return GetSlow();
00253         }
00254         
00255         static int32_t GetSlow() {
00256             if (atomic_or(&m_hasLevel, 1) == 0) {
00257 #if TARGET_HOST == TARGET_HOST_PALMOS
00258                 char envBuffer[128];
00259                 const char* env = NULL;
00260                 if (HostGetPreference(ENVNAME, envBuffer)) env = envBuffer;
00261 #else
00262                 const char* env = getenv(ENVNAME);
00263 #endif
00264                 if (env) {
00265                     m_level = atoi(env);
00266                     if (m_level < MINVAL) m_level = MINVAL;
00267                     if (m_level > MAXVAL) m_level = MAXVAL;
00268                 } else {
00269                     m_level = DEFVAL;
00270                 }
00271                 atomic_or(&m_hasLevel, 2);
00272                 if (env)
00273                     fprintf(stderr, "Adjusting to %s to: %d\n", ENVNAME, m_level);
00274             } else {
00275                 while ((m_hasLevel&2) == 0) 
00276                     SysThreadDelay(B_MICROSECONDS(2), B_RELATIVE_TIMEOUT);
00277             }
00278             return m_level;
00279         }
00280     
00281     private:
00282         static int32_t m_hasLevel;
00283         static int32_t m_level;
00284     };
00285     
00286     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00287     int32_t BDebugInteger<ENVNAME, DEFVAL, MINVAL, MAXVAL>::m_hasLevel = 0;
00288     template<const char* ENVNAME, int DEFVAL, int MINVAL, int MAXVAL>
00289     int32_t BDebugInteger<ENVNAME, DEFVAL, MINVAL, MAXVAL>::m_level = 0;
00290 
00291     template<class STATE>
00292     class BDebugState
00293     {
00294     public:
00295         static inline STATE* Get() {
00296             // The line below is courtesy of ADS.  Don't ask.
00297             if (m_hasState > 2) return m_state;
00298             return GetSlow();
00299         }
00300         
00301         static STATE* GetSlow() {
00302             if (atomic_or(&m_hasState, 1) == 0) {
00303                 m_state = new STATE;
00304                 atomic_or(&m_hasState, 2);
00305             } else {
00306                 while ((m_hasState&2) == 0)
00307                     SysThreadDelay(B_MICROSECONDS(2), B_RELATIVE_TIMEOUT);
00308             }
00309             return m_state;
00310         }
00311     
00312         ~BDebugState()
00313         {
00314             if ((atomic_or(&m_hasState, 4)&4) == 0) {
00315                 delete m_state;
00316             }
00317         }
00318         
00319     private:
00320         static int32_t m_hasState;
00321         static STATE* m_state;
00322     };
00323     
00324     template<class STATE> int32_t BDebugState<STATE>::m_hasState = 0;
00325     template<class STATE> STATE* BDebugState<STATE>::m_state = NULL;
00326 
00327 #endif
00328 
00329 /*-------------------------------------------------------------*/
00330 /*-------------------------------------------------------------*/
00331 
00334 #endif /* _SUPPORT_DEBUG_H */