]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/util/closeable.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / util / closeable.hh
CommitLineData
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
33namespace seastar {
34
35SEASTAR_CONCEPT(
36template <typename Object>
37concept 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.
49template <typename Object>
50SEASTAR_CONCEPT( requires closeable<Object> )
1e59de90
TL
51class [[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 }
61public:
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
95template <typename Closeable, typename Func>
96SEASTAR_CONCEPT(
97requires closeable<Closeable> && std::invocable<Func, Closeable&> &&
98 std::is_nothrow_move_constructible_v<Closeable> && std::is_nothrow_move_constructible_v<Func>
99)
100inline futurize_t<std::invoke_result_t<Func, Closeable&>>
101with_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
109SEASTAR_CONCEPT(
110template <typename Object>
111concept 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.
123template <typename Object>
124SEASTAR_CONCEPT( requires stoppable<Object> )
1e59de90
TL
125class [[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 }
135public:
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
169template <typename Stoppable, typename Func>
170SEASTAR_CONCEPT(
171requires stoppable<Stoppable> && std::invocable<Func, Stoppable&> &&
172 std::is_nothrow_move_constructible_v<Stoppable> && std::is_nothrow_move_constructible_v<Func>
173)
174inline futurize_t<std::invoke_result_t<Func, Stoppable&>>
175with_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