1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 8 #ifndef mozilla_BlockingResourceBase_h 9 #define mozilla_BlockingResourceBase_h 10 11 #include "mozilla/Logging.h" 12 13 #include "nscore.h" 14 #include "nsDebug.h" 15 #include "nsError.h" 16 #include "nsISupportsImpl.h" 17 18 #ifdef DEBUG 19 20 // NB: Comment this out to enable callstack tracking. 21 #define MOZ_CALLSTACK_DISABLED 22 23 #include "prinit.h" 24 25 #include "nsStringGlue.h" 26 27 #ifndef MOZ_CALLSTACK_DISABLED 28 #include "nsTArray.h" 29 #endif 30 31 #include "nsXPCOM.h" 32 #endif 33 34 // 35 // This header is not meant to be included by client code. 36 // 37 38 namespace mozilla { 39 40 #ifdef DEBUG 41 template <class T> class DeadlockDetector; 42 #endif 43 44 /** 45 * BlockingResourceBase 46 * Base class of resources that might block clients trying to acquire them. 47 * Does debugging and deadlock detection in DEBUG builds. 48 **/ 49 class BlockingResourceBase 50 { 51 public: 52 // Needs to be kept in sync with kResourceTypeNames. 53 enum BlockingResourceType { eMutex, eReentrantMonitor, eCondVar }; 54 55 /** 56 * kResourceTypeName 57 * Human-readable version of BlockingResourceType enum. 58 */ 59 static const char* const kResourceTypeName[]; 60 61 62 #ifdef DEBUG 63 64 static size_t 65 SizeOfDeadlockDetector(MallocSizeOf aMallocSizeOf); 66 67 /** 68 * Print 69 * Write a description of this blocking resource to |aOut|. If 70 * the resource appears to be currently acquired, the current 71 * acquisition context is printed and true is returned. 72 * Otherwise, we print the context from |aFirstSeen|, the 73 * first acquisition from which the code calling |Print()| 74 * became interested in us, and return false. 75 * 76 * *NOT* thread safe. Reads |mAcquisitionContext| without 77 * synchronization, but this will not cause correctness 78 * problems. 79 * 80 * FIXME bug 456272: hack alert: because we can't write call 81 * contexts into strings, all info is written to stderr, but 82 * only some info is written into |aOut| 83 */ 84 bool Print(nsACString& aOut) const; 85 86 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)87 SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const 88 { 89 // NB: |mName| is not reported as it's expected to be a static string. 90 // If we switch to a nsString it should be added to the tally. 91 // |mChainPrev| is not reported because its memory is not owned. 92 size_t n = aMallocSizeOf(this); 93 return n; 94 } 95 96 // ``DDT'' = ``Deadlock Detector Type'' 97 typedef DeadlockDetector<BlockingResourceBase> DDT; 98 99 protected: 100 #ifdef MOZ_CALLSTACK_DISABLED 101 typedef bool AcquisitionState; 102 #else 103 typedef AutoTArray<void*, 24> AcquisitionState; 104 #endif 105 106 /** 107 * BlockingResourceBase 108 * Initialize this blocking resource. Also hooks the resource into 109 * instrumentation code. 110 * 111 * Thread safe. 112 * 113 * @param aName A meaningful, unique name that can be used in 114 * error messages, et al. 115 * @param aType The specific type of |this|, if any. 116 **/ 117 BlockingResourceBase(const char* aName, BlockingResourceType aType); 118 119 ~BlockingResourceBase(); 120 121 /** 122 * CheckAcquire 123 * 124 * Thread safe. 125 **/ 126 void CheckAcquire(); 127 128 /** 129 * Acquire 130 * 131 * *NOT* thread safe. Requires ownership of underlying resource. 132 **/ 133 void Acquire(); //NS_NEEDS_RESOURCE(this) 134 135 /** 136 * Release 137 * Remove this resource from the current thread's acquisition chain. 138 * The resource does not have to be at the front of the chain, although 139 * it is confusing to release resources in a different order than they 140 * are acquired. This generates a warning. 141 * 142 * *NOT* thread safe. Requires ownership of underlying resource. 143 **/ 144 void Release(); //NS_NEEDS_RESOURCE(this) 145 146 /** 147 * ResourceChainFront 148 * 149 * Thread safe. 150 * 151 * @return the front of the resource acquisition chain, i.e., the last 152 * resource acquired. 153 */ ResourceChainFront()154 static BlockingResourceBase* ResourceChainFront() 155 { 156 return 157 (BlockingResourceBase*)PR_GetThreadPrivate(sResourceAcqnChainFrontTPI); 158 } 159 160 /** 161 * ResourceChainPrev 162 * 163 * *NOT* thread safe. Requires ownership of underlying resource. 164 */ ResourceChainPrev(const BlockingResourceBase * aResource)165 static BlockingResourceBase* ResourceChainPrev( 166 const BlockingResourceBase* aResource) 167 { 168 return aResource->mChainPrev; 169 } //NS_NEEDS_RESOURCE(this) 170 171 /** 172 * ResourceChainAppend 173 * Set |this| to the front of the resource acquisition chain, and link 174 * |this| to |aPrev|. 175 * 176 * *NOT* thread safe. Requires ownership of underlying resource. 177 */ ResourceChainAppend(BlockingResourceBase * aPrev)178 void ResourceChainAppend(BlockingResourceBase* aPrev) 179 { 180 mChainPrev = aPrev; 181 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this); 182 } //NS_NEEDS_RESOURCE(this) 183 184 /** 185 * ResourceChainRemove 186 * Remove |this| from the front of the resource acquisition chain. 187 * 188 * *NOT* thread safe. Requires ownership of underlying resource. 189 */ ResourceChainRemove()190 void ResourceChainRemove() 191 { 192 NS_ASSERTION(this == ResourceChainFront(), "not at chain front"); 193 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev); 194 } //NS_NEEDS_RESOURCE(this) 195 196 /** 197 * GetAcquisitionState 198 * Return whether or not this resource was acquired. 199 * 200 * *NOT* thread safe. Requires ownership of underlying resource. 201 */ GetAcquisitionState()202 AcquisitionState GetAcquisitionState() 203 { 204 return mAcquired; 205 } 206 207 /** 208 * SetAcquisitionState 209 * Set whether or not this resource was acquired. 210 * 211 * *NOT* thread safe. Requires ownership of underlying resource. 212 */ SetAcquisitionState(const AcquisitionState & aAcquisitionState)213 void SetAcquisitionState(const AcquisitionState& aAcquisitionState) 214 { 215 mAcquired = aAcquisitionState; 216 } 217 218 /** 219 * ClearAcquisitionState 220 * Indicate this resource is not acquired. 221 * 222 * *NOT* thread safe. Requires ownership of underlying resource. 223 */ ClearAcquisitionState()224 void ClearAcquisitionState() 225 { 226 #ifdef MOZ_CALLSTACK_DISABLED 227 mAcquired = false; 228 #else 229 mAcquired.Clear(); 230 #endif 231 } 232 233 /** 234 * IsAcquired 235 * Indicates if this resource is acquired. 236 * 237 * *NOT* thread safe. Requires ownership of underlying resource. 238 */ IsAcquired()239 bool IsAcquired() const 240 { 241 #ifdef MOZ_CALLSTACK_DISABLED 242 return mAcquired; 243 #else 244 return !mAcquired.IsEmpty(); 245 #endif 246 } 247 248 /** 249 * mChainPrev 250 * A series of resource acquisitions creates a chain of orders. This 251 * chain is implemented as a linked list; |mChainPrev| points to the 252 * resource most recently Acquire()'d before this one. 253 **/ 254 BlockingResourceBase* mChainPrev; 255 256 private: 257 /** 258 * mName 259 * A descriptive name for this resource. Used in error 260 * messages etc. 261 */ 262 const char* mName; 263 264 /** 265 * mType 266 * The more specific type of this resource. Used to implement 267 * special semantics (e.g., reentrancy of monitors). 268 **/ 269 BlockingResourceType mType; 270 271 /** 272 * mAcquired 273 * Indicates if this resource is currently acquired. 274 */ 275 AcquisitionState mAcquired; 276 277 #ifndef MOZ_CALLSTACK_DISABLED 278 /** 279 * mFirstSeen 280 * Inidicates where this resource was first acquired. 281 */ 282 AcquisitionState mFirstSeen; 283 #endif 284 285 /** 286 * sCallOnce 287 * Ensures static members are initialized only once, and in a 288 * thread-safe way. 289 */ 290 static PRCallOnceType sCallOnce; 291 292 /** 293 * sResourceAcqnChainFrontTPI 294 * Thread-private index to the front of each thread's resource 295 * acquisition chain. 296 */ 297 static unsigned sResourceAcqnChainFrontTPI; 298 299 /** 300 * sDeadlockDetector 301 * Does as named. 302 */ 303 static DDT* sDeadlockDetector; 304 305 /** 306 * InitStatics 307 * Inititialize static members of BlockingResourceBase that can't 308 * be statically initialized. 309 * 310 * *NOT* thread safe. 311 */ 312 static PRStatus InitStatics(); 313 314 /** 315 * Shutdown 316 * Free static members. 317 * 318 * *NOT* thread safe. 319 */ 320 static void Shutdown(); 321 322 static void StackWalkCallback(uint32_t aFrameNumber, void* aPc, 323 void* aSp, void* aClosure); 324 static void GetStackTrace(AcquisitionState& aState); 325 326 # ifdef MOZILLA_INTERNAL_API 327 // so it can call BlockingResourceBase::Shutdown() 328 friend void LogTerm(); 329 # endif // ifdef MOZILLA_INTERNAL_API 330 331 #else // non-DEBUG implementation 332 BlockingResourceBase(const char * aName,BlockingResourceType aType)333 BlockingResourceBase(const char* aName, BlockingResourceType aType) {} 334 ~BlockingResourceBase()335 ~BlockingResourceBase() {} 336 337 #endif 338 }; 339 340 341 } // namespace mozilla 342 343 344 #endif // mozilla_BlockingResourceBase_h 345