31 static bool s_exit_handler_print =
true;
32 static bool s_exit_handler_backtrace =
false;
33 static bool s_exit_handler_sleep_on_fatal =
false;
35 template<
class T>
union func_cast {
38 explicit func_cast(T t) { fun = t; }
39 explicit func_cast(
void* t) { ptr = t; }
63 typedef std::map<int, sig_handler_t>
SigMap;
76 void install(
int num,
const std::string& name,
struct sigaction& action);
80 int unsubscribe(
int signum,
void* user_context);
82 void back_trace(
int );
84 static void handler(
int signum, siginfo_t *
info,
void * );
97 static std::unique_ptr<implementation> imp;
99 imp = std::make_unique<implementation>();
106 struct sigaction new_action;
107 sigemptyset(&new_action.sa_mask);
108 new_action.sa_handler = 0;
109 new_action.sa_sigaction = handler;
110 new_action.sa_flags = SA_SIGINFO;
112 install(SIGILL,
"SIGILL", new_action);
113 install(SIGINT,
"SIGINT", new_action);
114 install(SIGTERM,
"SIGTERM", new_action);
115 install(SIGHUP,
"SIGHUP", new_action);
117 install(SIGQUIT,
"SIGQUIT", new_action);
118 install(SIGBUS,
"SIGBUS", new_action);
119 install(SIGXCPU,
"SIGXCPU", new_action);
120 sigaddset(&new_action.sa_mask,SIGSEGV);
121 sigaddset(&new_action.sa_mask,SIGABRT);
122 sigaddset(&new_action.sa_mask,SIGFPE);
123 install(SIGABRT,
"SIGABRT", new_action);
124 install(SIGFPE,
"SIGFPE", new_action);
125 install(SIGSEGV,
"SIGSEGV", new_action);
130 if ( m_map.empty() ) {
133 auto ihandler = m_map.find(signum);
134 if ( ihandler == m_map.end() ) {
136 struct sigaction new_action;
137 sigemptyset(&new_action.sa_mask);
138 new_action.sa_handler = 0;
140 new_action.sa_flags = SA_SIGINFO;
141 ::snprintf(text,
sizeof(text),
"%08X",signum);
142 install(signum, text, new_action);
143 ihandler = m_map.find(signum);
145 if ( ihandler != m_map.end() ) {
147 ihandler->second.user_handlers.emplace_back(entry);
155 auto ihandler = m_map.find(signum);
156 if ( ihandler != m_map.end() ) {
157 auto & handlers = ihandler->second.user_handlers;
158 for(
auto it = handlers.begin(); it != handlers.end(); ++it ) {
159 if ( it->user_context == user_context ) {
170 if ( s_exit_handler_backtrace ) {
173 int bt_size = ::backtrace(bt,
sizeof(bt) /
sizeof(
void *));
174 size_t len = ::snprintf(text,
sizeof(text),
"\n[INFO] (ExitSignalHandler) %s\n",
175 "---------------------- Backtrace ----------------------\n");
176 text[
sizeof(text)-2] =
'\n';
177 text[
sizeof(text)-1] = 0;
178 ::write(STDERR_FILENO, text, len);
179 len = ::snprintf(text,
sizeof(text),
"[INFO] Number of elements in backtrace: %d\n", bt_size);
180 text[
sizeof(text)-2] =
'\n';
181 text[
sizeof(text)-1] = 0;
182 ::write(STDERR_FILENO, text, len);
183 ::backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
184 for (
int i = 0; i < bt_size; i++) {
185 len = ::snprintf(text,
sizeof(text),
"[INFO] (SignalHandler) %02d --> %p\n", i, bt[i]);
186 text[
sizeof(text)-2] =
'\n';
187 text[
sizeof(text)-1] = 0;
188 ::write(STDERR_FILENO, text, len);
195 auto& action_entry = m_map[num];
196 int res = ::sigaction (num, &action, &action_entry.old_action);
199 auto len = ::snprintf(text,
sizeof(text),
"Failed to install exit handler for %s", name.c_str());
200 text[
sizeof(text)-2] =
'\n';
201 text[
sizeof(text)-1] = 0;
202 ::write(STDERR_FILENO, text, len);
205 action_entry.handler_action = action;
206 action_entry.name = name;
211 SigMap& m = instance().m_map;
212 SigMap::iterator iter_handler = m.find(signum);
213 if ( iter_handler != m.end() ) {
214 auto hdlr = iter_handler->second.old_action.sa_handler;
215 func_cast<void (*)(int)> dsc0(hdlr);
216 func_cast<void (*)(int,siginfo_t*,
void*)> dsc(dsc0.ptr);
218 if ( s_exit_handler_print ) {{
220 size_t len = ::snprintf(text,
sizeof(text),
221 "[FATAL] (SignalHandler) Handle signal: %d [%s] Old action:%p Mem:%p Code:%08X\n",
222 signum,iter_handler->second.name.c_str(),dsc.ptr,
info->si_addr,
info->si_code);
223 text[
sizeof(text)-2] =
'\n';
224 text[
sizeof(text)-1] = 0;
225 ::write(STDERR_FILENO,text,len);
227 if ( s_exit_handler_sleep_on_fatal ) {
228 bool _s_sleep =
true;
229 len = ::snprintf(text,
sizeof(text),
230 "[FATAL] (SignalHandler) Sleeping for debugging.... %s\n",
231 _s_sleep ?
"YES" :
"NO");
232 text[
sizeof(text)-2] =
'\n';
233 text[
sizeof(text)-1] = 0;
234 ::write(STDERR_FILENO,text,len);
235 while ( _s_sleep ) ::usleep(100000);
238 if ( !iter_handler->second.user_handlers.empty() ) {
239 auto& handlers = iter_handler->second.user_handlers;
240 for(
auto ih = handlers.rbegin(); ih != handlers.rend(); ++ih ) {
241 if ( ih->user_handler ) {
242 bool ret = (*(ih->user_handler))(ih->user_context, signum);
249 auto& entry = iter_handler->second.old_action;
250 if ( entry.sa_handler )
251 (*entry.sa_handler)(signum);
252 else if ( entry.sa_sigaction )
253 (*entry.sa_sigaction)(signum,
info, ptr);
256 if ( signum == SIGSEGV || signum == SIGBUS || signum == SIGILL || signum == SIGABRT ) {
257 instance().back_trace(signum);
259 else if (
info->si_signo == SIGSEGV ||
info->si_signo == SIGBUS ||
info->si_signo == SIGILL ||
info->si_signo == SIGABRT ) {
260 instance().back_trace(
info->si_signo);
263 if ( signum == SIGINT || signum == SIGHUP || signum == SIGFPE || signum == SIGPIPE ) {
264 if ( dsc.fun && (dsc0.fun != SIG_IGN) )
265 dsc.fun(signum,
info, ptr);
266 else if ( signum == SIGHUP )
269 else if ( signum == SIGSEGV && hdlr && hdlr != SIG_IGN && hdlr != SIG_DFL ) {
272 else if ( hdlr && hdlr != SIG_IGN && dsc.fun ) {
273 dsc.fun(signum,
info, ptr);
275 else if ( hdlr == SIG_DFL ) {
292 auto& imp = implementation::instance();
293 struct sigaction old_action { };
294 printout(INFO,
"SignalHandler",
"++ Re-apply signal handlers");
295 for(
const auto& e : imp.m_map ) {
296 ::sigaction (e.first, &e.second.handler_action, &old_action);
297 printout(DEBUG,
"SignalHandler",
298 "++ Re-apply signal handler for %-10s [%3ld entries]",
299 e.second.name.c_str(), e.second.user_handlers.size());
305 return implementation::instance().subscribe(sig_num, param, handler) == 1;