]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/condition-variable.hh
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / include / seastar / core / condition-variable.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) 2016 ScyllaDB, Ltd.
20 */
21
22 #pragma once
23
24 #include <seastar/core/future-util.hh>
25 #include <seastar/core/semaphore.hh>
26
27 namespace seastar {
28
29 /// \addtogroup fiber-module
30 /// @{
31
32 /// Exception thrown when a condition variable is broken by
33 /// \ref condition_variable::broken().
34 class broken_condition_variable : public std::exception {
35 public:
36 /// Reports the exception reason.
37 virtual const char* what() const noexcept {
38 return "Condition variable is broken";
39 }
40 };
41
42 /// Exception thrown when wait() operation times out
43 /// \ref condition_variable::wait(time_point timeout).
44 class condition_variable_timed_out : public std::exception {
45 public:
46 /// Reports the exception reason.
47 virtual const char* what() const noexcept {
48 return "Condition variable timed out";
49 }
50 };
51
52 /// \brief Conditional variable.
53 ///
54 /// This is a standard computer science condition variable sans locking,
55 /// since in seastar access to variables is atomic anyway, adapted
56 /// for futures. You can wait for variable to be notified.
57 ///
58 /// To support exceptional conditions, a \ref broken() method
59 /// is provided, which causes all current waiters to stop waiting,
60 /// with an exceptional future returned. This allows causing all
61 /// fibers that are blocked on a condition variable to continue.
62 /// This issimilar to POSIX's `pthread_cancel()`, with \ref wait()
63 /// acting as a cancellation point.
64
65 class condition_variable {
66 using duration = semaphore::duration;
67 using clock = semaphore::clock;
68 using time_point = semaphore::time_point;
69 struct condition_variable_exception_factory {
70 static condition_variable_timed_out timeout() {
71 return condition_variable_timed_out();
72 }
73 static broken_condition_variable broken() {
74 return broken_condition_variable();
75 }
76 };
77 basic_semaphore<condition_variable_exception_factory> _sem;
78 public:
79 /// Constructs a condition_variable object.
80 /// Initialzie the semaphore with a default value of 0 to enusre
81 /// the first call to wait() before signal() won't be waken up immediately.
82 condition_variable() : _sem(0) {}
83
84 /// Waits until condition variable is signaled, may wake up without condition been met
85 ///
86 /// \return a future that becomes ready when \ref signal() is called
87 /// If the condition variable was \ref broken() will return \ref broken_condition_variable
88 /// exception.
89 future<> wait() {
90 return _sem.wait();
91 }
92
93 /// Waits until condition variable is signaled or timeout is reached
94 ///
95 /// \param timeout time point at which wait will exit with a timeout
96 ///
97 /// \return a future that becomes ready when \ref signal() is called
98 /// If the condition variable was \ref broken() will return \ref broken_condition_variable
99 /// exception. If timepoint is reached will return \ref condition_variable_timed_out exception.
100 future<> wait(time_point timeout) {
101 return _sem.wait(timeout);
102 }
103
104 /// Waits until condition variable is signaled or timeout is reached
105 ///
106 /// \param timeout duration after which wait will exit with a timeout
107 ///
108 /// \return a future that becomes ready when \ref signal() is called
109 /// If the condition variable was \ref broken() will return \ref broken_condition_variable
110 /// exception. If timepoint is passed will return \ref condition_variable_timed_out exception.
111 future<> wait(duration timeout) {
112 return _sem.wait(timeout);
113 }
114
115 /// Waits until condition variable is notified and pred() == true, otherwise
116 /// wait again.
117 ///
118 /// \param pred predicate that checks that awaited condition is true
119 ///
120 /// \return a future that becomes ready when \ref signal() is called
121 /// If the condition variable was \ref broken(), may contain an exception.
122 template<typename Pred>
123 future<> wait(Pred&& pred) {
124 return do_until(std::forward<Pred>(pred), [this] {
125 return wait();
126 });
127 }
128
129 /// Waits until condition variable is notified and pred() == true or timeout is reached, otherwise
130 /// wait again.
131 ///
132 /// \param timeout time point at which wait will exit with a timeout
133 /// \param pred predicate that checks that awaited condition is true
134 ///
135 /// \return a future that becomes ready when \ref signal() is called
136 /// If the condition variable was \ref broken() will return \ref broken_condition_variable
137 /// exception. If timepoint is reached will return \ref condition_variable_timed_out exception.
138 /// \param
139 template<typename Pred>
140 future<> wait(time_point timeout, Pred&& pred) {
141 return do_until(std::forward<Pred>(pred), [this, timeout] () mutable {
142 return wait(timeout);
143 });
144 }
145
146 /// Waits until condition variable is notified and pred() == true or timeout is reached, otherwise
147 /// wait again.
148 ///
149 /// \param timeout duration after which wait will exit with a timeout
150 /// \param pred predicate that checks that awaited condition is true
151 ///
152 /// \return a future that becomes ready when \ref signal() is called
153 /// If the condition variable was \ref broken() will return \ref broken_condition_variable
154 /// exception. If timepoint is passed will return \ref condition_variable_timed_out exception.
155 template<typename Pred>
156 future<> wait(duration timeout, Pred&& pred) {
157 return wait(clock::now() + timeout, std::forward<Pred>(pred));
158 }
159 /// Notify variable and wake up a waiter if there is one
160 void signal() {
161 if (_sem.waiters()) {
162 _sem.signal();
163 }
164 }
165 /// Notify variable and wake up all waiter
166 void broadcast() {
167 _sem.signal(_sem.waiters());
168 }
169
170 /// Signal to waiters that an error occurred. \ref wait() will see
171 /// an exceptional future<> containing the provided exception parameter.
172 /// The future is made available immediately.
173 void broken() {
174 _sem.broken();
175 }
176 };
177
178 /// @}
179
180 }