File: EventTargetAndLockCapability.h

package info (click to toggle)
firefox 146.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,653,260 kB
  • sloc: cpp: 7,587,892; javascript: 6,509,455; ansic: 3,755,295; python: 1,410,813; xml: 629,201; asm: 438,677; java: 186,096; sh: 62,697; makefile: 18,086; objc: 13,087; perl: 12,811; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (147 lines) | stat: -rw-r--r-- 6,729 bytes parent folder | download | duplicates (12)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_EventTargetAndLockCapability_h
#define mozilla_EventTargetAndLockCapability_h

#include "MainThreadUtils.h"
#include "mozilla/ThreadSafety.h"
#include "mozilla/EventTargetCapability.h"

// This header contains helper types for combining a Lock and a thread
// capability allow using both independently, as well as combined together.
//
// This is useful for reflecting the "Single-Writer Mutex" pattern for the clang
// thread-safety analysis, allowing compile-time validation of the correct use
// of the combined capability.
//
// See https://firefox-source-docs.mozilla.org/xpcom/thread-safety.html for
// additional high-level documentation on the thread-safety analysis.

namespace mozilla {

// A thread-safety capability used to combine a Lock with the main thread
// capability to allow using each independently, as well as combined together.
//
// The MainThreadAndLockCapability grants shared (read-only) access if either on
// the main thread, or the inner mutex is held, and only allows exclusive
// (mutable) access if both the lock and the thread capability are held.
//
// This is used to implement the "Single-Writer Mutex" pattern, where a mutex is
// used to guard off-thread access to a value only mutated on a single thread,
// while not requiring the mutex for reads on that thread.
//
// There are no `AutoLock` helper types, instead the lock needs to be acquired
// using the normal locking mechanism (e.g. `MutexAutoLock lock(cap.Lock())`),
// followed by the relevant call to `NoteLockHeld` or `NoteExclusiveAccess`.
template <typename LockT>
class MOZ_CAPABILITY("combo (main thread + mutex)")
    MainThreadAndLockCapability {
 public:
  explicit MainThreadAndLockCapability(const char* aName) : mLock(aName) {}

  // Get access to the internal Lock. This can be used both to have values
  // normally guarded by this lock, as well as to acquire the lock as-needed.
  LockT& Lock() MOZ_RETURN_CAPABILITY(mLock) { return mLock; }

  // Note that we're on the main thread, and thus have shared (read-only) access
  // to values guarded by the MainThreadAndLockCapability for the thread-safety
  // analysis.
  void NoteOnMainThread() const MOZ_REQUIRES(sMainThreadCapability)
      MOZ_ASSERT_SHARED_CAPABILITY(this) {}

  // Note that we're holding the lock, and thus have shared (read-only) access
  // to values guarded by the MainThreadAndLockCapability for the thread-safety
  // analysis.
  void NoteLockHeld() const MOZ_REQUIRES(mLock)
      MOZ_ASSERT_SHARED_CAPABILITY(this) {}

  // Note that we're holding the lock while on the main thread, and thus have
  // exclusive (mutable) access to values guarded by the
  // MainThreadAndLockCapability for the thread-safety analysis.
  void NoteExclusiveAccess() const MOZ_REQUIRES(sMainThreadCapability, mLock)
      MOZ_ASSERT_CAPABILITY(this) {}

  // If you have previously called one of the above `Note` methods in the
  // current function scope, then have acquired `Lock()` and now want to
  // `NoteExclusiveAccess()`, this method can be called to clear the thread
  // safety analysis's understanding that the MainThreadAndLockCapability is
  // currently held.
  void ClearCurrentAccess() const
      MOZ_RELEASE_GENERIC(this) MOZ_NO_THREAD_SAFETY_ANALYSIS {}

 private:
  LockT mLock;
};

// Similar to MainThreadAndLockCapability, this is a thread-safety capability
// used to combine a Lock with an EventTarget capability to allow using each
// independently, as well as combined together.
//
// The EventTargetAndLockCapability grants shared (read-only) access if either
// on the event target, or the inner lock is held, and only allows exclusive
// (mutable) access if both the lock and the event target capability are held.
//
// This is used to implement the "Single-Writer Mutex" pattern, where a mutex is
// used to guard off-thread access to a value only mutated on a single thread,
// while not requiring the mutex for reads on that thread.
//
// There are no `AutoLock` helper types, instead the lock needs to be acquired
// using the normal locking mechanism (e.g. `MutexAutoLock lock(cap.Lock())`),
// followed by the relevant call to `NoteLockHeld` or `NoteExclusiveAccess`.
template <typename TargetT, typename LockT>
class MOZ_CAPABILITY("combo (event target + mutex)")
    EventTargetAndLockCapability {
 public:
  EventTargetAndLockCapability(const char* aName, TargetT* aTarget)
      : mLock(aName), mTarget(aTarget) {}

  // Get access to the internal Lock. This can be used both to have values
  // normally guarded by this lock, as well as to acquire the lock as-needed.
  LockT& Lock() MOZ_RETURN_CAPABILITY(mLock) { return mLock; }

  // Get access to the internal EventTargetCapability. This can be used both to
  // have values normally guarded by this capability, as well as to assert the
  // capability as needed.
  const mozilla::EventTargetCapability<TargetT>& Target() const
      MOZ_RETURN_CAPABILITY(mTarget) {
    return mTarget;
  }

  // Note that we're on the event target, and thus have shared (read-only)
  // access to values guarded by the EventTargetAndLockCapability for the
  // thread-safety analysis.
  void NoteOnTarget() const MOZ_REQUIRES(mTarget)
      MOZ_ASSERT_SHARED_CAPABILITY(this) {}

  // Note that we're holding the lock, and thus have shared (read-only) access
  // to values guarded by the EventTargetAndLockCapability for the thread-safety
  // analysis.
  void NoteLockHeld() const MOZ_REQUIRES(mLock)
      MOZ_ASSERT_SHARED_CAPABILITY(this) {}

  // Note that we're holding the lock while on the event target, and thus have
  // exclusive (mutable) access to values guarded by the
  // EventTargetAndLockCapability for the thread-safety analysis.
  void NoteExclusiveAccess() const MOZ_REQUIRES(mTarget, mLock)
      MOZ_ASSERT_CAPABILITY(this) {}

  // If you have previously called one of the above `Note` methods in the
  // current function scope, then have acquired `Mutex()` and now want to
  // `NoteExclusiveAccess()`, this method can be called to clear the thread
  // safety analysis's understanding that the EventTargetAndLockCapability is
  // currently held.
  void ClearCurrentAccess() const
      MOZ_RELEASE_GENERIC(this) MOZ_NO_THREAD_SAFETY_ANALYSIS {}

 private:
  LockT mLock;
  mozilla::EventTargetCapability<TargetT> mTarget;
};

}  // namespace mozilla

#endif  // mozilla_EventTargetAndLockCapability_h