/work/obj-fuzz/dist/include/mozilla/BlockingResourceBase.h
Line | Count | Source |
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 "nsString.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, eRecursiveMutex }; |
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 | | 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 | | */ |
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 | | */ |
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 | | */ |
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 | | */ |
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 | | */ |
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 | | */ |
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 | | */ |
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 | | |
333 | 849 | BlockingResourceBase(const char* aName, BlockingResourceType aType) {} |
334 | | |
335 | 19 | ~BlockingResourceBase() {} |
336 | | |
337 | | #endif |
338 | | }; |
339 | | |
340 | | |
341 | | } // namespace mozilla |
342 | | |
343 | | |
344 | | #endif // mozilla_BlockingResourceBase_h |