]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/common/tri_mutex.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / crimson / common / tri_mutex.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "tri_mutex.h"
5
6seastar::future<> read_lock::lock()
7{
8 return static_cast<tri_mutex*>(this)->lock_for_read();
9}
10
11void read_lock::unlock()
12{
13 static_cast<tri_mutex*>(this)->unlock_for_read();
14}
15
16seastar::future<> write_lock::lock()
17{
18 return static_cast<tri_mutex*>(this)->lock_for_write(false);
19}
20
21void write_lock::unlock()
22{
23 static_cast<tri_mutex*>(this)->unlock_for_write();
24}
25
26seastar::future<> excl_lock::lock()
27{
28 return static_cast<tri_mutex*>(this)->lock_for_excl();
29}
30
31void excl_lock::unlock()
32{
33 static_cast<tri_mutex*>(this)->unlock_for_excl();
34}
35
36seastar::future<> excl_lock_from_read::lock()
37{
38 static_cast<tri_mutex*>(this)->promote_from_read();
39 return seastar::make_ready_future<>();
40}
41
42void excl_lock_from_read::unlock()
43{
44 static_cast<tri_mutex*>(this)->demote_to_read();
45}
46
47seastar::future<> excl_lock_from_write::lock()
48{
49 static_cast<tri_mutex*>(this)->promote_from_write();
50 return seastar::make_ready_future<>();
51}
52
53void excl_lock_from_write::unlock()
54{
55 static_cast<tri_mutex*>(this)->demote_to_write();
56}
57
58seastar::future<> excl_lock_from_excl::lock()
59{
60 return seastar::make_ready_future<>();
61}
62
63void excl_lock_from_excl::unlock()
64{
65}
66
67tri_mutex::~tri_mutex()
68{
69 assert(!is_acquired());
70}
71
72seastar::future<> tri_mutex::lock_for_read()
73{
74 if (try_lock_for_read()) {
75 return seastar::make_ready_future<>();
76 }
77 waiters.emplace_back(seastar::promise<>(), type_t::read);
78 return waiters.back().pr.get_future();
79}
80
81bool tri_mutex::try_lock_for_read() noexcept
82{
83 if (!writers && !exclusively_used && waiters.empty()) {
84 ++readers;
85 return true;
86 } else {
87 return false;
88 }
89}
90
91void tri_mutex::unlock_for_read()
92{
93 assert(readers > 0);
94 if (--readers == 0) {
95 wake();
96 }
97}
98
99void tri_mutex::promote_from_read()
100{
101 assert(readers == 1);
102 --readers;
103 exclusively_used = true;
104}
105
106void tri_mutex::demote_to_read()
107{
108 assert(exclusively_used);
109 exclusively_used = false;
110 ++readers;
111}
112
113seastar::future<> tri_mutex::lock_for_write(bool greedy)
114{
115 if (try_lock_for_write(greedy)) {
116 return seastar::make_ready_future<>();
117 }
118 waiters.emplace_back(seastar::promise<>(), type_t::write);
119 return waiters.back().pr.get_future();
120}
121
122bool tri_mutex::try_lock_for_write(bool greedy) noexcept
123{
124 if (!readers && !exclusively_used) {
125 if (greedy || waiters.empty()) {
126 ++writers;
127 return true;
128 }
129 }
130 return false;
131}
132
133void tri_mutex::unlock_for_write()
134{
135 assert(writers > 0);
136 if (--writers == 0) {
137 wake();
138 }
139}
140
141void tri_mutex::promote_from_write()
142{
143 assert(writers == 1);
144 --writers;
145 exclusively_used = true;
146}
147
148void tri_mutex::demote_to_write()
149{
150 assert(exclusively_used);
151 exclusively_used = false;
152 ++writers;
153}
154
155// for exclusive users
156seastar::future<> tri_mutex::lock_for_excl()
157{
158 if (try_lock_for_excl()) {
159 return seastar::make_ready_future<>();
160 }
161 waiters.emplace_back(seastar::promise<>(), type_t::exclusive);
162 return waiters.back().pr.get_future();
163}
164
165bool tri_mutex::try_lock_for_excl() noexcept
166{
167 if (!readers && !writers && !exclusively_used) {
168 exclusively_used = true;
169 return true;
170 } else {
171 return false;
172 }
173}
174
175void tri_mutex::unlock_for_excl()
176{
177 assert(exclusively_used);
178 exclusively_used = false;
179 wake();
180}
181
182bool tri_mutex::is_acquired() const
183{
184 if (readers) {
185 return true;
186 } else if (writers) {
187 return true;
188 } else if (exclusively_used) {
189 return true;
190 } else {
191 return false;
192 }
193}
194
195void tri_mutex::wake()
196{
197 assert(!readers && !writers && !exclusively_used);
198 type_t type = type_t::none;
199 while (!waiters.empty()) {
200 auto& waiter = waiters.front();
201 if (type == type_t::exclusive) {
202 break;
203 } if (type == type_t::none) {
204 type = waiter.type;
205 } else if (type != waiter.type) {
206 // to be woken in the next batch
207 break;
208 }
209 switch (type) {
210 case type_t::read:
211 ++readers;
212 break;
213 case type_t::write:
214 ++writers;
215 break;
216 case type_t::exclusive:
217 exclusively_used = true;
218 break;
219 default:
220 assert(0);
221 }
222 waiter.pr.set_value();
223 waiters.pop_front();
224 }
225}