Bug 895720 - Actually use the fuzz value.
[gecko.git] / xpcom / glue / BlockingResourceBase.h
blobe54d99a246f0581e23d433ef10a37fbd624b50fd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
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/. */
8 #ifndef mozilla_BlockingResourceBase_h
9 #define mozilla_BlockingResourceBase_h
11 #include "prlog.h"
13 #include "nscore.h"
14 #include "nsDebug.h"
15 #include "nsError.h"
16 #include "nsTraceRefcnt.h"
18 #ifdef DEBUG
19 #include "prinit.h"
20 #include "prthread.h"
22 #include "nsStringGlue.h"
24 #include "mozilla/DeadlockDetector.h"
25 #include "nsXPCOM.h"
26 #endif
29 // This header is not meant to be included by client code.
32 namespace mozilla {
35 /**
36 * BlockingResourceBase
37 * Base class of resources that might block clients trying to acquire them.
38 * Does debugging and deadlock detection in DEBUG builds.
39 **/
40 class NS_COM_GLUE BlockingResourceBase
42 public:
43 // Needs to be kept in sync with kResourceTypeNames.
44 enum BlockingResourceType { eMutex, eReentrantMonitor, eCondVar };
46 /**
47 * kResourceTypeName
48 * Human-readable version of BlockingResourceType enum.
50 static const char* const kResourceTypeName[];
53 #ifdef DEBUG
55 private:
56 // forward declaration for the following typedef
57 struct DeadlockDetectorEntry;
59 // ``DDT'' = ``Deadlock Detector Type''
60 typedef DeadlockDetector<DeadlockDetectorEntry> DDT;
62 /**
63 * DeadlockDetectorEntry
64 * We free BlockingResources, but we never free entries in the
65 * deadlock detector. This struct outlives its BlockingResource
66 * and preserves all the state needed to print subsequent
67 * error messages.
69 * These objects are owned by the deadlock detector.
71 struct DeadlockDetectorEntry
73 DeadlockDetectorEntry(const char* aName,
74 BlockingResourceType aType) :
75 mName(aName),
76 mType(aType),
77 mAcquisitionContext(CallStack::kNone)
79 NS_ABORT_IF_FALSE(mName, "Name must be nonnull");
82 /**
83 * Print
84 * Write a description of this blocking resource to |out|. If
85 * the resource appears to be currently acquired, the current
86 * acquisition context is printed and true is returned.
87 * Otherwise, we print the context from |aFirstSeen|, the
88 * first acquisition from which the code calling |Print()|
89 * became interested in us, and return false. |Print()| can
90 * be forced to print the context from |aFirstSeen| regardless
91 * by passing |aPrintFirstSeenCx=true|.
93 * *NOT* thread safe. Reads |mAcquisitionContext| without
94 * synchronization, but this will not cause correctness
95 * problems.
97 * FIXME bug 456272: hack alert: because we can't write call
98 * contexts into strings, all info is written to stderr, but
99 * only some info is written into |out|
101 bool Print(const DDT::ResourceAcquisition& aFirstSeen,
102 nsACString& out,
103 bool aPrintFirstSeenCx=false) const;
106 * mName
107 * A descriptive name for this resource. Used in error
108 * messages etc.
110 const char* mName;
112 * mType
113 * The more specific type of this resource. Used to implement
114 * special semantics (e.g., reentrancy of monitors).
116 BlockingResourceType mType;
118 * mAcquisitionContext
119 * The calling context from which this resource was acquired, or
120 * |CallStack::kNone| if it is currently free (or freed).
122 CallStack mAcquisitionContext;
125 protected:
127 * BlockingResourceBase
128 * Initialize this blocking resource. Also hooks the resource into
129 * instrumentation code.
131 * Thread safe.
133 * @param aName A meaningful, unique name that can be used in
134 * error messages, et al.
135 * @param aType The specific type of |this|, if any.
137 BlockingResourceBase(const char* aName, BlockingResourceType aType);
139 ~BlockingResourceBase();
142 * CheckAcquire
144 * Thread safe.
146 * @param aCallContext the client's calling context from which the
147 * original acquisition request was made.
149 void CheckAcquire(const CallStack& aCallContext);
152 * Acquire
154 * *NOT* thread safe. Requires ownership of underlying resource.
156 * @param aCallContext the client's calling context from which the
157 * original acquisition request was made.
159 void Acquire(const CallStack& aCallContext); //NS_NEEDS_RESOURCE(this)
162 * Release
163 * Remove this resource from the current thread's acquisition chain.
164 * The resource does not have to be at the front of the chain, although
165 * it is confusing to release resources in a different order than they
166 * are acquired. This generates a warning.
168 * *NOT* thread safe. Requires ownership of underlying resource.
170 void Release(); //NS_NEEDS_RESOURCE(this)
173 * PrintCycle
174 * Append to |out| detailed information about the circular
175 * dependency in |cycle|. Returns true if it *appears* that this
176 * cycle may represent an imminent deadlock, but this is merely a
177 * heuristic; the value returned may be a false positive or false
178 * negative.
180 * *NOT* thread safe. Calls |Print()|.
182 * FIXME bug 456272 hack alert: because we can't write call
183 * contexts into strings, all info is written to stderr, but only
184 * some info is written into |out|
186 static bool PrintCycle(const DDT::ResourceAcquisitionArray* cycle,
187 nsACString& out);
190 * ResourceChainFront
192 * Thread safe.
194 * @return the front of the resource acquisition chain, i.e., the last
195 * resource acquired.
197 static BlockingResourceBase* ResourceChainFront()
199 return (BlockingResourceBase*)
200 PR_GetThreadPrivate(sResourceAcqnChainFrontTPI);
204 * ResourceChainPrev
206 * *NOT* thread safe. Requires ownership of underlying resource.
208 static BlockingResourceBase*
209 ResourceChainPrev(const BlockingResourceBase* aResource)
211 return aResource->mChainPrev;
212 } //NS_NEEDS_RESOURCE(this)
215 * ResourceChainAppend
216 * Set |this| to the front of the resource acquisition chain, and link
217 * |this| to |aPrev|.
219 * *NOT* thread safe. Requires ownership of underlying resource.
221 void ResourceChainAppend(BlockingResourceBase* aPrev)
223 mChainPrev = aPrev;
224 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this);
225 } //NS_NEEDS_RESOURCE(this)
228 * ResourceChainRemove
229 * Remove |this| from the front of the resource acquisition chain.
231 * *NOT* thread safe. Requires ownership of underlying resource.
233 void ResourceChainRemove()
235 NS_ASSERTION(this == ResourceChainFront(), "not at chain front");
236 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev);
237 } //NS_NEEDS_RESOURCE(this)
240 * GetAcquisitionContext
241 * Return the calling context from which this resource was acquired,
242 * or CallStack::kNone if it's currently free.
244 * *NOT* thread safe. Requires ownership of underlying resource.
246 CallStack
247 GetAcquisitionContext()
249 return mDDEntry->mAcquisitionContext;
253 * SetAcquisitionContext
254 * Set the calling context from which this resource was acquired.
256 * *NOT* thread safe. Requires ownership of underlying resource.
258 void
259 SetAcquisitionContext(CallStack aAcquisitionContext)
261 mDDEntry->mAcquisitionContext = aAcquisitionContext;
265 * mChainPrev
266 * A series of resource acquisitions creates a chain of orders. This
267 * chain is implemented as a linked list; |mChainPrev| points to the
268 * resource most recently Acquire()'d before this one.
270 BlockingResourceBase* mChainPrev;
272 private:
274 * mDDEntry
275 * The key for this BlockingResourceBase in the deadlock detector.
277 DeadlockDetectorEntry* mDDEntry;
280 * sCallOnce
281 * Ensures static members are initialized only once, and in a
282 * thread-safe way.
284 static PRCallOnceType sCallOnce;
287 * sResourceAcqnChainFrontTPI
288 * Thread-private index to the front of each thread's resource
289 * acquisition chain.
291 static unsigned sResourceAcqnChainFrontTPI;
294 * sDeadlockDetector
295 * Does as named.
297 static DDT* sDeadlockDetector;
300 * InitStatics
301 * Inititialize static members of BlockingResourceBase that can't
302 * be statically initialized.
304 * *NOT* thread safe.
306 static PRStatus InitStatics() {
307 PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI, 0);
308 sDeadlockDetector = new DDT();
309 if (!sDeadlockDetector)
310 NS_RUNTIMEABORT("can't allocate deadlock detector");
311 return PR_SUCCESS;
315 * Shutdown
316 * Free static members.
318 * *NOT* thread safe.
320 static void Shutdown() {
321 delete sDeadlockDetector;
322 sDeadlockDetector = 0;
325 # ifdef MOZILLA_INTERNAL_API
326 // so it can call BlockingResourceBase::Shutdown()
327 friend void LogTerm();
328 # endif // ifdef MOZILLA_INTERNAL_API
330 #else // non-DEBUG implementation
332 BlockingResourceBase(const char* aName, BlockingResourceType aType)
336 ~BlockingResourceBase()
340 #endif
344 } // namespace mozilla
347 #endif // mozilla_BlockingResourceBase_h