xpcom/glue/BlockingResourceBase.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial