aaronpuchert created this revision.
aaronpuchert added a reviewer: aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
aaronpuchert requested review of this revision.

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.

There has been confusion in the past about how to annotate scoped
capabilities (see e.g. PR33504), hopefully this clears things up.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87066

Files:
  clang/docs/ThreadSafetyAnalysis.rst


Index: clang/docs/ThreadSafetyAnalysis.rst
===================================================================
--- clang/docs/ThreadSafetyAnalysis.rst
+++ clang/docs/ThreadSafetyAnalysis.rst
@@ -402,6 +402,9 @@
 and destructor refer to the capability via different names; see the
 ``MutexLocker`` class in :ref:`mutexheader`, below.
 
+Scoped capabilities are associated with a set of (proper) capabilities on
+construction, every subsequent operation is forwarded to that set.
+
 
 TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
 ---------------------------------------------------------
@@ -886,6 +889,9 @@
     const Mutex& operator!() const { return *this; }
   };
 
+  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.
@@ -894,12 +900,49 @@
     Mutex* mut;
 
   public:
+    // Acquires mu, implicitly acquires *this and connects it to mu.
     MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu) {
       mu->Lock();
     }
+    // Assumes mu is held, implicitly acquires *this and connects it to mu.
+    MutexLocker(t_mutex &mu, adopt_lock_t) REQUIRES(mu) : mut(mu) {}
+
+    // Acquires mu in shared mode, implicitly acquires *this and connects to 
mu.
+    MutexLocker(Mutex *mu, shared_lock_t) ACQUIRE_SHARED(mu) : mut(mu) {
+      mu->ReaderLock();
+    }
+    // Assumes mu is held in shared mode, implicitly acquires *this and
+    // connects it to mu.
+    MutexLocker(t_mutex &mu, adopt_lock_t, shared_lock_t) REQUIRES_SHARED(mu) 
: mut(mu) {}
+
+    // Assumes mu is not held, implicitly acquires *this and connects it to mu.
+    MutexLocker(t_mutex &mu, defer_lock_t) EXCLUDES(mu) : mut(mu) {}
+
+    // Releases *this and all underlying capabilities, if they are still held.
+    // There is no warning on double unlock.
     ~MutexLocker() RELEASE() {
+      mut->GenericUnlock();
+    }
+
+    // (Re-)Acquire all underlying capabilities exclusively.
+    void Lock() ACQUIRE() {
+      mut->Lock();
+    }
+
+    // (Re-)Acquire all underlying capabilities in shared mode.
+    void ReaderLock() ACQUIRE_SHARED() {
+      mut->ReaderLock();
+    }
+
+    // Releases *this and all underlying capabilities. Warns on double unlock.
+    void Unlock() RELEASE() {
       mut->Unlock();
     }
+
+    // Releases *this and all underlying capabilities. Warns on double unlock.
+    void ReaderUnlock() RELEASE() {
+      mut->ReaderUnlock();
+    }
   };
 
 


Index: clang/docs/ThreadSafetyAnalysis.rst
===================================================================
--- clang/docs/ThreadSafetyAnalysis.rst
+++ clang/docs/ThreadSafetyAnalysis.rst
@@ -402,6 +402,9 @@
 and destructor refer to the capability via different names; see the
 ``MutexLocker`` class in :ref:`mutexheader`, below.
 
+Scoped capabilities are associated with a set of (proper) capabilities on
+construction, every subsequent operation is forwarded to that set.
+
 
 TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
 ---------------------------------------------------------
@@ -886,6 +889,9 @@
     const Mutex& operator!() const { return *this; }
   };
 
+  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.
@@ -894,12 +900,49 @@
     Mutex* mut;
 
   public:
+    // Acquires mu, implicitly acquires *this and connects it to mu.
     MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu) {
       mu->Lock();
     }
+    // Assumes mu is held, implicitly acquires *this and connects it to mu.
+    MutexLocker(t_mutex &mu, adopt_lock_t) REQUIRES(mu) : mut(mu) {}
+
+    // Acquires mu in shared mode, implicitly acquires *this and connects to mu.
+    MutexLocker(Mutex *mu, shared_lock_t) ACQUIRE_SHARED(mu) : mut(mu) {
+      mu->ReaderLock();
+    }
+    // Assumes mu is held in shared mode, implicitly acquires *this and
+    // connects it to mu.
+    MutexLocker(t_mutex &mu, adopt_lock_t, shared_lock_t) REQUIRES_SHARED(mu) : mut(mu) {}
+
+    // Assumes mu is not held, implicitly acquires *this and connects it to mu.
+    MutexLocker(t_mutex &mu, defer_lock_t) EXCLUDES(mu) : mut(mu) {}
+
+    // Releases *this and all underlying capabilities, if they are still held.
+    // There is no warning on double unlock.
     ~MutexLocker() RELEASE() {
+      mut->GenericUnlock();
+    }
+
+    // (Re-)Acquire all underlying capabilities exclusively.
+    void Lock() ACQUIRE() {
+      mut->Lock();
+    }
+
+    // (Re-)Acquire all underlying capabilities in shared mode.
+    void ReaderLock() ACQUIRE_SHARED() {
+      mut->ReaderLock();
+    }
+
+    // Releases *this and all underlying capabilities. Warns on double unlock.
+    void Unlock() RELEASE() {
       mut->Unlock();
     }
+
+    // Releases *this and all underlying capabilities. Warns on double unlock.
+    void ReaderUnlock() RELEASE() {
+      mut->ReaderUnlock();
+    }
   };
 
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to