Seastar
High performance C++ framework for concurrent servers
gate.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 2014 Cloudius Systems
20  */
21 
22 #pragma once
23 
24 #include <seastar/core/future.hh>
25 #include <seastar/util/std-compat.hh>
26 #include <exception>
27 
28 namespace seastar {
29 
32 
35 class gate_closed_exception : public std::exception {
36 public:
37  virtual const char* what() const noexcept override {
38  return "gate closed";
39  }
40 };
41 
47 class gate {
48  size_t _count = 0;
49  std::optional<promise<>> _stopped;
50 public:
51  gate() = default;
52  gate(const gate&) = delete;
53  gate(gate&&) = default;
54  gate& operator=(gate&&) = default;
55  ~gate() {
56  assert(!_count && "gate destroyed with outstanding requests");
57  }
62  bool try_enter() noexcept {
63  bool opened = !_stopped;
64  if (opened) {
65  ++_count;
66  }
67  return opened;
68  }
73  void enter() {
74  if (!try_enter()) {
75  throw gate_closed_exception();
76  }
77  }
82  void leave() noexcept {
83  --_count;
84  if (!_count && _stopped) {
85  _stopped->set_value();
86  }
87  }
97  void check() {
98  if (_stopped) {
99  throw gate_closed_exception();
100  }
101  }
107  future<> close() noexcept {
108  assert(!_stopped && "seastar::gate::close() cannot be called more than once");
109  _stopped = std::make_optional(promise<>());
110  if (!_count) {
111  _stopped->set_value();
112  }
113  return _stopped->get_future();
114  }
115 
117  size_t get_count() const noexcept {
118  return _count;
119  }
120 
122  bool is_closed() const noexcept {
123  return bool(_stopped);
124  }
125 
135  class holder {
136  gate* _g;
137 
138  public:
141  holder() noexcept : _g(nullptr) { }
142 
145  explicit holder(gate& g) : _g(&g) {
146  _g->enter();
147  }
148 
154  holder(const holder& x) noexcept : _g(x._g) {
155  if (_g) {
156  _g->_count++;
157  }
158  }
159 
163  holder(holder&& x) noexcept : _g(std::exchange(x._g, nullptr)) { }
164 
167  release();
168  }
169 
176  holder& operator=(const holder& x) noexcept {
177  if (x._g != _g) {
178  release();
179  _g = x._g;
180  if (_g) {
181  _g->_count++;
182  }
183  }
184  return *this;
185  }
186 
191  holder& operator=(holder&& x) noexcept {
192  if (&x != this) {
193  release();
194  _g = std::exchange(x._g, nullptr);
195  }
196  return *this;
197  }
198 
200  void release() noexcept {
201  if (_g) {
202  _g->leave();
203  _g = nullptr;
204  }
205  }
206  };
207 
211  return holder(*this);
212  }
213 };
214 
215 namespace internal {
216 
217 template <typename Func>
218 inline
219 auto
220 invoke_func_with_gate(gate& g, Func&& func) noexcept {
221  return futurize_invoke(std::forward<Func>(func)).finally([&g] { g.leave(); });
222 }
223 
224 } // namespace intgernal
225 
234 template <typename Func>
235 inline
236 auto
237 with_gate(gate& g, Func&& func) {
238  g.enter();
239  return internal::invoke_func_with_gate(g, std::forward<Func>(func));
240 }
241 
253 template <typename Func>
254 inline
255 auto
256 try_with_gate(gate& g, Func&& func) noexcept {
257  if (!g.try_enter()) {
258  using futurator = futurize<std::result_of_t<Func()>>;
260  }
261  return internal::invoke_func_with_gate(g, std::forward<Func>(func));
262 }
264 
265 }
A representation of a possibly not-yet-computed value.
Definition: future.hh:1337
Definition: gate.hh:135
holder(gate &g)
Definition: gate.hh:145
holder & operator=(holder &&x) noexcept
Definition: gate.hh:191
~holder()
Destroy a holder and leave the referenced gate.
Definition: gate.hh:166
holder(holder &&x) noexcept
Definition: gate.hh:163
holder(const holder &x) noexcept
Definition: gate.hh:154
void release() noexcept
Leave the held gate.
Definition: gate.hh:200
holder & operator=(const holder &x) noexcept
Definition: gate.hh:176
holder() noexcept
Definition: gate.hh:141
Definition: gate.hh:35
Definition: gate.hh:47
bool try_enter() noexcept
Definition: gate.hh:62
bool is_closed() const noexcept
Returns whether the gate is closed.
Definition: gate.hh:122
future close() noexcept
Definition: gate.hh:107
size_t get_count() const noexcept
Returns a current number of registered in-progress requests.
Definition: gate.hh:117
void check()
Definition: gate.hh:97
holder hold()
Definition: gate.hh:210
void enter()
Definition: gate.hh:73
void leave() noexcept
Definition: gate.hh:82
promise - allows a future value to be made available at a later time.
Definition: future.hh:957
auto with_gate(gate &g, Func &&func)
Definition: gate.hh:237
auto try_with_gate(gate &g, Func &&func) noexcept
Definition: gate.hh:256
future< T... > make_exception_future(std::exception_ptr &&value) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2054
Seastar API namespace.
Definition: abort_on_ebadf.hh:24
Converts a type to a future type, if it isn't already.
Definition: future.hh:1956