Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/Mutex.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef mozilla_Mutex_h
8
#define mozilla_Mutex_h
9
10
#include "mozilla/BlockingResourceBase.h"
11
#include "mozilla/GuardObjects.h"
12
#include "mozilla/PlatformMutex.h"
13
14
//
15
// Provides:
16
//
17
//  - Mutex, a non-recursive mutex
18
//  - MutexAutoLock, an RAII class for ensuring that Mutexes are properly
19
//    locked and unlocked
20
//  - MutexAutoUnlock, complementary sibling to MutexAutoLock
21
//
22
//  - OffTheBooksMutex, a non-recursive mutex that doesn't do leak checking
23
//  - OffTheBooksMutexAuto{Lock,Unlock} - Like MutexAuto{Lock,Unlock}, but for
24
//    an OffTheBooksMutex.
25
//
26
// Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare
27
// calls to Lock and Unlock.
28
//
29
namespace mozilla {
30
31
/**
32
 * OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't
33
 * include leak checking.  Sometimes you want to intentionally "leak" a mutex
34
 * until shutdown; in these cases, OffTheBooksMutex is for you.
35
 */
36
class OffTheBooksMutex : public detail::MutexImpl, BlockingResourceBase
37
{
38
public:
39
  /**
40
   * @param aName A name which can reference this lock
41
   * @returns If failure, nullptr
42
   *          If success, a valid Mutex* which must be destroyed
43
   *          by Mutex::DestroyMutex()
44
   **/
45
  explicit OffTheBooksMutex(const char* aName,
46
                            recordreplay::Behavior aRecorded = recordreplay::Behavior::Preserve)
47
    : detail::MutexImpl(aRecorded)
48
    , BlockingResourceBase(aName, eMutex)
49
#ifdef DEBUG
50
    , mOwningThread(nullptr)
51
#endif
52
748
  {
53
748
  }
54
55
  ~OffTheBooksMutex()
56
6
  {
57
#ifdef DEBUG
58
    MOZ_ASSERT(!mOwningThread, "destroying a still-owned lock!");
59
#endif
60
  }
61
62
#ifndef DEBUG
63
  /**
64
   * Lock this mutex.
65
   **/
66
4.47M
  void Lock() { this->lock(); }
67
68
  /**
69
   * Unlock this mutex.
70
   **/
71
4.47M
  void Unlock() { this->unlock(); }
72
73
  /**
74
   * Assert that the current thread owns this mutex in debug builds.
75
   *
76
   * Does nothing in non-debug builds.
77
   **/
78
20.1k
  void AssertCurrentThreadOwns() const {}
79
80
  /**
81
   * Assert that the current thread does not own this mutex.
82
   *
83
   * Note that this function is not implemented for debug builds *and*
84
   * non-debug builds due to difficulties in dealing with memory ordering.
85
   *
86
   * It is therefore mostly useful as documentation.
87
   **/
88
0
  void AssertNotCurrentThreadOwns() const {}
89
90
#else
91
  void Lock();
92
  void Unlock();
93
94
  void AssertCurrentThreadOwns() const;
95
96
  void AssertNotCurrentThreadOwns() const
97
  {
98
    // FIXME bug 476536
99
  }
100
101
#endif  // ifndef DEBUG
102
103
private:
104
  OffTheBooksMutex();
105
  OffTheBooksMutex(const OffTheBooksMutex&);
106
  OffTheBooksMutex& operator=(const OffTheBooksMutex&);
107
108
  friend class OffTheBooksCondVar;
109
110
#ifdef DEBUG
111
  PRThread* mOwningThread;
112
#endif
113
};
114
115
/**
116
 * Mutex
117
 * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
118
 * mutex within a scope, instead of calling Lock/Unlock directly.
119
 */
120
class Mutex : public OffTheBooksMutex
121
{
122
public:
123
  explicit Mutex(const char* aName,
124
                 recordreplay::Behavior aRecorded = recordreplay::Behavior::Preserve)
125
    : OffTheBooksMutex(aName, aRecorded)
126
717
  {
127
717
    MOZ_COUNT_CTOR(Mutex);
128
717
  }
129
130
  ~Mutex()
131
0
  {
132
0
    MOZ_COUNT_DTOR(Mutex);
133
0
  }
134
135
private:
136
  Mutex();
137
  Mutex(const Mutex&);
138
  Mutex& operator=(const Mutex&);
139
};
140
141
template<typename T>
142
class MOZ_RAII BaseAutoUnlock;
143
144
/**
145
 * MutexAutoLock
146
 * Acquires the Mutex when it enters scope, and releases it when it leaves
147
 * scope.
148
 *
149
 * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock.
150
 */
151
template<typename T>
152
class MOZ_RAII BaseAutoLock
153
{
154
public:
155
  /**
156
   * Constructor
157
   * The constructor aquires the given lock.  The destructor
158
   * releases the lock.
159
   *
160
   * @param aLock A valid mozilla::Mutex* returned by
161
   *              mozilla::Mutex::NewMutex.
162
   **/
163
  explicit BaseAutoLock(T aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
164
    : mLock(aLock)
165
1.95M
  {
166
1.95M
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
1.95M
    mLock.Lock();
168
1.95M
  }
mozilla::BaseAutoLock<mozilla::Mutex&>::BaseAutoLock(mozilla::Mutex&)
Line
Count
Source
165
29.6k
  {
166
29.6k
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
29.6k
    mLock.Lock();
168
29.6k
  }
mozilla::BaseAutoLock<mozilla::AnyStaticMutex>::BaseAutoLock(mozilla::AnyStaticMutex)
Line
Count
Source
165
1.47k
  {
166
1.47k
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
1.47k
    mLock.Lock();
168
1.47k
  }
mozilla::BaseAutoLock<mozilla::OffTheBooksMutex&>::BaseAutoLock(mozilla::OffTheBooksMutex&)
Line
Count
Source
165
167
  {
166
167
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
167
    mLock.Lock();
168
167
  }
mozilla::BaseAutoLock<SafeMutex&>::BaseAutoLock(SafeMutex&)
Line
Count
Source
165
1.92M
  {
166
1.92M
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
1.92M
    mLock.Lock();
168
1.92M
  }
mozilla::BaseAutoLock<PSMutex&>::BaseAutoLock(PSMutex&)
Line
Count
Source
165
58
  {
166
58
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
167
58
    mLock.Lock();
168
58
  }
169
170
  ~BaseAutoLock(void)
171
1.95M
  {
172
1.95M
    mLock.Unlock();
173
1.95M
  }
mozilla::BaseAutoLock<mozilla::Mutex&>::~BaseAutoLock()
Line
Count
Source
171
29.6k
  {
172
29.6k
    mLock.Unlock();
173
29.6k
  }
mozilla::BaseAutoLock<mozilla::AnyStaticMutex>::~BaseAutoLock()
Line
Count
Source
171
1.47k
  {
172
1.47k
    mLock.Unlock();
173
1.47k
  }
mozilla::BaseAutoLock<mozilla::OffTheBooksMutex&>::~BaseAutoLock()
Line
Count
Source
171
167
  {
172
167
    mLock.Unlock();
173
167
  }
mozilla::BaseAutoLock<SafeMutex&>::~BaseAutoLock()
Line
Count
Source
171
1.92M
  {
172
1.92M
    mLock.Unlock();
173
1.92M
  }
mozilla::BaseAutoLock<PSMutex&>::~BaseAutoLock()
Line
Count
Source
171
58
  {
172
58
    mLock.Unlock();
173
58
  }
174
175
  // Assert that aLock is the mutex passed to the constructor and that the
176
  // current thread owns the mutex.  In coding patterns such as:
177
  //
178
  // void LockedMethod(const MutexAutoLock& aProofOfLock)
179
  // {
180
  //   aProofOfLock.AssertOwns(mMutex);
181
  //   ...
182
  // }
183
  //
184
  // Without this assertion, it could be that mMutex is not actually
185
  // locked. It's possible to have code like:
186
  //
187
  // MutexAutoLock lock(someMutex);
188
  // ...
189
  // MutexAutoUnlock unlock(someMutex);
190
  // ...
191
  // LockedMethod(lock);
192
  //
193
  // and in such a case, simply asserting that the mutex pointers match is not
194
  // sufficient; mutex ownership must be asserted as well.
195
  //
196
  // Note that if you are going to use the coding pattern presented above, you
197
  // should use this method in preference to using AssertCurrentThreadOwns on
198
  // the mutex you expected to be held, since this method provides stronger
199
  // guarantees.
200
  void AssertOwns(const T& aLock) const
201
0
  {
202
0
    MOZ_ASSERT(&aLock == &mLock);
203
0
    mLock.AssertCurrentThreadOwns();
204
0
  }
205
206
private:
207
  BaseAutoLock();
208
  BaseAutoLock(BaseAutoLock&);
209
  BaseAutoLock& operator=(BaseAutoLock&);
210
  static void* operator new(size_t) CPP_THROW_NEW;
211
212
  friend class BaseAutoUnlock<T>;
213
214
  T mLock;
215
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
216
};
217
218
typedef BaseAutoLock<Mutex&> MutexAutoLock;
219
typedef BaseAutoLock<OffTheBooksMutex&> OffTheBooksMutexAutoLock;
220
221
/**
222
 * MutexAutoUnlock
223
 * Releases the Mutex when it enters scope, and re-acquires it when it leaves
224
 * scope.
225
 *
226
 * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock.
227
 */
228
template<typename T>
229
class MOZ_RAII BaseAutoUnlock
230
{
231
public:
232
  explicit BaseAutoUnlock(T aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
233
    : mLock(aLock)
234
100
  {
235
100
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
236
100
    mLock.Unlock();
237
100
  }
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::Mutex&>::BaseAutoUnlock(mozilla::Mutex&)
mozilla::BaseAutoUnlock<SafeMutex&>::BaseAutoUnlock(SafeMutex&)
Line
Count
Source
234
100
  {
235
100
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
236
100
    mLock.Unlock();
237
100
  }
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::AnyStaticMutex>::BaseAutoUnlock(mozilla::AnyStaticMutex)
238
239
  explicit BaseAutoUnlock(
240
    BaseAutoLock<T>& aAutoLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
241
    : mLock(aAutoLock.mLock)
242
  {
243
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
244
    NS_ASSERTION(mLock, "null lock");
245
    mLock->Unlock();
246
  }
247
248
  ~BaseAutoUnlock()
249
100
  {
250
100
    mLock.Lock();
251
100
  }
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::Mutex&>::~BaseAutoUnlock()
mozilla::BaseAutoUnlock<SafeMutex&>::~BaseAutoUnlock()
Line
Count
Source
249
100
  {
250
100
    mLock.Lock();
251
100
  }
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::AnyStaticMutex>::~BaseAutoUnlock()
252
253
private:
254
  BaseAutoUnlock();
255
  BaseAutoUnlock(BaseAutoUnlock&);
256
  BaseAutoUnlock& operator=(BaseAutoUnlock&);
257
  static void* operator new(size_t) CPP_THROW_NEW;
258
259
  T mLock;
260
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
261
};
262
263
typedef BaseAutoUnlock<Mutex&> MutexAutoUnlock;
264
typedef BaseAutoUnlock<OffTheBooksMutex&> OffTheBooksMutexAutoUnlock;
265
266
} // namespace mozilla
267
268
269
#endif // ifndef mozilla_Mutex_h