Line data Source code
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
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 : */
154 382899 : static BlockingResourceBase* ResourceChainFront()
155 : {
156 : return
157 382899 : (BlockingResourceBase*)PR_GetThreadPrivate(sResourceAcqnChainFrontTPI);
158 : }
159 :
160 : /**
161 : * ResourceChainPrev
162 : *
163 : * *NOT* thread safe. Requires ownership of underlying resource.
164 : */
165 814 : static BlockingResourceBase* ResourceChainPrev(
166 : const BlockingResourceBase* aResource)
167 : {
168 814 : 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 : */
178 93730 : void ResourceChainAppend(BlockingResourceBase* aPrev)
179 : {
180 93730 : mChainPrev = aPrev;
181 93730 : PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this);
182 93718 : } //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 : */
190 93660 : void ResourceChainRemove()
191 : {
192 93660 : NS_ASSERTION(this == ResourceChainFront(), "not at chain front");
193 93648 : PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev);
194 93651 : } //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 : */
202 752 : AcquisitionState GetAcquisitionState()
203 : {
204 752 : 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 : */
213 694 : void SetAcquisitionState(const AcquisitionState& aAcquisitionState)
214 : {
215 694 : mAcquired = aAcquisitionState;
216 694 : }
217 :
218 : /**
219 : * ClearAcquisitionState
220 : * Indicate this resource is not acquired.
221 : *
222 : * *NOT* thread safe. Requires ownership of underlying resource.
223 : */
224 94402 : void ClearAcquisitionState()
225 : {
226 : #ifdef MOZ_CALLSTACK_DISABLED
227 94402 : mAcquired = false;
228 : #else
229 : mAcquired.Clear();
230 : #endif
231 94402 : }
232 :
233 : /**
234 : * IsAcquired
235 : * Indicates if this resource is acquired.
236 : *
237 : * *NOT* thread safe. Requires ownership of underlying resource.
238 : */
239 239523 : bool IsAcquired() const
240 : {
241 : #ifdef MOZ_CALLSTACK_DISABLED
242 239523 : 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 :
333 : BlockingResourceBase(const char* aName, BlockingResourceType aType) {}
334 :
335 : ~BlockingResourceBase() {}
336 :
337 : #endif
338 : };
339 :
340 :
341 : } // namespace mozilla
342 :
343 :
344 : #endif // mozilla_BlockingResourceBase_h
|