Kea  2.3.3-git
readwrite_mutex.h
Go to the documentation of this file.
1 // Copyright (C) 2020-2022 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef READWRITE_MUTEX_H
8 #define READWRITE_MUTEX_H
9 
15 
16 #include <exceptions/exceptions.h>
17 #include <boost/noncopyable.hpp>
18 #include <climits>
19 #include <condition_variable>
20 #include <mutex>
21 
22 namespace isc {
23 namespace util {
24 
29 class ReadWriteMutex : public boost::noncopyable {
30 public:
31 
33 
35  static const unsigned WRITE_ENTERED =
36  1U << (sizeof(unsigned) * CHAR_BIT - 1);
37 
39  static const unsigned MAX_READERS = ~WRITE_ENTERED;
40 
42  ReadWriteMutex() : state_(0) {
43  }
44 
49  virtual ~ReadWriteMutex() {
50  std::lock_guard<std::mutex> lk(mutex_);
51  }
52 
54  void writeLock() {
55  std::unique_lock<std::mutex> lk(mutex_);
56  // Wait until the write entered flag can be set.
57  gate1_.wait(lk, [&]() { return (!writeEntered()); });
58  state_ |= WRITE_ENTERED;
59  // Wait until there are no more readers.
60  gate2_.wait(lk, [&]() { return (readers() == 0); });
61  }
62 
66  void writeUnlock() {
67  std::lock_guard<std::mutex> lk(mutex_);
68  state_ = 0;
69  // Wake-up waiting threads when exiting the guard.
70  gate1_.notify_all();
71  }
72 
74  void readLock() {
75  std::unique_lock<std::mutex> lk(mutex_);
76  // Wait if there is a writer or if readers overflow.
77  gate1_.wait(lk, [&]() { return (state_ < MAX_READERS); });
78  ++state_;
79  }
80 
84  void readUnlock() {
85  std::lock_guard<std::mutex> lk(mutex_);
86  unsigned prev = state_--;
87  if (writeEntered()) {
88  if (readers() == 0) {
89  // Last reader: wake up a waiting writer.
90  gate2_.notify_one();
91  }
92  } else {
93  if (prev == MAX_READERS) {
94  // Reader overflow: wake up one waiting reader.
95  gate1_.notify_one();
96  }
97  }
98  }
99 
100 private:
101 
103 
105  bool writeEntered() const {
106  return (state_ & WRITE_ENTERED);
107  }
108 
110  unsigned readers() const {
111  return (state_ & MAX_READERS);
112  }
113 
115 
119  std::mutex mutex_;
120 
124  std::condition_variable gate1_;
125 
129  std::condition_variable gate2_;
130 
134  unsigned state_;
135 };
136 
140 class ReadLockGuard : public boost::noncopyable {
141 public:
142 
146  ReadLockGuard(ReadWriteMutex& rw_mutex) : rw_mutex_(rw_mutex) {
147  rw_mutex_.readLock();
148  }
149 
151  virtual ~ReadLockGuard() {
152  rw_mutex_.readUnlock();
153  }
154 
155 private:
157  ReadWriteMutex& rw_mutex_;
158 
159 };
160 
164 class WriteLockGuard : public boost::noncopyable {
165 public:
166 
170  WriteLockGuard(ReadWriteMutex& rw_mutex) : rw_mutex_(rw_mutex) {
171  rw_mutex_.writeLock();
172  }
173 
175  virtual ~WriteLockGuard() {
176  rw_mutex_.writeUnlock();
177  }
178 
179 private:
181  ReadWriteMutex& rw_mutex_;
182 };
183 
184 } // namespace util
185 } // namespace isc
186 
187 #endif // READWRITE_MUTEX_H
WriteLockGuard(ReadWriteMutex &rw_mutex)
Constructor.
Write mutex RAII handler.
virtual ~ReadLockGuard()
Destructor.
Read-Write Mutex.
ReadWriteMutex()
Constructor.
static const unsigned MAX_READERS
The maximum number of readers (flag complement so 2^31 - 1).
virtual ~ReadWriteMutex()
Destructor.
static const unsigned WRITE_ENTERED
Constants.
virtual ~WriteLockGuard()
Destructor.
Defines the logger used by the top-level component of kea-lfc.
ReadLockGuard(ReadWriteMutex &rw_mutex)
Constructor.
void readUnlock()
Unlock read.
void writeLock()
Lock write.
void readLock()
Lock read.
Read mutex RAII handler.
void writeUnlock()
Unlock write.