[clang] bbb3baf - Thread safety analysis: Improve documentation for scoped capabilities
Aaron Puchert via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 6 11:38:23 PDT 2020
Author: Aaron Puchert
Date: 2020-09-06T20:37:42+02:00
New Revision: bbb3baf6205c54231257f64fd18661a13a5c97ee
URL: https://github.com/llvm/llvm-project/commit/bbb3baf6205c54231257f64fd18661a13a5c97ee
DIFF: https://github.com/llvm/llvm-project/commit/bbb3baf6205c54231257f64fd18661a13a5c97ee.diff
LOG: Thread safety analysis: Improve documentation for scoped capabilities
They are for more powerful than the current documentation implies, this
adds
* adopting a lock,
* deferring a lock,
* manually unlocking the scoped capability,
* relocking the scoped capability, possibly in a different mode,
* try-relocking the scoped capability.
Also there is now a generic explanation how attributes on scoped
capabilities work. There has been confusion in the past about how to
annotate them (see e.g. PR33504), hopefully this clears things up.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D87066
Added:
Modified:
clang/docs/ThreadSafetyAnalysis.rst
Removed:
################################################################################
diff --git a/clang/docs/ThreadSafetyAnalysis.rst b/clang/docs/ThreadSafetyAnalysis.rst
index e6ce0e04e70a..e4a3342c02bd 100644
--- a/clang/docs/ThreadSafetyAnalysis.rst
+++ b/clang/docs/ThreadSafetyAnalysis.rst
@@ -402,6 +402,13 @@ the destructor. Such classes require special handling because the constructor
and destructor refer to the capability via
diff erent names; see the
``MutexLocker`` class in :ref:`mutexheader`, below.
+Scoped capabilities are treated as capabilities that are implicitly acquired
+on construction and released on destruction. They are associated with
+the set of (regular) capabilities named in thread safety attributes on the
+constructor. Acquire-type attributes on other member functions are treated as
+applying to that set of associated capabilities, while ``RELEASE`` implies that
+a function releases all associated capabilities in whatever mode they're held.
+
TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
---------------------------------------------------------
@@ -886,19 +893,78 @@ implementation.
const Mutex& operator!() const { return *this; }
};
+ // Tag types for selecting a constructor.
+ struct adopt_lock_t {} inline constexpr adopt_lock = {};
+ struct defer_lock_t {} inline constexpr defer_lock = {};
+ struct shared_lock_t {} inline constexpr shared_lock = {};
// MutexLocker is an RAII class that acquires a mutex in its constructor, and
// releases it in its destructor.
class SCOPED_CAPABILITY MutexLocker {
private:
Mutex* mut;
+ bool locked;
public:
- MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu) {
+ // Acquire mu, implicitly acquire *this and associate it with mu.
+ MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu), locked(true) {
mu->Lock();
}
+
+ // Assume mu is held, implicitly acquire *this and associate it with mu.
+ MutexLocker(Mutex *mu, adopt_lock_t) REQUIRES(mu) : mut(mu), locked(true) {}
+
+ // Acquire mu in shared mode, implicitly acquire *this and associate it with mu.
+ MutexLocker(Mutex *mu, shared_lock_t) ACQUIRE_SHARED(mu) : mut(mu), locked(true) {
+ mu->ReaderLock();
+ }
+
+ // Assume mu is held in shared mode, implicitly acquire *this and associate it with mu.
+ MutexLocker(Mutex *mu, adopt_lock_t, shared_lock_t) REQUIRES_SHARED(mu)
+ : mut(mu), locked(true) {}
+
+ // Assume mu is not held, implicitly acquire *this and associate it with mu.
+ MutexLocker(Mutex *mu, defer_lock_t) EXCLUDES(mu) : mut(mu), locked(false) {}
+
+ // Release *this and all associated mutexes, if they are still held.
+ // There is no warning if the scope was already unlocked before.
~MutexLocker() RELEASE() {
+ if (locked)
+ mut->GenericUnlock();
+ }
+
+ // Acquire all associated mutexes exclusively.
+ void Lock() ACQUIRE() {
+ mut->Lock();
+ locked = true;
+ }
+
+ // Try to acquire all associated mutexes exclusively.
+ bool TryLock() TRY_ACQUIRE(true) {
+ return locked = mut->TryLock();
+ }
+
+ // Acquire all associated mutexes in shared mode.
+ void ReaderLock() ACQUIRE_SHARED() {
+ mut->ReaderLock();
+ locked = true;
+ }
+
+ // Try to acquire all associated mutexes in shared mode.
+ bool ReaderTryLock() TRY_ACQUIRE_SHARED(true) {
+ return locked = mut->ReaderTryLock();
+ }
+
+ // Release all associated mutexes. Warn on double unlock.
+ void Unlock() RELEASE() {
mut->Unlock();
+ locked = false;
+ }
+
+ // Release all associated mutexes. Warn on double unlock.
+ void ReaderUnlock() RELEASE() {
+ mut->ReaderUnlock();
+ locked = false;
}
};
More information about the cfe-commits
mailing list