]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/folly/folly/synchronization/detail/ProxyLockable.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / third-party / folly / folly / synchronization / detail / ProxyLockable.h
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5
6 #pragma once
7
8 #include <folly/Optional.h>
9
10 #include <mutex>
11
12 namespace folly {
13 namespace detail {
14
15 /**
16 * ProxyLockable is a "concept" that is used usually for mutexes that don't
17 * return void, but rather a proxy object that contains data that should be
18 * passed to the unlock function.
19 *
20 * This is in contrast with the normal Lockable concept that imposes no
21 * requirement on the return type of lock(), and requires an unlock() with no
22 * parameters. Here we require that lock() returns non-void and that unlock()
23 * accepts the return type of lock() by value, rvalue-reference or
24 * const-reference
25 *
26 * Here we define two classes, that can be used by the top level to implement
27 * specializations for std::unique_lock and std::lock_guard. Both
28 * ProxyLockableUniqueLock and ProxyLockableLockGuard implement the entire
29 * interface of std::unique_lock and std::lock_guard respectively
30 */
31 template <typename Mutex>
32 class ProxyLockableUniqueLock {
33 public:
34 using mutex_type = Mutex;
35 using proxy_type =
36 _t<std::decay<decltype(std::declval<mutex_type>().lock())>>;
37
38 /**
39 * Default constructor initializes the unique_lock to an empty state
40 */
41 ProxyLockableUniqueLock() = default;
42
43 /**
44 * Destructor releases the mutex if it is locked
45 */
46 ~ProxyLockableUniqueLock();
47
48 /**
49 * Move constructor and move assignment operators take state from the other
50 * lock
51 */
52 ProxyLockableUniqueLock(ProxyLockableUniqueLock&& other) noexcept;
53 ProxyLockableUniqueLock& operator=(ProxyLockableUniqueLock&&) noexcept;
54
55 /**
56 * Locks the mutex, blocks until the mutex can be acquired.
57 *
58 * The mutex is guaranteed to be acquired after this function returns.
59 */
60 ProxyLockableUniqueLock(mutex_type&) noexcept;
61
62 /**
63 * Explicit locking constructors to control how the lock() method is called
64 *
65 * std::defer_lock_t causes the mutex to get tracked, but not locked
66 * std::try_to_lock_t causes try_lock() to be called. The current object is
67 * converts to true if the lock was successful
68 */
69 ProxyLockableUniqueLock(mutex_type& mtx, std::defer_lock_t) noexcept;
70 ProxyLockableUniqueLock(mutex_type& mtx, std::try_to_lock_t);
71
72 /**
73 * Timed locking constructors
74 */
75 template <typename Rep, typename Period>
76 ProxyLockableUniqueLock(
77 mutex_type& mtx,
78 const std::chrono::duration<Rep, Period>& duration);
79 template <typename Clock, typename Duration>
80 ProxyLockableUniqueLock(
81 mutex_type& mtx,
82 const std::chrono::time_point<Clock, Duration>& time);
83
84 /**
85 * Lock and unlock methods
86 *
87 * lock() and try_lock() throw if the mutex is already locked, or there is
88 * no mutex. unlock() throws if there is no mutex or if the mutex was not
89 * locked
90 */
91 void lock();
92 void unlock();
93 bool try_lock();
94
95 /**
96 * Timed locking methods
97 *
98 * These throw if there was no mutex, or if the mutex was already locked
99 */
100 template <typename Rep, typename Period>
101 bool try_lock_for(const std::chrono::duration<Rep, Period>& duration);
102 template <typename Clock, typename Duration>
103 bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time);
104
105 /**
106 * Swap this unique lock with the other one
107 */
108 void swap(ProxyLockableUniqueLock& other) noexcept;
109
110 /**
111 * Returns true if the unique lock contains a lock and also has acquired an
112 * exclusive lock successfully
113 */
114 bool owns_lock() const noexcept;
115 explicit operator bool() const noexcept;
116
117 /**
118 * mutex() return a pointer to the mutex if there is a contained mutex and
119 * proxy() returns a pointer to the contained proxy if the mutex is locked
120 *
121 * If the unique lock was not constructed with a mutex, then mutex() returns
122 * nullptr. If the mutex is not locked, then proxy() returns nullptr
123 */
124 mutex_type* mutex() const noexcept;
125 proxy_type* proxy() const noexcept;
126
127 private:
128 friend class ProxyLockableTest;
129
130 /**
131 * If the optional has a value, the mutex is locked, if it is empty, it is
132 * not
133 */
134 mutable folly::Optional<proxy_type> proxy_{};
135 mutex_type* mutex_{nullptr};
136 };
137
138 template <typename Mutex>
139 class ProxyLockableLockGuard : private ProxyLockableUniqueLock<Mutex> {
140 public:
141 using mutex_type = Mutex;
142
143 /**
144 * Constructor locks the mutex, and destructor unlocks
145 */
146 ProxyLockableLockGuard(mutex_type& mtx);
147 ~ProxyLockableLockGuard() = default;
148
149 /**
150 * This class is not movable or assignable
151 *
152 * For more complicated usecases, consider the UniqueLock variant, which
153 * provides more options
154 */
155 ProxyLockableLockGuard(const ProxyLockableLockGuard&) = delete;
156 ProxyLockableLockGuard(ProxyLockableLockGuard&&) = delete;
157 ProxyLockableLockGuard& operator=(ProxyLockableLockGuard&&) = delete;
158 ProxyLockableLockGuard& operator=(const ProxyLockableLockGuard&) = delete;
159 };
160
161 } // namespace detail
162 } // namespace folly
163
164 #include <folly/synchronization/detail/ProxyLockable-inl.h>