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
|