Coverage Report

Created: 2018-09-25 14:53

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