Seastar
High performance C++ framework for concurrent servers
rwlock.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19  * Copyright (C) 2015 Cloudius Systems, Ltd.
20  */
21 
22 #pragma once
23 
24 #include <seastar/core/semaphore.hh>
25 
26 namespace seastar {
27 
29 // lock / unlock semantics for rwlock, so it can be used with with_lock()
30 template<typename Clock>
31 class basic_rwlock;
32 
33 template<typename Clock = typename timer<>::clock>
34 class rwlock_for_read {
35 public:
36  future<> lock() {
37  return static_cast<basic_rwlock<Clock>*>(this)->read_lock();
38  }
39  void unlock() {
40  static_cast<basic_rwlock<Clock>*>(this)->read_unlock();
41  }
42  friend class basic_rwlock<Clock>;
43 };
44 
45 template<typename Clock = typename timer<>::clock>
46 class rwlock_for_write {
47 public:
48  future<> lock() {
49  return static_cast<basic_rwlock<Clock>*>(this)->write_lock();
50  }
51  void unlock() {
52  static_cast<basic_rwlock<Clock>*>(this)->write_unlock();
53  }
54  friend class basic_rwlock<Clock>;
55 };
57 
58 
61 
68 template<typename Clock = typename timer<>::clock>
69 class basic_rwlock : private rwlock_for_read<Clock>, rwlock_for_write<Clock> {
71 
72  static constexpr size_t max_ops = semaphore_type::max_counter();
73 
74  semaphore_type _sem;
75 public:
76  basic_rwlock()
77  : _sem(max_ops) {
78  }
79 
83  rwlock_for_read<Clock>& for_read() {
84  return *this;
85  }
86 
90  rwlock_for_write<Clock>& for_write() {
91  return *this;
92  }
93 
97  future<> read_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
98  return _sem.wait(timeout);
99  }
100 
102  return _sem.wait(as);
103  }
104 
108  void read_unlock() {
109  assert(_sem.current() < max_ops);
110  _sem.signal();
111  }
112 
117  future<> write_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
118  return _sem.wait(timeout, max_ops);
119  }
120 
122  return _sem.wait(as, max_ops);
123  }
124 
128  void write_unlock() {
129  assert(_sem.current() == 0);
130  _sem.signal(max_ops);
131  }
132 
134  bool try_read_lock() {
135  return _sem.try_wait();
136  }
137 
139  bool try_write_lock() {
140  return _sem.try_wait(max_ops);
141  }
142 
144 
156  future<holder> hold_read_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
157  return get_units(_sem, 1, timeout);
158  }
159 
161  return get_units(_sem, 1, as);
162  }
163 
175  future<holder> hold_write_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
176  return get_units(_sem, max_ops, timeout);
177  }
178 
180  return get_units(_sem, max_ops, as);
181  }
182 
184  bool locked() const {
185  return _sem.available_units() != max_ops;
186  }
187 
188  friend class rwlock_for_read<Clock>;
189  friend class rwlock_for_write<Clock>;
190 };
191 
192 using rwlock = basic_rwlock<>;
193 
195 
196 }
Definition: abort_source.hh:51
Definition: rwlock.hh:69
future read_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:97
void read_unlock()
Definition: rwlock.hh:108
rwlock_for_read< Clock > & for_read()
Definition: rwlock.hh:83
future< holder > hold_write_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:175
future write_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:117
bool try_read_lock()
Tries to acquire the lock in read mode iff this can be done without waiting.
Definition: rwlock.hh:134
bool try_write_lock()
Tries to acquire the lock in write mode iff this can be done without waiting.
Definition: rwlock.hh:139
bool locked() const
Checks if any read or write locks are currently held.
Definition: rwlock.hh:184
future< holder > hold_read_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:156
rwlock_for_write< Clock > & for_write()
Definition: rwlock.hh:90
void write_unlock()
Definition: rwlock.hh:128
Counted resource guard.
Definition: semaphore.hh:148
static constexpr size_t max_counter() noexcept
Returns the maximum number of units the semaphore counter can hold.
Definition: semaphore.hh:196
size_t current() const noexcept
Definition: semaphore.hh:370
future wait(size_t nr=1) noexcept
Definition: semaphore.hh:227
ssize_t available_units() const noexcept
Definition: semaphore.hh:376
bool try_wait(size_t nr=1) noexcept
Definition: semaphore.hh:359
void signal(size_t nr=1) noexcept
Definition: semaphore.hh:322
Definition: semaphore.hh:432
Seastar API namespace.
Definition: abort_on_ebadf.hh:24