@@ -209,21 +209,21 @@ must be held on entry to the function, *and must still be held on exit*.
209209 }
210210
211211
212- ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...)
213- --------------------------------------------------------------------
212+ ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...), RELEASE_GENERIC(...)
213+ ------------------------------------------------------------------------------------------
214214
215215*Previously *: ``EXCLUSIVE_LOCK_FUNCTION ``, ``SHARED_LOCK_FUNCTION ``,
216216``UNLOCK_FUNCTION ``
217217
218- ``ACQUIRE `` is an attribute on functions or methods, which
219- declares that the function acquires a capability, but does not release it. The
220- caller must not hold the given capability on entry, and it will hold the
221- capability on exit. ``ACQUIRE_SHARED `` is similar .
218+ ``ACQUIRE `` and `` ACQUIRE_SHARED `` are attributes on functions or methods
219+ declaring that the function acquires a capability, but does not release it.
220+ The given capability must not be held on entry, and will be held on exit
221+ (exclusively for `` ACQUIRE ``, shared for ``ACQUIRE_SHARED ``) .
222222
223- ``RELEASE `` and ``RELEASE_SHARED `` declare that the function releases the given
224- capability. The caller must hold the capability on entry, and will no longer
225- hold it on exit. It does not matter whether the given capability is shared or
226- exclusive .
223+ ``RELEASE ``, `` RELEASE_SHARED ``, and ``RELEASE_GENERIC `` declare that the
224+ function releases the given capability. The capability must be held on entry
225+ (exclusively for `` RELEASE ``, shared for `` RELEASE_SHARED ``, exclusively or
226+ shared for `` RELEASE_GENERIC ``), and will no longer be held on exit .
227227
228228.. code-block :: c++
229229
@@ -402,6 +402,13 @@ the destructor. Such classes require special handling because the constructor
402402and destructor refer to the capability via different names; see the
403403``MutexLocker `` class in :ref: `mutexheader `, below.
404404
405+ Scoped capabilities are treated as capabilities that are implicitly acquired
406+ on construction and released on destruction. They are associated with
407+ the set of (regular) capabilities named in thread safety attributes on the
408+ constructor. Acquire-type attributes on other member functions are treated as
409+ applying to that set of associated capabilities, while ``RELEASE `` implies that
410+ a function releases all associated capabilities in whatever mode they're held.
411+
405412
406413TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
407414---------------------------------------------------------
@@ -414,6 +421,26 @@ The first argument must be ``true`` or ``false``, to specify which return value
414421indicates success, and the remaining arguments are interpreted in the same way
415422as ``ACQUIRE ``. See :ref: `mutexheader `, below, for example uses.
416423
424+ Because the analysis doesn't support conditional locking, a capability is
425+ treated as acquired after the first branch on the return value of a try-acquire
426+ function.
427+
428+ .. code-block :: c++
429+
430+ Mutex mu;
431+ int a GUARDED_BY(mu);
432+
433+ void foo() {
434+ bool success = mu.TryLock();
435+ a = 0; // Warning, mu is not locked.
436+ if (success) {
437+ a = 0; // Ok.
438+ mu.Unlock();
439+ } else {
440+ a = 0; // Warning, mu is not locked.
441+ }
442+ }
443+
417444
418445ASSERT_CAPABILITY(...) and ASSERT_SHARED_CAPABILITY(...)
419446--------------------------------------------------------
@@ -800,6 +827,9 @@ implementation.
800827 #define RELEASE_SHARED(...) \
801828 THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
802829
830+ #define RELEASE_GENERIC(...) \
831+ THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
832+
803833 #define TRY_ACQUIRE(...) \
804834 THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
805835
@@ -844,6 +874,9 @@ implementation.
844874 // Release/unlock a shared mutex.
845875 void ReaderUnlock() RELEASE_SHARED();
846876
877+ // Generic unlock, can unlock exclusive and shared mutexes.
878+ void GenericUnlock() RELEASE_GENERIC();
879+
847880 // Try to acquire the mutex. Returns true on success, and false on failure.
848881 bool TryLock() TRY_ACQUIRE(true);
849882
@@ -860,19 +893,78 @@ implementation.
860893 const Mutex& operator!() const { return *this; }
861894 };
862895
896+ // Tag types for selecting a constructor.
897+ struct adopt_lock_t {} inline constexpr adopt_lock = {};
898+ struct defer_lock_t {} inline constexpr defer_lock = {};
899+ struct shared_lock_t {} inline constexpr shared_lock = {};
863900
864901 // MutexLocker is an RAII class that acquires a mutex in its constructor, and
865902 // releases it in its destructor.
866903 class SCOPED_CAPABILITY MutexLocker {
867904 private:
868905 Mutex* mut;
906+ bool locked;
869907
870908 public:
871- MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu) {
909+ // Acquire mu, implicitly acquire *this and associate it with mu.
910+ MutexLocker(Mutex *mu) ACQUIRE(mu) : mut(mu), locked(true) {
872911 mu->Lock();
873912 }
913+
914+ // Assume mu is held, implicitly acquire *this and associate it with mu.
915+ MutexLocker(Mutex *mu, adopt_lock_t) REQUIRES(mu) : mut(mu), locked(true) {}
916+
917+ // Acquire mu in shared mode, implicitly acquire *this and associate it with mu.
918+ MutexLocker(Mutex *mu, shared_lock_t) ACQUIRE_SHARED(mu) : mut(mu), locked(true) {
919+ mu->ReaderLock();
920+ }
921+
922+ // Assume mu is held in shared mode, implicitly acquire *this and associate it with mu.
923+ MutexLocker(Mutex *mu, adopt_lock_t, shared_lock_t) REQUIRES_SHARED(mu)
924+ : mut(mu), locked(true) {}
925+
926+ // Assume mu is not held, implicitly acquire *this and associate it with mu.
927+ MutexLocker(Mutex *mu, defer_lock_t) EXCLUDES(mu) : mut(mu), locked(false) {}
928+
929+ // Release *this and all associated mutexes, if they are still held.
930+ // There is no warning if the scope was already unlocked before.
874931 ~MutexLocker() RELEASE() {
932+ if (locked)
933+ mut->GenericUnlock();
934+ }
935+
936+ // Acquire all associated mutexes exclusively.
937+ void Lock() ACQUIRE() {
938+ mut->Lock();
939+ locked = true;
940+ }
941+
942+ // Try to acquire all associated mutexes exclusively.
943+ bool TryLock() TRY_ACQUIRE(true) {
944+ return locked = mut->TryLock();
945+ }
946+
947+ // Acquire all associated mutexes in shared mode.
948+ void ReaderLock() ACQUIRE_SHARED() {
949+ mut->ReaderLock();
950+ locked = true;
951+ }
952+
953+ // Try to acquire all associated mutexes in shared mode.
954+ bool ReaderTryLock() TRY_ACQUIRE_SHARED(true) {
955+ return locked = mut->ReaderTryLock();
956+ }
957+
958+ // Release all associated mutexes. Warn on double unlock.
959+ void Unlock() RELEASE() {
875960 mut->Unlock();
961+ locked = false;
962+ }
963+
964+ // Release all associated mutexes. Warn on double unlock.
965+ void ReaderUnlock() RELEASE() {
966+ mut->ReaderUnlock();
967+ locked = false;
876968 }
877969 };
878970
0 commit comments