Merge tracemonkey and mozilla-central. (a=blockers)
[mozilla-central.git] / xpcom / glue / BlockingResourceBase.h
blob8291591d9c7c9a3fa314944adeae1c21ce75e263
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
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
14 * License.
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.
23 * Contributor(s):
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
44 #include "prlock.h"
45 #include "prlog.h"
47 #include "nscore.h"
48 #include "nsDebug.h"
49 #include "nsError.h"
51 #ifdef DEBUG
52 #include "prinit.h"
53 #include "prthread.h"
55 #include "nsStringGlue.h"
57 #include "mozilla/DeadlockDetector.h"
58 #include "nsXPCOM.h"
59 #endif
62 // This header is not meant to be included by client code.
65 namespace mozilla {
68 /**
69 * BlockingResourceBase
70 * Base class of resources that might block clients trying to acquire them.
71 * Does debugging and deadlock detection in DEBUG builds.
72 **/
73 class NS_COM_GLUE BlockingResourceBase
75 public:
76 // Needs to be kept in sync with kResourceTypeNames.
77 enum BlockingResourceType { eMutex, eMonitor, eCondVar };
79 /**
80 * kResourceTypeName
81 * Human-readable version of BlockingResourceType enum.
83 static const char* const kResourceTypeName[];
86 #ifdef DEBUG
88 private:
89 // forward declaration for the following typedef
90 struct DeadlockDetectorEntry;
92 // ``DDT'' = ``Deadlock Detector Type''
93 typedef DeadlockDetector<DeadlockDetectorEntry> DDT;
95 /**
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
100 * error messages.
102 * These objects are owned by the deadlock detector.
104 struct DeadlockDetectorEntry
106 DeadlockDetectorEntry(const char* aName,
107 BlockingResourceType aType) :
108 mName(aName),
109 mType(aType),
110 mAcquisitionContext(CallStack::kNone)
115 * Print
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
127 * problems.
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,
134 nsACString& out,
135 bool aPrintFirstSeenCx=false) const;
138 * mName
139 * A descriptive name for this resource. Used in error
140 * messages etc.
142 const char* mName;
144 * mType
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;
157 protected:
159 * BlockingResourceBase
160 * Initialize this blocking resource. Also hooks the resource into
161 * instrumentation code.
163 * Thread safe.
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();
174 * CheckAcquire
176 * Thread safe.
178 * @param aCallContext the client's calling context from which the
179 * original acquisition request was made.
181 void CheckAcquire(const CallStack& aCallContext);
184 * Acquire
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)
194 * Release
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)
205 * PrintCycle
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
210 * negative.
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,
219 nsACString& out);
222 * ResourceChainFront
224 * Thread safe.
226 * @return the front of the resource acquisition chain, i.e., the last
227 * resource acquired.
229 static BlockingResourceBase* ResourceChainFront()
231 return (BlockingResourceBase*)
232 PR_GetThreadPrivate(sResourceAcqnChainFrontTPI);
236 * ResourceChainPrev
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
249 * |this| to |aPrev|.
251 * *NOT* thread safe. Requires ownership of underlying resource.
253 void ResourceChainAppend(BlockingResourceBase* aPrev)
255 mChainPrev = 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.
278 CallStack
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.
290 void
291 SetAcquisitionContext(CallStack aAcquisitionContext)
293 mDDEntry->mAcquisitionContext = aAcquisitionContext;
297 * mChainPrev
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;
304 private:
306 * mDDEntry
307 * The key for this BlockingResourceBase in the deadlock detector.
309 DeadlockDetectorEntry* mDDEntry;
312 * sCallOnce
313 * Ensures static members are initialized only once, and in a
314 * thread-safe way.
316 static PRCallOnceType sCallOnce;
319 * sResourceAcqnChainFrontTPI
320 * Thread-private index to the front of each thread's resource
321 * acquisition chain.
323 static PRUintn sResourceAcqnChainFrontTPI;
326 * sDeadlockDetector
327 * Does as named.
329 static DDT* sDeadlockDetector;
332 * InitStatics
333 * Inititialize static members of BlockingResourceBase that can't
334 * be statically initialized.
336 * *NOT* thread safe.
338 static PRStatus InitStatics() {
339 PR_NewThreadPrivateIndex(&sResourceAcqnChainFrontTPI, 0);
340 sDeadlockDetector = new DDT();
341 if (!sDeadlockDetector)
342 NS_RUNTIMEABORT("can't allocate deadlock detector");
343 return PR_SUCCESS;
347 * Shutdown
348 * Free static members.
350 * *NOT* thread safe.
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()
372 #endif
376 } // namespace mozilla
379 #endif // mozilla_BlockingResourceBase_h