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
|
// Copyright (C) 2020-2021 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() = default;
/// @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);
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) {
}
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();
}
void
IOSignalSet::add(int signum) {
impl_->add(signum);
}
void
IOSignalSet::remove(int signum) {
impl_->remove(signum);
}
} // namespace asiolink
} // namespace isc
|