xref: /aosp_15_r20/external/libchrome/base/synchronization/lock.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_SYNCHRONIZATION_LOCK_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_SYNCHRONIZATION_LOCK_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include "base/base_export.h"
9*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock_impl.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
13*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
14*635a8641SAndroid Build Coastguard Worker 
15*635a8641SAndroid Build Coastguard Worker namespace base {
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker // A convenient wrapper for an OS specific critical section.  The only real
18*635a8641SAndroid Build Coastguard Worker // intelligence in this class is in debug mode for the support for the
19*635a8641SAndroid Build Coastguard Worker // AssertAcquired() method.
20*635a8641SAndroid Build Coastguard Worker class BASE_EXPORT Lock {
21*635a8641SAndroid Build Coastguard Worker  public:
22*635a8641SAndroid Build Coastguard Worker #if !DCHECK_IS_ON()
23*635a8641SAndroid Build Coastguard Worker    // Optimized wrapper implementation
Lock()24*635a8641SAndroid Build Coastguard Worker   Lock() : lock_() {}
~Lock()25*635a8641SAndroid Build Coastguard Worker   ~Lock() {}
Acquire()26*635a8641SAndroid Build Coastguard Worker   void Acquire() { lock_.Lock(); }
Release()27*635a8641SAndroid Build Coastguard Worker   void Release() { lock_.Unlock(); }
28*635a8641SAndroid Build Coastguard Worker 
29*635a8641SAndroid Build Coastguard Worker   // If the lock is not held, take it and return true. If the lock is already
30*635a8641SAndroid Build Coastguard Worker   // held by another thread, immediately return false. This must not be called
31*635a8641SAndroid Build Coastguard Worker   // by a thread already holding the lock (what happens is undefined and an
32*635a8641SAndroid Build Coastguard Worker   // assertion may fail).
Try()33*635a8641SAndroid Build Coastguard Worker   bool Try() { return lock_.Try(); }
34*635a8641SAndroid Build Coastguard Worker 
35*635a8641SAndroid Build Coastguard Worker   // Null implementation if not debug.
AssertAcquired()36*635a8641SAndroid Build Coastguard Worker   void AssertAcquired() const {}
37*635a8641SAndroid Build Coastguard Worker #else
38*635a8641SAndroid Build Coastguard Worker   Lock();
39*635a8641SAndroid Build Coastguard Worker   ~Lock();
40*635a8641SAndroid Build Coastguard Worker 
41*635a8641SAndroid Build Coastguard Worker   // NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if
42*635a8641SAndroid Build Coastguard Worker   // a thread attempts to acquire the lock a second time (while already holding
43*635a8641SAndroid Build Coastguard Worker   // it).
44*635a8641SAndroid Build Coastguard Worker   void Acquire() {
45*635a8641SAndroid Build Coastguard Worker     lock_.Lock();
46*635a8641SAndroid Build Coastguard Worker     CheckUnheldAndMark();
47*635a8641SAndroid Build Coastguard Worker   }
48*635a8641SAndroid Build Coastguard Worker   void Release() {
49*635a8641SAndroid Build Coastguard Worker     CheckHeldAndUnmark();
50*635a8641SAndroid Build Coastguard Worker     lock_.Unlock();
51*635a8641SAndroid Build Coastguard Worker   }
52*635a8641SAndroid Build Coastguard Worker 
53*635a8641SAndroid Build Coastguard Worker   bool Try() {
54*635a8641SAndroid Build Coastguard Worker     bool rv = lock_.Try();
55*635a8641SAndroid Build Coastguard Worker     if (rv) {
56*635a8641SAndroid Build Coastguard Worker       CheckUnheldAndMark();
57*635a8641SAndroid Build Coastguard Worker     }
58*635a8641SAndroid Build Coastguard Worker     return rv;
59*635a8641SAndroid Build Coastguard Worker   }
60*635a8641SAndroid Build Coastguard Worker 
61*635a8641SAndroid Build Coastguard Worker   void AssertAcquired() const;
62*635a8641SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
63*635a8641SAndroid Build Coastguard Worker 
64*635a8641SAndroid Build Coastguard Worker   // Whether Lock mitigates priority inversion when used from different thread
65*635a8641SAndroid Build Coastguard Worker   // priorities.
HandlesMultipleThreadPriorities()66*635a8641SAndroid Build Coastguard Worker   static bool HandlesMultipleThreadPriorities() {
67*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
68*635a8641SAndroid Build Coastguard Worker     // Windows mitigates priority inversion by randomly boosting the priority of
69*635a8641SAndroid Build Coastguard Worker     // ready threads.
70*635a8641SAndroid Build Coastguard Worker     // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
71*635a8641SAndroid Build Coastguard Worker     return true;
72*635a8641SAndroid Build Coastguard Worker #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
73*635a8641SAndroid Build Coastguard Worker     // POSIX mitigates priority inversion by setting the priority of a thread
74*635a8641SAndroid Build Coastguard Worker     // holding a Lock to the maximum priority of any other thread waiting on it.
75*635a8641SAndroid Build Coastguard Worker     return internal::LockImpl::PriorityInheritanceAvailable();
76*635a8641SAndroid Build Coastguard Worker #else
77*635a8641SAndroid Build Coastguard Worker #error Unsupported platform
78*635a8641SAndroid Build Coastguard Worker #endif
79*635a8641SAndroid Build Coastguard Worker   }
80*635a8641SAndroid Build Coastguard Worker 
81*635a8641SAndroid Build Coastguard Worker   // Both Windows and POSIX implementations of ConditionVariable need to be
82*635a8641SAndroid Build Coastguard Worker   // able to see our lock and tweak our debugging counters, as they release and
83*635a8641SAndroid Build Coastguard Worker   // acquire locks inside of their condition variable APIs.
84*635a8641SAndroid Build Coastguard Worker   friend class ConditionVariable;
85*635a8641SAndroid Build Coastguard Worker 
86*635a8641SAndroid Build Coastguard Worker  private:
87*635a8641SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
88*635a8641SAndroid Build Coastguard Worker   // Members and routines taking care of locks assertions.
89*635a8641SAndroid Build Coastguard Worker   // Note that this checks for recursive locks and allows them
90*635a8641SAndroid Build Coastguard Worker   // if the variable is set.  This is allowed by the underlying implementation
91*635a8641SAndroid Build Coastguard Worker   // on windows but not on Posix, so we're doing unneeded checks on Posix.
92*635a8641SAndroid Build Coastguard Worker   // It's worth it to share the code.
93*635a8641SAndroid Build Coastguard Worker   void CheckHeldAndUnmark();
94*635a8641SAndroid Build Coastguard Worker   void CheckUnheldAndMark();
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker   // All private data is implicitly protected by lock_.
97*635a8641SAndroid Build Coastguard Worker   // Be VERY careful to only access members under that lock.
98*635a8641SAndroid Build Coastguard Worker   base::PlatformThreadRef owning_thread_ref_;
99*635a8641SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker   // Platform specific underlying lock implementation.
102*635a8641SAndroid Build Coastguard Worker   internal::LockImpl lock_;
103*635a8641SAndroid Build Coastguard Worker 
104*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(Lock);
105*635a8641SAndroid Build Coastguard Worker };
106*635a8641SAndroid Build Coastguard Worker 
107*635a8641SAndroid Build Coastguard Worker // A helper class that acquires the given Lock while the AutoLock is in scope.
108*635a8641SAndroid Build Coastguard Worker class AutoLock {
109*635a8641SAndroid Build Coastguard Worker  public:
110*635a8641SAndroid Build Coastguard Worker   struct AlreadyAcquired {};
111*635a8641SAndroid Build Coastguard Worker 
AutoLock(Lock & lock)112*635a8641SAndroid Build Coastguard Worker   explicit AutoLock(Lock& lock) : lock_(lock) {
113*635a8641SAndroid Build Coastguard Worker     lock_.Acquire();
114*635a8641SAndroid Build Coastguard Worker   }
115*635a8641SAndroid Build Coastguard Worker 
AutoLock(Lock & lock,const AlreadyAcquired &)116*635a8641SAndroid Build Coastguard Worker   AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
117*635a8641SAndroid Build Coastguard Worker     lock_.AssertAcquired();
118*635a8641SAndroid Build Coastguard Worker   }
119*635a8641SAndroid Build Coastguard Worker 
~AutoLock()120*635a8641SAndroid Build Coastguard Worker   ~AutoLock() {
121*635a8641SAndroid Build Coastguard Worker     lock_.AssertAcquired();
122*635a8641SAndroid Build Coastguard Worker     lock_.Release();
123*635a8641SAndroid Build Coastguard Worker   }
124*635a8641SAndroid Build Coastguard Worker 
125*635a8641SAndroid Build Coastguard Worker  private:
126*635a8641SAndroid Build Coastguard Worker   Lock& lock_;
127*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(AutoLock);
128*635a8641SAndroid Build Coastguard Worker };
129*635a8641SAndroid Build Coastguard Worker 
130*635a8641SAndroid Build Coastguard Worker // AutoUnlock is a helper that will Release() the |lock| argument in the
131*635a8641SAndroid Build Coastguard Worker // constructor, and re-Acquire() it in the destructor.
132*635a8641SAndroid Build Coastguard Worker class AutoUnlock {
133*635a8641SAndroid Build Coastguard Worker  public:
AutoUnlock(Lock & lock)134*635a8641SAndroid Build Coastguard Worker   explicit AutoUnlock(Lock& lock) : lock_(lock) {
135*635a8641SAndroid Build Coastguard Worker     // We require our caller to have the lock.
136*635a8641SAndroid Build Coastguard Worker     lock_.AssertAcquired();
137*635a8641SAndroid Build Coastguard Worker     lock_.Release();
138*635a8641SAndroid Build Coastguard Worker   }
139*635a8641SAndroid Build Coastguard Worker 
~AutoUnlock()140*635a8641SAndroid Build Coastguard Worker   ~AutoUnlock() {
141*635a8641SAndroid Build Coastguard Worker     lock_.Acquire();
142*635a8641SAndroid Build Coastguard Worker   }
143*635a8641SAndroid Build Coastguard Worker 
144*635a8641SAndroid Build Coastguard Worker  private:
145*635a8641SAndroid Build Coastguard Worker   Lock& lock_;
146*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
147*635a8641SAndroid Build Coastguard Worker };
148*635a8641SAndroid Build Coastguard Worker 
149*635a8641SAndroid Build Coastguard Worker }  // namespace base
150*635a8641SAndroid Build Coastguard Worker 
151*635a8641SAndroid Build Coastguard Worker #endif  // BASE_SYNCHRONIZATION_LOCK_H_
152