BlockingResourceBase.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef mozilla_BlockingResourceBase_h
  6. #define mozilla_BlockingResourceBase_h
  7. #include "mozilla/Logging.h"
  8. #include "nscore.h"
  9. #include "nsDebug.h"
  10. #include "nsError.h"
  11. #include "nsISupportsImpl.h"
  12. #ifdef DEBUG
  13. // NB: Comment this out to enable callstack tracking.
  14. #define MOZ_CALLSTACK_DISABLED
  15. #include "prinit.h"
  16. #include "nsStringGlue.h"
  17. #ifndef MOZ_CALLSTACK_DISABLED
  18. #include "nsTArray.h"
  19. #endif
  20. #include "nsXPCOM.h"
  21. #endif
  22. //
  23. // This header is not meant to be included by client code.
  24. //
  25. namespace mozilla {
  26. #ifdef DEBUG
  27. template <class T> class DeadlockDetector;
  28. #endif
  29. /**
  30. * BlockingResourceBase
  31. * Base class of resources that might block clients trying to acquire them.
  32. * Does debugging and deadlock detection in DEBUG builds.
  33. **/
  34. class BlockingResourceBase
  35. {
  36. public:
  37. // Needs to be kept in sync with kResourceTypeNames.
  38. enum BlockingResourceType { eMutex, eReentrantMonitor, eCondVar };
  39. /**
  40. * kResourceTypeName
  41. * Human-readable version of BlockingResourceType enum.
  42. */
  43. static const char* const kResourceTypeName[];
  44. #ifdef DEBUG
  45. static size_t
  46. SizeOfDeadlockDetector(MallocSizeOf aMallocSizeOf);
  47. /**
  48. * Print
  49. * Write a description of this blocking resource to |aOut|. If
  50. * the resource appears to be currently acquired, the current
  51. * acquisition context is printed and true is returned.
  52. * Otherwise, we print the context from |aFirstSeen|, the
  53. * first acquisition from which the code calling |Print()|
  54. * became interested in us, and return false.
  55. *
  56. * *NOT* thread safe. Reads |mAcquisitionContext| without
  57. * synchronization, but this will not cause correctness
  58. * problems.
  59. *
  60. * FIXME bug 456272: hack alert: because we can't write call
  61. * contexts into strings, all info is written to stderr, but
  62. * only some info is written into |aOut|
  63. */
  64. bool Print(nsACString& aOut) const;
  65. size_t
  66. SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  67. {
  68. // NB: |mName| is not reported as it's expected to be a static string.
  69. // If we switch to a nsString it should be added to the tally.
  70. // |mChainPrev| is not reported because its memory is not owned.
  71. size_t n = aMallocSizeOf(this);
  72. return n;
  73. }
  74. // ``DDT'' = ``Deadlock Detector Type''
  75. typedef DeadlockDetector<BlockingResourceBase> DDT;
  76. protected:
  77. #ifdef MOZ_CALLSTACK_DISABLED
  78. typedef bool AcquisitionState;
  79. #else
  80. typedef AutoTArray<void*, 24> AcquisitionState;
  81. #endif
  82. /**
  83. * BlockingResourceBase
  84. * Initialize this blocking resource. Also hooks the resource into
  85. * instrumentation code.
  86. *
  87. * Thread safe.
  88. *
  89. * @param aName A meaningful, unique name that can be used in
  90. * error messages, et al.
  91. * @param aType The specific type of |this|, if any.
  92. **/
  93. BlockingResourceBase(const char* aName, BlockingResourceType aType);
  94. ~BlockingResourceBase();
  95. /**
  96. * CheckAcquire
  97. *
  98. * Thread safe.
  99. **/
  100. void CheckAcquire();
  101. /**
  102. * Acquire
  103. *
  104. * *NOT* thread safe. Requires ownership of underlying resource.
  105. **/
  106. void Acquire(); //NS_NEEDS_RESOURCE(this)
  107. /**
  108. * Release
  109. * Remove this resource from the current thread's acquisition chain.
  110. * The resource does not have to be at the front of the chain, although
  111. * it is confusing to release resources in a different order than they
  112. * are acquired. This generates a warning.
  113. *
  114. * *NOT* thread safe. Requires ownership of underlying resource.
  115. **/
  116. void Release(); //NS_NEEDS_RESOURCE(this)
  117. /**
  118. * ResourceChainFront
  119. *
  120. * Thread safe.
  121. *
  122. * @return the front of the resource acquisition chain, i.e., the last
  123. * resource acquired.
  124. */
  125. static BlockingResourceBase* ResourceChainFront()
  126. {
  127. return
  128. (BlockingResourceBase*)PR_GetThreadPrivate(sResourceAcqnChainFrontTPI);
  129. }
  130. /**
  131. * ResourceChainPrev
  132. *
  133. * *NOT* thread safe. Requires ownership of underlying resource.
  134. */
  135. static BlockingResourceBase* ResourceChainPrev(
  136. const BlockingResourceBase* aResource)
  137. {
  138. return aResource->mChainPrev;
  139. } //NS_NEEDS_RESOURCE(this)
  140. /**
  141. * ResourceChainAppend
  142. * Set |this| to the front of the resource acquisition chain, and link
  143. * |this| to |aPrev|.
  144. *
  145. * *NOT* thread safe. Requires ownership of underlying resource.
  146. */
  147. void ResourceChainAppend(BlockingResourceBase* aPrev)
  148. {
  149. mChainPrev = aPrev;
  150. PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, this);
  151. } //NS_NEEDS_RESOURCE(this)
  152. /**
  153. * ResourceChainRemove
  154. * Remove |this| from the front of the resource acquisition chain.
  155. *
  156. * *NOT* thread safe. Requires ownership of underlying resource.
  157. */
  158. void ResourceChainRemove()
  159. {
  160. NS_ASSERTION(this == ResourceChainFront(), "not at chain front");
  161. PR_SetThreadPrivate(sResourceAcqnChainFrontTPI, mChainPrev);
  162. } //NS_NEEDS_RESOURCE(this)
  163. /**
  164. * GetAcquisitionState
  165. * Return whether or not this resource was acquired.
  166. *
  167. * *NOT* thread safe. Requires ownership of underlying resource.
  168. */
  169. AcquisitionState GetAcquisitionState()
  170. {
  171. return mAcquired;
  172. }
  173. /**
  174. * SetAcquisitionState
  175. * Set whether or not this resource was acquired.
  176. *
  177. * *NOT* thread safe. Requires ownership of underlying resource.
  178. */
  179. void SetAcquisitionState(const AcquisitionState& aAcquisitionState)
  180. {
  181. mAcquired = aAcquisitionState;
  182. }
  183. /**
  184. * ClearAcquisitionState
  185. * Indicate this resource is not acquired.
  186. *
  187. * *NOT* thread safe. Requires ownership of underlying resource.
  188. */
  189. void ClearAcquisitionState()
  190. {
  191. #ifdef MOZ_CALLSTACK_DISABLED
  192. mAcquired = false;
  193. #else
  194. mAcquired.Clear();
  195. #endif
  196. }
  197. /**
  198. * IsAcquired
  199. * Indicates if this resource is acquired.
  200. *
  201. * *NOT* thread safe. Requires ownership of underlying resource.
  202. */
  203. bool IsAcquired() const
  204. {
  205. #ifdef MOZ_CALLSTACK_DISABLED
  206. return mAcquired;
  207. #else
  208. return !mAcquired.IsEmpty();
  209. #endif
  210. }
  211. /**
  212. * mChainPrev
  213. * A series of resource acquisitions creates a chain of orders. This
  214. * chain is implemented as a linked list; |mChainPrev| points to the
  215. * resource most recently Acquire()'d before this one.
  216. **/
  217. BlockingResourceBase* mChainPrev;
  218. private:
  219. /**
  220. * mName
  221. * A descriptive name for this resource. Used in error
  222. * messages etc.
  223. */
  224. const char* mName;
  225. /**
  226. * mType
  227. * The more specific type of this resource. Used to implement
  228. * special semantics (e.g., reentrancy of monitors).
  229. **/
  230. BlockingResourceType mType;
  231. /**
  232. * mAcquired
  233. * Indicates if this resource is currently acquired.
  234. */
  235. AcquisitionState mAcquired;
  236. #ifndef MOZ_CALLSTACK_DISABLED
  237. /**
  238. * mFirstSeen
  239. * Inidicates where this resource was first acquired.
  240. */
  241. AcquisitionState mFirstSeen;
  242. #endif
  243. /**
  244. * sCallOnce
  245. * Ensures static members are initialized only once, and in a
  246. * thread-safe way.
  247. */
  248. static PRCallOnceType sCallOnce;
  249. /**
  250. * sResourceAcqnChainFrontTPI
  251. * Thread-private index to the front of each thread's resource
  252. * acquisition chain.
  253. */
  254. static unsigned sResourceAcqnChainFrontTPI;
  255. /**
  256. * sDeadlockDetector
  257. * Does as named.
  258. */
  259. static DDT* sDeadlockDetector;
  260. /**
  261. * InitStatics
  262. * Inititialize static members of BlockingResourceBase that can't
  263. * be statically initialized.
  264. *
  265. * *NOT* thread safe.
  266. */
  267. static PRStatus InitStatics();
  268. /**
  269. * Shutdown
  270. * Free static members.
  271. *
  272. * *NOT* thread safe.
  273. */
  274. static void Shutdown();
  275. static void StackWalkCallback(uint32_t aFrameNumber, void* aPc,
  276. void* aSp, void* aClosure);
  277. static void GetStackTrace(AcquisitionState& aState);
  278. # ifdef MOZILLA_INTERNAL_API
  279. // so it can call BlockingResourceBase::Shutdown()
  280. friend void LogTerm();
  281. # endif // ifdef MOZILLA_INTERNAL_API
  282. #else // non-DEBUG implementation
  283. BlockingResourceBase(const char* aName, BlockingResourceType aType) {}
  284. ~BlockingResourceBase() {}
  285. #endif
  286. };
  287. } // namespace mozilla
  288. #endif // mozilla_BlockingResourceBase_h