]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
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) 2021 Cloudius Systems, Ltd. | |
20 | */ | |
21 | ||
22 | #pragma once | |
23 | ||
1e59de90 | 24 | #include <functional> |
20effc67 TL |
25 | #include <seastar/core/future.hh> |
26 | #include <seastar/util/concepts.hh> | |
27 | #include <seastar/util/defer.hh> | |
28 | ||
29 | /// \file | |
30 | ||
31 | /// \example closeable_test.cc | |
32 | ||
33 | namespace seastar { | |
34 | ||
35 | SEASTAR_CONCEPT( | |
36 | template <typename Object> | |
37 | concept closeable = requires (Object o) { | |
38 | { o.close() } SEASTAR_DEFERRED_ACTION_NOEXCEPT -> std::same_as<future<>>; | |
39 | }; | |
40 | ) | |
41 | ||
42 | /// Template helper to auto-close \c obj when destroyed. | |
43 | /// | |
44 | /// \tparam Object a class exposing a \c close() method that returns a \c future<> | |
45 | /// that is called when the controller is destroyed. | |
46 | /// | |
47 | /// Must be used in a seastar thread as the destructor | |
48 | /// needs to wait on the \c obj close() future. | |
49 | template <typename Object> | |
50 | SEASTAR_CONCEPT( requires closeable<Object> ) | |
1e59de90 TL |
51 | class [[nodiscard("unassigned deferred_close")]] deferred_close { |
52 | std::reference_wrapper<Object> _obj; | |
20effc67 TL |
53 | bool _closed = false; |
54 | ||
55 | void do_close() noexcept { | |
56 | if (!_closed) { | |
57 | _closed = true; | |
1e59de90 | 58 | _obj.get().close().get(); |
20effc67 TL |
59 | } |
60 | } | |
61 | public: | |
62 | /// Construct an object that will auto-close \c obj when destroyed. | |
63 | /// \tparam obj the object to auto-close. | |
64 | deferred_close(Object& obj) noexcept : _obj(obj) {} | |
1e59de90 TL |
65 | /// Moves the \c deferred_close into a new one, and |
66 | /// the old one is canceled. | |
67 | deferred_close(deferred_close&& x) noexcept : _obj(x._obj), _closed(std::exchange(x._closed, true)) {} | |
68 | deferred_close(const deferred_close&) = delete; | |
69 | /// Move-assign another \ref deferred_close. | |
70 | /// The current \ref deferred_close is closed before being assigned. | |
71 | /// And the other one's state is transferred to the current one. | |
72 | deferred_close& operator=(deferred_close&& x) noexcept { | |
73 | do_close(); | |
74 | _obj = x._obj; | |
75 | _closed = std::exchange(x._closed, true); | |
76 | return *this; | |
77 | } | |
20effc67 TL |
78 | /// Destruct the deferred_close object and auto-close \c obj. |
79 | ~deferred_close() { | |
80 | do_close(); | |
81 | } | |
82 | /// Close \c obj once now. | |
83 | void close_now() noexcept { | |
84 | assert(!_closed); | |
85 | do_close(); | |
86 | } | |
1e59de90 TL |
87 | |
88 | /// Prevents close() from being called when this object is destroyed. | |
89 | /// Cannot call close_now() any more after this. | |
90 | void cancel() noexcept { | |
91 | _closed = true; | |
92 | } | |
20effc67 TL |
93 | }; |
94 | ||
95 | template <typename Closeable, typename Func> | |
96 | SEASTAR_CONCEPT( | |
97 | requires closeable<Closeable> && std::invocable<Func, Closeable&> && | |
98 | std::is_nothrow_move_constructible_v<Closeable> && std::is_nothrow_move_constructible_v<Func> | |
99 | ) | |
100 | inline futurize_t<std::invoke_result_t<Func, Closeable&>> | |
101 | with_closeable(Closeable&& obj, Func func) noexcept { | |
102 | return do_with(std::move(obj), [func = std::move(func)] (Closeable& obj) mutable { | |
103 | return futurize_invoke(func, obj).finally([&obj] { | |
104 | return obj.close(); | |
105 | }); | |
106 | }); | |
107 | } | |
108 | ||
109 | SEASTAR_CONCEPT( | |
110 | template <typename Object> | |
111 | concept stoppable = requires (Object o) { | |
112 | { o.stop() } SEASTAR_DEFERRED_ACTION_NOEXCEPT -> std::same_as<future<>>; | |
113 | }; | |
114 | ) | |
115 | ||
116 | /// Template helper to auto-stop \c obj when destroyed. | |
117 | /// | |
118 | /// \tparam Object a class exposing a \c stop() method that returns a \c future<> | |
119 | /// that is called when the controller is destroyed. | |
120 | /// | |
121 | /// Must be used in a seastar thread as the destructor | |
122 | /// needs to wait on the \c obj stop() future. | |
123 | template <typename Object> | |
124 | SEASTAR_CONCEPT( requires stoppable<Object> ) | |
1e59de90 TL |
125 | class [[nodiscard("unassigned deferred_stop")]] deferred_stop { |
126 | std::reference_wrapper<Object> _obj; | |
20effc67 TL |
127 | bool _stopped = false; |
128 | ||
129 | void do_stop() noexcept { | |
130 | if (!_stopped) { | |
131 | _stopped = true; | |
1e59de90 | 132 | _obj.get().stop().get(); |
20effc67 TL |
133 | } |
134 | } | |
135 | public: | |
136 | /// Construct an object that will auto-stop \c obj when destroyed. | |
137 | /// \tparam obj the object to auto-stop. | |
138 | deferred_stop(Object& obj) noexcept : _obj(obj) {} | |
1e59de90 TL |
139 | /// Moves the \c deferred_stop into a new one, and |
140 | /// the old one is canceled. | |
141 | deferred_stop(deferred_stop&& x) noexcept : _obj(x._obj), _stopped(std::exchange(x._stopped, true)) {} | |
142 | deferred_stop(const deferred_stop&) = delete; | |
143 | /// Move-assign another \ref deferred_stop. | |
144 | /// The current \ref deferred_stop is stopped before being assigned. | |
145 | /// And the other one's state is transferred to the current one. | |
146 | deferred_stop& operator=(deferred_stop&& x) noexcept { | |
147 | do_stop(); | |
148 | _obj = x._obj; | |
149 | _stopped = std::exchange(x._stopped, true); | |
150 | return *this; | |
151 | } | |
20effc67 TL |
152 | /// Destruct the deferred_stop object and auto-stop \c obj. |
153 | ~deferred_stop() { | |
154 | do_stop(); | |
155 | } | |
156 | /// Stop \c obj once now. | |
157 | void stop_now() noexcept { | |
158 | assert(!_stopped); | |
159 | do_stop(); | |
160 | } | |
1e59de90 TL |
161 | |
162 | /// Prevents stop() from being called when this object is destroyed. | |
163 | /// Cannot call stop_now() any more after this. | |
164 | void cancel() noexcept { | |
165 | _stopped = true; | |
166 | } | |
20effc67 TL |
167 | }; |
168 | ||
169 | template <typename Stoppable, typename Func> | |
170 | SEASTAR_CONCEPT( | |
171 | requires stoppable<Stoppable> && std::invocable<Func, Stoppable&> && | |
172 | std::is_nothrow_move_constructible_v<Stoppable> && std::is_nothrow_move_constructible_v<Func> | |
173 | ) | |
174 | inline futurize_t<std::invoke_result_t<Func, Stoppable&>> | |
175 | with_stoppable(Stoppable&& obj, Func func) noexcept { | |
176 | return do_with(std::move(obj), [func = std::move(func)] (Stoppable& obj) mutable { | |
177 | return futurize_invoke(func, obj).finally([&obj] { | |
178 | return obj.stop(); | |
179 | }); | |
180 | }); | |
181 | } | |
182 | ||
183 | } // namespace seastar |