2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <folly/fibers/GenericBaton.h>
28 * Like mutex but allows timed_lock in addition to lock and try_lock.
30 template <typename BatonType>
34 pthread_spin_init(&lock_, PTHREAD_PROCESS_PRIVATE);
38 pthread_spin_destroy(&lock_);
41 TimedMutex(const TimedMutex& rhs) = delete;
42 TimedMutex& operator=(const TimedMutex& rhs) = delete;
43 TimedMutex(TimedMutex&& rhs) = delete;
44 TimedMutex& operator=(TimedMutex&& rhs) = delete;
46 // Lock the mutex. The thread / fiber is blocked until the mutex is free
49 // Lock the mutex. The thread / fiber will be blocked for a time duration.
51 // @return true if the mutex was locked, false otherwise
52 template <typename Rep, typename Period>
53 bool timed_lock(const std::chrono::duration<Rep, Period>& duration);
55 // Try to obtain lock without blocking the thread or fiber
58 // Unlock the mutex and wake up a waiter if there is one
62 typedef boost::intrusive::list_member_hook<> MutexWaiterHookType;
64 // represents a waiter waiting for the lock. The waiter waits on the
65 // baton until it is woken up by a post or timeout expires.
68 MutexWaiterHookType hook;
71 typedef boost::intrusive::
72 member_hook<MutexWaiter, MutexWaiterHookType, &MutexWaiter::hook>
75 typedef boost::intrusive::list<
78 boost::intrusive::constant_time_size<true>>
81 pthread_spinlock_t lock_; //< lock to protect waiter list
82 bool locked_ = false; //< is this locked by some thread?
83 MutexWaiterList waiters_; //< list of waiters
89 * A readers-writer lock which allows multiple readers to hold the
90 * lock simultaneously or only one writer.
92 * NOTE: This is a reader-preferred RWLock i.e. readers are give priority
93 * when there are both readers and writers waiting to get the lock.
95 template <typename BatonType>
99 pthread_spin_init(&lock_, PTHREAD_PROCESS_PRIVATE);
103 pthread_spin_destroy(&lock_);
106 TimedRWMutex(const TimedRWMutex& rhs) = delete;
107 TimedRWMutex& operator=(const TimedRWMutex& rhs) = delete;
108 TimedRWMutex(TimedRWMutex&& rhs) = delete;
109 TimedRWMutex& operator=(TimedRWMutex&& rhs) = delete;
111 // Lock for shared access. The thread / fiber is blocked until the lock
115 // Like read_lock except the thread /fiber is blocked for a time duration
116 // @return true if locked successfully, false otherwise.
117 template <typename Rep, typename Period>
118 bool timed_read_lock(const std::chrono::duration<Rep, Period>& duration);
120 // Like read_lock but doesn't block the thread / fiber if the lock can't
122 // @return true if lock was acquired, false otherwise.
123 bool try_read_lock();
125 // Obtain an exclusive lock. The thread / fiber is blocked until the lock
129 // Like write_lock except the thread / fiber is blocked for a time duration
130 // @return true if locked successfully, false otherwise.
131 template <typename Rep, typename Period>
132 bool timed_write_lock(const std::chrono::duration<Rep, Period>& duration);
134 // Like write_lock but doesn't block the thread / fiber if the lock cant be
136 // @return true if lock was acquired, false otherwise.
137 bool try_write_lock();
139 // Wrapper for write_lock() for compatibility with Mutex
144 // Realease the lock. The thread / fiber will wake up all readers if there are
145 // any. If there are waiting writers then only one of them will be woken up.
146 // NOTE: readers are given priority over writers (see above comment)
149 // Downgrade the lock. The thread / fiber will wake up all readers if there
155 explicit ReadHolder(TimedRWMutex& lock) : lock_(&lock) {
165 ReadHolder(const ReadHolder& rhs) = delete;
166 ReadHolder& operator=(const ReadHolder& rhs) = delete;
167 ReadHolder(ReadHolder&& rhs) = delete;
168 ReadHolder& operator=(ReadHolder&& rhs) = delete;
176 explicit WriteHolder(TimedRWMutex& lock) : lock_(&lock) {
186 WriteHolder(const WriteHolder& rhs) = delete;
187 WriteHolder& operator=(const WriteHolder& rhs) = delete;
188 WriteHolder(WriteHolder&& rhs) = delete;
189 WriteHolder& operator=(WriteHolder&& rhs) = delete;
196 // invariants that must hold when the lock is not held by anyone
197 void verify_unlocked_properties() {
198 assert(readers_ == 0);
199 assert(read_waiters_.empty());
200 assert(write_waiters_.empty());
203 // Different states the lock can be in
210 typedef boost::intrusive::list_member_hook<> MutexWaiterHookType;
212 // represents a waiter waiting for the lock.
215 MutexWaiterHookType hook;
218 typedef boost::intrusive::
219 member_hook<MutexWaiter, MutexWaiterHookType, &MutexWaiter::hook>
222 typedef boost::intrusive::list<
225 boost::intrusive::constant_time_size<true>>
228 pthread_spinlock_t lock_; //< lock protecting the internal state
229 // (state_, read_waiters_, etc.)
230 State state_ = State::UNLOCKED;
232 uint32_t readers_ = 0; //< Number of readers who have the lock
234 MutexWaiterList write_waiters_; //< List of thread / fibers waiting for
237 MutexWaiterList read_waiters_; //< List of thread / fibers waiting for
243 #include "TimedMutex-inl.h"