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 
104  void read_unlock() {
105  assert(_sem.current() < max_ops);
106  _sem.signal();
107  }
108 
113  future<> write_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
114  return _sem.wait(timeout, max_ops);
115  }
116 
120  void write_unlock() {
121  assert(_sem.current() == 0);
122  _sem.signal(max_ops);
123  }
124 
126  bool try_read_lock() {
127  return _sem.try_wait();
128  }
129 
131  bool try_write_lock() {
132  return _sem.try_wait(max_ops);
133  }
134 
136 
148  future<holder> hold_read_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
149  return get_units(_sem, 1, timeout);
150  }
151 
163  future<holder> hold_write_lock(typename semaphore_type::time_point timeout = semaphore_type::time_point::max()) {
164  return get_units(_sem, max_ops, timeout);
165  }
166 
168  bool locked() const {
169  return _sem.available_units() != max_ops;
170  }
171 
172  friend class rwlock_for_read<Clock>;
173  friend class rwlock_for_write<Clock>;
174 };
175 
176 using rwlock = basic_rwlock<>;
177 
179 
180 }
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:104
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:163
future write_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:113
bool try_read_lock()
Tries to acquire the lock in read mode iff this can be done without waiting.
Definition: rwlock.hh:126
bool try_write_lock()
Tries to acquire the lock in write mode iff this can be done without waiting.
Definition: rwlock.hh:131
bool locked() const
Checks if any read or write locks are currently held.
Definition: rwlock.hh:168
future< holder > hold_read_lock(typename semaphore_type::time_point timeout=semaphore_type::time_point::max())
Definition: rwlock.hh:148
rwlock_for_write< Clock > & for_write()
Definition: rwlock.hh:90
void write_unlock()
Definition: rwlock.hh:120
Counted resource guard.
Definition: semaphore.hh:106
static constexpr size_t max_counter() noexcept
Returns the maximum number of units the semaphore counter can hold.
Definition: semaphore.hh:139
size_t current() const noexcept
Definition: semaphore.hh:277
future wait(size_t nr=1) noexcept
Definition: semaphore.hh:170
ssize_t available_units() const noexcept
Definition: semaphore.hh:283
bool try_wait(size_t nr=1) noexcept
Definition: semaphore.hh:266
void signal(size_t nr=1) noexcept
Definition: semaphore.hh:229
A representation of a possibly not-yet-computed value.
Definition: future.hh:1337
Definition: semaphore.hh:335
Seastar API namespace.
Definition: abort_on_ebadf.hh:24