-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsignals_handler.cpp
More file actions
162 lines (122 loc) · 3.86 KB
/
signals_handler.cpp
File metadata and controls
162 lines (122 loc) · 3.86 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "signals_handler.hpp"
#include <fc/log/logger.hpp>
#include <boost/bind/bind.hpp>
namespace appbase {
signals_handler::signals_handler( interrupt_request_generation_type&& _interrupt_request_generation )
: interrupt_request_generation( _interrupt_request_generation )
{
}
signals_handler::~signals_handler()
{
/*
The best moment for clearing signals is time of destroying an object then for sure we don't need signals.
Otherwise can be a situation that signals were removed, but an application gets another SIGINT and that signal won't be able to be process correctly.
*/
clear_signals();
}
void signals_handler::init( std::promise<void> after_attach_signals )
{
attach_signals();
after_attach_signals.set_value();
io_serv.run();
}
void signals_handler::generate_interrupt_request()
{
interrupt_request_generation();
}
boost::asio::io_service& signals_handler::get_io_service()
{
return io_serv;
}
void signals_handler::clear_signals()
{
if( !signals )
return;
boost::system::error_code ec;
signals->cancel( ec );
signals.reset();
if( ec.value() != 0 )
{
ilog("Error during cancelling signal: " + ec.message());
}
}
void signals_handler::handle_signal( const boost::system::error_code& err, int signal_number )
{
/// Handle signal only if it was really present (it is possible to get error_code for 'Operation cancelled' together with signal_number == 0)
if( signal_number == 0 )
return;
static uint32_t _handling_signals_counter = 0;
signals->async_wait( boost::bind( &signals_handler::handle_signal, this, boost::placeholders::_1, boost::placeholders::_2 ) );
++_handling_signals_counter;
last_signal_number = signal_number;
if( last_signal_number == SIGINT || last_signal_number == SIGTERM )
{
generate_interrupt_request();
}
}
void signals_handler::attach_signals()
{
/** To avoid killing process by broken pipe and continue regular app shutdown.
* Useful for usecase: `hived | tee hived.ilog` and pressing Ctrl+C
**/
signal(SIGPIPE, SIG_IGN);
signals = p_signal_set( new boost::asio::signal_set( io_serv, SIGINT, SIGTERM ) );
signals->async_wait( boost::bind( &signals_handler::handle_signal, this, boost::placeholders::_1, boost::placeholders::_2 ) );
}
signals_handler_wrapper::signals_handler_wrapper( signals_handler::interrupt_request_generation_type&& _interrupt_request_generation )
: handler( std::move( _interrupt_request_generation ) ), io_wrapper_( handler.get_io_service() )
{
}
void signals_handler_wrapper::init()
{
std::future<void> after_attach_signals_future = after_attach_signals_promise.get_future();
handler_thread = std::make_unique<std::thread>(
[this]()
{
handler.init( std::move( after_attach_signals_promise ) );
}
);
after_attach_signals_future.get();
block_signals();
initialized = true;
}
void signals_handler_wrapper::wait4stop( bool log )
{
if( initialized )
{
if( handler_thread->joinable() )
{
if( log ) ilog("Clearing signals");
handler.clear_signals();
if( log ) ilog("Signals have been cleared");
if( log ) ilog("Stopping IO service");
get_io_service().stop();
if( log ) ilog("IO service has been stopped");
if( log ) ilog("Joining handler's thread");
handler_thread->join();
if( log ) ilog("Handler's thread has been joined");
}
}
thread_closed = true;
}
bool signals_handler_wrapper::is_thread_closed()
{
return thread_closed;
}
void signals_handler_wrapper::block_signals()
{
sigset_t blockset;
sigemptyset(&blockset);
sigaddset(&blockset, SIGINT);
sigaddset(&blockset, SIGTERM);
sigprocmask(SIG_BLOCK, &blockset, NULL);
}
boost::asio::io_service& signals_handler_wrapper::get_io_service()
{
return handler.get_io_service();
}
io_service_wrapper& signals_handler_wrapper::get_io_service_wrapper()
{
return io_wrapper_;
}
}