]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/common/tri_mutex.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / crimson / common / tri_mutex.h
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#pragma once
5
6#include <seastar/core/future.hh>
7#include <seastar/core/circular_buffer.hh>
8
9class read_lock {
10public:
11 seastar::future<> lock();
12 void unlock();
13};
14
15class write_lock {
16public:
17 seastar::future<> lock();
18 void unlock();
19};
20
21class excl_lock {
22public:
23 seastar::future<> lock();
24 void unlock();
25};
26
27// promote from read to excl
28class excl_lock_from_read {
29public:
30 seastar::future<> lock();
31 void unlock();
32};
33
34// promote from write to excl
35class excl_lock_from_write {
36public:
37 seastar::future<> lock();
38 void unlock();
39};
40
41// promote from excl to excl
42class excl_lock_from_excl {
43public:
44 seastar::future<> lock();
45 void unlock();
46};
47
48/// shared/exclusive mutual exclusion
49///
50/// this lock design uses reader and writer is entirely and completely
51/// independent of the conventional reader/writer lock usage. Here, what we
52/// mean is that we can pipeline reads, and we can pipeline writes, but we
53/// cannot allow a read while writes are in progress or a write while reads are
54/// in progress. Any rmw operation is therefore exclusive.
55///
56/// tri_mutex is based on seastar::shared_mutex, but instead of two kinds of
57/// waiters, tri_mutex keeps track of three kinds of lock users:
58/// - readers
59/// - writers
60/// - exclusive users
61class tri_mutex : private read_lock,
62 write_lock,
63 excl_lock,
64 excl_lock_from_read,
65 excl_lock_from_write,
66 excl_lock_from_excl
67{
68public:
69 tri_mutex() = default;
70 ~tri_mutex();
71
72 read_lock& for_read() {
73 return *this;
74 }
75 write_lock& for_write() {
76 return *this;
77 }
78 excl_lock& for_excl() {
79 return *this;
80 }
81 excl_lock_from_read& excl_from_read() {
82 return *this;
83 }
84 excl_lock_from_write& excl_from_write() {
85 return *this;
86 }
87 excl_lock_from_write& excl_from_excl() {
88 return *this;
89 }
90
91 // for shared readers
92 seastar::future<> lock_for_read();
93 bool try_lock_for_read() noexcept;
94 void unlock_for_read();
95 void promote_from_read();
96 void demote_to_read();
97 unsigned get_readers() const {
98 return readers;
99 }
100
101 // for shared writers
102 seastar::future<> lock_for_write(bool greedy);
103 bool try_lock_for_write(bool greedy) noexcept;
104 void unlock_for_write();
105 void promote_from_write();
106 void demote_to_write();
107 unsigned get_writers() const {
108 return writers;
109 }
110
111 // for exclusive users
112 seastar::future<> lock_for_excl();
113 bool try_lock_for_excl() noexcept;
114 void unlock_for_excl();
115 bool is_excl_acquired() const {
116 return exclusively_used;
117 }
118
119 bool is_acquired() const;
120
121 /// pass the provided exception to any waiting waiters
122 template<typename Exception>
123 void abort(Exception ex) {
124 while (!waiters.empty()) {
125 auto& waiter = waiters.front();
126 waiter.pr.set_exception(std::make_exception_ptr(ex));
127 waiters.pop_front();
128 }
129 }
130
131private:
132 void wake();
133 unsigned readers = 0;
134 unsigned writers = 0;
135 bool exclusively_used = false;
136 enum class type_t : uint8_t {
137 read,
138 write,
139 exclusive,
140 none,
141 };
142 struct waiter_t {
143 waiter_t(seastar::promise<>&& pr, type_t type)
144 : pr(std::move(pr)), type(type)
145 {}
146 seastar::promise<> pr;
147 type_t type;
148 };
149 seastar::circular_buffer<waiter_t> waiters;
150 friend class read_lock;
151 friend class write_lock;
152 friend class excl_lock;
153 friend class excl_lock_from_read;
154 friend class excl_lock_from_write;
155 friend class excl_lock_from_excl;
156};