1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
// Copyright (C) 2020-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <asiolink/io_service_signal.h>
#include <exceptions/exceptions.h>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio/signal_set.hpp>
#include <functional>
namespace ph = std::placeholders;
namespace isc {
namespace asiolink {
/// @brief Implementation class of IOSignalSet.
class IOSignalSetImpl : public boost::enable_shared_from_this<IOSignalSetImpl>,
public boost::noncopyable {
public:
/// @brief Constructor.
///
/// @param io_service the process IO service.
/// @param handler the signal handler.
IOSignalSetImpl(IOServicePtr io_service, IOSignalHandler handler);
/// @brief Destructor.
~IOSignalSetImpl();
/// @brief Install the callback on the IO service queue.
void install();
/// @brief Add a signal to the ASIO signal set.
///
/// @param signum the signal number.
void add(int signum);
/// @brief Remove a signal from the ASIO signal set.
///
/// @param signum the signal number.
void remove(int signum);
/// @brief Cancel the remaining installed signal handler callbacks.
void cancel();
private:
/// @brief Extends the lifetime of IOService to avoid heap-use-after-free.
IOServicePtr io_service_;
/// @brief the ASIO signal set.
boost::asio::signal_set signal_set_;
/// @brief the signal handler.
IOSignalHandler handler_;
/// @brief the callback (called on cancel or received signal).
///
/// The callback is installed on the IO service queue and calls
/// the handler if the operation was not aborted.
void callback(const boost::system::error_code& ec, int signum);
};
IOSignalSetImpl::IOSignalSetImpl(IOServicePtr io_service,
IOSignalHandler handler)
: io_service_(io_service),
signal_set_(io_service_->get_io_service()),
handler_(handler) {
}
IOSignalSetImpl::~IOSignalSetImpl() {
handler_ = IOSignalHandler();
}
void
IOSignalSetImpl::cancel() {
signal_set_.cancel();
}
void
IOSignalSetImpl::callback(const boost::system::error_code& ec, int signum) {
if (ec && ec.value() == boost::asio::error::operation_aborted) {
return;
}
install();
if (!ec && (signum > 0)) {
try {
handler_(signum);
} catch (const std::exception& ex) {
}
}
}
void
IOSignalSetImpl::install() {
signal_set_.async_wait(std::bind(&IOSignalSetImpl::callback,
shared_from_this(),
ph::_1, ph::_2));
}
void
IOSignalSetImpl::add(int signum) {
try {
signal_set_.add(signum);
} catch (const boost::system::system_error& ex) {
isc_throw(isc::Unexpected,
"Failed to add signal " << signum << ": " << ex.what());
}
}
void
IOSignalSetImpl::remove(int signum) {
try {
signal_set_.remove(signum);
} catch (const boost::system::system_error& ex) {
isc_throw(isc::Unexpected,
"Failed to remove signal " << signum << ": " << ex.what());
}
}
IOSignalSet::IOSignalSet(IOServicePtr io_service, IOSignalHandler handler) :
impl_(new IOSignalSetImpl(io_service, handler)) {
// It can throw but the error is fatal...
impl_->install();
}
IOSignalSet::~IOSignalSet() {
impl_->cancel();
}
void
IOSignalSet::add(int signum) {
impl_->add(signum);
}
void
IOSignalSet::remove(int signum) {
impl_->remove(signum);
}
} // namespace asiolink
} // namespace isc
|