1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Chris Jones <jones.chris.g@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 :
41 : #ifndef mozilla_BlockingResourceBase_h
42 : #define mozilla_BlockingResourceBase_h
43 :
44 : #include "prlock.h"
45 : #include "prlog.h"
46 :
47 : #include "nscore.h"
48 : #include "nsDebug.h"
49 : #include "nsError.h"
50 : #include "nsTraceRefcnt.h"
51 :
52 : #ifdef DEBUG
53 : #include "prinit.h"
54 : #include "prthread.h"
55 :
56 : #include "nsStringGlue.h"
57 :
58 : #include "mozilla/DeadlockDetector.h"
59 : #include "nsXPCOM.h"
60 : #endif
61 :
62 : //
63 : // This header is not meant to be included by client code.
64 : //
65 :
66 : namespace mozilla {
67 :
68 :
69 : /**
70 : * BlockingResourceBase
71 : * Base class of resources that might block clients trying to acquire them.
72 : * Does debugging and deadlock detection in DEBUG builds.
73 : **/
74 : class NS_COM_GLUE BlockingResourceBase
75 : {
76 : public:
77 : // Needs to be kept in sync with kResourceTypeNames.
78 : enum BlockingResourceType { eMutex, eReentrantMonitor, eCondVar };
79 :
80 : /**
81 : * kResourceTypeName
82 : * Human-readable version of BlockingResourceType enum.
83 : */
84 : static const char* const kResourceTypeName[];
85 :
86 :
87 : #ifdef DEBUG
88 :
89 : private:
90 : // forward declaration for the following typedef
91 : struct DeadlockDetectorEntry;
92 :
93 : // ``DDT'' = ``Deadlock Detector Type''
94 : typedef DeadlockDetector<DeadlockDetectorEntry> DDT;
95 :
96 : /**
97 : * DeadlockDetectorEntry
98 : * We free BlockingResources, but we never free entries in the
99 : * deadlock detector. This struct outlives its BlockingResource
100 : * and preserves all the state needed to print subsequent
101 : * error messages.
102 : *
103 : * These objects are owned by the deadlock detector.
104 : */
105 : struct DeadlockDetectorEntry
106 : {
107 182916 : DeadlockDetectorEntry(const char* aName,
108 : BlockingResourceType aType) :
109 : mName(aName),
110 : mType(aType),
111 182916 : mAcquisitionContext(CallStack::kNone)
112 : {
113 182916 : NS_ABORT_IF_FALSE(mName, "Name must be nonnull");
114 182916 : }
115 :
116 : /**
117 : * Print
118 : * Write a description of this blocking resource to |out|. If
119 : * the resource appears to be currently acquired, the current
120 : * acquisition context is printed and true is returned.
121 : * Otherwise, we print the context from |aFirstSeen|, the
122 : * first acquisition from which the code calling |Print()|
123 : * became interested in us, and return false. |Print()| can
124 : * be forced to print the context from |aFirstSeen| regardless
125 : * by passing |aPrintFirstSeenCx=true|.
126 : *
127 : * *NOT* thread safe. Reads |mAcquisitionContext| without
128 : * synchronization, but this will not cause correctness
129 : * problems.
130 : *
131 : * FIXME bug 456272: hack alert: because we can't write call
132 : * contexts into strings, all info is written to stderr, but
133 : * only some info is written into |out|
134 : */
135 : bool Print(const DDT::ResourceAcquisition& aFirstSeen,
136 : nsACString& out,
137 : bool aPrintFirstSeenCx=false) const;
138 :
139 : /**
140 : * mName
141 : * A descriptive name for this resource. Used in error
142 : * messages etc.
143 : */
144 : const char* mName;
145 : /**
146 : * mType
147 : * The more specific type of this resource. Used to implement
148 : * special semantics (e.g., reentrancy of monitors).
149 : **/
150 : BlockingResourceType mType;
151 : /**
152 : * mAcquisitionContext
153 : * The calling context from which this resource was acquired, or
154 : * |CallStack::kNone| if it is currently free (or freed).
155 : */
156 : CallStack mAcquisitionContext;
157 : };
158 :
159 : protected:
160 : /**
161 : * BlockingResourceBase
162 : * Initialize this blocking resource. Also hooks the resource into
163 : * instrumentation code.
164 : *
165 : * Thread safe.
166 : *
167 : * @param aName A meaningful, unique name that can be used in
168 : * error messages, et al.
169 : * @param aType The specific type of |this|, if any.
170 : **/
171 : BlockingResourceBase(const char* aName, BlockingResourceType aType);
172 :
173 : ~BlockingResourceBase();
174 :
175 : /**
176 : * CheckAcquire
177 : *
178 : * Thread safe.
179 : *
180 : * @param aCallContext the client's calling context from which the
181 : * original acquisition request was made.
182 : **/
183 : void CheckAcquire(const CallStack& aCallContext);
184 :
185 : /**
186 : * Acquire
187 : *
188 : * *NOT* thread safe. Requires ownership of underlying resource.
189 : *
190 : * @param aCallContext the client's calling context from which the
191 : * original acquisition request was made.
192 : **/
193 : void Acquire(const CallStack& aCallContext); //NS_NEEDS_RESOURCE(this)
194 :
195 : /**
196 : * Release
197 : * Remove this resource from the current thread's acquisition chain.
198 : * The resource does not have to be at the front of the chain, although
199 : * it is confusing to release resources in a different order than they
200 : * are acquired. This generates a warning.
201 : *
202 : * *NOT* thread safe. Requires ownership of underlying resource.
203 : **/
204 : void Release(); //NS_NEEDS_RESOURCE(this)
205 :
206 : /**
207 : * PrintCycle
208 : * Append to |out| detailed information about the circular
209 : * dependency in |cycle|. Returns true if it *appears* that this
210 : * cycle may represent an imminent deadlock, but this is merely a
211 : * heuristic; the value returned may be a false positive or false
212 : * negative.
213 : *
214 : * *NOT* thread safe. Calls |Print()|.
215 : *
216 : * FIXME bug 456272 hack alert: because we can't write call
217 : * contexts into strings, all info is written to stderr, but only
218 : * some info is written into |out|
219 : */
220 : static bool PrintCycle(const DDT::ResourceAcquisitionArray* cycle,
221 : nsACString& out);
222 :
223 : /**
224 : * ResourceChainFront
225 : *
226 : * Thread safe.
227 : *
228 : * @return the front of the resource acquisition chain, i.e., the last
229 : * resource acquired.
230 : */
231 128531732 : static BlockingResourceBase* ResourceChainFront()
232 : {
233 : return (BlockingResourceBase*)
234 128531732 : PR_GetThreadPrivate(sResourceAcqnChainFrontTPI);
235 : }
236 :
237 : /**
238 : * ResourceChainPrev
239 : *
240 : * *NOT* thread safe. Requires ownership of underlying resource.
241 : */
242 : static BlockingResourceBase*
243 499782 : ResourceChainPrev(const BlockingResourceBase* aResource)
244 : {
245 499782 : return aResource->mChainPrev;
246 : } //NS_NEEDS_RESOURCE(this)
247 :
248 : /**
249 : * ResourceChainAppend
250 : * Set |this| to the front of the resource acquisition chain, and link
251 : * |this| to |aPrev|.
252 : *
253 : * *NOT* thread safe. Requires ownership of underlying resource.
254 : */
255 26691326 : void ResourceChainAppend(BlockingResourceBase* aPrev)
256 : {
257 26691326 : mChainPrev = aPrev;
258 26691326 : PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this);
259 26691188 : } //NS_NEEDS_RESOURCE(this)
260 :
261 : /**
262 : * ResourceChainRemove
263 : * Remove |this| from the front of the resource acquisition chain.
264 : *
265 : * *NOT* thread safe. Requires ownership of underlying resource.
266 : */
267 26691672 : void ResourceChainRemove()
268 : {
269 26691672 : NS_ASSERTION(this == ResourceChainFront(), "not at chain front");
270 26691523 : PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev);
271 26691252 : } //NS_NEEDS_RESOURCE(this)
272 :
273 : /**
274 : * GetAcquisitionContext
275 : * Return the calling context from which this resource was acquired,
276 : * or CallStack::kNone if it's currently free.
277 : *
278 : * *NOT* thread safe. Requires ownership of underlying resource.
279 : */
280 : CallStack
281 111875 : GetAcquisitionContext()
282 : {
283 111875 : return mDDEntry->mAcquisitionContext;
284 : }
285 :
286 : /**
287 : * SetAcquisitionContext
288 : * Set the calling context from which this resource was acquired.
289 : *
290 : * *NOT* thread safe. Requires ownership of underlying resource.
291 : */
292 : void
293 223748 : SetAcquisitionContext(CallStack aAcquisitionContext)
294 : {
295 223748 : mDDEntry->mAcquisitionContext = aAcquisitionContext;
296 223744 : }
297 :
298 : /**
299 : * mChainPrev
300 : * A series of resource acquisitions creates a chain of orders. This
301 : * chain is implemented as a linked list; |mChainPrev| points to the
302 : * resource most recently Acquire()'d before this one.
303 : **/
304 : BlockingResourceBase* mChainPrev;
305 :
306 : private:
307 : /**
308 : * mDDEntry
309 : * The key for this BlockingResourceBase in the deadlock detector.
310 : */
311 : DeadlockDetectorEntry* mDDEntry;
312 :
313 : /**
314 : * sCallOnce
315 : * Ensures static members are initialized only once, and in a
316 : * thread-safe way.
317 : */
318 : static PRCallOnceType sCallOnce;
319 :
320 : /**
321 : * sResourceAcqnChainFrontTPI
322 : * Thread-private index to the front of each thread's resource
323 : * acquisition chain.
324 : */
325 : static PRUintn sResourceAcqnChainFrontTPI;
326 :
327 : /**
328 : * sDeadlockDetector
329 : * Does as named.
330 : */
331 : static DDT* sDeadlockDetector;
332 :
333 : /**
334 : * InitStatics
335 : * Inititialize static members of BlockingResourceBase that can't
336 : * be statically initialized.
337 : *
338 : * *NOT* thread safe.
339 : */
340 1446 : static PRStatus InitStatics() {
341 1446 : PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI, 0);
342 1446 : sDeadlockDetector = new DDT();
343 1446 : if (!sDeadlockDetector)
344 0 : NS_RUNTIMEABORT("can't allocate deadlock detector");
345 1446 : return PR_SUCCESS;
346 : }
347 :
348 : /**
349 : * Shutdown
350 : * Free static members.
351 : *
352 : * *NOT* thread safe.
353 : */
354 1442 : static void Shutdown() {
355 1442 : delete sDeadlockDetector;
356 1442 : sDeadlockDetector = 0;
357 1442 : }
358 :
359 : # ifdef MOZILLA_INTERNAL_API
360 : // so it can call BlockingResourceBase::Shutdown()
361 : friend void LogTerm();
362 : # endif // ifdef MOZILLA_INTERNAL_API
363 :
364 : #else // non-DEBUG implementation
365 :
366 : BlockingResourceBase(const char* aName, BlockingResourceType aType)
367 : {
368 : }
369 :
370 : ~BlockingResourceBase()
371 : {
372 : }
373 :
374 : #endif
375 : };
376 :
377 :
378 : } // namespace mozilla
379 :
380 :
381 : #endif // mozilla_BlockingResourceBase_h
|