@@ -209,21 +209,21 @@ must be held on entry to the function, *and must still be held on exit*.
209
209
}
210
210
211
211
212
- ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...)
213
- --------------------------------------------------------------------
212
+ ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...), RELEASE_GENERIC(...)
213
+ ------------------------------------------------------------------------------------------
214
214
215
215
*Previously *: ``EXCLUSIVE_LOCK_FUNCTION ``, ``SHARED_LOCK_FUNCTION ``,
216
216
``UNLOCK_FUNCTION ``
217
217
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 ``) .
222
222
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 .
227
227
228
228
.. code-block :: c++
229
229
@@ -402,6 +402,13 @@ the destructor. Such classes require special handling because the constructor
402
402
and destructor refer to the capability via different names; see the
403
403
``MutexLocker `` class in :ref: `mutexheader `, below.
404
404
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
+
405
412
406
413
TRY_ACQUIRE(<bool>, ...), TRY_ACQUIRE_SHARED(<bool>, ...)
407
414
---------------------------------------------------------
@@ -414,6 +421,26 @@ The first argument must be ``true`` or ``false``, to specify which return value
414
421
indicates success, and the remaining arguments are interpreted in the same way
415
422
as ``ACQUIRE ``. See :ref: `mutexheader `, below, for example uses.
416
423
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
+
417
444
418
445
ASSERT_CAPABILITY(...) and ASSERT_SHARED_CAPABILITY(...)
419
446
--------------------------------------------------------
@@ -800,6 +827,9 @@ implementation.
800
827
#define RELEASE_SHARED(...) \
801
828
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
802
829
830
+ #define RELEASE_GENERIC(...) \
831
+ THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
832
+
803
833
#define TRY_ACQUIRE(...) \
804
834
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
805
835
@@ -844,6 +874,9 @@ implementation.
844
874
// Release/unlock a shared mutex.
845
875
void ReaderUnlock() RELEASE_SHARED();
846
876
877
+ // Generic unlock, can unlock exclusive and shared mutexes.
878
+ void GenericUnlock() RELEASE_GENERIC();
879
+
847
880
// Try to acquire the mutex. Returns true on success, and false on failure.
848
881
bool TryLock() TRY_ACQUIRE(true);
849
882
@@ -860,19 +893,78 @@ implementation.
860
893
const Mutex& operator!() const { return *this; }
861
894
};
862
895
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 = {};
863
900
864
901
// MutexLocker is an RAII class that acquires a mutex in its constructor, and
865
902
// releases it in its destructor.
866
903
class SCOPED_CAPABILITY MutexLocker {
867
904
private:
868
905
Mutex* mut;
906
+ bool locked;
869
907
870
908
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) {
872
911
mu->Lock();
873
912
}
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.
874
931
~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() {
875
960
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;
876
968
}
877
969
};
878
970
0 commit comments