DebugLock.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_DEBUGLOCK_H
00014 #define _SUPPORT_DEBUGLOCK_H
00015 
00016 #include <BuildDefines.h>
00017 
00018 #ifndef SUPPORTS_LOCK_DEBUG
00019 
00020 // Lock debugging is not specified.  Turn it on if this is a debug build.
00021 #if BUILD_TYPE == BUILD_TYPE_DEBUG
00022 #define SUPPORTS_LOCK_DEBUG 1
00023 #else
00024 #define SUPPORTS_LOCK_DEBUG 0
00025 #endif
00026 
00027 #endif
00028 
00029 #if !SUPPORTS_LOCK_DEBUG
00030 
00031 static inline void AssertNoLocks() { }
00032 
00033 #else   // !SUPPORTS_LOCK_DEBUG
00034 
00035 #include <support/SupportDefs.h>
00036 #include <support/StdIO.h>
00037 #include <support/String.h>
00038 #include <support/StringIO.h>
00039 
00040 #include <new>
00041 
00042 #if _SUPPORTS_NAMESPACE
00043 namespace palmos {
00044 namespace support {
00045 #endif
00046 
00047 class SCallStack;
00048 
00049 static int32_t LockDebugLevel();
00050 static bool LockDebugStackCrawls();
00051 
00052 // Assert if the calling thread is currently holding any
00053 // locks that are instrumented by lock debugging.
00054 void AssertNoLocks();
00055 
00056 class StaticStringIO : public sptr<BStringIO>
00057 {
00058 public:
00059     inline StaticStringIO() : sptr<BStringIO>(new BStringIO) { }
00060     inline ~StaticStringIO() { }
00061 };
00062 
00063 struct block_links;
00064 
00065 enum {
00066     /*
00067      * These flags can be passed in to the lock constructor.
00068      */
00069     
00070     // Set to allow the lock to be deleted by a thread that is holding it.
00071     LOCK_CAN_DELETE_WHILE_HELD      = 0x00000001,
00072     
00073     // Set to allow the lock to always be deleted, even if another thread holds it.
00074     LOCK_ANYONE_CAN_DELETE          = 0x00000002,
00075     
00076     /*
00077      * These flags can be passed in to the lock constructor or Lock() function.
00078      */
00079     
00080     // Set to not perform deadlock checks -- don't add this acquire to deadlock graph.
00081     LOCK_SKIP_DEADLOCK_CHECK        = 0x00010000,
00082     
00083     // Set to not remember for future deadlock checks that this lock is being held.
00084     LOCK_DO_NOT_REGISTER_HELD       = 0x00020000,
00085     
00086     // Set to allow a threads besides the current owner to perform an unlock.
00087     LOCK_ANYONE_CAN_UNLOCK          = 0x00040000
00088 };
00089 
00090 class DebugLockNode
00091 {
00092 public:
00093                                 DebugLockNode(  const char* type,
00094                                                 const void* addr,
00095                                                 const char* name,
00096                                                 uint32_t debug_flags = 0);
00097             
00098     virtual void                Delete();
00099             
00100             int32_t             IncRefs() const;
00101             int32_t             DecRefs() const;
00102             
00103             const char*         Type() const;
00104             const void*         Addr() const;
00105             const char*         Name() const;
00106             uint32_t            GlobalFlags() const;
00107             
00108             const SCallStack*   CreationStack() const;
00109     
00110             nsecs_t             CreationTime() const;
00111 
00112             bool                LockGraph() const;
00113             void                UnlockGraph() const;
00114             bool                AddToGraph();
00115             void                RegisterAsHeld();
00116             void                UnregisterAsHeld();
00117     
00118             void                SetMaxContention(int32_t c);
00119             int32_t             MaxContention() const;
00120     
00121             int32_t             BlockCount() const;
00122 
00123             void                RemoveFromContention();
00124             void                RemoveFromBlockCount();
00125 
00126     virtual void                PrintToStream(const sptr<ITextOutput>& io) const;
00127     virtual void                PrintStacksToStream(sptr<ITextOutput>& io) const;
00128     static  void                PrintContentionToStream(const sptr<ITextOutput>& io);
00129     
00130     // Private implementation.
00131     inline  const block_links*  Links() const   { return m_links; }
00132     
00133 protected:
00134     virtual                     ~DebugLockNode();
00135     virtual void                PrintSubclassToStream(const sptr<ITextOutput>& io) const;
00136     
00137 private:
00138     mutable int32_t             m_refs;         // instance reference count
00139     
00140     // Lock-specific information.  Does not change after creation.
00141             SString const       m_type;         // descriptive type of this object
00142             const void* const   m_addr;         // user-visible address of lock
00143             SString const       m_name;         // descriptive name of lock
00144             uint32_t const      m_globalFlags;  // overall operating flags
00145             SCallStack* const   m_createStack;  // where the lock was created
00146             nsecs_t const       m_createTime;   // when the lock was created
00147     
00148     // Lock linkage information.  Protected by the global graph lock.
00149             block_links*        m_links;        // linkage to other locks
00150 
00151     // Lock contention tracking.  Protected by global contention lock.
00152             int32_t             m_maxContention;// maximum number of waiting threads
00153             bool                m_inContention; // in the high contention list?
00154             int32_t             m_blockCount;   // number of times a thread has blocked here.
00155             bool                m_inBlockCount; // in the high block count list?
00156 };
00157 
00158 inline const sptr<ITextOutput>& operator<<(const sptr<ITextOutput>& io, const DebugLockNode& db)
00159 {
00160     db.PrintToStream(io);
00161     return io;
00162 }
00163 
00164 class DebugLock : public DebugLockNode
00165 {
00166 public:
00167                                 DebugLock(  const char* type,
00168                                             const void* addr,
00169                                             const char* name,
00170                                             uint32_t debug_flags = 0);
00171     
00172     virtual void                Delete();
00173     
00174     virtual void                PrintStacksToStream(sptr<ITextOutput>& io) const;
00175 
00176             status_t            Lock(   uint32_t flags = B_TIMEOUT,
00177                                         nsecs_t timeout = B_INFINITE_TIMEOUT,
00178                                         uint32_t debug_flags = 0);
00179             status_t            Unlock();
00180             bool                IsLocked() const;
00181 
00182             const SCallStack*   OwnerStack() const;
00183 
00184             // For use by SConditionVariable::Wait().
00185             void                RestoreOwnership();
00186             volatile int32_t*               RemoveOwnership();
00187             
00188 protected:
00189     virtual                     ~DebugLock();
00190     virtual void                PrintSubclassToStream(const sptr<ITextOutput>& io) const;
00191     
00192 private:
00193             status_t            do_lock(uint32_t flags, nsecs_t timeout,
00194                                         uint32_t debug_flags, bool restoreOnly = false);
00195             status_t            do_unlock(bool removeOnly = false);
00196 
00197     // Lock-specific information.  Protected by the lock itself.
00198             volatile int32_t        m_gehnaphore;   // implementation of this lock
00199             sem_id              m_sem;          // alternate implementation
00200             int32_t             m_held;         // lock implementation validation
00201             SysHandle           m_owner;        // who currently holds the lock
00202             int32_t             m_ownerFlags;   // passed in from Lock()
00203             SCallStack*         m_ownerStack;   // stack of last lock accessor
00204             int32_t             m_contention;   // current waiting threads
00205             bool                m_deleted;      // no longer valid?
00206 };
00207 
00208 
00209 extern int32_t gLockDebugLevel;
00210 int32_t LockDebugLevelSlow();
00211 static inline int32_t LockDebugLevel() {
00212     if (gLockDebugLevel >= 0) return gLockDebugLevel;
00213     return LockDebugLevelSlow();
00214 }
00215 
00216 extern bool gLockDebugStackCrawls;
00217 static inline bool LockDebugStackCrawls() {
00218     if (gLockDebugLevel < 0) LockDebugLevelSlow();
00219     return gLockDebugStackCrawls;
00220 }
00221 
00222 #if _SUPPORTS_NAMESPACE
00223 } } // namespace palmos::support
00224 #endif
00225 
00226 #endif  // !SUPPORTS_LOCK_DEBUG
00227 
00228 #endif  // _SUPPORT_DEBUGLOCK_H