1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is mozilla.org code.
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.
24 * Chris Jones <jones.chris.g@gmail.com>
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.
38 * ***** END LICENSE BLOCK ***** */
41 #ifndef mozilla_BlockingResourceBase_h
42 #define mozilla_BlockingResourceBase_h
55 #include "nsStringGlue.h"
57 #include "mozilla/DeadlockDetector.h"
62 // This header is not meant to be included by client code.
69 * BlockingResourceBase
70 * Base class of resources that might block clients trying to acquire them.
71 * Does debugging and deadlock detection in DEBUG builds.
73 class NS_COM_GLUE BlockingResourceBase
76 // Needs to be kept in sync with kResourceTypeNames.
77 enum BlockingResourceType
{ eMutex
, eMonitor
, eCondVar
};
81 * Human-readable version of BlockingResourceType enum.
83 static const char* const kResourceTypeName
[];
89 // forward declaration for the following typedef
90 struct DeadlockDetectorEntry
;
92 // ``DDT'' = ``Deadlock Detector Type''
93 typedef DeadlockDetector
<DeadlockDetectorEntry
> DDT
;
96 * DeadlockDetectorEntry
97 * We free BlockingResources, but we never free entries in the
98 * deadlock detector. This struct outlives its BlockingResource
99 * and preserves all the state needed to print subsequent
102 * These objects are owned by the deadlock detector.
104 struct DeadlockDetectorEntry
106 DeadlockDetectorEntry(const char* aName
,
107 BlockingResourceType aType
) :
110 mAcquisitionContext(CallStack::kNone
)
116 * Write a description of this blocking resource to |out|. If
117 * the resource appears to be currently acquired, the current
118 * acquisition context is printed and true is returned.
119 * Otherwise, we print the context from |aFirstSeen|, the
120 * first acquisition from which the code calling |Print()|
121 * became interested in us, and return false. |Print()| can
122 * be forced to print the context from |aFirstSeen| regardless
123 * by passing |aPrintFirstSeenCx=true|.
125 * *NOT* thread safe. Reads |mAcquisitionContext| without
126 * synchronization, but this will not cause correctness
129 * FIXME bug 456272: hack alert: because we can't write call
130 * contexts into strings, all info is written to stderr, but
131 * only some info is written into |out|
133 bool Print(const DDT::ResourceAcquisition
& aFirstSeen
,
135 bool aPrintFirstSeenCx
=false) const;
139 * A descriptive name for this resource. Used in error
145 * The more specific type of this resource. Used to implement
146 * special semantics (e.g., reentrancy of monitors).
148 BlockingResourceType mType
;
150 * mAcquisitionContext
151 * The calling context from which this resource was acquired, or
152 * |CallStack::kNone| if it is currently free (or freed).
154 CallStack mAcquisitionContext
;
159 * BlockingResourceBase
160 * Initialize this blocking resource. Also hooks the resource into
161 * instrumentation code.
165 * @param aName A meaningful, unique name that can be used in
166 * error messages, et al.
167 * @param aType The specific type of |this|, if any.
169 BlockingResourceBase(const char* aName
, BlockingResourceType aType
);
171 ~BlockingResourceBase();
178 * @param aCallContext the client's calling context from which the
179 * original acquisition request was made.
181 void CheckAcquire(const CallStack
& aCallContext
);
186 * *NOT* thread safe. Requires ownership of underlying resource.
188 * @param aCallContext the client's calling context from which the
189 * original acquisition request was made.
191 void Acquire(const CallStack
& aCallContext
); //NS_NEEDS_RESOURCE(this)
195 * Remove this resource from the current thread's acquisition chain.
196 * The resource does not have to be at the front of the chain, although
197 * it is confusing to release resources in a different order than they
198 * are acquired. This generates a warning.
200 * *NOT* thread safe. Requires ownership of underlying resource.
202 void Release(); //NS_NEEDS_RESOURCE(this)
206 * Append to |out| detailed information about the circular
207 * dependency in |cycle|. Returns true if it *appears* that this
208 * cycle may represent an imminent deadlock, but this is merely a
209 * heuristic; the value returned may be a false positive or false
212 * *NOT* thread safe. Calls |Print()|.
214 * FIXME bug 456272 hack alert: because we can't write call
215 * contexts into strings, all info is written to stderr, but only
216 * some info is written into |out|
218 static bool PrintCycle(const DDT::ResourceAcquisitionArray
* cycle
,
226 * @return the front of the resource acquisition chain, i.e., the last
229 static BlockingResourceBase
* ResourceChainFront()
231 return (BlockingResourceBase
*)
232 PR_GetThreadPrivate(sResourceAcqnChainFrontTPI
);
238 * *NOT* thread safe. Requires ownership of underlying resource.
240 static BlockingResourceBase
*
241 ResourceChainPrev(const BlockingResourceBase
* aResource
)
243 return aResource
->mChainPrev
;
244 } //NS_NEEDS_RESOURCE(this)
247 * ResourceChainAppend
248 * Set |this| to the front of the resource acquisition chain, and link
251 * *NOT* thread safe. Requires ownership of underlying resource.
253 void ResourceChainAppend(BlockingResourceBase
* aPrev
)
256 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI
, this);
257 } //NS_NEEDS_RESOURCE(this)
260 * ResourceChainRemove
261 * Remove |this| from the front of the resource acquisition chain.
263 * *NOT* thread safe. Requires ownership of underlying resource.
265 void ResourceChainRemove()
267 NS_ASSERTION(this == ResourceChainFront(), "not at chain front");
268 PR_SetThreadPrivate(sResourceAcqnChainFrontTPI
, mChainPrev
);
269 } //NS_NEEDS_RESOURCE(this)
272 * GetAcquisitionContext
273 * Return the calling context from which this resource was acquired,
274 * or CallStack::kNone if it's currently free.
276 * *NOT* thread safe. Requires ownership of underlying resource.
279 GetAcquisitionContext()
281 return mDDEntry
->mAcquisitionContext
;
285 * SetAcquisitionContext
286 * Set the calling context from which this resource was acquired.
288 * *NOT* thread safe. Requires ownership of underlying resource.
291 SetAcquisitionContext(CallStack aAcquisitionContext
)
293 mDDEntry
->mAcquisitionContext
= aAcquisitionContext
;
298 * A series of resource acquisitions creates a chain of orders. This
299 * chain is implemented as a linked list; |mChainPrev| points to the
300 * resource most recently Acquire()'d before this one.
302 BlockingResourceBase
* mChainPrev
;
307 * The key for this BlockingResourceBase in the deadlock detector.
309 DeadlockDetectorEntry
* mDDEntry
;
313 * Ensures static members are initialized only once, and in a
316 static PRCallOnceType sCallOnce
;
319 * sResourceAcqnChainFrontTPI
320 * Thread-private index to the front of each thread's resource
323 static PRUintn sResourceAcqnChainFrontTPI
;
329 static DDT
* sDeadlockDetector
;
333 * Inititialize static members of BlockingResourceBase that can't
334 * be statically initialized.
338 static PRStatus
InitStatics() {
339 PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI
, 0);
340 sDeadlockDetector
= new DDT();
341 if (!sDeadlockDetector
)
342 NS_RUNTIMEABORT("can't allocate deadlock detector");
348 * Free static members.
352 static void Shutdown() {
353 delete sDeadlockDetector
;
354 sDeadlockDetector
= 0;
357 # ifdef MOZILLA_INTERNAL_API
358 // so it can call BlockingResourceBase::Shutdown()
359 friend void LogTerm();
360 # endif // ifdef MOZILLA_INTERNAL_API
362 #else // non-DEBUG implementation
364 BlockingResourceBase(const char* aName
, BlockingResourceType aType
)
368 ~BlockingResourceBase()
376 } // namespace mozilla
379 #endif // mozilla_BlockingResourceBase_h