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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright 2014 Cloudius Systems
24 #include <seastar/core/future.hh>
25 #include <seastar/util/std-compat.hh>
30 /// \addtogroup fiber-module
33 /// Exception thrown when a \ref gate object has been closed
34 /// by the \ref gate::close() method.
35 class gate_closed_exception : public std::exception {
37 virtual const char* what() const noexcept override {
42 /// Facility to stop new requests, and to tell when existing requests are done.
44 /// When stopping a service that serves asynchronous requests, we are faced with
45 /// two problems: preventing new requests from coming in, and knowing when existing
46 /// requests have completed. The \c gate class provides a solution.
49 std::optional<promise<>> _stopped;
51 /// Tries to register an in-progress request.
53 /// If the gate is not closed, the request is registered and the function returns `true`,
54 /// Otherwise the function just returns `false` and has no other effect.
55 bool try_enter() noexcept {
56 bool opened = !_stopped;
62 /// Registers an in-progress request.
64 /// If the gate is not closed, the request is registered. Otherwise,
65 /// a \ref gate_closed_exception is thrown.
68 throw gate_closed_exception();
71 /// Unregisters an in-progress request.
73 /// If the gate is closed, and there are no more in-progress requests,
74 /// the `_stopped` promise will be fulfilled.
75 void leave() noexcept {
77 if (!_count && _stopped) {
78 _stopped->set_value();
81 /// Potentially stop an in-progress request.
83 /// If the gate is already closed, a \ref gate_closed_exception is thrown.
84 /// By using \ref enter() and \ref leave(), the program can ensure that
85 /// no further requests are serviced. However, long-running requests may
86 /// continue to run. The check() method allows such a long operation to
87 /// voluntarily stop itself after the gate is closed, by making calls to
88 /// check() in appropriate places. check() with throw an exception and
89 /// bail out of the long-running code if the gate is closed.
92 throw gate_closed_exception();
97 /// Future calls to \ref enter() will fail with an exception, and when
98 /// all current requests call \ref leave(), the returned future will be
100 future<> close() noexcept {
101 assert(!_stopped && "seastar::gate::close() cannot be called more than once");
102 _stopped = std::make_optional(promise<>());
104 _stopped->set_value();
106 return _stopped->get_future();
109 /// Returns a current number of registered in-progress requests.
110 size_t get_count() const noexcept {
114 /// Returns whether the gate is closed.
115 bool is_closed() const noexcept {
116 return bool(_stopped);
122 template <typename Func>
125 invoke_func_with_gate(gate& g, Func&& func) noexcept {
126 return futurize_invoke(std::forward<Func>(func)).finally([&g] { g.leave(); });
129 } // namespace intgernal
131 /// Executes the function \c func making sure the gate \c g is properly entered
132 /// and later on, properly left.
134 /// \param func function to be executed
135 /// \param g the gate. Caller must make sure that it outlives this function.
136 /// \returns whatever \c func returns
139 template <typename Func>
142 with_gate(gate& g, Func&& func) {
144 return internal::invoke_func_with_gate(g, std::forward<Func>(func));
147 /// Executes the function \c func if the gate \c g can be entered
148 /// and later on, properly left.
150 /// \param func function to be executed
151 /// \param g the gate. Caller must make sure that it outlives this function.
153 /// If the gate is already closed, an exception future holding
154 /// \ref gate_closed_exception is returned, otherwise
155 /// \returns whatever \c func returns.
158 template <typename Func>
161 try_with_gate(gate& g, Func&& func) noexcept {
162 if (!g.try_enter()) {
163 using futurator = futurize<std::result_of_t<Func()>>;
164 return futurator::make_exception_future(gate_closed_exception());
166 return internal::invoke_func_with_gate(g, std::forward<Func>(func));