1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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
16 #include "nsTraceRefcnt.h"
22 #include "nsStringGlue.h"
24 #include "mozilla/DeadlockDetector.h"
29 // This header is not meant to be included by client code.
36 * BlockingResourceBase
37 * Base class of resources that might block clients trying to acquire them.
38 * Does debugging and deadlock detection in DEBUG builds.
40 class NS_COM_GLUE BlockingResourceBase
43 // Needs to be kept in sync with kResourceTypeNames.
44 enum BlockingResourceType
{ eMutex
, eReentrantMonitor
, eCondVar
};
48 * Human-readable version of BlockingResourceType enum.
50 static const char* const kResourceTypeName
[];
56 // forward declaration for the following typedef
57 struct DeadlockDetectorEntry
;
59 // ``DDT'' = ``Deadlock Detector Type''
60 typedef DeadlockDetector
<DeadlockDetectorEntry
> DDT
;
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
69 * These objects are owned by the deadlock detector.
71 struct DeadlockDetectorEntry
73 DeadlockDetectorEntry(const char* aName
,
74 BlockingResourceType aType
) :
77 mAcquisitionContext(CallStack::kNone
)
79 NS_ABORT_IF_FALSE(mName
, "Name must be nonnull");
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
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
,
103 bool aPrintFirstSeenCx
=false) const;
107 * A descriptive name for this resource. Used in error
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
;
127 * BlockingResourceBase
128 * Initialize this blocking resource. Also hooks the resource into
129 * instrumentation code.
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();
146 * @param aCallContext the client's calling context from which the
147 * original acquisition request was made.
149 void CheckAcquire(const CallStack
& aCallContext
);
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)
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)
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
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
,
194 * @return the front of the resource acquisition chain, i.e., the last
197 static BlockingResourceBase
* ResourceChainFront()
199 return (BlockingResourceBase
*)
200 PR_GetThreadPrivate(sResourceAcqnChainFrontTPI
);
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
219 * *NOT* thread safe. Requires ownership of underlying resource.
221 void ResourceChainAppend(BlockingResourceBase
* 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.
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.
259 SetAcquisitionContext(CallStack aAcquisitionContext
)
261 mDDEntry
->mAcquisitionContext
= aAcquisitionContext
;
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
;
275 * The key for this BlockingResourceBase in the deadlock detector.
277 DeadlockDetectorEntry
* mDDEntry
;
281 * Ensures static members are initialized only once, and in a
284 static PRCallOnceType sCallOnce
;
287 * sResourceAcqnChainFrontTPI
288 * Thread-private index to the front of each thread's resource
291 static unsigned sResourceAcqnChainFrontTPI
;
297 static DDT
* sDeadlockDetector
;
301 * Inititialize static members of BlockingResourceBase that can't
302 * be statically initialized.
306 static PRStatus
InitStatics() {
307 PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI
, 0);
308 sDeadlockDetector
= new DDT();
309 if (!sDeadlockDetector
)
310 NS_RUNTIMEABORT("can't allocate deadlock detector");
316 * Free static members.
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()
344 } // namespace mozilla
347 #endif // mozilla_BlockingResourceBase_h