1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/BlockingResourceBase.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,347 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: sw=4 ts=4 et : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 + 1.11 +#ifndef mozilla_BlockingResourceBase_h 1.12 +#define mozilla_BlockingResourceBase_h 1.13 + 1.14 +#include "prlog.h" 1.15 + 1.16 +#include "nscore.h" 1.17 +#include "nsDebug.h" 1.18 +#include "nsError.h" 1.19 +#include "nsISupportsImpl.h" 1.20 + 1.21 +#ifdef DEBUG 1.22 +#include "prinit.h" 1.23 +#include "prthread.h" 1.24 + 1.25 +#include "nsStringGlue.h" 1.26 + 1.27 +#include "mozilla/DeadlockDetector.h" 1.28 +#include "nsXPCOM.h" 1.29 +#endif 1.30 + 1.31 +// 1.32 +// This header is not meant to be included by client code. 1.33 +// 1.34 + 1.35 +namespace mozilla { 1.36 + 1.37 + 1.38 +/** 1.39 + * BlockingResourceBase 1.40 + * Base class of resources that might block clients trying to acquire them. 1.41 + * Does debugging and deadlock detection in DEBUG builds. 1.42 + **/ 1.43 +class NS_COM_GLUE BlockingResourceBase 1.44 +{ 1.45 +public: 1.46 + // Needs to be kept in sync with kResourceTypeNames. 1.47 + enum BlockingResourceType { eMutex, eReentrantMonitor, eCondVar }; 1.48 + 1.49 + /** 1.50 + * kResourceTypeName 1.51 + * Human-readable version of BlockingResourceType enum. 1.52 + */ 1.53 + static const char* const kResourceTypeName[]; 1.54 + 1.55 + 1.56 +#ifdef DEBUG 1.57 + 1.58 +private: 1.59 + // forward declaration for the following typedef 1.60 + struct DeadlockDetectorEntry; 1.61 + 1.62 + // ``DDT'' = ``Deadlock Detector Type'' 1.63 + typedef DeadlockDetector<DeadlockDetectorEntry> DDT; 1.64 + 1.65 + /** 1.66 + * DeadlockDetectorEntry 1.67 + * We free BlockingResources, but we never free entries in the 1.68 + * deadlock detector. This struct outlives its BlockingResource 1.69 + * and preserves all the state needed to print subsequent 1.70 + * error messages. 1.71 + * 1.72 + * These objects are owned by the deadlock detector. 1.73 + */ 1.74 + struct DeadlockDetectorEntry 1.75 + { 1.76 + DeadlockDetectorEntry(const char* aName, 1.77 + BlockingResourceType aType) : 1.78 + mName(aName), 1.79 + mType(aType), 1.80 + mAcquisitionContext(CallStack::kNone) 1.81 + { 1.82 + NS_ABORT_IF_FALSE(mName, "Name must be nonnull"); 1.83 + } 1.84 + 1.85 + /** 1.86 + * Print 1.87 + * Write a description of this blocking resource to |out|. If 1.88 + * the resource appears to be currently acquired, the current 1.89 + * acquisition context is printed and true is returned. 1.90 + * Otherwise, we print the context from |aFirstSeen|, the 1.91 + * first acquisition from which the code calling |Print()| 1.92 + * became interested in us, and return false. |Print()| can 1.93 + * be forced to print the context from |aFirstSeen| regardless 1.94 + * by passing |aPrintFirstSeenCx=true|. 1.95 + * 1.96 + * *NOT* thread safe. Reads |mAcquisitionContext| without 1.97 + * synchronization, but this will not cause correctness 1.98 + * problems. 1.99 + * 1.100 + * FIXME bug 456272: hack alert: because we can't write call 1.101 + * contexts into strings, all info is written to stderr, but 1.102 + * only some info is written into |out| 1.103 + */ 1.104 + bool Print(const DDT::ResourceAcquisition& aFirstSeen, 1.105 + nsACString& out, 1.106 + bool aPrintFirstSeenCx=false) const; 1.107 + 1.108 + /** 1.109 + * mName 1.110 + * A descriptive name for this resource. Used in error 1.111 + * messages etc. 1.112 + */ 1.113 + const char* mName; 1.114 + /** 1.115 + * mType 1.116 + * The more specific type of this resource. Used to implement 1.117 + * special semantics (e.g., reentrancy of monitors). 1.118 + **/ 1.119 + BlockingResourceType mType; 1.120 + /** 1.121 + * mAcquisitionContext 1.122 + * The calling context from which this resource was acquired, or 1.123 + * |CallStack::kNone| if it is currently free (or freed). 1.124 + */ 1.125 + CallStack mAcquisitionContext; 1.126 + }; 1.127 + 1.128 +protected: 1.129 + /** 1.130 + * BlockingResourceBase 1.131 + * Initialize this blocking resource. Also hooks the resource into 1.132 + * instrumentation code. 1.133 + * 1.134 + * Thread safe. 1.135 + * 1.136 + * @param aName A meaningful, unique name that can be used in 1.137 + * error messages, et al. 1.138 + * @param aType The specific type of |this|, if any. 1.139 + **/ 1.140 + BlockingResourceBase(const char* aName, BlockingResourceType aType); 1.141 + 1.142 + ~BlockingResourceBase(); 1.143 + 1.144 + /** 1.145 + * CheckAcquire 1.146 + * 1.147 + * Thread safe. 1.148 + * 1.149 + * @param aCallContext the client's calling context from which the 1.150 + * original acquisition request was made. 1.151 + **/ 1.152 + void CheckAcquire(const CallStack& aCallContext); 1.153 + 1.154 + /** 1.155 + * Acquire 1.156 + * 1.157 + * *NOT* thread safe. Requires ownership of underlying resource. 1.158 + * 1.159 + * @param aCallContext the client's calling context from which the 1.160 + * original acquisition request was made. 1.161 + **/ 1.162 + void Acquire(const CallStack& aCallContext); //NS_NEEDS_RESOURCE(this) 1.163 + 1.164 + /** 1.165 + * Release 1.166 + * Remove this resource from the current thread's acquisition chain. 1.167 + * The resource does not have to be at the front of the chain, although 1.168 + * it is confusing to release resources in a different order than they 1.169 + * are acquired. This generates a warning. 1.170 + * 1.171 + * *NOT* thread safe. Requires ownership of underlying resource. 1.172 + **/ 1.173 + void Release(); //NS_NEEDS_RESOURCE(this) 1.174 + 1.175 + /** 1.176 + * PrintCycle 1.177 + * Append to |out| detailed information about the circular 1.178 + * dependency in |cycle|. Returns true if it *appears* that this 1.179 + * cycle may represent an imminent deadlock, but this is merely a 1.180 + * heuristic; the value returned may be a false positive or false 1.181 + * negative. 1.182 + * 1.183 + * *NOT* thread safe. Calls |Print()|. 1.184 + * 1.185 + * FIXME bug 456272 hack alert: because we can't write call 1.186 + * contexts into strings, all info is written to stderr, but only 1.187 + * some info is written into |out| 1.188 + */ 1.189 + static bool PrintCycle(const DDT::ResourceAcquisitionArray* cycle, 1.190 + nsACString& out); 1.191 + 1.192 + /** 1.193 + * ResourceChainFront 1.194 + * 1.195 + * Thread safe. 1.196 + * 1.197 + * @return the front of the resource acquisition chain, i.e., the last 1.198 + * resource acquired. 1.199 + */ 1.200 + static BlockingResourceBase* ResourceChainFront() 1.201 + { 1.202 + return (BlockingResourceBase*) 1.203 + PR_GetThreadPrivate(sResourceAcqnChainFrontTPI); 1.204 + } 1.205 + 1.206 + /** 1.207 + * ResourceChainPrev 1.208 + * 1.209 + * *NOT* thread safe. Requires ownership of underlying resource. 1.210 + */ 1.211 + static BlockingResourceBase* 1.212 + ResourceChainPrev(const BlockingResourceBase* aResource) 1.213 + { 1.214 + return aResource->mChainPrev; 1.215 + } //NS_NEEDS_RESOURCE(this) 1.216 + 1.217 + /** 1.218 + * ResourceChainAppend 1.219 + * Set |this| to the front of the resource acquisition chain, and link 1.220 + * |this| to |aPrev|. 1.221 + * 1.222 + * *NOT* thread safe. Requires ownership of underlying resource. 1.223 + */ 1.224 + void ResourceChainAppend(BlockingResourceBase* aPrev) 1.225 + { 1.226 + mChainPrev = aPrev; 1.227 + PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this); 1.228 + } //NS_NEEDS_RESOURCE(this) 1.229 + 1.230 + /** 1.231 + * ResourceChainRemove 1.232 + * Remove |this| from the front of the resource acquisition chain. 1.233 + * 1.234 + * *NOT* thread safe. Requires ownership of underlying resource. 1.235 + */ 1.236 + void ResourceChainRemove() 1.237 + { 1.238 + NS_ASSERTION(this == ResourceChainFront(), "not at chain front"); 1.239 + PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev); 1.240 + } //NS_NEEDS_RESOURCE(this) 1.241 + 1.242 + /** 1.243 + * GetAcquisitionContext 1.244 + * Return the calling context from which this resource was acquired, 1.245 + * or CallStack::kNone if it's currently free. 1.246 + * 1.247 + * *NOT* thread safe. Requires ownership of underlying resource. 1.248 + */ 1.249 + CallStack 1.250 + GetAcquisitionContext() 1.251 + { 1.252 + return mDDEntry->mAcquisitionContext; 1.253 + } 1.254 + 1.255 + /** 1.256 + * SetAcquisitionContext 1.257 + * Set the calling context from which this resource was acquired. 1.258 + * 1.259 + * *NOT* thread safe. Requires ownership of underlying resource. 1.260 + */ 1.261 + void 1.262 + SetAcquisitionContext(CallStack aAcquisitionContext) 1.263 + { 1.264 + mDDEntry->mAcquisitionContext = aAcquisitionContext; 1.265 + } 1.266 + 1.267 + /** 1.268 + * mChainPrev 1.269 + * A series of resource acquisitions creates a chain of orders. This 1.270 + * chain is implemented as a linked list; |mChainPrev| points to the 1.271 + * resource most recently Acquire()'d before this one. 1.272 + **/ 1.273 + BlockingResourceBase* mChainPrev; 1.274 + 1.275 +private: 1.276 + /** 1.277 + * mDDEntry 1.278 + * The key for this BlockingResourceBase in the deadlock detector. 1.279 + */ 1.280 + DeadlockDetectorEntry* mDDEntry; 1.281 + 1.282 + /** 1.283 + * sCallOnce 1.284 + * Ensures static members are initialized only once, and in a 1.285 + * thread-safe way. 1.286 + */ 1.287 + static PRCallOnceType sCallOnce; 1.288 + 1.289 + /** 1.290 + * sResourceAcqnChainFrontTPI 1.291 + * Thread-private index to the front of each thread's resource 1.292 + * acquisition chain. 1.293 + */ 1.294 + static unsigned sResourceAcqnChainFrontTPI; 1.295 + 1.296 + /** 1.297 + * sDeadlockDetector 1.298 + * Does as named. 1.299 + */ 1.300 + static DDT* sDeadlockDetector; 1.301 + 1.302 + /** 1.303 + * InitStatics 1.304 + * Inititialize static members of BlockingResourceBase that can't 1.305 + * be statically initialized. 1.306 + * 1.307 + * *NOT* thread safe. 1.308 + */ 1.309 + static PRStatus InitStatics() { 1.310 + PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI, 0); 1.311 + sDeadlockDetector = new DDT(); 1.312 + if (!sDeadlockDetector) 1.313 + NS_RUNTIMEABORT("can't allocate deadlock detector"); 1.314 + return PR_SUCCESS; 1.315 + } 1.316 + 1.317 + /** 1.318 + * Shutdown 1.319 + * Free static members. 1.320 + * 1.321 + * *NOT* thread safe. 1.322 + */ 1.323 + static void Shutdown() { 1.324 + delete sDeadlockDetector; 1.325 + sDeadlockDetector = 0; 1.326 + } 1.327 + 1.328 +# ifdef MOZILLA_INTERNAL_API 1.329 + // so it can call BlockingResourceBase::Shutdown() 1.330 + friend void LogTerm(); 1.331 +# endif // ifdef MOZILLA_INTERNAL_API 1.332 + 1.333 +#else // non-DEBUG implementation 1.334 + 1.335 + BlockingResourceBase(const char* aName, BlockingResourceType aType) 1.336 + { 1.337 + } 1.338 + 1.339 + ~BlockingResourceBase() 1.340 + { 1.341 + } 1.342 + 1.343 +#endif 1.344 +}; 1.345 + 1.346 + 1.347 +} // namespace mozilla 1.348 + 1.349 + 1.350 +#endif // mozilla_BlockingResourceBase_h