Bitcoin Core
32.1.0
P2P Digital Currency
Toggle main menu visibility
Loading...
Searching...
No Matches
src
util
btcsignals.h
Go to the documentation of this file.
1
// Copyright (c) The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_UTIL_BTCSIGNALS_H
6
#define BITCOIN_UTIL_BTCSIGNALS_H
7
8
#include <
sync.h
>
9
10
#include <algorithm>
11
#include <atomic>
12
#include <functional>
13
#include <memory>
14
#include <optional>
15
#include <type_traits>
16
#include <utility>
17
#include <vector>
18
30
31
namespace
btcsignals
{
32
34
class
null_value
35
{
36
public
:
37
using
result_type
= void;
38
};
39
41
class
any_of
42
{
43
public
:
44
// This is the only supported combiner with a non-void return type. As
45
// such, its behavior is embedded into the signal functor.
46
using
result_type
= bool;
47
};
48
49
template
<
typename
Signature,
typename
Combiner = null_value>
50
class
signal
;
51
52
/*
53
* State object representing the liveness of a registered callback.
54
* signal::connect() returns an enabled connection which can be held and
55
* disabled in the future.
56
*/
57
class
connection
58
{
59
template
<
typename
Signature,
typename
Combiner>
60
friend
class
signal
;
64
class
liveness
65
{
66
friend
class
connection
;
67
std::atomic_bool
m_connected
{
true
};
68
69
void
disconnect
() {
m_connected
.store(
false
); }
70
public
:
71
bool
connected
()
const
{
return
m_connected
.load(); }
72
};
73
77
std::shared_ptr<liveness>
m_state
{};
78
82
explicit
connection
(std::shared_ptr<liveness>&& state) :
m_state
{
std
::move(state)}{}
83
84
public
:
88
constexpr
connection
() noexcept = default;
89
100
void
disconnect
()
101
{
102
if
(
m_state
) {
103
m_state
->disconnect();
104
}
105
}
106
111
bool
connected
()
const
112
{
113
return
m_state
&&
m_state
->connected();
114
}
115
};
116
117
/*
118
* RAII-style connection management
119
*/
120
class
scoped_connection
121
{
122
connection
m_conn
;
123
124
public
:
125
explicit
scoped_connection
(
connection
rhs) noexcept :
m_conn
{std::move(rhs)} {}
126
127
scoped_connection
(
scoped_connection
&&) noexcept = default;
128
132
scoped_connection
& operator=(
scoped_connection
&&) = delete;
133
scoped_connection
& operator=(const
scoped_connection
&) = delete;
134
scoped_connection
(const
scoped_connection
&) = delete;
135
136
void
disconnect
()
137
{
138
m_conn
.
disconnect
();
139
}
140
141
~scoped_connection
()
142
{
143
disconnect
();
144
}
145
};
146
147
/*
148
* Functor for calling zero or more connected callbacks
149
*/
150
template
<
typename
Signature,
typename
Combiner>
151
class
signal
152
{
153
using
function_type
= std::function<Signature>;
154
155
/*
156
* Helper struct for maintaining a callback and its associated connection liveness
157
*/
158
struct
connection_holder
:
connection::liveness
{
159
template
<
typename
Callable>
160
connection_holder
(Callable&& callback) :
m_callback
{
std
::forward<Callable>(callback)}
161
{
162
}
163
164
const
function_type
m_callback
;
165
};
166
167
mutable
Mutex
m_mutex
;
168
169
std::vector<std::shared_ptr<connection_holder>> m_connections
GUARDED_BY
(
m_mutex
){};
170
171
public
:
172
using
result_type
= Combiner::result_type;
173
174
constexpr
signal
() noexcept = default;
175
~
signal
() = default;
176
177
/*
178
* For simplicity, disable all moving/copying/assigning.
179
*/
180
signal
(const
signal
&) = delete;
181
signal
(
signal
&&) = delete;
182
signal
& operator=(const
signal
&) = delete;
183
signal
& operator=(
signal
&&) = delete;
184
185
/*
186
* Execute all enabled callbacks for the signal. Rather than allowing for
187
* custom combiners, the behavior of any_of is hard-coded here.
188
*
189
* Callbacks which return void require special handling.
190
*
191
* In order to avoid locking during the callbacks, the list of callbacks is
192
* cached before they are called. This allows a callback to call connect(),
193
* but the newly connected callback will not be run during the current
194
* signal invocation.
195
*
196
* Note that the parameters are accepted as universal references, though
197
* they are not perfectly forwarded as that could cause a use-after-move if
198
* more than one callback is enabled.
199
*/
200
template <typename... Args>
201
[[nodiscard]]
result_type
operator()(Args&&...
args
) const
EXCLUSIVE_LOCKS_REQUIRED
(!
m_mutex
)
202
{
203
std::vector<std::shared_ptr<connection_holder>> connections;
204
{
205
LOCK
(
m_mutex
);
206
connections = m_connections;
207
}
208
if
constexpr
(std::is_void_v<result_type>) {
209
static_assert
(std::is_same_v<result_type, typename function_type::result_type>,
210
"Callback result type must be equal to the combiner result type (void)."
);
211
for
(
const
auto
&
connection
: connections) {
212
if
(
connection
->
connected
()) {
213
connection
->m_callback(
args
...);
214
}
215
}
216
}
else
{
217
static_assert
(std::is_same_v<Combiner, any_of>,
218
"only the any_of combiner is supported and hard-coded into this functor."
);
219
static_assert
(std::is_same_v<result_type, typename function_type::result_type>,
220
"Callback result type must be equal to the combiner result type (bool)."
);
221
result_type
ret
{
false
};
222
for
(
const
auto
&
connection
: connections) {
223
if
(
connection
->
connected
()) {
224
ret
|=
connection
->m_callback(
args
...);
225
}
226
}
227
return
ret
;
228
}
229
}
230
231
/*
232
* Connect a new callback to the signal. A forwarding callable accepts
233
* anything that can be stored in a std::function.
234
*/
235
template
<
typename
Callable>
236
connection
connect
(Callable&& func)
EXCLUSIVE_LOCKS_REQUIRED
(!
m_mutex
)
237
{
238
LOCK
(
m_mutex
);
239
240
// Garbage-collect disconnected connections to prevent unbounded growth
241
std::erase_if(m_connections, [](
const
auto
& holder) {
return
!holder->connected(); });
242
243
const
auto
& entry = m_connections.emplace_back(std::make_shared<connection_holder>(std::forward<Callable>(func)));
244
return
connection
(entry);
245
}
246
247
/*
248
* Returns true if there are no enabled callbacks
249
*/
250
[[nodiscard]]
bool
empty
() const
EXCLUSIVE_LOCKS_REQUIRED
(!
m_mutex
)
251
{
252
LOCK
(
m_mutex
);
253
return
std::ranges::none_of(m_connections, [](
const
auto
& holder) {
254
return
holder->connected();
255
});
256
}
257
};
258
259
}
// namespace btcsignals
260
261
#endif
// BITCOIN_UTIL_BTCSIGNALS_H
ret
int ret
Definition
bitcoin-cli.cpp:1691
args
ArgsManager & args
Definition
bitcoind.cpp:280
btcsignals::any_of
A combiner, which checks if at least one callback returned true.
Definition
btcsignals.h:42
btcsignals::any_of::result_type
bool result_type
Definition
btcsignals.h:46
btcsignals::connection::liveness
Track liveness.
Definition
btcsignals.h:65
btcsignals::connection::liveness::disconnect
void disconnect()
Definition
btcsignals.h:69
btcsignals::connection::liveness::connected
bool connected() const
Definition
btcsignals.h:71
btcsignals::connection::liveness::m_connected
std::atomic_bool m_connected
Definition
btcsignals.h:67
btcsignals::connection::liveness::connection
friend class connection
Definition
btcsignals.h:66
btcsignals::connection
Definition
btcsignals.h:58
btcsignals::connection::disconnect
void disconnect()
If a callback is associated with this connection, prevent it from being called in the future.
Definition
btcsignals.h:100
btcsignals::connection::m_state
std::shared_ptr< liveness > m_state
connections have shared_ptr-like copy and move semantics.
Definition
btcsignals.h:77
btcsignals::connection::connection
connection(std::shared_ptr< liveness > &&state)
Only a signal can create an enabled connection.
Definition
btcsignals.h:82
btcsignals::connection::signal
friend class signal
Definition
btcsignals.h:60
btcsignals::connection::connection
constexpr connection() noexcept=default
The default constructor creates a connection with no associated signal.
btcsignals::connection::connected
bool connected() const
Returns true if this connection was created by a signal and has not been disabled.
Definition
btcsignals.h:111
btcsignals::null_value
The default combiner, which only returns void.
Definition
btcsignals.h:35
btcsignals::null_value::result_type
void result_type
Definition
btcsignals.h:37
btcsignals::scoped_connection::scoped_connection
scoped_connection(scoped_connection &&) noexcept=default
btcsignals::scoped_connection::disconnect
void disconnect()
Definition
btcsignals.h:136
btcsignals::scoped_connection::scoped_connection
scoped_connection(connection rhs) noexcept
Definition
btcsignals.h:125
btcsignals::scoped_connection::~scoped_connection
~scoped_connection()
Definition
btcsignals.h:141
btcsignals::scoped_connection::m_conn
connection m_conn
Definition
btcsignals.h:122
btcsignals::signal
Definition
btcsignals.h:152
btcsignals::signal::function_type
std::function< Signature > function_type
Definition
btcsignals.h:153
btcsignals::signal::GUARDED_BY
std::vector< std::shared_ptr< connection_holder > > m_connections GUARDED_BY(m_mutex)
Definition
btcsignals.h:169
btcsignals::signal::connect
connection connect(Callable &&func) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Definition
btcsignals.h:236
btcsignals::signal::result_type
Combiner::result_type result_type
Definition
btcsignals.h:172
btcsignals::signal::m_mutex
Mutex m_mutex
Definition
btcsignals.h:167
btcsignals::signal::signal
constexpr signal() noexcept=default
btcsignals::signal::empty
bool empty() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Definition
btcsignals.h:250
btcsignals
btcsignals is a simple mechanism for signaling events to multiple subscribers.
Definition
handler.h:11
std
Definition
transaction.h:420
btcsignals::signal::connection_holder::m_callback
const function_type m_callback
Definition
btcsignals.h:164
btcsignals::signal::connection_holder::connection_holder
connection_holder(Callable &&callback)
Definition
btcsignals.h:160
sync.h
Mutex
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition
sync.h:131
LOCK
#define LOCK(cs)
Definition
sync.h:268
EXCLUSIVE_LOCKS_REQUIRED
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition
threadsafety.h:49
Generated on
for Bitcoin Core by
1.18.0