]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/abort_source.hh
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / include / seastar / core / abort_source.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) 2017 ScyllaDB.
20 */
21
22 #pragma once
23
24 #include <seastar/util/noncopyable_function.hh>
25 #include <seastar/util/optimized_optional.hh>
26 #include <seastar/util/std-compat.hh>
27
28 #include <boost/intrusive/list.hpp>
29
30 #include <exception>
31
32 namespace bi = boost::intrusive;
33
34 namespace seastar {
35
36 /// \addtogroup fiber-module
37 /// @{
38
39 /// Exception thrown when an \ref abort_source object has been
40 /// notified by the \ref abort_source::request_abort() method.
41 class abort_requested_exception : public std::exception {
42 public:
43 virtual const char* what() const noexcept override {
44 return "abort requested";
45 }
46 };
47
48 /// Facility to communicate a cancellation request to a fiber.
49 /// Callbacks can be registered with the \c abort_source, which are called
50 /// atomically with a call to request_abort().
51 class abort_source {
52 //FIXME: Add noexcept in function type when we move to C++17
53 using subscription_callback_type = noncopyable_function<void()>;
54
55 public:
56 /// Represents a handle to the callback registered by a given fiber. Ending the
57 /// lifetime of the \c subscription will unregister the callback, if it hasn't
58 /// been invoked yet.
59 class subscription : public bi::list_base_hook<bi::link_mode<bi::auto_unlink>> {
60 friend class abort_source;
61
62 abort_source* _as = nullptr;
63 subscription_callback_type _target;
64
65 explicit subscription(abort_source& as, subscription_callback_type target)
66 : _as(&as)
67 , _target(std::move(target)) {
68 as._subscriptions->push_back(*this);
69 }
70
71 void on_abort() {
72 _target();
73 }
74
75 public:
76 subscription() = default;
77
78 subscription(subscription&& other) noexcept(std::is_nothrow_move_constructible<subscription_callback_type>::value)
79 : _as(other._as)
80 , _target(std::move(other._target)) {
81 subscription_list_type::node_algorithms::swap_nodes(other.this_ptr(), this_ptr());
82 }
83
84 subscription& operator=(subscription&& other) noexcept(std::is_nothrow_move_assignable<subscription_callback_type>::value) {
85 if (this != &other) {
86 _target = std::move(other._target);
87 _as = other._as;
88 if (is_linked()) {
89 subscription_list_type::node_algorithms::unlink(this_ptr());
90 }
91 subscription_list_type::node_algorithms::swap_nodes(other.this_ptr(), this_ptr());
92 }
93 return *this;
94 }
95
96 explicit operator bool() const noexcept {
97 return _as != nullptr;
98 }
99 };
100
101 private:
102 using subscription_list_type = bi::list<subscription, bi::constant_time_size<false>>;
103 compat::optional<subscription_list_type> _subscriptions = subscription_list_type();
104
105 public:
106 /// Delays the invocation of the callback \c f until \ref request_abort() is called.
107 /// \returns an engaged \ref optimized_optional containing a \ref subscription that can be used to control
108 /// the lifetime of the callback \c f, if \ref abort_requested() is \c false. Otherwise,
109 /// returns a disengaged \ref optimized_optional.
110 optimized_optional<subscription> subscribe(subscription_callback_type f) noexcept(std::is_nothrow_move_constructible<subscription_callback_type>::value) {
111 if (abort_requested()) {
112 return { };
113 }
114 return { subscription(*this, std::move(f)) };
115 }
116
117 /// Requests that the target operation be aborted. Current subscriptions
118 /// are invoked inline with this call, and no new ones can be registered.
119 void request_abort() {
120 _subscriptions->clear_and_dispose([] (subscription* s) { s->on_abort(); });
121 _subscriptions = { };
122 }
123
124 /// Returns whether an abort has been requested.
125 bool abort_requested() const noexcept {
126 return !_subscriptions;
127 }
128
129
130 /// Throws a \ref if cancellation has been requested.
131 void check() const {
132 if (abort_requested()) {
133 throw abort_requested_exception();
134 }
135 }
136 };
137
138 /// @}
139
140 }